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