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