]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c
add error handling on usb related modules.
[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
739802e4 224/**\r
225 Get the pci memory address according to the allocated host memory address.\r
226\r
227 @param Pool The memory pool of the host controller.\r
228 @param Mem The memory to free.\r
229 @param Size The size of the memory to free.\r
230\r
231 @return the pci memory address\r
232**/\r
233EFI_PHYSICAL_ADDRESS\r
234UsbHcGetPciAddressForHostMem (\r
235 IN USBHC_MEM_POOL *Pool,\r
236 IN VOID *Mem,\r
237 IN UINTN Size\r
238 )\r
239{\r
240 USBHC_MEM_BLOCK *Head;\r
241 USBHC_MEM_BLOCK *Block;\r
242 UINTN AllocSize;\r
243 EFI_PHYSICAL_ADDRESS PhyAddr;\r
244 UINTN Offset;\r
245\r
246 Head = Pool->Head;\r
247 AllocSize = USBHC_MEM_ROUND (Size);\r
248\r
249 for (Block = Head; Block != NULL; Block = Block->Next) {\r
250 //\r
251 // scan the memory block list for the memory block that\r
252 // completely contains the allocated memory.\r
253 //\r
254 if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
255 break;\r
256 }\r
257 }\r
258\r
259 ASSERT ((Block != NULL));\r
260 //\r
261 // calculate the pci memory address for host memory address.\r
262 //\r
263 Offset = (UINT8 *)Mem - Block->BufHost;\r
ce422d36 264 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);\r
739802e4 265 return PhyAddr;\r
266}\r
267\r
913cb9dc 268\r
269/**\r
78c2ffb5 270 Insert the memory block to the pool's list of the blocks.\r
913cb9dc 271\r
78c2ffb5 272 @param Head The head of the memory pool's block list.\r
273 @param Block The memory block to insert.\r
913cb9dc 274\r
913cb9dc 275**/\r
913cb9dc 276VOID\r
277UsbHcInsertMemBlockToPool (\r
278 IN USBHC_MEM_BLOCK *Head,\r
279 IN USBHC_MEM_BLOCK *Block\r
280 )\r
281{\r
282 ASSERT ((Head != NULL) && (Block != NULL));\r
283 Block->Next = Head->Next;\r
284 Head->Next = Block;\r
285}\r
286\r
287\r
288/**\r
289 Is the memory block empty?\r
290\r
78c2ffb5 291 @param Block The memory block to check.\r
913cb9dc 292\r
78c2ffb5 293 @retval TRUE The memory block is empty.\r
294 @retval FALSE The memory block isn't empty.\r
913cb9dc 295\r
296**/\r
913cb9dc 297BOOLEAN\r
298UsbHcIsMemBlockEmpty (\r
299 IN USBHC_MEM_BLOCK *Block\r
300 )\r
301{\r
302 UINTN Index;\r
303\r
304 for (Index = 0; Index < Block->BitsLen; Index++) {\r
305 if (Block->Bits[Index] != 0) {\r
306 return FALSE;\r
307 }\r
308 }\r
309\r
310 return TRUE;\r
311}\r
312\r
313\r
314/**\r
78c2ffb5 315 Unlink the memory block from the pool's list.\r
913cb9dc 316\r
78c2ffb5 317 @param Head The block list head of the memory's pool.\r
913cb9dc 318 @param BlockToUnlink The memory block to unlink.\r
319\r
913cb9dc 320**/\r
913cb9dc 321VOID\r
322UsbHcUnlinkMemBlock (\r
323 IN USBHC_MEM_BLOCK *Head,\r
324 IN USBHC_MEM_BLOCK *BlockToUnlink\r
325 )\r
326{\r
327 USBHC_MEM_BLOCK *Block;\r
328\r
329 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
330\r
331 for (Block = Head; Block != NULL; Block = Block->Next) {\r
332 if (Block->Next == BlockToUnlink) {\r
333 Block->Next = BlockToUnlink->Next;\r
334 BlockToUnlink->Next = NULL;\r
335 break;\r
336 }\r
337 }\r
338}\r
339\r
340\r
341/**\r
78c2ffb5 342 Initialize the memory management pool for the host controller.\r
913cb9dc 343\r
78c2ffb5 344 @param PciIo The PciIo that can be used to access the host controller.\r
345 @param Check4G Whether the host controller requires allocated memory\r
346 from one 4G address space.\r
347 @param Which4G The 4G memory area each memory allocated should be from.\r
913cb9dc 348\r
78c2ffb5 349 @retval EFI_SUCCESS The memory pool is initialized.\r
350 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
913cb9dc 351\r
352**/\r
353USBHC_MEM_POOL *\r
354UsbHcInitMemPool (\r
355 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
356 IN BOOLEAN Check4G,\r
357 IN UINT32 Which4G\r
358 )\r
359{\r
360 USBHC_MEM_POOL *Pool;\r
361\r
362 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
363\r
364 if (Pool == NULL) {\r
365 return Pool;\r
366 }\r
367\r
368 Pool->PciIo = PciIo;\r
369 Pool->Check4G = Check4G;\r
370 Pool->Which4G = Which4G;\r
371 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
372\r
373 if (Pool->Head == NULL) {\r
374 gBS->FreePool (Pool);\r
375 Pool = NULL;\r
376 }\r
377\r
378 return Pool;\r
379}\r
380\r
381\r
382/**\r
78c2ffb5 383 Release the memory management pool.\r
913cb9dc 384\r
78c2ffb5 385 @param Pool The USB memory pool to free.\r
913cb9dc 386\r
78c2ffb5 387 @retval EFI_SUCCESS The memory pool is freed.\r
388 @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
913cb9dc 389\r
390**/\r
391EFI_STATUS\r
392UsbHcFreeMemPool (\r
393 IN USBHC_MEM_POOL *Pool\r
394 )\r
395{\r
396 USBHC_MEM_BLOCK *Block;\r
397\r
398 ASSERT (Pool->Head != NULL);\r
399\r
400 //\r
401 // Unlink all the memory blocks from the pool, then free them.\r
402 // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
403 // first block.\r
404 //\r
405 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
406 UsbHcUnlinkMemBlock (Pool->Head, Block);\r
407 UsbHcFreeMemBlock (Pool, Block);\r
408 }\r
409\r
410 UsbHcFreeMemBlock (Pool, Pool->Head);\r
411 gBS->FreePool (Pool);\r
412 return EFI_SUCCESS;\r
413}\r
414\r
415\r
416/**\r
417 Allocate some memory from the host controller's memory pool\r
418 which can be used to communicate with host controller.\r
419\r
78c2ffb5 420 @param Pool The host controller's memory pool.\r
421 @param Size Size of the memory to allocate.\r
913cb9dc 422\r
78c2ffb5 423 @return The allocated memory or NULL.\r
913cb9dc 424\r
425**/\r
426VOID *\r
427UsbHcAllocateMem (\r
428 IN USBHC_MEM_POOL *Pool,\r
429 IN UINTN Size\r
430 )\r
431{\r
432 USBHC_MEM_BLOCK *Head;\r
433 USBHC_MEM_BLOCK *Block;\r
434 USBHC_MEM_BLOCK *NewBlock;\r
435 VOID *Mem;\r
436 UINTN AllocSize;\r
437 UINTN Pages;\r
438\r
439 Mem = NULL;\r
440 AllocSize = USBHC_MEM_ROUND (Size);\r
441 Head = Pool->Head;\r
442 ASSERT (Head != NULL);\r
443\r
444 //\r
445 // First check whether current memory blocks can satisfy the allocation.\r
446 //\r
447 for (Block = Head; Block != NULL; Block = Block->Next) {\r
448 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
449\r
450 if (Mem != NULL) {\r
451 ZeroMem (Mem, Size);\r
452 break;\r
453 }\r
454 }\r
455\r
456 if (Mem != NULL) {\r
457 return Mem;\r
458 }\r
459\r
460 //\r
461 // Create a new memory block if there is not enough memory\r
462 // in the pool. If the allocation size is larger than the\r
463 // default page number, just allocate a large enough memory\r
464 // block. Otherwise allocate default pages.\r
465 //\r
466 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
467 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
468 } else {\r
469 Pages = USBHC_MEM_DEFAULT_PAGES;\r
470 }\r
471\r
472 NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
473\r
474 if (NewBlock == NULL) {\r
1c619535 475 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
913cb9dc 476 return NULL;\r
477 }\r
478\r
479 //\r
480 // Add the new memory block to the pool, then allocate memory from it\r
481 //\r
482 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
483 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
484\r
485 if (Mem != NULL) {\r
486 ZeroMem (Mem, Size);\r
487 }\r
488\r
489 return Mem;\r
490}\r
491\r
492\r
493/**\r
78c2ffb5 494 Free the allocated memory back to the memory pool.\r
913cb9dc 495\r
78c2ffb5 496 @param Pool The memory pool of the host controller.\r
497 @param Mem The memory to free.\r
498 @param Size The size of the memory to free.\r
913cb9dc 499\r
913cb9dc 500**/\r
501VOID\r
502UsbHcFreeMem (\r
503 IN USBHC_MEM_POOL *Pool,\r
504 IN VOID *Mem,\r
505 IN UINTN Size\r
506 )\r
507{\r
508 USBHC_MEM_BLOCK *Head;\r
509 USBHC_MEM_BLOCK *Block;\r
510 UINT8 *ToFree;\r
511 UINTN AllocSize;\r
512 UINTN Byte;\r
513 UINTN Bit;\r
514 UINTN Count;\r
515\r
516 Head = Pool->Head;\r
517 AllocSize = USBHC_MEM_ROUND (Size);\r
518 ToFree = (UINT8 *) Mem;\r
519\r
520 for (Block = Head; Block != NULL; Block = Block->Next) {\r
521 //\r
522 // scan the memory block list for the memory block that\r
523 // completely contains the memory to free.\r
524 //\r
525 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
526 //\r
527 // compute the start byte and bit in the bit array\r
528 //\r
529 Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
530 Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
531\r
532 //\r
533 // reset associated bits in bit arry\r
534 //\r
535 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
536 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
537\r
c52fa98c 538 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
913cb9dc 539 NEXT_BIT (Byte, Bit);\r
540 }\r
541\r
542 break;\r
543 }\r
544 }\r
545\r
546 //\r
547 // If Block == NULL, it means that the current memory isn't\r
548 // in the host controller's pool. This is critical because\r
549 // the caller has passed in a wrong memory point\r
550 //\r
551 ASSERT (Block != NULL);\r
552\r
553 //\r
554 // Release the current memory block if it is empty and not the head\r
555 //\r
556 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
913cb9dc 557 UsbHcUnlinkMemBlock (Head, Block);\r
558 UsbHcFreeMemBlock (Pool, Block);\r
559 }\r
560\r
561 return ;\r
562}\r