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