]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
MdeModulePkg: Fix typos in comments and variables
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / UsbHcMem.c
CommitLineData
d987459f
SZ
1/** @file\r
2PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
3which is used to enable recovery function from USB Drivers.\r
4\r
2048c585 5Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>\r
d987459f
SZ
6\r
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 "XhcPeim.h"\r
19\r
20/**\r
21 Allocate a block of memory to be used by the buffer pool.\r
22\r
23 @param Pages How many pages to allocate.\r
24\r
25 @return Pointer to the allocated memory block or NULL if failed.\r
26\r
27**/\r
28USBHC_MEM_BLOCK *\r
29UsbHcAllocMemBlock (\r
30 IN UINTN Pages\r
31 )\r
32{\r
33 USBHC_MEM_BLOCK *Block;\r
34 EFI_STATUS Status;\r
35 UINTN PageNumber;\r
36 EFI_PHYSICAL_ADDRESS TempPtr;\r
37\r
38 PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK));\r
39 Status = PeiServicesAllocatePages (\r
40 EfiBootServicesData,\r
41 PageNumber,\r
42 &TempPtr\r
43 );\r
44\r
45 if (EFI_ERROR (Status)) {\r
46 return NULL;\r
47 }\r
48 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\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 = (USBHC_MEM_BLOCK *) (UINTN) TempPtr;\r
57 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
58 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
59\r
60 PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen);\r
61 Status = PeiServicesAllocatePages (\r
62 EfiBootServicesData,\r
63 PageNumber,\r
64 &TempPtr\r
65 );\r
66\r
67 if (EFI_ERROR (Status)) {\r
68 return NULL;\r
69 }\r
70 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
71\r
72 Block->Bits = (UINT8 *) (UINTN) TempPtr;\r
73\r
74 Status = PeiServicesAllocatePages (\r
75 EfiBootServicesData,\r
76 Pages,\r
77 &TempPtr\r
78 );\r
79 if (EFI_ERROR (Status)) {\r
80 return NULL;\r
81 }\r
82 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));\r
83\r
84 Block->BufHost = (UINT8 *) (UINTN) TempPtr;;\r
85 Block->Buf = (UINT8 *) (UINTN) TempPtr;\r
86 Block->Next = NULL;\r
87\r
88 return Block;\r
89}\r
90\r
91/**\r
92 Free the memory block from the memory pool.\r
93\r
94 @param Pool The memory pool to free the block from.\r
95 @param Block The memory block to free.\r
96\r
97**/\r
98VOID\r
99UsbHcFreeMemBlock (\r
100 IN USBHC_MEM_POOL *Pool,\r
101 IN USBHC_MEM_BLOCK *Block\r
102 )\r
103{\r
104 ASSERT ((Pool != NULL) && (Block != NULL));\r
105 //\r
106 // No free memory in PEI.\r
107 //\r
108}\r
109\r
110/**\r
111 Alloc some memory from the block.\r
112\r
113 @param Block The memory block to allocate memory from.\r
114 @param Units Number of memory units to allocate.\r
115\r
116 @return The pointer to the allocated memory.\r
117 If couldn't allocate the needed memory, the return value is NULL.\r
118\r
119**/\r
120VOID *\r
121UsbHcAllocMemFromBlock (\r
122 IN USBHC_MEM_BLOCK *Block,\r
123 IN UINTN Units\r
124 )\r
125{\r
126 UINTN Byte;\r
127 UINT8 Bit;\r
128 UINTN StartByte;\r
129 UINT8 StartBit;\r
130 UINTN Available;\r
131 UINTN Count;\r
132\r
133 ASSERT ((Block != 0) && (Units != 0));\r
134\r
135 StartByte = 0;\r
136 StartBit = 0;\r
137 Available = 0;\r
138\r
139 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
140 //\r
141 // If current bit is zero, the corresponding memory unit is\r
142 // available, otherwise we need to restart our searching.\r
143 // Available counts the consective number of zero bit.\r
144 //\r
145 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
146 Available++;\r
147\r
148 if (Available >= Units) {\r
149 break;\r
150 }\r
151\r
152 NEXT_BIT (Byte, Bit);\r
153 } else {\r
154 NEXT_BIT (Byte, Bit);\r
155\r
156 Available = 0;\r
157 StartByte = Byte;\r
158 StartBit = Bit;\r
159 }\r
160 }\r
161\r
162 if (Available < Units) {\r
163 return NULL;\r
164 }\r
165\r
166 //\r
167 // Mark the memory as allocated\r
168 //\r
169 Byte = StartByte;\r
170 Bit = StartBit;\r
171\r
172 for (Count = 0; Count < Units; Count++) {\r
173 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
174\r
175 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
176 NEXT_BIT (Byte, Bit);\r
177 }\r
178\r
179 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
180}\r
181\r
182/**\r
183 Calculate the corresponding pci bus address according to the Mem parameter.\r
184\r
185 @param Pool The memory pool of the host controller.\r
186 @param Mem The pointer to host memory.\r
187 @param Size The size of the memory region.\r
188\r
189 @return The pci memory address\r
190\r
191**/\r
192EFI_PHYSICAL_ADDRESS\r
193UsbHcGetPciAddrForHostAddr (\r
194 IN USBHC_MEM_POOL *Pool,\r
195 IN VOID *Mem,\r
196 IN UINTN Size\r
197 )\r
198{\r
199 USBHC_MEM_BLOCK *Head;\r
200 USBHC_MEM_BLOCK *Block;\r
201 UINTN AllocSize;\r
202 EFI_PHYSICAL_ADDRESS PhyAddr;\r
203 UINTN Offset;\r
204\r
205 Head = Pool->Head;\r
206 AllocSize = USBHC_MEM_ROUND (Size);\r
207\r
208 if (Mem == NULL) {\r
209 return 0;\r
210 }\r
211\r
212 for (Block = Head; Block != NULL; Block = Block->Next) {\r
213 //\r
214 // scan the memory block list for the memory block that\r
215 // completely contains the allocated memory.\r
216 //\r
217 if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
218 break;\r
219 }\r
220 }\r
221\r
222 ASSERT ((Block != NULL));\r
223 //\r
224 // calculate the pci memory address for host memory address.\r
225 //\r
226 Offset = (UINT8 *) Mem - Block->BufHost;\r
227 PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->Buf + Offset);\r
228 return PhyAddr;\r
229}\r
230\r
231/**\r
232 Calculate the corresponding host address according to the pci address.\r
233\r
234 @param Pool The memory pool of the host controller.\r
235 @param Mem The pointer to pci memory.\r
236 @param Size The size of the memory region.\r
237\r
238 @return The host memory address\r
239\r
240**/\r
241EFI_PHYSICAL_ADDRESS\r
242UsbHcGetHostAddrForPciAddr (\r
243 IN USBHC_MEM_POOL *Pool,\r
244 IN VOID *Mem,\r
245 IN UINTN Size\r
246 )\r
247{\r
248 USBHC_MEM_BLOCK *Head;\r
249 USBHC_MEM_BLOCK *Block;\r
250 UINTN AllocSize;\r
251 EFI_PHYSICAL_ADDRESS HostAddr;\r
252 UINTN Offset;\r
253\r
254 Head = Pool->Head;\r
255 AllocSize = USBHC_MEM_ROUND (Size);\r
256\r
257 if (Mem == NULL) {\r
258 return 0;\r
259 }\r
260\r
261 for (Block = Head; Block != NULL; Block = Block->Next) {\r
262 //\r
263 // scan the memory block list for the memory block that\r
264 // completely contains the allocated memory.\r
265 //\r
266 if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
267 break;\r
268 }\r
269 }\r
270\r
271 ASSERT ((Block != NULL));\r
272 //\r
273 // calculate the host memory address for pci memory address.\r
274 //\r
275 Offset = (UINT8 *) Mem - Block->Buf;\r
276 HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset);\r
277 return HostAddr;\r
278}\r
279\r
280/**\r
281 Insert the memory block to the pool's list of the blocks.\r
282\r
283 @param Head The head of the memory pool's block list.\r
284 @param Block The memory block to insert.\r
285\r
286**/\r
287VOID\r
288UsbHcInsertMemBlockToPool (\r
289 IN USBHC_MEM_BLOCK *Head,\r
290 IN USBHC_MEM_BLOCK *Block\r
291 )\r
292{\r
293 ASSERT ((Head != NULL) && (Block != NULL));\r
294 Block->Next = Head->Next;\r
295 Head->Next = Block;\r
296}\r
297\r
298/**\r
299 Is the memory block empty?\r
300\r
301 @param Block The memory block to check.\r
302\r
303 @retval TRUE The memory block is empty.\r
304 @retval FALSE The memory block isn't empty.\r
305\r
306**/\r
307BOOLEAN\r
308UsbHcIsMemBlockEmpty (\r
309 IN USBHC_MEM_BLOCK *Block\r
310 )\r
311{\r
312 UINTN Index;\r
313\r
314 for (Index = 0; Index < Block->BitsLen; Index++) {\r
315 if (Block->Bits[Index] != 0) {\r
316 return FALSE;\r
317 }\r
318 }\r
319\r
320 return TRUE;\r
321}\r
322\r
323/**\r
324 Unlink the memory block from the pool's list.\r
325\r
326 @param Head The block list head of the memory's pool.\r
327 @param BlockToUnlink The memory block to unlink.\r
328\r
329**/\r
330VOID\r
331UsbHcUnlinkMemBlock (\r
332 IN USBHC_MEM_BLOCK *Head,\r
333 IN USBHC_MEM_BLOCK *BlockToUnlink\r
334 )\r
335{\r
336 USBHC_MEM_BLOCK *Block;\r
337\r
338 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
339\r
340 for (Block = Head; Block != NULL; Block = Block->Next) {\r
341 if (Block->Next == BlockToUnlink) {\r
342 Block->Next = BlockToUnlink->Next;\r
343 BlockToUnlink->Next = NULL;\r
344 break;\r
345 }\r
346 }\r
347}\r
348\r
349/**\r
350 Initialize the memory management pool for the host controller.\r
351\r
352 @return Pointer to the allocated memory pool or NULL if failed.\r
353\r
354**/\r
355USBHC_MEM_POOL *\r
356UsbHcInitMemPool (\r
357 VOID\r
358 )\r
359{\r
360 USBHC_MEM_POOL *Pool;\r
361 UINTN PageNumber;\r
362 EFI_STATUS Status;\r
363 EFI_PHYSICAL_ADDRESS TempPtr;\r
364\r
365 PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL));\r
366 Status = PeiServicesAllocatePages (\r
367 EfiBootServicesData,\r
368 PageNumber,\r
369 &TempPtr\r
370 );\r
371 if (EFI_ERROR (Status)) {\r
372 return NULL;\r
373 }\r
374 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
375\r
376 Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);\r
377 Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES);\r
378\r
379 if (Pool->Head == NULL) {\r
380 //\r
381 // No free memory in PEI.\r
382 //\r
383 Pool = NULL;\r
384 }\r
385\r
386 return Pool;\r
387}\r
388\r
389/**\r
390 Release the memory management pool.\r
391\r
392 @param Pool The USB memory pool to free.\r
393\r
394**/\r
395VOID\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}\r
416\r
417/**\r
418 Allocate some memory from the host controller's memory pool\r
419 which can be used to communicate with host controller.\r
420\r
421 @param Pool The host controller's memory pool.\r
422 @param Size Size of the memory to allocate.\r
423\r
424 @return The allocated memory or NULL.\r
425\r
426**/\r
427VOID *\r
428UsbHcAllocateMem (\r
429 IN USBHC_MEM_POOL *Pool,\r
430 IN UINTN Size\r
431 )\r
432{\r
433 USBHC_MEM_BLOCK *Head;\r
434 USBHC_MEM_BLOCK *Block;\r
435 USBHC_MEM_BLOCK *NewBlock;\r
436 VOID *Mem;\r
437 UINTN AllocSize;\r
438 UINTN Pages;\r
439\r
440 Mem = NULL;\r
441 AllocSize = USBHC_MEM_ROUND (Size);\r
442 Head = Pool->Head;\r
443 ASSERT (Head != NULL);\r
444\r
445 //\r
446 // First check whether current memory blocks can satisfy the allocation.\r
447 //\r
448 for (Block = Head; Block != NULL; Block = Block->Next) {\r
449 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
450\r
451 if (Mem != NULL) {\r
452 ZeroMem (Mem, Size);\r
453 break;\r
454 }\r
455 }\r
456\r
457 if (Mem != NULL) {\r
458 return Mem;\r
459 }\r
460\r
461 //\r
462 // Create a new memory block if there is not enough memory\r
463 // in the pool. If the allocation size is larger than the\r
464 // default page number, just allocate a large enough memory\r
465 // block. Otherwise allocate default pages.\r
466 //\r
467 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
468 Pages = EFI_SIZE_TO_PAGES (AllocSize);\r
469 } else {\r
470 Pages = USBHC_MEM_DEFAULT_PAGES;\r
471 }\r
472 NewBlock = UsbHcAllocMemBlock (Pages);\r
473\r
474 if (NewBlock == NULL) {\r
475 return NULL;\r
476 }\r
477\r
478 //\r
479 // Add the new memory block to the pool, then allocate memory from it\r
480 //\r
481 UsbHcInsertMemBlockToPool (Head, NewBlock);\r
482 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
483\r
484 if (Mem != NULL) {\r
485 ZeroMem (Mem, Size);\r
486 }\r
487\r
488 return Mem;\r
489}\r
490\r
491/**\r
492 Free the allocated memory back to the memory pool.\r
493\r
494 @param Pool The memory pool of the host controller.\r
495 @param Mem The memory to free.\r
496 @param Size The size of the memory to free.\r
497\r
498**/\r
499VOID\r
500UsbHcFreeMem (\r
501 IN USBHC_MEM_POOL *Pool,\r
502 IN VOID *Mem,\r
503 IN UINTN Size\r
504 )\r
505{\r
506 USBHC_MEM_BLOCK *Head;\r
507 USBHC_MEM_BLOCK *Block;\r
508 UINT8 *ToFree;\r
509 UINTN AllocSize;\r
510 UINTN Byte;\r
511 UINTN Bit;\r
512 UINTN Count;\r
513\r
514 Head = Pool->Head;\r
515 AllocSize = USBHC_MEM_ROUND (Size);\r
516 ToFree = (UINT8 *) Mem;\r
517\r
518 for (Block = Head; Block != NULL; Block = Block->Next) {\r
519 //\r
520 // scan the memory block list for the memory block that\r
521 // completely contains the memory to free.\r
522 //\r
523 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
524 //\r
525 // compute the start byte and bit in the bit array\r
526 //\r
527 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
528 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
529\r
530 //\r
2048c585 531 // reset associated bits in bit array\r
d987459f
SZ
532 //\r
533 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
534 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
535\r
536 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
537 NEXT_BIT (Byte, Bit);\r
538 }\r
539\r
540 break;\r
541 }\r
542 }\r
543\r
544 //\r
545 // If Block == NULL, it means that the current memory isn't\r
546 // in the host controller's pool. This is critical because\r
547 // the caller has passed in a wrong memory pointer\r
548 //\r
549 ASSERT (Block != NULL);\r
550\r
551 //\r
552 // Release the current memory block if it is empty and not the head\r
553 //\r
554 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
555 //UsbHcUnlinkMemBlock (Head, Block);\r
556 UsbHcFreeMemBlock (Pool, Block);\r
557 }\r
558}\r
559\r
560/**\r
561 Allocates pages at a specified alignment.\r
562\r
563 If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
564\r
565 @param Pages The number of pages to allocate.\r
566 @param Alignment The requested alignment of the allocation. Must be a power of two.\r
567 @param HostAddress The system memory address to map to the PCI controller.\r
568 @param DeviceAddress The resulting map address for the bus master PCI controller to\r
569 use to access the hosts HostAddress.\r
570\r
571 @retval EFI_SUCCESS Success to allocate aligned pages.\r
572 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
573 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.\r
574\r
575**/\r
576EFI_STATUS\r
577UsbHcAllocateAlignedPages (\r
578 IN UINTN Pages,\r
579 IN UINTN Alignment,\r
580 OUT VOID **HostAddress,\r
581 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
582 )\r
583{\r
584 EFI_STATUS Status;\r
585 EFI_PHYSICAL_ADDRESS Memory;\r
586 UINTN AlignedMemory;\r
587 UINTN AlignmentMask;\r
588 UINTN RealPages;\r
589\r
590 //\r
591 // Alignment must be a power of two or zero.\r
592 //\r
593 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
594\r
595 if ((Alignment & (Alignment - 1)) != 0) {\r
596 return EFI_INVALID_PARAMETER;\r
597 }\r
598\r
599 if (Pages == 0) {\r
600 return EFI_INVALID_PARAMETER;\r
601 }\r
602\r
603 if (Alignment > EFI_PAGE_SIZE) {\r
604 //\r
e50a226b 605 // Calculate the total number of pages since alignment is larger than page size.\r
d987459f
SZ
606 //\r
607 AlignmentMask = Alignment - 1;\r
608 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
609 //\r
610 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
611 //\r
612 ASSERT (RealPages > Pages);\r
613\r
614 Status = PeiServicesAllocatePages (\r
615 EfiBootServicesData,\r
616 Pages,\r
617 &Memory\r
618 );\r
619 if (EFI_ERROR (Status)) {\r
620 return EFI_OUT_OF_RESOURCES;\r
621 }\r
622 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
623 } else {\r
624 //\r
625 // Do not over-allocate pages in this case.\r
626 //\r
627 Status = PeiServicesAllocatePages (\r
628 EfiBootServicesData,\r
629 Pages,\r
630 &Memory\r
631 );\r
632 if (EFI_ERROR (Status)) {\r
633 return EFI_OUT_OF_RESOURCES;\r
634 }\r
635 AlignedMemory = (UINTN) Memory;\r
636 }\r
637\r
638 *HostAddress = (VOID *) AlignedMemory;\r
639 *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;\r
640\r
641 return EFI_SUCCESS;\r
642}\r
643\r
644/**\r
645 Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
646\r
647 @param HostAddress The system memory address to map to the PCI controller.\r
648 @param Pages The number of pages to free.\r
649\r
650**/\r
651VOID\r
652UsbHcFreeAlignedPages (\r
653 IN VOID *HostAddress,\r
654 IN UINTN Pages\r
655 )\r
656{\r
657 ASSERT (Pages != 0);\r
658 //\r
659 // No free memory in PEI.\r
660 //\r
661}\r
662\r