]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / UsbHcMem.c
... / ...
CommitLineData
1/** @file\r
2\r
3 The routine procedure for uhci memory allocate/free.\r
4\r
5Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "Uhci.h"\r
11\r
12/**\r
13 Allocate a block of memory to be used by the buffer pool.\r
14\r
15 @param Pool The buffer pool to allocate memory for.\r
16 @param Pages How many pages to allocate.\r
17\r
18 @return The allocated memory block or NULL if failed.\r
19\r
20**/\r
21USBHC_MEM_BLOCK *\r
22UsbHcAllocMemBlock (\r
23 IN USBHC_MEM_POOL *Pool,\r
24 IN UINTN Pages\r
25 )\r
26{\r
27 USBHC_MEM_BLOCK *Block;\r
28 EFI_PCI_IO_PROTOCOL *PciIo;\r
29 VOID *BufHost;\r
30 VOID *Mapping;\r
31 EFI_PHYSICAL_ADDRESS MappedAddr;\r
32 UINTN Bytes;\r
33 EFI_STATUS Status;\r
34\r
35 PciIo = Pool->PciIo;\r
36\r
37 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
38 if (Block == NULL) {\r
39 return NULL;\r
40 }\r
41\r
42 //\r
43 // each bit in the bit array represents USBHC_MEM_UNIT\r
44 // bytes of memory in the memory block.\r
45 //\r
46 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
47\r
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
49 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
50 Block->Bits = AllocateZeroPool (Block->BitsLen);\r
51\r
52 if (Block->Bits == NULL) {\r
53 gBS->FreePool (Block);\r
54 return NULL;\r
55 }\r
56\r
57 //\r
58 // Allocate the number of Pages of memory, then map it for\r
59 // bus master read and write.\r
60 //\r
61 Status = PciIo->AllocateBuffer (\r
62 PciIo,\r
63 AllocateAnyPages,\r
64 EfiBootServicesData,\r
65 Pages,\r
66 &BufHost,\r
67 0\r
68 );\r
69\r
70 if (EFI_ERROR (Status)) {\r
71 goto FREE_BITARRAY;\r
72 }\r
73\r
74 Bytes = EFI_PAGES_TO_SIZE (Pages);\r
75 Status = PciIo->Map (\r
76 PciIo,\r
77 EfiPciIoOperationBusMasterCommonBuffer,\r
78 BufHost,\r
79 &Bytes,\r
80 &MappedAddr,\r
81 &Mapping\r
82 );\r
83\r
84 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
85 goto FREE_BUFFER;\r
86 }\r
87\r
88 //\r
89 // Check whether the data structure used by the host controller\r
90 // should be restricted into the same 4G\r
91 //\r
92 if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
93 PciIo->Unmap (PciIo, Mapping);\r
94 goto FREE_BUFFER;\r
95 }\r
96\r
97 Block->BufHost = BufHost;\r
98 Block->Buf = (UINT8 *)((UINTN)MappedAddr);\r
99 Block->Mapping = Mapping;\r
100\r
101 return Block;\r
102\r
103FREE_BUFFER:\r
104 PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
105\r
106FREE_BITARRAY:\r
107 gBS->FreePool (Block->Bits);\r
108 gBS->FreePool (Block);\r
109 return NULL;\r
110}\r
111\r
112/**\r
113 Free the memory block from the memory pool.\r
114\r
115 @param Pool The memory pool to free the block from.\r
116 @param Block The memory block to free.\r
117\r
118**/\r
119VOID\r
120UsbHcFreeMemBlock (\r
121 IN USBHC_MEM_POOL *Pool,\r
122 IN USBHC_MEM_BLOCK *Block\r
123 )\r
124{\r
125 EFI_PCI_IO_PROTOCOL *PciIo;\r
126\r
127 ASSERT ((Pool != NULL) && (Block != NULL));\r
128\r
129 PciIo = Pool->PciIo;\r
130\r
131 //\r
132 // Unmap the common buffer then free the structures\r
133 //\r
134 PciIo->Unmap (PciIo, Block->Mapping);\r
135 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
136\r
137 gBS->FreePool (Block->Bits);\r
138 gBS->FreePool (Block);\r
139}\r
140\r
141/**\r
142 Alloc some memory from the block.\r
143\r
144 @param Block The memory block to allocate memory from.\r
145 @param Units Number of memory units to allocate.\r
146\r
147 @return EFI_SUCCESS The needed memory is allocated.\r
148 @return EFI_NOT_FOUND Can't find the free memory.\r
149\r
150**/\r
151VOID *\r
152UsbHcAllocMemFromBlock (\r
153 IN USBHC_MEM_BLOCK *Block,\r
154 IN UINTN Units\r
155 )\r
156{\r
157 UINTN Byte;\r
158 UINT8 Bit;\r
159 UINTN StartByte;\r
160 UINT8 StartBit;\r
161 UINTN Available;\r
162 UINTN Count;\r
163\r
164 ASSERT ((Block != 0) && (Units != 0));\r
165\r
166 StartByte = 0;\r
167 StartBit = 0;\r
168 Available = 0;\r
169\r
170 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
171 //\r
172 // If current bit is zero, the corresponding memory unit is\r
173 // available, otherwise we need to restart our searching.\r
174 // Available counts the consective number of zero bit.\r
175 //\r
176 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
177 Available++;\r
178\r
179 if (Available >= Units) {\r
180 break;\r
181 }\r
182\r
183 NEXT_BIT (Byte, Bit);\r
184 } else {\r
185 NEXT_BIT (Byte, Bit);\r
186\r
187 Available = 0;\r
188 StartByte = Byte;\r
189 StartBit = Bit;\r
190 }\r
191 }\r
192\r
193 if (Available < Units) {\r
194 return NULL;\r
195 }\r
196\r
197 //\r
198 // Mark the memory as allocated\r
199 //\r
200 Byte = StartByte;\r
201 Bit = StartBit;\r
202\r
203 for (Count = 0; Count < Units; Count++) {\r
204 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
205\r
206 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)USB_HC_BIT (Bit));\r
207 NEXT_BIT (Byte, Bit);\r
208 }\r
209\r
210 return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
211}\r
212\r
213/**\r
214 Calculate the corresponding pci bus address according to the Mem parameter.\r
215\r
216 @param Pool The memory pool of the host controller.\r
217 @param Mem The pointer to host memory.\r
218 @param Size The size of the memory region.\r
219\r
220 @return the pci memory address\r
221**/\r
222EFI_PHYSICAL_ADDRESS\r
223UsbHcGetPciAddressForHostMem (\r
224 IN USBHC_MEM_POOL *Pool,\r
225 IN VOID *Mem,\r
226 IN UINTN Size\r
227 )\r
228{\r
229 USBHC_MEM_BLOCK *Head;\r
230 USBHC_MEM_BLOCK *Block;\r
231 UINTN AllocSize;\r
232 EFI_PHYSICAL_ADDRESS PhyAddr;\r
233 UINTN Offset;\r
234\r
235 Head = Pool->Head;\r
236 AllocSize = USBHC_MEM_ROUND (Size);\r
237\r
238 if (Mem == NULL) {\r
239 return 0;\r
240 }\r
241\r
242 for (Block = Head; Block != NULL; Block = Block->Next) {\r
243 //\r
244 // scan the memory block list for the memory block that\r
245 // completely contains the allocated memory.\r
246 //\r
247 if ((Block->BufHost <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
248 break;\r
249 }\r
250 }\r
251\r
252 ASSERT ((Block != NULL));\r
253 //\r
254 // calculate the pci memory address for host memory address.\r
255 //\r
256 Offset = (UINT8 *)Mem - Block->BufHost;\r
257 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->Buf + Offset);\r
258 return PhyAddr;\r
259}\r
260\r
261/**\r
262 Insert the memory block to the pool's list of the blocks.\r
263\r
264 @param Head The head of the memory pool's block list.\r
265 @param Block The memory block to insert.\r
266\r
267**/\r
268VOID\r
269UsbHcInsertMemBlockToPool (\r
270 IN USBHC_MEM_BLOCK *Head,\r
271 IN USBHC_MEM_BLOCK *Block\r
272 )\r
273{\r
274 ASSERT ((Head != NULL) && (Block != NULL));\r
275 Block->Next = Head->Next;\r
276 Head->Next = Block;\r
277}\r
278\r
279/**\r
280 Is the memory block empty?\r
281\r
282 @param Block The memory block to check.\r
283\r
284 @return TRUE The memory block is empty.\r
285 @return FALSE The memory block isn't empty.\r
286\r
287**/\r
288BOOLEAN\r
289UsbHcIsMemBlockEmpty (\r
290 IN USBHC_MEM_BLOCK *Block\r
291 )\r
292{\r
293 UINTN Index;\r
294\r
295 for (Index = 0; Index < Block->BitsLen; Index++) {\r
296 if (Block->Bits[Index] != 0) {\r
297 return FALSE;\r
298 }\r
299 }\r
300\r
301 return TRUE;\r
302}\r
303\r
304/**\r
305 Unlink the memory block from the pool's list.\r
306\r
307 @param Head The block list head of the memory's pool.\r
308 @param BlockToUnlink The memory block to unlink.\r
309\r
310**/\r
311VOID\r
312UsbHcUnlinkMemBlock (\r
313 IN USBHC_MEM_BLOCK *Head,\r
314 IN USBHC_MEM_BLOCK *BlockToUnlink\r
315 )\r
316{\r
317 USBHC_MEM_BLOCK *Block;\r
318\r
319 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
320\r
321 for (Block = Head; Block != NULL; Block = Block->Next) {\r
322 if (Block->Next == BlockToUnlink) {\r
323 Block->Next = BlockToUnlink->Next;\r
324 BlockToUnlink->Next = NULL;\r
325 break;\r
326 }\r
327 }\r
328}\r
329\r
330/**\r
331 Initialize the memory management pool for the host controller.\r
332\r
333 @param PciIo The PciIo that can be used to access the host controller.\r
334 @param Check4G Whether the host controller requires allocated memory\r
335 from one 4G address space.\r
336 @param Which4G The 4G memory area each memory allocated should be from.\r
337\r
338 @return EFI_SUCCESS The memory pool is initialized.\r
339 @return EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
340\r
341**/\r
342USBHC_MEM_POOL *\r
343UsbHcInitMemPool (\r
344 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
345 IN BOOLEAN Check4G,\r
346 IN UINT32 Which4G\r
347 )\r
348{\r
349 USBHC_MEM_POOL *Pool;\r
350\r
351 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
352\r
353 if (Pool == NULL) {\r
354 return Pool;\r
355 }\r
356\r
357 Pool->PciIo = PciIo;\r
358 Pool->Check4G = Check4G;\r
359 Pool->Which4G = Which4G;\r
360 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
361\r
362 if (Pool->Head == NULL) {\r
363 gBS->FreePool (Pool);\r
364 Pool = NULL;\r
365 }\r
366\r
367 return Pool;\r
368}\r
369\r
370/**\r
371 Release the memory management pool.\r
372\r
373 @param Pool The USB memory pool to free.\r
374\r
375 @return EFI_SUCCESS The memory pool is freed.\r
376 @return EFI_DEVICE_ERROR Failed to free the memory pool.\r
377\r
378**/\r
379EFI_STATUS\r
380UsbHcFreeMemPool (\r
381 IN USBHC_MEM_POOL *Pool\r
382 )\r
383{\r
384 USBHC_MEM_BLOCK *Block;\r
385\r
386 ASSERT (Pool->Head != NULL);\r
387\r
388 //\r
389 // Unlink all the memory blocks from the pool, then free them.\r
390 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
391 // first block.\r
392 //\r
393 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
394 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
395 UsbHcFreeMemBlock (Pool, Block);\r
396 }\r
397\r
398 UsbHcFreeMemBlock (Pool, Pool->Head);\r
399 gBS->FreePool (Pool);\r
400 return EFI_SUCCESS;\r
401}\r
402\r
403/**\r
404 Allocate some memory from the host controller's memory pool\r
405 which can be used to communicate with host controller.\r
406\r
407 @param Pool The host controller's memory pool.\r
408 @param Size Size of the memory to allocate.\r
409\r
410 @return The allocated memory or NULL.\r
411\r
412**/\r
413VOID *\r
414UsbHcAllocateMem (\r
415 IN USBHC_MEM_POOL *Pool,\r
416 IN UINTN Size\r
417 )\r
418{\r
419 USBHC_MEM_BLOCK *Head;\r
420 USBHC_MEM_BLOCK *Block;\r
421 USBHC_MEM_BLOCK *NewBlock;\r
422 VOID *Mem;\r
423 UINTN AllocSize;\r
424 UINTN Pages;\r
425\r
426 Mem = NULL;\r
427 AllocSize = USBHC_MEM_ROUND (Size);\r
428 Head = Pool->Head;\r
429 ASSERT (Head != NULL);\r
430\r
431 //\r
432 // First check whether current memory blocks can satisfy the allocation.\r
433 //\r
434 for (Block = Head; Block != NULL; Block = Block->Next) {\r
435 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
436\r
437 if (Mem != NULL) {\r
438 ZeroMem (Mem, Size);\r
439 break;\r
440 }\r
441 }\r
442\r
443 if (Mem != NULL) {\r
444 return Mem;\r
445 }\r
446\r
447 //\r
448 // Create a new memory block if there is not enough memory\r
449 // in the pool. If the allocation size is larger than the\r
450 // default page number, just allocate a large enough memory\r
451 // block. Otherwise allocate default pages.\r
452 //\r
453 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
454 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
455 } else {\r
456 Pages = USBHC_MEM_DEFAULT_PAGES;\r
457 }\r
458\r
459 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
460\r
461 if (NewBlock == NULL) {\r
462 DEBUG ((DEBUG_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
463 return NULL;\r
464 }\r
465\r
466 //\r
467 // Add the new memory block to the pool, then allocate memory from it\r
468 //\r
469 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
470 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
471\r
472 if (Mem != NULL) {\r
473 ZeroMem (Mem, Size);\r
474 }\r
475\r
476 return Mem;\r
477}\r
478\r
479/**\r
480 Free the allocated memory back to the memory pool.\r
481\r
482 @param Pool The memory pool of the host controller.\r
483 @param Mem The memory to free.\r
484 @param Size The size of the memory to free.\r
485\r
486**/\r
487VOID\r
488UsbHcFreeMem (\r
489 IN USBHC_MEM_POOL *Pool,\r
490 IN VOID *Mem,\r
491 IN UINTN Size\r
492 )\r
493{\r
494 USBHC_MEM_BLOCK *Head;\r
495 USBHC_MEM_BLOCK *Block;\r
496 UINT8 *ToFree;\r
497 UINTN AllocSize;\r
498 UINTN Byte;\r
499 UINTN Bit;\r
500 UINTN Count;\r
501\r
502 Head = Pool->Head;\r
503 AllocSize = USBHC_MEM_ROUND (Size);\r
504 ToFree = (UINT8 *)Mem;\r
505\r
506 for (Block = Head; Block != NULL; Block = Block->Next) {\r
507 //\r
508 // scan the memory block list for the memory block that\r
509 // completely contains the memory to free.\r
510 //\r
511 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
512 //\r
513 // compute the start byte and bit in the bit array\r
514 //\r
515 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
516 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
517\r
518 //\r
519 // reset associated bits in bit array\r
520 //\r
521 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
522 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
523\r
524 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
525 NEXT_BIT (Byte, Bit);\r
526 }\r
527\r
528 break;\r
529 }\r
530 }\r
531\r
532 //\r
533 // If Block == NULL, it means that the current memory isn't\r
534 // in the host controller's pool. This is critical because\r
535 // the caller has passed in a wrong memory point\r
536 //\r
537 ASSERT (Block != NULL);\r
538\r
539 //\r
540 // Release the current memory block if it is empty and not the head\r
541 //\r
542 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
543 UsbHcUnlinkMemBlock (Head, Block);\r
544 UsbHcFreeMemBlock (Pool, Block);\r
545 }\r
546\r
547 return;\r
548}\r