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