]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c
Typo corrected
[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
913cb9dc 5Copyright (c) 2007, Intel Corporation\r
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
78c2ffb5 127 @return None.\r
913cb9dc 128\r
129**/\r
913cb9dc 130VOID\r
131UsbHcFreeMemBlock (\r
132 IN USBHC_MEM_POOL *Pool,\r
133 IN USBHC_MEM_BLOCK *Block\r
134 )\r
135{\r
136 EFI_PCI_IO_PROTOCOL *PciIo;\r
137\r
138 ASSERT ((Pool != NULL) && (Block != NULL));\r
139\r
140 PciIo = Pool->PciIo;\r
141\r
142 //\r
143 // Unmap the common buffer then free the structures\r
144 //\r
145 PciIo->Unmap (PciIo, Block->Mapping);\r
146 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
147\r
148 gBS->FreePool (Block->Bits);\r
149 gBS->FreePool (Block);\r
150}\r
151\r
152\r
153/**\r
78c2ffb5 154 Alloc some memory from the block.\r
913cb9dc 155\r
78c2ffb5 156 @param Block The memory block to allocate memory from.\r
157 @param Units Number of memory units to allocate.\r
913cb9dc 158\r
78c2ffb5 159 @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
160 the return value is NULL.\r
913cb9dc 161\r
162**/\r
913cb9dc 163VOID *\r
164UsbHcAllocMemFromBlock (\r
165 IN USBHC_MEM_BLOCK *Block,\r
166 IN UINTN Units\r
167 )\r
168{\r
169 UINTN Byte;\r
170 UINT8 Bit;\r
171 UINTN StartByte;\r
172 UINT8 StartBit;\r
173 UINTN Available;\r
174 UINTN Count;\r
175\r
176 ASSERT ((Block != 0) && (Units != 0));\r
177\r
178 StartByte = 0;\r
179 StartBit = 0;\r
180 Available = 0;\r
181\r
182 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
183 //\r
184 // If current bit is zero, the corresponding memory unit is\r
185 // available, otherwise we need to restart our searching.\r
186 // Available counts the consective number of zero bit.\r
187 //\r
188 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
189 Available++;\r
190\r
191 if (Available >= Units) {\r
192 break;\r
193 }\r
194\r
195 NEXT_BIT (Byte, Bit);\r
196\r
197 } else {\r
198 NEXT_BIT (Byte, Bit);\r
199\r
200 Available = 0;\r
201 StartByte = Byte;\r
202 StartBit = Bit;\r
203 }\r
204 }\r
205\r
206 if (Available < Units) {\r
207 return NULL;\r
208 }\r
209\r
210 //\r
211 // Mark the memory as allocated\r
212 //\r
213 Byte = StartByte;\r
214 Bit = StartBit;\r
215\r
216 for (Count = 0; Count < Units; Count++) {\r
217 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
218\r
d074a8e1 219 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));\r
913cb9dc 220 NEXT_BIT (Byte, Bit);\r
221 }\r
222\r
223 return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
224}\r
225\r
226\r
227/**\r
78c2ffb5 228 Insert the memory block to the pool's list of the blocks.\r
913cb9dc 229\r
78c2ffb5 230 @param Head The head of the memory pool's block list.\r
231 @param Block The memory block to insert.\r
913cb9dc 232\r
78c2ffb5 233 @return None.\r
913cb9dc 234\r
235**/\r
913cb9dc 236VOID\r
237UsbHcInsertMemBlockToPool (\r
238 IN USBHC_MEM_BLOCK *Head,\r
239 IN USBHC_MEM_BLOCK *Block\r
240 )\r
241{\r
242 ASSERT ((Head != NULL) && (Block != NULL));\r
243 Block->Next = Head->Next;\r
244 Head->Next = Block;\r
245}\r
246\r
247\r
248/**\r
249 Is the memory block empty?\r
250\r
78c2ffb5 251 @param Block The memory block to check.\r
913cb9dc 252\r
78c2ffb5 253 @retval TRUE The memory block is empty.\r
254 @retval FALSE The memory block isn't empty.\r
913cb9dc 255\r
256**/\r
913cb9dc 257BOOLEAN\r
258UsbHcIsMemBlockEmpty (\r
259 IN USBHC_MEM_BLOCK *Block\r
260 )\r
261{\r
262 UINTN Index;\r
263\r
264 for (Index = 0; Index < Block->BitsLen; Index++) {\r
265 if (Block->Bits[Index] != 0) {\r
266 return FALSE;\r
267 }\r
268 }\r
269\r
270 return TRUE;\r
271}\r
272\r
273\r
274/**\r
78c2ffb5 275 Unlink the memory block from the pool's list.\r
913cb9dc 276\r
78c2ffb5 277 @param Head The block list head of the memory's pool.\r
913cb9dc 278 @param BlockToUnlink The memory block to unlink.\r
279\r
78c2ffb5 280 @return None.\r
913cb9dc 281\r
282**/\r
913cb9dc 283VOID\r
284UsbHcUnlinkMemBlock (\r
285 IN USBHC_MEM_BLOCK *Head,\r
286 IN USBHC_MEM_BLOCK *BlockToUnlink\r
287 )\r
288{\r
289 USBHC_MEM_BLOCK *Block;\r
290\r
291 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
292\r
293 for (Block = Head; Block != NULL; Block = Block->Next) {\r
294 if (Block->Next == BlockToUnlink) {\r
295 Block->Next = BlockToUnlink->Next;\r
296 BlockToUnlink->Next = NULL;\r
297 break;\r
298 }\r
299 }\r
300}\r
301\r
302\r
303/**\r
78c2ffb5 304 Initialize the memory management pool for the host controller.\r
913cb9dc 305\r
78c2ffb5 306 @param PciIo The PciIo that can be used to access the host controller.\r
307 @param Check4G Whether the host controller requires allocated memory\r
308 from one 4G address space.\r
309 @param Which4G The 4G memory area each memory allocated should be from.\r
913cb9dc 310\r
78c2ffb5 311 @retval EFI_SUCCESS The memory pool is initialized.\r
312 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
913cb9dc 313\r
314**/\r
315USBHC_MEM_POOL *\r
316UsbHcInitMemPool (\r
317 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
318 IN BOOLEAN Check4G,\r
319 IN UINT32 Which4G\r
320 )\r
321{\r
322 USBHC_MEM_POOL *Pool;\r
323\r
324 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
325\r
326 if (Pool == NULL) {\r
327 return Pool;\r
328 }\r
329\r
330 Pool->PciIo = PciIo;\r
331 Pool->Check4G = Check4G;\r
332 Pool->Which4G = Which4G;\r
333 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
334\r
335 if (Pool->Head == NULL) {\r
336 gBS->FreePool (Pool);\r
337 Pool = NULL;\r
338 }\r
339\r
340 return Pool;\r
341}\r
342\r
343\r
344/**\r
78c2ffb5 345 Release the memory management pool.\r
913cb9dc 346\r
78c2ffb5 347 @param Pool The USB memory pool to free.\r
913cb9dc 348\r
78c2ffb5 349 @retval EFI_SUCCESS The memory pool is freed.\r
350 @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
913cb9dc 351\r
352**/\r
353EFI_STATUS\r
354UsbHcFreeMemPool (\r
355 IN USBHC_MEM_POOL *Pool\r
356 )\r
357{\r
358 USBHC_MEM_BLOCK *Block;\r
359\r
360 ASSERT (Pool->Head != NULL);\r
361\r
362 //\r
363 // Unlink all the memory blocks from the pool, then free them.\r
364 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
365 // first block.\r
366 //\r
367 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
368 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
369 UsbHcFreeMemBlock (Pool, Block);\r
370 }\r
371\r
372 UsbHcFreeMemBlock (Pool, Pool->Head);\r
373 gBS->FreePool (Pool);\r
374 return EFI_SUCCESS;\r
375}\r
376\r
377\r
378/**\r
379 Allocate some memory from the host controller's memory pool\r
380 which can be used to communicate with host controller.\r
381\r
78c2ffb5 382 @param Pool The host controller's memory pool.\r
383 @param Size Size of the memory to allocate.\r
913cb9dc 384\r
78c2ffb5 385 @return The allocated memory or NULL.\r
913cb9dc 386\r
387**/\r
388VOID *\r
389UsbHcAllocateMem (\r
390 IN USBHC_MEM_POOL *Pool,\r
391 IN UINTN Size\r
392 )\r
393{\r
394 USBHC_MEM_BLOCK *Head;\r
395 USBHC_MEM_BLOCK *Block;\r
396 USBHC_MEM_BLOCK *NewBlock;\r
397 VOID *Mem;\r
398 UINTN AllocSize;\r
399 UINTN Pages;\r
400\r
401 Mem = NULL;\r
402 AllocSize = USBHC_MEM_ROUND (Size);\r
403 Head = Pool->Head;\r
404 ASSERT (Head != NULL);\r
405\r
406 //\r
407 // First check whether current memory blocks can satisfy the allocation.\r
408 //\r
409 for (Block = Head; Block != NULL; Block = Block->Next) {\r
410 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
411\r
412 if (Mem != NULL) {\r
413 ZeroMem (Mem, Size);\r
414 break;\r
415 }\r
416 }\r
417\r
418 if (Mem != NULL) {\r
419 return Mem;\r
420 }\r
421\r
422 //\r
423 // Create a new memory block if there is not enough memory\r
424 // in the pool. If the allocation size is larger than the\r
425 // default page number, just allocate a large enough memory\r
426 // block. Otherwise allocate default pages.\r
427 //\r
428 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
429 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
430 } else {\r
431 Pages = USBHC_MEM_DEFAULT_PAGES;\r
432 }\r
433\r
434 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
435\r
436 if (NewBlock == NULL) {\r
1c619535 437 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
913cb9dc 438 return NULL;\r
439 }\r
440\r
441 //\r
442 // Add the new memory block to the pool, then allocate memory from it\r
443 //\r
444 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
445 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
446\r
447 if (Mem != NULL) {\r
448 ZeroMem (Mem, Size);\r
449 }\r
450\r
451 return Mem;\r
452}\r
453\r
454\r
455/**\r
78c2ffb5 456 Free the allocated memory back to the memory pool.\r
913cb9dc 457\r
78c2ffb5 458 @param Pool The memory pool of the host controller.\r
459 @param Mem The memory to free.\r
460 @param Size The size of the memory to free.\r
913cb9dc 461\r
78c2ffb5 462 @return None.\r
913cb9dc 463\r
464**/\r
465VOID\r
466UsbHcFreeMem (\r
467 IN USBHC_MEM_POOL *Pool,\r
468 IN VOID *Mem,\r
469 IN UINTN Size\r
470 )\r
471{\r
472 USBHC_MEM_BLOCK *Head;\r
473 USBHC_MEM_BLOCK *Block;\r
474 UINT8 *ToFree;\r
475 UINTN AllocSize;\r
476 UINTN Byte;\r
477 UINTN Bit;\r
478 UINTN Count;\r
479\r
480 Head = Pool->Head;\r
481 AllocSize = USBHC_MEM_ROUND (Size);\r
482 ToFree = (UINT8 *) Mem;\r
483\r
484 for (Block = Head; Block != NULL; Block = Block->Next) {\r
485 //\r
486 // scan the memory block list for the memory block that\r
487 // completely contains the memory to free.\r
488 //\r
489 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
490 //\r
491 // compute the start byte and bit in the bit array\r
492 //\r
493 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
494 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
495\r
496 //\r
497 // reset associated bits in bit arry\r
498 //\r
499 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
500 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
501\r
c52fa98c 502 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
913cb9dc 503 NEXT_BIT (Byte, Bit);\r
504 }\r
505\r
506 break;\r
507 }\r
508 }\r
509\r
510 //\r
511 // If Block == NULL, it means that the current memory isn't\r
512 // in the host controller's pool. This is critical because\r
513 // the caller has passed in a wrong memory point\r
514 //\r
515 ASSERT (Block != NULL);\r
516\r
517 //\r
518 // Release the current memory block if it is empty and not the head\r
519 //\r
520 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
913cb9dc 521 UsbHcUnlinkMemBlock (Head, Block);\r
522 UsbHcFreeMemBlock (Pool, Block);\r
523 }\r
524\r
525 return ;\r
526}\r