2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Allocate a block of memory to be used by the buffer pool.
23 @param Pages How many pages to allocate.
25 @return Pointer to the allocated memory block or NULL if failed.
33 USBHC_MEM_BLOCK
*Block
;
36 EFI_PHYSICAL_ADDRESS MappedAddr
;
39 EFI_PHYSICAL_ADDRESS TempPtr
;
41 PageNumber
= EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK
));
42 Status
= PeiServicesAllocatePages (
48 if (EFI_ERROR (Status
)) {
51 ZeroMem ((VOID
*) (UINTN
) TempPtr
, EFI_PAGES_TO_SIZE (PageNumber
));
54 // each bit in the bit array represents USBHC_MEM_UNIT
55 // bytes of memory in the memory block.
57 ASSERT (USBHC_MEM_UNIT
* 8 <= EFI_PAGE_SIZE
);
59 Block
= (USBHC_MEM_BLOCK
*) (UINTN
) TempPtr
;
60 Block
->BufLen
= EFI_PAGES_TO_SIZE (Pages
);
61 Block
->BitsLen
= Block
->BufLen
/ (USBHC_MEM_UNIT
* 8);
63 PageNumber
= EFI_SIZE_TO_PAGES (Block
->BitsLen
);
64 Status
= PeiServicesAllocatePages (
70 if (EFI_ERROR (Status
)) {
73 ZeroMem ((VOID
*) (UINTN
) TempPtr
, EFI_PAGES_TO_SIZE (PageNumber
));
75 Block
->Bits
= (UINT8
*) (UINTN
) TempPtr
;
77 Status
= IoMmuAllocateBuffer (
83 if (EFI_ERROR (Status
)) {
86 ZeroMem ((VOID
*) (UINTN
) BufHost
, EFI_PAGES_TO_SIZE (Pages
));
88 Block
->BufHost
= (UINT8
*) (UINTN
) BufHost
;
89 Block
->Buf
= (UINT8
*) (UINTN
) MappedAddr
;
90 Block
->Mapping
= Mapping
;
97 Free the memory block from the memory pool.
99 @param Pool The memory pool to free the block from.
100 @param Block The memory block to free.
105 IN USBHC_MEM_POOL
*Pool
,
106 IN USBHC_MEM_BLOCK
*Block
109 ASSERT ((Pool
!= NULL
) && (Block
!= NULL
));
111 IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block
->BufLen
), Block
->BufHost
, Block
->Mapping
);
114 // No free memory in PEI.
119 Alloc some memory from the block.
121 @param Block The memory block to allocate memory from.
122 @param Units Number of memory units to allocate.
124 @return The pointer to the allocated memory.
125 If couldn't allocate the needed memory, the return value is NULL.
129 UsbHcAllocMemFromBlock (
130 IN USBHC_MEM_BLOCK
*Block
,
141 ASSERT ((Block
!= 0) && (Units
!= 0));
147 for (Byte
= 0, Bit
= 0; Byte
< Block
->BitsLen
;) {
149 // If current bit is zero, the corresponding memory unit is
150 // available, otherwise we need to restart our searching.
151 // Available counts the consective number of zero bit.
153 if (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
)) {
156 if (Available
>= Units
) {
160 NEXT_BIT (Byte
, Bit
);
162 NEXT_BIT (Byte
, Bit
);
170 if (Available
< Units
) {
175 // Mark the memory as allocated
180 for (Count
= 0; Count
< Units
; Count
++) {
181 ASSERT (!USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
183 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] | (UINT8
) USB_HC_BIT (Bit
));
184 NEXT_BIT (Byte
, Bit
);
187 return Block
->BufHost
+ (StartByte
* 8 + StartBit
) * USBHC_MEM_UNIT
;
191 Calculate the corresponding pci bus address according to the Mem parameter.
193 @param Pool The memory pool of the host controller.
194 @param Mem The pointer to host memory.
195 @param Size The size of the memory region.
197 @return The pci memory address
201 UsbHcGetPciAddrForHostAddr (
202 IN USBHC_MEM_POOL
*Pool
,
207 USBHC_MEM_BLOCK
*Head
;
208 USBHC_MEM_BLOCK
*Block
;
210 EFI_PHYSICAL_ADDRESS PhyAddr
;
214 AllocSize
= USBHC_MEM_ROUND (Size
);
220 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
222 // scan the memory block list for the memory block that
223 // completely contains the allocated memory.
225 if ((Block
->BufHost
<= (UINT8
*) Mem
) && (((UINT8
*) Mem
+ AllocSize
) <= (Block
->BufHost
+ Block
->BufLen
))) {
230 ASSERT ((Block
!= NULL
));
232 // calculate the pci memory address for host memory address.
234 Offset
= (UINT8
*) Mem
- Block
->BufHost
;
235 PhyAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (Block
->Buf
+ Offset
);
240 Calculate the corresponding host address according to the pci address.
242 @param Pool The memory pool of the host controller.
243 @param Mem The pointer to pci memory.
244 @param Size The size of the memory region.
246 @return The host memory address
250 UsbHcGetHostAddrForPciAddr (
251 IN USBHC_MEM_POOL
*Pool
,
256 USBHC_MEM_BLOCK
*Head
;
257 USBHC_MEM_BLOCK
*Block
;
259 EFI_PHYSICAL_ADDRESS HostAddr
;
263 AllocSize
= USBHC_MEM_ROUND (Size
);
269 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
271 // scan the memory block list for the memory block that
272 // completely contains the allocated memory.
274 if ((Block
->Buf
<= (UINT8
*) Mem
) && (((UINT8
*) Mem
+ AllocSize
) <= (Block
->Buf
+ Block
->BufLen
))) {
279 ASSERT ((Block
!= NULL
));
281 // calculate the host memory address for pci memory address.
283 Offset
= (UINT8
*) Mem
- Block
->Buf
;
284 HostAddr
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (Block
->BufHost
+ Offset
);
289 Insert the memory block to the pool's list of the blocks.
291 @param Head The head of the memory pool's block list.
292 @param Block The memory block to insert.
296 UsbHcInsertMemBlockToPool (
297 IN USBHC_MEM_BLOCK
*Head
,
298 IN USBHC_MEM_BLOCK
*Block
301 ASSERT ((Head
!= NULL
) && (Block
!= NULL
));
302 Block
->Next
= Head
->Next
;
307 Is the memory block empty?
309 @param Block The memory block to check.
311 @retval TRUE The memory block is empty.
312 @retval FALSE The memory block isn't empty.
316 UsbHcIsMemBlockEmpty (
317 IN USBHC_MEM_BLOCK
*Block
322 for (Index
= 0; Index
< Block
->BitsLen
; Index
++) {
323 if (Block
->Bits
[Index
] != 0) {
332 Unlink the memory block from the pool's list.
334 @param Head The block list head of the memory's pool.
335 @param BlockToUnlink The memory block to unlink.
339 UsbHcUnlinkMemBlock (
340 IN USBHC_MEM_BLOCK
*Head
,
341 IN USBHC_MEM_BLOCK
*BlockToUnlink
344 USBHC_MEM_BLOCK
*Block
;
346 ASSERT ((Head
!= NULL
) && (BlockToUnlink
!= NULL
));
348 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
349 if (Block
->Next
== BlockToUnlink
) {
350 Block
->Next
= BlockToUnlink
->Next
;
351 BlockToUnlink
->Next
= NULL
;
358 Initialize the memory management pool for the host controller.
360 @return Pointer to the allocated memory pool or NULL if failed.
368 USBHC_MEM_POOL
*Pool
;
371 EFI_PHYSICAL_ADDRESS TempPtr
;
373 PageNumber
= EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL
));
374 Status
= PeiServicesAllocatePages (
379 if (EFI_ERROR (Status
)) {
382 ZeroMem ((VOID
*) (UINTN
) TempPtr
, EFI_PAGES_TO_SIZE (PageNumber
));
384 Pool
= (USBHC_MEM_POOL
*) ((UINTN
) TempPtr
);
385 Pool
->Head
= UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES
);
387 if (Pool
->Head
== NULL
) {
389 // No free memory in PEI.
398 Release the memory management pool.
400 @param Pool The USB memory pool to free.
405 IN USBHC_MEM_POOL
*Pool
408 USBHC_MEM_BLOCK
*Block
;
410 ASSERT (Pool
->Head
!= NULL
);
413 // Unlink all the memory blocks from the pool, then free them.
414 // UsbHcUnlinkMemBlock can't be used to unlink and free the
417 for (Block
= Pool
->Head
->Next
; Block
!= NULL
; Block
= Pool
->Head
->Next
) {
418 //UsbHcUnlinkMemBlock (Pool->Head, Block);
419 UsbHcFreeMemBlock (Pool
, Block
);
422 UsbHcFreeMemBlock (Pool
, Pool
->Head
);
426 Allocate some memory from the host controller's memory pool
427 which can be used to communicate with host controller.
429 @param Pool The host controller's memory pool.
430 @param Size Size of the memory to allocate.
432 @return The allocated memory or NULL.
437 IN USBHC_MEM_POOL
*Pool
,
441 USBHC_MEM_BLOCK
*Head
;
442 USBHC_MEM_BLOCK
*Block
;
443 USBHC_MEM_BLOCK
*NewBlock
;
449 AllocSize
= USBHC_MEM_ROUND (Size
);
451 ASSERT (Head
!= NULL
);
454 // First check whether current memory blocks can satisfy the allocation.
456 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
457 Mem
= UsbHcAllocMemFromBlock (Block
, AllocSize
/ USBHC_MEM_UNIT
);
470 // Create a new memory block if there is not enough memory
471 // in the pool. If the allocation size is larger than the
472 // default page number, just allocate a large enough memory
473 // block. Otherwise allocate default pages.
475 if (AllocSize
> EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES
)) {
476 Pages
= EFI_SIZE_TO_PAGES (AllocSize
);
478 Pages
= USBHC_MEM_DEFAULT_PAGES
;
480 NewBlock
= UsbHcAllocMemBlock (Pages
);
482 if (NewBlock
== NULL
) {
487 // Add the new memory block to the pool, then allocate memory from it
489 UsbHcInsertMemBlockToPool (Head
, NewBlock
);
490 Mem
= UsbHcAllocMemFromBlock (NewBlock
, AllocSize
/ USBHC_MEM_UNIT
);
500 Free the allocated memory back to the memory pool.
502 @param Pool The memory pool of the host controller.
503 @param Mem The memory to free.
504 @param Size The size of the memory to free.
509 IN USBHC_MEM_POOL
*Pool
,
514 USBHC_MEM_BLOCK
*Head
;
515 USBHC_MEM_BLOCK
*Block
;
523 AllocSize
= USBHC_MEM_ROUND (Size
);
524 ToFree
= (UINT8
*) Mem
;
526 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
528 // scan the memory block list for the memory block that
529 // completely contains the memory to free.
531 if ((Block
->BufHost
<= ToFree
) && ((ToFree
+ AllocSize
) <= (Block
->BufHost
+ Block
->BufLen
))) {
533 // compute the start byte and bit in the bit array
535 Byte
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) / 8;
536 Bit
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) % 8;
539 // reset associated bits in bit array
541 for (Count
= 0; Count
< (AllocSize
/ USBHC_MEM_UNIT
); Count
++) {
542 ASSERT (USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
544 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] ^ USB_HC_BIT (Bit
));
545 NEXT_BIT (Byte
, Bit
);
553 // If Block == NULL, it means that the current memory isn't
554 // in the host controller's pool. This is critical because
555 // the caller has passed in a wrong memory pointer
557 ASSERT (Block
!= NULL
);
560 // Release the current memory block if it is empty and not the head
562 if ((Block
!= Head
) && UsbHcIsMemBlockEmpty (Block
)) {
563 //UsbHcUnlinkMemBlock (Head, Block);
564 UsbHcFreeMemBlock (Pool
, Block
);
569 Allocates pages at a specified alignment.
571 If Alignment is not a power of two and Alignment is not zero, then ASSERT().
573 @param Pages The number of pages to allocate.
574 @param Alignment The requested alignment of the allocation. Must be a power of two.
575 @param HostAddress The system memory address to map to the PCI controller.
576 @param DeviceAddress The resulting map address for the bus master PCI controller to
577 use to access the hosts HostAddress.
578 @param Mapping A resulting value to pass to Unmap().
580 @retval EFI_SUCCESS Success to allocate aligned pages.
581 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
582 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
586 UsbHcAllocateAlignedPages (
589 OUT VOID
**HostAddress
,
590 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
598 EFI_PHYSICAL_ADDRESS DeviceMemory
;
599 UINTN AlignedDeviceMemory
;
603 // Alignment must be a power of two or zero.
605 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
607 if ((Alignment
& (Alignment
- 1)) != 0) {
608 return EFI_INVALID_PARAMETER
;
612 return EFI_INVALID_PARAMETER
;
615 if (Alignment
> EFI_PAGE_SIZE
) {
617 // Calculate the total number of pages since alignment is larger than page size.
619 AlignmentMask
= Alignment
- 1;
620 RealPages
= Pages
+ EFI_SIZE_TO_PAGES (Alignment
);
622 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
624 ASSERT (RealPages
> Pages
);
626 Status
= IoMmuAllocateBuffer (
632 if (EFI_ERROR (Status
)) {
633 return EFI_OUT_OF_RESOURCES
;
635 AlignedMemory
= ((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
;
636 AlignedDeviceMemory
= ((UINTN
) DeviceMemory
+ AlignmentMask
) & ~AlignmentMask
;
639 // Do not over-allocate pages in this case.
641 Status
= IoMmuAllocateBuffer (
647 if (EFI_ERROR (Status
)) {
648 return EFI_OUT_OF_RESOURCES
;
650 AlignedMemory
= (UINTN
) Memory
;
651 AlignedDeviceMemory
= (UINTN
) DeviceMemory
;
654 *HostAddress
= (VOID
*) AlignedMemory
;
655 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
) AlignedDeviceMemory
;
661 Frees memory that was allocated with UsbHcAllocateAlignedPages().
663 @param HostAddress The system memory address to map to the PCI controller.
664 @param Pages The number of pages to free.
665 @param Mapping The mapping value returned from Map().
669 UsbHcFreeAlignedPages (
670 IN VOID
*HostAddress
,
677 IoMmuFreeBuffer (Pages
, HostAddress
, Mapping
);