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