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) {
334 Initialize the memory management pool for the host controller.
336 @return Pointer to the allocated memory pool or NULL if failed.
344 USBHC_MEM_POOL
*Pool
;
347 EFI_PHYSICAL_ADDRESS TempPtr
;
349 PageNumber
= EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL
));
350 Status
= PeiServicesAllocatePages (
355 if (EFI_ERROR (Status
)) {
358 ZeroMem ((VOID
*) (UINTN
) TempPtr
, EFI_PAGES_TO_SIZE (PageNumber
));
360 Pool
= (USBHC_MEM_POOL
*) ((UINTN
) TempPtr
);
361 Pool
->Head
= UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES
);
363 if (Pool
->Head
== NULL
) {
365 // No free memory in PEI.
374 Release the memory management pool.
376 @param Pool The USB memory pool to free.
381 IN USBHC_MEM_POOL
*Pool
384 USBHC_MEM_BLOCK
*Block
;
386 ASSERT (Pool
->Head
!= NULL
);
389 // Unlink all the memory blocks from the pool, then free them.
390 // UsbHcUnlinkMemBlock can't be used to unlink and free the
393 for (Block
= Pool
->Head
->Next
; Block
!= NULL
; Block
= Pool
->Head
->Next
) {
394 //UsbHcUnlinkMemBlock (Pool->Head, Block);
395 UsbHcFreeMemBlock (Pool
, Block
);
398 UsbHcFreeMemBlock (Pool
, Pool
->Head
);
402 Allocate some memory from the host controller's memory pool
403 which can be used to communicate with host controller.
405 @param Pool The host controller's memory pool.
406 @param Size Size of the memory to allocate.
408 @return The allocated memory or NULL.
413 IN USBHC_MEM_POOL
*Pool
,
417 USBHC_MEM_BLOCK
*Head
;
418 USBHC_MEM_BLOCK
*Block
;
419 USBHC_MEM_BLOCK
*NewBlock
;
425 AllocSize
= USBHC_MEM_ROUND (Size
);
427 ASSERT (Head
!= NULL
);
430 // First check whether current memory blocks can satisfy the allocation.
432 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
433 Mem
= UsbHcAllocMemFromBlock (Block
, AllocSize
/ USBHC_MEM_UNIT
);
446 // Create a new memory block if there is not enough memory
447 // in the pool. If the allocation size is larger than the
448 // default page number, just allocate a large enough memory
449 // block. Otherwise allocate default pages.
451 if (AllocSize
> EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES
)) {
452 Pages
= EFI_SIZE_TO_PAGES (AllocSize
);
454 Pages
= USBHC_MEM_DEFAULT_PAGES
;
456 NewBlock
= UsbHcAllocMemBlock (Pages
);
458 if (NewBlock
== NULL
) {
463 // Add the new memory block to the pool, then allocate memory from it
465 UsbHcInsertMemBlockToPool (Head
, NewBlock
);
466 Mem
= UsbHcAllocMemFromBlock (NewBlock
, AllocSize
/ USBHC_MEM_UNIT
);
476 Free the allocated memory back to the memory pool.
478 @param Pool The memory pool of the host controller.
479 @param Mem The memory to free.
480 @param Size The size of the memory to free.
485 IN USBHC_MEM_POOL
*Pool
,
490 USBHC_MEM_BLOCK
*Head
;
491 USBHC_MEM_BLOCK
*Block
;
499 AllocSize
= USBHC_MEM_ROUND (Size
);
500 ToFree
= (UINT8
*) Mem
;
502 for (Block
= Head
; Block
!= NULL
; Block
= Block
->Next
) {
504 // scan the memory block list for the memory block that
505 // completely contains the memory to free.
507 if ((Block
->BufHost
<= ToFree
) && ((ToFree
+ AllocSize
) <= (Block
->BufHost
+ Block
->BufLen
))) {
509 // compute the start byte and bit in the bit array
511 Byte
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) / 8;
512 Bit
= ((ToFree
- Block
->BufHost
) / USBHC_MEM_UNIT
) % 8;
515 // reset associated bits in bit array
517 for (Count
= 0; Count
< (AllocSize
/ USBHC_MEM_UNIT
); Count
++) {
518 ASSERT (USB_HC_BIT_IS_SET (Block
->Bits
[Byte
], Bit
));
520 Block
->Bits
[Byte
] = (UINT8
) (Block
->Bits
[Byte
] ^ USB_HC_BIT (Bit
));
521 NEXT_BIT (Byte
, Bit
);
529 // If Block == NULL, it means that the current memory isn't
530 // in the host controller's pool. This is critical because
531 // the caller has passed in a wrong memory pointer
533 ASSERT (Block
!= NULL
);
536 // Release the current memory block if it is empty and not the head
538 if ((Block
!= Head
) && UsbHcIsMemBlockEmpty (Block
)) {
539 //UsbHcUnlinkMemBlock (Head, Block);
540 UsbHcFreeMemBlock (Pool
, Block
);
545 Allocates pages at a specified alignment.
547 If Alignment is not a power of two and Alignment is not zero, then ASSERT().
549 @param Pages The number of pages to allocate.
550 @param Alignment The requested alignment of the allocation. Must be a power of two.
551 @param HostAddress The system memory address to map to the PCI controller.
552 @param DeviceAddress The resulting map address for the bus master PCI controller to
553 use to access the hosts HostAddress.
554 @param Mapping A resulting value to pass to Unmap().
556 @retval EFI_SUCCESS Success to allocate aligned pages.
557 @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
558 @retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
562 UsbHcAllocateAlignedPages (
565 OUT VOID
**HostAddress
,
566 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
574 EFI_PHYSICAL_ADDRESS DeviceMemory
;
575 UINTN AlignedDeviceMemory
;
579 // Alignment must be a power of two or zero.
581 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
583 if ((Alignment
& (Alignment
- 1)) != 0) {
584 return EFI_INVALID_PARAMETER
;
588 return EFI_INVALID_PARAMETER
;
591 if (Alignment
> EFI_PAGE_SIZE
) {
593 // Calculate the total number of pages since alignment is larger than page size.
595 AlignmentMask
= Alignment
- 1;
596 RealPages
= Pages
+ EFI_SIZE_TO_PAGES (Alignment
);
598 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
600 ASSERT (RealPages
> Pages
);
602 Status
= IoMmuAllocateBuffer (
608 if (EFI_ERROR (Status
)) {
609 return EFI_OUT_OF_RESOURCES
;
611 AlignedMemory
= ((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
;
612 AlignedDeviceMemory
= ((UINTN
) DeviceMemory
+ AlignmentMask
) & ~AlignmentMask
;
615 // Do not over-allocate pages in this case.
617 Status
= IoMmuAllocateBuffer (
623 if (EFI_ERROR (Status
)) {
624 return EFI_OUT_OF_RESOURCES
;
626 AlignedMemory
= (UINTN
) Memory
;
627 AlignedDeviceMemory
= (UINTN
) DeviceMemory
;
630 *HostAddress
= (VOID
*) AlignedMemory
;
631 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
) AlignedDeviceMemory
;
637 Frees memory that was allocated with UsbHcAllocateAlignedPages().
639 @param HostAddress The system memory address to map to the PCI controller.
640 @param Pages The number of pages to free.
641 @param Mapping The mapping value returned from Map().
645 UsbHcFreeAlignedPages (
646 IN VOID
*HostAddress
,
653 IoMmuFreeBuffer (Pages
, HostAddress
, Mapping
);