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