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