MdeModulePkg XhciPei/UsbBusPei: Add XHCI recovery support.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15611 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Star Zeng 2014-07-02 03:20:49 +00:00 committed by lzeng14
parent ef96ba3cbe
commit d987459f8e
17 changed files with 7576 additions and 226 deletions

View File

@ -0,0 +1,662 @@
/** @file
PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
which is used to enable recovery function from USB Drivers.
Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "XhcPeim.h"
/**
Allocate a block of memory to be used by the buffer pool.
@param Pages How many pages to allocate.
@return Pointer to the allocated memory block or NULL if failed.
**/
USBHC_MEM_BLOCK *
UsbHcAllocMemBlock (
IN UINTN Pages
)
{
USBHC_MEM_BLOCK *Block;
EFI_STATUS Status;
UINTN PageNumber;
EFI_PHYSICAL_ADDRESS TempPtr;
PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK));
Status = PeiServicesAllocatePages (
EfiBootServicesData,
PageNumber,
&TempPtr
);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
//
// each bit in the bit array represents USBHC_MEM_UNIT
// bytes of memory in the memory block.
//
ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
Block = (USBHC_MEM_BLOCK *) (UINTN) TempPtr;
Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen);
Status = PeiServicesAllocatePages (
EfiBootServicesData,
PageNumber,
&TempPtr
);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
Block->Bits = (UINT8 *) (UINTN) TempPtr;
Status = PeiServicesAllocatePages (
EfiBootServicesData,
Pages,
&TempPtr
);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));
Block->BufHost = (UINT8 *) (UINTN) TempPtr;;
Block->Buf = (UINT8 *) (UINTN) TempPtr;
Block->Next = NULL;
return Block;
}
/**
Free the memory block from the memory pool.
@param Pool The memory pool to free the block from.
@param Block The memory block to free.
**/
VOID
UsbHcFreeMemBlock (
IN USBHC_MEM_POOL *Pool,
IN USBHC_MEM_BLOCK *Block
)
{
ASSERT ((Pool != NULL) && (Block != NULL));
//
// No free memory in PEI.
//
}
/**
Alloc some memory from the block.
@param Block The memory block to allocate memory from.
@param Units Number of memory units to allocate.
@return The pointer to the allocated memory.
If couldn't allocate the needed memory, the return value is NULL.
**/
VOID *
UsbHcAllocMemFromBlock (
IN USBHC_MEM_BLOCK *Block,
IN UINTN Units
)
{
UINTN Byte;
UINT8 Bit;
UINTN StartByte;
UINT8 StartBit;
UINTN Available;
UINTN Count;
ASSERT ((Block != 0) && (Units != 0));
StartByte = 0;
StartBit = 0;
Available = 0;
for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
//
// If current bit is zero, the corresponding memory unit is
// available, otherwise we need to restart our searching.
// Available counts the consective number of zero bit.
//
if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
Available++;
if (Available >= Units) {
break;
}
NEXT_BIT (Byte, Bit);
} else {
NEXT_BIT (Byte, Bit);
Available = 0;
StartByte = Byte;
StartBit = Bit;
}
}
if (Available < Units) {
return NULL;
}
//
// Mark the memory as allocated
//
Byte = StartByte;
Bit = StartBit;
for (Count = 0; Count < Units; Count++) {
ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
NEXT_BIT (Byte, Bit);
}
return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
}
/**
Calculate the corresponding pci bus address according to the Mem parameter.
@param Pool The memory pool of the host controller.
@param Mem The pointer to host memory.
@param Size The size of the memory region.
@return The pci memory address
**/
EFI_PHYSICAL_ADDRESS
UsbHcGetPciAddrForHostAddr (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
UINTN AllocSize;
EFI_PHYSICAL_ADDRESS PhyAddr;
UINTN Offset;
Head = Pool->Head;
AllocSize = USBHC_MEM_ROUND (Size);
if (Mem == NULL) {
return 0;
}
for (Block = Head; Block != NULL; Block = Block->Next) {
//
// scan the memory block list for the memory block that
// completely contains the allocated memory.
//
if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
break;
}
}
ASSERT ((Block != NULL));
//
// calculate the pci memory address for host memory address.
//
Offset = (UINT8 *) Mem - Block->BufHost;
PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->Buf + Offset);
return PhyAddr;
}
/**
Calculate the corresponding host address according to the pci address.
@param Pool The memory pool of the host controller.
@param Mem The pointer to pci memory.
@param Size The size of the memory region.
@return The host memory address
**/
EFI_PHYSICAL_ADDRESS
UsbHcGetHostAddrForPciAddr (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
UINTN AllocSize;
EFI_PHYSICAL_ADDRESS HostAddr;
UINTN Offset;
Head = Pool->Head;
AllocSize = USBHC_MEM_ROUND (Size);
if (Mem == NULL) {
return 0;
}
for (Block = Head; Block != NULL; Block = Block->Next) {
//
// scan the memory block list for the memory block that
// completely contains the allocated memory.
//
if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {
break;
}
}
ASSERT ((Block != NULL));
//
// calculate the host memory address for pci memory address.
//
Offset = (UINT8 *) Mem - Block->Buf;
HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset);
return HostAddr;
}
/**
Insert the memory block to the pool's list of the blocks.
@param Head The head of the memory pool's block list.
@param Block The memory block to insert.
**/
VOID
UsbHcInsertMemBlockToPool (
IN USBHC_MEM_BLOCK *Head,
IN USBHC_MEM_BLOCK *Block
)
{
ASSERT ((Head != NULL) && (Block != NULL));
Block->Next = Head->Next;
Head->Next = Block;
}
/**
Is the memory block empty?
@param Block The memory block to check.
@retval TRUE The memory block is empty.
@retval FALSE The memory block isn't empty.
**/
BOOLEAN
UsbHcIsMemBlockEmpty (
IN USBHC_MEM_BLOCK *Block
)
{
UINTN Index;
for (Index = 0; Index < Block->BitsLen; Index++) {
if (Block->Bits[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Unlink the memory block from the pool's list.
@param Head The block list head of the memory's pool.
@param BlockToUnlink The memory block to unlink.
**/
VOID
UsbHcUnlinkMemBlock (
IN USBHC_MEM_BLOCK *Head,
IN USBHC_MEM_BLOCK *BlockToUnlink
)
{
USBHC_MEM_BLOCK *Block;
ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
for (Block = Head; Block != NULL; Block = Block->Next) {
if (Block->Next == BlockToUnlink) {
Block->Next = BlockToUnlink->Next;
BlockToUnlink->Next = NULL;
break;
}
}
}
/**
Initialize the memory management pool for the host controller.
@return Pointer to the allocated memory pool or NULL if failed.
**/
USBHC_MEM_POOL *
UsbHcInitMemPool (
VOID
)
{
USBHC_MEM_POOL *Pool;
UINTN PageNumber;
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS TempPtr;
PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL));
Status = PeiServicesAllocatePages (
EfiBootServicesData,
PageNumber,
&TempPtr
);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));
Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES);
if (Pool->Head == NULL) {
//
// No free memory in PEI.
//
Pool = NULL;
}
return Pool;
}
/**
Release the memory management pool.
@param Pool The USB memory pool to free.
**/
VOID
UsbHcFreeMemPool (
IN USBHC_MEM_POOL *Pool
)
{
USBHC_MEM_BLOCK *Block;
ASSERT (Pool->Head != NULL);
//
// Unlink all the memory blocks from the pool, then free them.
// UsbHcUnlinkMemBlock can't be used to unlink and free the
// first block.
//
for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
//UsbHcUnlinkMemBlock (Pool->Head, Block);
UsbHcFreeMemBlock (Pool, Block);
}
UsbHcFreeMemBlock (Pool, Pool->Head);
}
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@return The allocated memory or NULL.
**/
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
USBHC_MEM_BLOCK *NewBlock;
VOID *Mem;
UINTN AllocSize;
UINTN Pages;
Mem = NULL;
AllocSize = USBHC_MEM_ROUND (Size);
Head = Pool->Head;
ASSERT (Head != NULL);
//
// First check whether current memory blocks can satisfy the allocation.
//
for (Block = Head; Block != NULL; Block = Block->Next) {
Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
break;
}
}
if (Mem != NULL) {
return Mem;
}
//
// Create a new memory block if there is not enough memory
// in the pool. If the allocation size is larger than the
// default page number, just allocate a large enough memory
// block. Otherwise allocate default pages.
//
if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
Pages = EFI_SIZE_TO_PAGES (AllocSize);
} else {
Pages = USBHC_MEM_DEFAULT_PAGES;
}
NewBlock = UsbHcAllocMemBlock (Pages);
if (NewBlock == NULL) {
return NULL;
}
//
// Add the new memory block to the pool, then allocate memory from it
//
UsbHcInsertMemBlockToPool (Head, NewBlock);
Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
}
return Mem;
}
/**
Free the allocated memory back to the memory pool.
@param Pool The memory pool of the host controller.
@param Mem The memory to free.
@param Size The size of the memory to free.
**/
VOID
UsbHcFreeMem (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
UINT8 *ToFree;
UINTN AllocSize;
UINTN Byte;
UINTN Bit;
UINTN Count;
Head = Pool->Head;
AllocSize = USBHC_MEM_ROUND (Size);
ToFree = (UINT8 *) Mem;
for (Block = Head; Block != NULL; Block = Block->Next) {
//
// scan the memory block list for the memory block that
// completely contains the memory to free.
//
if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
//
// compute the start byte and bit in the bit array
//
Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
//
// reset associated bits in bit arry
//
for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
NEXT_BIT (Byte, Bit);
}
break;
}
}
//
// If Block == NULL, it means that the current memory isn't
// in the host controller's pool. This is critical because
// the caller has passed in a wrong memory pointer
//
ASSERT (Block != NULL);
//
// Release the current memory block if it is empty and not the head
//
if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
//UsbHcUnlinkMemBlock (Head, Block);
UsbHcFreeMemBlock (Pool, Block);
}
}
/**
Allocates pages at a specified alignment.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
@param Pages The number of pages to allocate.
@param Alignment The requested alignment of the allocation. Must be a power of two.
@param HostAddress The system memory address to map to the PCI controller.
@param DeviceAddress The resulting map address for the bus master PCI controller to
use to access the hosts HostAddress.
@retval EFI_SUCCESS Success to allocate aligned pages.
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
@retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
**/
EFI_STATUS
UsbHcAllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment,
OUT VOID **HostAddress,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Memory;
UINTN AlignedMemory;
UINTN AlignmentMask;
UINTN RealPages;
//
// Alignment must be a power of two or zero.
//
ASSERT ((Alignment & (Alignment - 1)) == 0);
if ((Alignment & (Alignment - 1)) != 0) {
return EFI_INVALID_PARAMETER;
}
if (Pages == 0) {
return EFI_INVALID_PARAMETER;
}
if (Alignment > EFI_PAGE_SIZE) {
//
// Caculate the total number of pages since alignment is larger than page size.
//
AlignmentMask = Alignment - 1;
RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
//
// Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
//
ASSERT (RealPages > Pages);
Status = PeiServicesAllocatePages (
EfiBootServicesData,
Pages,
&Memory
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
} else {
//
// Do not over-allocate pages in this case.
//
Status = PeiServicesAllocatePages (
EfiBootServicesData,
Pages,
&Memory
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
AlignedMemory = (UINTN) Memory;
}
*HostAddress = (VOID *) AlignedMemory;
*DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;
return EFI_SUCCESS;
}
/**
Frees memory that was allocated with UsbHcAllocateAlignedPages().
@param HostAddress The system memory address to map to the PCI controller.
@param Pages The number of pages to free.
**/
VOID
UsbHcFreeAlignedPages (
IN VOID *HostAddress,
IN UINTN Pages
)
{
ASSERT (Pages != 0);
//
// No free memory in PEI.
//
}

View File

@ -0,0 +1,142 @@
/** @file
Private Header file for Usb Host Controller PEIM
Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _EFI_PEI_XHCI_MEM_H_
#define _EFI_PEI_XHCI_MEM_H_
#include <Uefi.h>
#define USBHC_MEM_DEFAULT_PAGES 16
typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
struct _USBHC_MEM_BLOCK {
UINT8 *Bits; // Bit array to record which unit is allocated
UINTN BitsLen;
UINT8 *Buf;
UINT8 *BufHost;
UINTN BufLen; // Memory size in bytes
USBHC_MEM_BLOCK *Next;
};
//
// Memory allocation unit, must be 2^n, n>4
//
#define USBHC_MEM_UNIT 64
#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)
#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
#define USB_HC_BIT_IS_SET(Data, Bit) \
((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
//
// Advance the byte and bit to the next bit, adjust byte accordingly.
//
#define NEXT_BIT(Byte, Bit) \
do { \
(Bit)++; \
if ((Bit) > 7) { \
(Byte)++; \
(Bit) = 0; \
} \
} while (0)
//
// USBHC_MEM_POOL is used to manage the memory used by USB
// host controller. XHCI requires the control memory and transfer
// data to be on the same 4G memory.
//
typedef struct _USBHC_MEM_POOL {
BOOLEAN Check4G;
UINT32 Which4G;
USBHC_MEM_BLOCK *Head;
} USBHC_MEM_POOL;
/**
Calculate the corresponding pci bus address according to the Mem parameter.
@param Pool The memory pool of the host controller.
@param Mem The pointer to host memory.
@param Size The size of the memory region.
@return The pci memory address
**/
EFI_PHYSICAL_ADDRESS
UsbHcGetPciAddrForHostAddr (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
);
/**
Calculate the corresponding host address according to the pci address.
@param Pool The memory pool of the host controller.
@param Mem The pointer to pci memory.
@param Size The size of the memory region.
@return The host memory address
**/
EFI_PHYSICAL_ADDRESS
UsbHcGetHostAddrForPciAddr (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
);
/**
Allocates pages at a specified alignment.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
@param Pages The number of pages to allocate.
@param Alignment The requested alignment of the allocation. Must be a power of two.
@param HostAddress The system memory address to map to the PCI controller.
@param DeviceAddress The resulting map address for the bus master PCI controller to
use to access the hosts HostAddress.
@retval EFI_SUCCESS Success to allocate aligned pages.
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
@retval EFI_OUT_OF_RESOURCES Do not have enough resources to allocate memory.
**/
EFI_STATUS
UsbHcAllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment,
OUT VOID **HostAddress,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
);
/**
Frees memory that was allocated with UsbHcAllocateAlignedPages().
@param HostAddress The system memory address to map to the PCI controller.
@param Pages The number of pages to free.
**/
VOID
UsbHcFreeAlignedPages (
IN VOID *HostAddress,
IN UINTN Pages
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,240 @@
/** @file
Private Header file for Usb Host Controller PEIM
Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _RECOVERY_XHC_H_
#define _RECOVERY_XHC_H_
#include <PiPei.h>
#include <Ppi/UsbController.h>
#include <Ppi/Usb2HostController.h>
#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/TimerLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
typedef struct _PEI_XHC_DEV PEI_XHC_DEV;
typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;
#include "UsbHcMem.h"
#include "XhciReg.h"
#include "XhciSched.h"
#define CMD_RING_TRB_NUMBER 0x100
#define TR_RING_TRB_NUMBER 0x100
#define ERST_NUMBER 0x01
#define EVENT_RING_TRB_NUMBER 0x200
#define XHC_1_MICROSECOND 1
#define XHC_1_MILLISECOND (1000 * XHC_1_MICROSECOND)
#define XHC_1_SECOND (1000 * XHC_1_MILLISECOND)
//
// XHC reset timeout experience values.
// The unit is microsecond, setting it as 1s.
//
#define XHC_RESET_TIMEOUT (1 * XHC_1_SECOND)
//
// XHC delay experience value for polling operation.
// The unit is microsecond, set it as 1ms.
//
#define XHC_POLL_DELAY (1 * XHC_1_MILLISECOND)
//
// Wait for root port state stable.
//
#define XHC_ROOT_PORT_STATE_STABLE (200 * XHC_1_MILLISECOND)
#define XHC_GENERIC_TIMEOUT (10 * XHC_1_MILLISECOND)
#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))
#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
#define XHC_REG_BIT_IS_SET(XHC, Offset, Bit) \
(XHC_BIT_IS_SET(XhcPeiReadOpReg ((XHC), (Offset)), (Bit)))
#define USB_DESC_TYPE_HUB 0x29
#define USB_DESC_TYPE_HUB_SUPER_SPEED 0x2a
//
// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
// three fields: One bit direction, 2 bit type, and 5 bit
// target.
//
#define USB_REQUEST_TYPE(Dir, Type, Target) \
((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))
struct _USB_DEV_CONTEXT {
//
// Whether this entry in UsbDevContext array is used or not.
//
BOOLEAN Enabled;
//
// The slot id assigned to the new device through XHCI's Enable_Slot cmd.
//
UINT8 SlotId;
//
// The route string presented an attached usb device.
//
USB_DEV_ROUTE RouteString;
//
// The route string of parent device if it exists. Otherwise it's zero.
//
USB_DEV_ROUTE ParentRouteString;
//
// The actual device address assigned by XHCI through Address_Device command.
//
UINT8 XhciDevAddr;
//
// The requested device address from UsbBus driver through Set_Address standard usb request.
// As XHCI spec replaces this request with Address_Device command, we have to record the
// requested device address and establish a mapping relationship with the actual device address.
// Then UsbBus driver just need to be aware of the requested device address to access usb device
// through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual
// device address and access the actual device.
//
UINT8 BusDevAddr;
//
// The pointer to the input device context.
//
VOID *InputContext;
//
// The pointer to the output device context.
//
VOID *OutputContext;
//
// The transfer queue for every endpoint.
//
VOID *EndpointTransferRing[31];
//
// The device descriptor which is stored to support XHCI's Evaluate_Context cmd.
//
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
//
// As a usb device may include multiple configuration descriptors, we dynamically allocate an array
// to store them.
// Note that every configuration descriptor stored here includes those lower level descriptors,
// such as Interface descriptor, Endpoint descriptor, and so on.
// These information is used to support XHCI's Config_Endpoint cmd.
//
EFI_USB_CONFIG_DESCRIPTOR **ConfDesc;
};
#define USB_XHC_DEV_SIGNATURE SIGNATURE_32 ('x', 'h', 'c', 'i')
struct _PEI_XHC_DEV {
UINTN Signature;
PEI_USB2_HOST_CONTROLLER_PPI Usb2HostControllerPpi;
EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
UINT32 UsbHostControllerBaseAddress;
USBHC_MEM_POOL *MemPool;
//
// XHCI configuration data
//
UINT8 CapLength; ///< Capability Register Length
XHC_HCSPARAMS1 HcSParams1; ///< Structural Parameters 1
XHC_HCSPARAMS2 HcSParams2; ///< Structural Parameters 2
XHC_HCCPARAMS HcCParams; ///< Capability Parameters
UINT32 DBOff; ///< Doorbell Offset
UINT32 RTSOff; ///< Runtime Register Space Offset
UINT32 PageSize;
UINT32 MaxScratchpadBufs;
UINT64 *ScratchBuf;
UINT64 *ScratchEntry;
UINT64 *DCBAA;
UINT32 MaxSlotsEn;
//
// Cmd Transfer Ring
//
TRANSFER_RING CmdRing;
//
// EventRing
//
EVENT_RING EventRing;
//
// Store device contexts managed by XHCI device
// The array supports up to 255 devices, entry 0 is reserved and should not be used.
//
USB_DEV_CONTEXT UsbDevContext[256];
};
#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)
/**
Initialize the memory management pool for the host controller.
@return Pointer to the allocated memory pool or NULL if failed.
**/
USBHC_MEM_POOL *
UsbHcInitMemPool (
VOID
)
;
/**
Release the memory management pool.
@param Pool The USB memory pool to free.
**/
VOID
UsbHcFreeMemPool (
IN USBHC_MEM_POOL *Pool
)
;
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@return The allocated memory or NULL.
**/
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
)
;
/**
Free the allocated memory back to the memory pool.
@param Pool The memory pool of the host controller.
@param Mem The memory to free.
@param Size The size of the memory to free.
**/
VOID
UsbHcFreeMem (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
;
#endif

View File

@ -0,0 +1,59 @@
## @file
# Component description file for XhcPeim PEIM to produce gPeiUsb2HostControllerPpiGuid
# based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers.
#
# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions
# of the BSD License which accompanies this distribution. The
# full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = XhciPei
FILE_GUID = 65E5746E-9C14-467d-B5B3-932A66D59F79
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = XhcPeimEntry
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
XhcPeim.c
XhcPeim.h
XhciSched.c
UsbHcMem.c
XhciReg.h
XhciSched.h
UsbHcMem.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
IoLib
TimerLib
BaseMemoryLib
PeimEntryPoint
PeiServicesLib
MemoryAllocationLib
[Ppis]
gPeiUsb2HostControllerPpiGuid ## PRODUCES
gPeiUsbControllerPpiGuid ## CONSUMES
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid

View File

@ -0,0 +1,471 @@
/** @file
Private Header file for Usb Host Controller PEIM
Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _EFI_PEI_XHCI_REG_H_
#define _EFI_PEI_XHCI_REG_H_
//
// Capability registers offset
//
#define XHC_CAPLENGTH_OFFSET 0x00 // Capability register length offset
#define XHC_HCIVERSION_OFFSET 0x02 // Interface Version Number 02-03h
#define XHC_HCSPARAMS1_OFFSET 0x04 // Structural Parameters 1
#define XHC_HCSPARAMS2_OFFSET 0x08 // Structural Parameters 2
#define XHC_HCSPARAMS3_OFFSET 0x0c // Structural Parameters 3
#define XHC_HCCPARAMS_OFFSET 0x10 // Capability Parameters
#define XHC_DBOFF_OFFSET 0x14 // Doorbell Offset
#define XHC_RTSOFF_OFFSET 0x18 // Runtime Register Space Offset
//
// Operational registers offset
//
#define XHC_USBCMD_OFFSET 0x0000 // USB Command Register Offset
#define XHC_USBSTS_OFFSET 0x0004 // USB Status Register Offset
#define XHC_PAGESIZE_OFFSET 0x0008 // USB Page Size Register Offset
#define XHC_DNCTRL_OFFSET 0x0014 // Device Notification Control Register Offset
#define XHC_CRCR_OFFSET 0x0018 // Command Ring Control Register Offset
#define XHC_DCBAAP_OFFSET 0x0030 // Device Context Base Address Array Pointer Register Offset
#define XHC_CONFIG_OFFSET 0x0038 // Configure Register Offset
#define XHC_PORTSC_OFFSET 0x0400 // Port Status and Control Register Offset
//
// Runtime registers offset
//
#define XHC_MFINDEX_OFFSET 0x00 // Microframe Index Register Offset
#define XHC_IMAN_OFFSET 0x20 // Interrupter X Management Register Offset
#define XHC_IMOD_OFFSET 0x24 // Interrupter X Moderation Register Offset
#define XHC_ERSTSZ_OFFSET 0x28 // Event Ring Segment Table Size Register Offset
#define XHC_ERSTBA_OFFSET 0x30 // Event Ring Segment Table Base Address Register Offset
#define XHC_ERDP_OFFSET 0x38 // Event Ring Dequeue Pointer Register Offset
//
// Register Bit Definition
//
#define XHC_USBCMD_RUN BIT0 // Run/Stop
#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
#define XHC_USBCMD_INTE BIT2 // Interrupter Enable
#define XHC_USBCMD_HSEE BIT3 // Host System Error Enable
#define XHC_USBSTS_HALT BIT0 // Host Controller Halted
#define XHC_USBSTS_HSE BIT2 // Host System Error
#define XHC_USBSTS_EINT BIT3 // Event Interrupt
#define XHC_USBSTS_PCD BIT4 // Port Change Detect
#define XHC_USBSTS_SSS BIT8 // Save State Status
#define XHC_USBSTS_RSS BIT9 // Restore State Status
#define XHC_USBSTS_SRE BIT10 // Save/Restore Error
#define XHC_USBSTS_CNR BIT11 // Host Controller Not Ready
#define XHC_USBSTS_HCE BIT12 // Host Controller Error
#define XHC_PAGESIZE_MASK 0xFFFF // Page Size
#define XHC_CRCR_RCS BIT0 // Ring Cycle State
#define XHC_CRCR_CS BIT1 // Command Stop
#define XHC_CRCR_CA BIT2 // Command Abort
#define XHC_CRCR_CRR BIT3 // Command Ring Running
#define XHC_CONFIG_MASK 0xFF // Max Device Slots Enabled
#define XHC_PORTSC_CCS BIT0 // Current Connect Status
#define XHC_PORTSC_PED BIT1 // Port Enabled/Disabled
#define XHC_PORTSC_OCA BIT3 // Over-current Active
#define XHC_PORTSC_RESET BIT4 // Port Reset
#define XHC_PORTSC_PLS (BIT5|BIT6|BIT7|BIT8) // Port Link State
#define XHC_PORTSC_PP BIT9 // Port Power
#define XHC_PORTSC_PS (BIT10|BIT11|BIT12) // Port Speed
#define XHC_PORTSC_LWS BIT16 // Port Link State Write Strobe
#define XHC_PORTSC_CSC BIT17 // Connect Status Change
#define XHC_PORTSC_PEC BIT18 // Port Enabled/Disabled Change
#define XHC_PORTSC_WRC BIT19 // Warm Port Reset Change
#define XHC_PORTSC_OCC BIT20 // Over-Current Change
#define XHC_PORTSC_PRC BIT21 // Port Reset Change
#define XHC_PORTSC_PLC BIT22 // Port Link State Change
#define XHC_PORTSC_CEC BIT23 // Port Config Error Change
#define XHC_PORTSC_CAS BIT24 // Cold Attach Status
#define XHC_HUB_PORTSC_CCS BIT0 // Hub's Current Connect Status
#define XHC_HUB_PORTSC_PED BIT1 // Hub's Port Enabled/Disabled
#define XHC_HUB_PORTSC_OCA BIT3 // Hub's Over-current Active
#define XHC_HUB_PORTSC_RESET BIT4 // Hub's Port Reset
#define XHC_HUB_PORTSC_PP BIT9 // Hub's Port Power
#define XHC_HUB_PORTSC_CSC BIT16 // Hub's Connect Status Change
#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change
#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change
#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change
#define XHC_HUB_PORTSC_BHRC BIT21 // Hub's Port Warm Reset Change
#define XHC_IMAN_IP BIT0 // Interrupt Pending
#define XHC_IMAN_IE BIT1 // Interrupt Enable
#define XHC_IMODI_MASK 0x0000FFFF // Interrupt Moderation Interval
#define XHC_IMODC_MASK 0xFFFF0000 // Interrupt Moderation Counter
#pragma pack (1)
typedef struct {
UINT8 MaxSlots; // Number of Device Slots
UINT16 MaxIntrs:11; // Number of Interrupters
UINT16 Rsvd:5;
UINT8 MaxPorts; // Number of Ports
} HCSPARAMS1;
//
// Structural Parameters 1 Register Bitmap Definition
//
typedef union {
UINT32 Dword;
HCSPARAMS1 Data;
} XHC_HCSPARAMS1;
typedef struct {
UINT32 Ist:4; // Isochronous Scheduling Threshold
UINT32 Erst:4; // Event Ring Segment Table Max
UINT32 Rsvd:13;
UINT32 ScratchBufHi:5; // Max Scratchpad Buffers Hi
UINT32 Spr:1; // Scratchpad Restore
UINT32 ScratchBufLo:5; // Max Scratchpad Buffers Lo
} HCSPARAMS2;
//
// Structural Parameters 2 Register Bitmap Definition
//
typedef union {
UINT32 Dword;
HCSPARAMS2 Data;
} XHC_HCSPARAMS2;
typedef struct {
UINT16 Ac64:1; // 64-bit Addressing Capability
UINT16 Bnc:1; // BW Negotiation Capability
UINT16 Csz:1; // Context Size
UINT16 Ppc:1; // Port Power Control
UINT16 Pind:1; // Port Indicators
UINT16 Lhrc:1; // Light HC Reset Capability
UINT16 Ltc:1; // Latency Tolerance Messaging Capability
UINT16 Nss:1; // No Secondary SID Support
UINT16 Pae:1; // Parse All Event Data
UINT16 Rsvd:3;
UINT16 MaxPsaSize:4; // Maximum Primary Stream Array Size
UINT16 ExtCapReg; // xHCI Extended Capabilities Pointer
} HCCPARAMS;
//
// Capability Parameters Register Bitmap Definition
//
typedef union {
UINT32 Dword;
HCCPARAMS Data;
} XHC_HCCPARAMS;
#pragma pack ()
//
// XHCi Data and Ctrl Structures
//
#pragma pack(1)
typedef struct {
UINT8 Pi;
UINT8 SubClassCode;
UINT8 BaseCode;
} USB_CLASSC;
typedef struct {
UINT8 Length;
UINT8 DescType;
UINT8 NumPorts;
UINT16 HubCharacter;
UINT8 PwrOn2PwrGood;
UINT8 HubContrCurrent;
UINT8 Filler[16];
} EFI_USB_HUB_DESCRIPTOR;
#pragma pack()
//
// Hub Class Feature Selector for Clear Port Feature Request
// It's the extension of hub class feature selector of USB 2.0 in USB 3.0 Spec.
// For more details, Please refer to USB 3.0 Spec Table 10-7.
//
typedef enum {
Usb3PortBHPortReset = 28,
Usb3PortBHPortResetChange = 29
} XHC_PORT_FEATURE;
//
// Structure to map the hardware port states to the
// UEFI's port states.
//
typedef struct {
UINT32 HwState;
UINT16 UefiState;
} USB_PORT_STATE_MAP;
//
// Structure to map the hardware port states to feature selector for clear port feature request.
//
typedef struct {
UINT32 HwState;
UINT16 Selector;
} USB_CLEAR_PORT_MAP;
/**
Read XHCI Operation register.
@param Xhc The XHCI device.
@param Offset The operation register offset.
@retval the register content read.
**/
UINT32
XhcPeiReadOpReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset
);
/**
Write the data to the XHCI operation register.
@param Xhc The XHCI device.
@param Offset The operation register offset.
@param Data The data to write.
**/
VOID
XhcPeiWriteOpReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Data
);
/**
Set one bit of the operational register while keeping other bits.
@param Xhc The XHCI device.
@param Offset The offset of the operational register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcPeiSetOpRegBit (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
);
/**
Clear one bit of the operational register while keeping other bits.
@param Xhc The XHCI device.
@param Offset The offset of the operational register.
@param Bit The bit mask of the register to clear.
**/
VOID
XhcPeiClearOpRegBit (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
);
/**
Wait the operation register's bit as specified by Bit
to be set (or clear).
@param Xhc The XHCI device.
@param Offset The offset of the operational register.
@param Bit The bit of the register to wait for.
@param WaitToSet Wait the bit to set or clear.
@param Timeout The time to wait before abort (in microsecond, us).
@retval EFI_SUCCESS The bit successfully changed by host controller.
@retval EFI_TIMEOUT The time out occurred.
**/
EFI_STATUS
XhcPeiWaitOpRegBit (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Bit,
IN BOOLEAN WaitToSet,
IN UINT32 Timeout
);
/**
Read XHCI door bell register.
@param Xhc The XHCI device.
@param Offset The offset of the door bell register.
@return The register content read
**/
UINT32
XhcPeiReadDoorBellReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset
);
/**
Write the data to the XHCI door bell register.
@param Xhc The XHCI device.
@param Offset The offset of the door bell register.
@param Data The data to write.
**/
VOID
XhcPeiWriteDoorBellReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Data
);
/**
Read XHCI runtime register.
@param Xhc The XHCI device.
@param Offset The offset of the runtime register.
@return The register content read
**/
UINT32
XhcPeiReadRuntimeReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset
);
/**
Write the data to the XHCI runtime register.
@param Xhc The XHCI device.
@param Offset The offset of the runtime register.
@param Data The data to write.
**/
VOID
XhcPeiWriteRuntimeReg (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Data
);
/**
Set one bit of the runtime register while keeping other bits.
@param Xhc The XHCI device.
@param Offset The offset of the runtime register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcPeiSetRuntimeRegBit (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
);
/**
Clear one bit of the runtime register while keeping other bits.
@param Xhc The XHCI device.
@param Offset The offset of the runtime register.
@param Bit The bit mask of the register to set.
**/
VOID
XhcPeiClearRuntimeRegBit (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Offset,
IN UINT32 Bit
);
/**
Check whether Xhc is halted.
@param Xhc The XHCI device.
@retval TRUE The controller is halted.
@retval FALSE The controller isn't halted.
**/
BOOLEAN
XhcPeiIsHalt (
IN PEI_XHC_DEV *Xhc
);
/**
Check whether system error occurred.
@param Xhc The XHCI device.
@retval TRUE System error happened.
@retval FALSE No system error.
**/
BOOLEAN
XhcPeiIsSysError (
IN PEI_XHC_DEV *Xhc
);
/**
Reset the host controller.
@param Xhc The XHCI device.
@param Timeout Time to wait before abort (in millisecond, ms).
@retval EFI_TIMEOUT The transfer failed due to time out.
@retval Others Failed to reset the host.
**/
EFI_STATUS
XhcPeiResetHC (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Timeout
);
/**
Halt the host controller.
@param Xhc The XHCI device.
@param Timeout Time to wait before abort.
@retval EFI_TIMEOUT Failed to halt the controller before Timeout.
@retval EFI_SUCCESS The XHCI is halt.
**/
EFI_STATUS
XhcPeiHaltHC (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Timeout
);
/**
Set the XHCI to run.
@param Xhc The XHCI device.
@param Timeout Time to wait before abort.
@retval EFI_SUCCESS The XHCI is running.
@retval Others Failed to set the XHCI to run.
**/
EFI_STATUS
XhcPeiRunHC (
IN PEI_XHC_DEV *Xhc,
IN UINT32 Timeout
);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/** @file
Usb Hub Request Support In PEI Phase
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
@ -319,6 +319,139 @@ PeiGetHubDescriptor (
);
}
/**
Get a given SuperSpeed hub descriptor.
@param PeiServices General-purpose services that are available to every PEIM.
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
@param HubDescriptor Caller allocated buffer to store the hub descriptor if
successfully returned.
@retval EFI_SUCCESS Hub descriptor is obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
@retval Others Other failure occurs.
**/
EFI_STATUS
PeiGetSuperSpeedHubDesc (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB_IO_PPI *UsbIoPpi,
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
)
{
EFI_USB_DEVICE_REQUEST DevReq;
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DevReq.RequestType = USB_RT_HUB | 0x80;
DevReq.Request = USB_HUB_GET_DESCRIPTOR;
DevReq.Value = USB_DT_SUPERSPEED_HUB << 8;
DevReq.Length = 12;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DevReq,
EfiUsbDataIn,
PcdGet32 (PcdUsbTransferTimeoutValue),
HubDescriptor,
12
);
}
/**
Read the whole usb hub descriptor. It is necessary
to do it in two steps because hub descriptor is of
variable length.
@param PeiServices General-purpose services that are available to every PEIM.
@param PeiUsbDevice Indicates the hub controller device.
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
@param HubDescriptor Caller allocated buffer to store the hub descriptor if
successfully returned.
@retval EFI_SUCCESS Hub descriptor is obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.
@retval Others Other failure occurs.
**/
EFI_STATUS
PeiUsbHubReadDesc (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB_DEVICE *PeiUsbDevice,
IN PEI_USB_IO_PPI *UsbIoPpi,
OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor
)
{
EFI_STATUS Status;
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
//
// Get the super speed hub descriptor
//
Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);
} else {
//
// First get the hub descriptor length
//
Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the whole hub descriptor
//
Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
}
return Status;
}
/**
USB hub control transfer to set the hub depth.
@param PeiServices General-purpose services that are available to every PEIM.
@param PeiUsbDevice Indicates the hub controller device.
@param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.
@retval EFI_SUCCESS Depth of the hub is set.
@retval Others Failed to set the depth.
**/
EFI_STATUS
PeiUsbHubCtrlSetHubDepth (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_USB_DEVICE *PeiUsbDevice,
IN PEI_USB_IO_PPI *UsbIoPpi
)
{
EFI_USB_DEVICE_REQUEST DevReq;
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
//
// Fill Device request packet
//
DevReq.RequestType = USB_RT_HUB;
DevReq.Request = USB_HUB_REQ_SET_DEPTH;
DevReq.Value = PeiUsbDevice->Tier;
DevReq.Length = 0;
return UsbIoPpi->UsbControlTransfer (
PeiServices,
UsbIoPpi,
&DevReq,
EfiUsbNoData,
PcdGet32 (PcdUsbTransferTimeoutValue),
NULL,
0
);
}
/**
Configure a given hub.
@ -339,32 +472,18 @@ PeiDoHubConfig (
EFI_STATUS Status;
EFI_USB_HUB_STATUS HubStatus;
UINTN Index;
UINT32 PortStatus;
PEI_USB_IO_PPI *UsbIoPpi;
ZeroMem (&HubDescriptor, sizeof (HubDescriptor));
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
//
// First get the hub descriptor length
// Get the hub descriptor
//
Status = PeiGetHubDescriptor (
Status = PeiUsbHubReadDesc (
PeiServices,
PeiUsbDevice,
UsbIoPpi,
2,
&HubDescriptor
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
//
// First get the whole descriptor, then
// get the number of hub ports
//
Status = PeiGetHubDescriptor (
PeiServices,
UsbIoPpi,
HubDescriptor.Length,
&HubDescriptor
);
if (EFI_ERROR (Status)) {
@ -373,74 +492,66 @@ PeiDoHubConfig (
PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;
Status = PeiHubGetHubStatus (
PeiServices,
UsbIoPpi,
(UINT32 *) &HubStatus
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
//
// Get all hub ports status
//
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
Status = PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
&PortStatus
);
if (EFI_ERROR (Status)) {
continue;
}
}
//
// Power all the hub ports
//
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
Status = PeiHubSetPortFeature (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
EfiUsbPortPower
);
if (EFI_ERROR (Status)) {
continue;
}
}
//
// Clear Hub Status Change
//
Status = PeiHubGetHubStatus (
PeiServices,
UsbIoPpi,
(UINT32 *) &HubStatus
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
PeiUsbHubCtrlSetHubDepth (
PeiServices,
PeiUsbDevice,
UsbIoPpi
);
} else {
//
// Hub power supply change happens
// Power all the hub ports
//
if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_LOCAL_POWER
);
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
Status = PeiHubSetPortFeature (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
EfiUsbPortPower
);
if (EFI_ERROR (Status)) {
DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
continue;
}
}
DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood));
if (HubDescriptor.PwrOn2PwrGood > 0) {
MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
}
//
// Hub change overcurrent happens
// Clear Hub Status Change
//
if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_OVER_CURRENT
);
Status = PeiHubGetHubStatus (
PeiServices,
UsbIoPpi,
(UINT32 *) &HubStatus
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
} else {
//
// Hub power supply change happens
//
if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_LOCAL_POWER
);
}
//
// Hub change overcurrent happens
//
if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
PeiHubClearHubFeature (
PeiServices,
UsbIoPpi,
C_HUB_OVER_CURRENT
);
}
}
}
@ -462,10 +573,10 @@ PeiResetHubPort (
IN UINT8 PortNum
)
{
UINT8 Try;
EFI_STATUS Status;
UINTN Index;
EFI_USB_PORT_STATUS HubPortStatus;
MicroSecondDelay (100 * 1000);
//
@ -478,27 +589,49 @@ PeiResetHubPort (
EfiUsbPortReset
);
Try = 10;
do {
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
PortNum,
(UINT32 *) &HubPortStatus
);
MicroSecondDelay (2 * 1000);
Try -= 1;
} while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);
//
// Drive the reset signal for worst 20ms. Check USB 2.0 Spec
// section 7.1.7.5 for timing requirements.
//
MicroSecondDelay (USB_SET_PORT_RESET_STALL);
//
// clear reset root port
// Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
//
ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
Status = PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
PortNum,
(UINT32 *) &HubPortStatus
);
if (EFI_ERROR (Status)) {
return;
}
if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
break;
}
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
}
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
return;
}
//
// clear reset change root port
//
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
PortNum,
EfiUsbPortReset
EfiUsbPortResetChange
);
MicroSecondDelay (1 * 1000);

View File

@ -1,7 +1,7 @@
/** @file
Constants definitions for Usb Hub Peim
Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
@ -80,6 +80,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
#define USB_HUB_REQ_SET_DEPTH 12
#define MAXBYTES 8
#pragma pack(1)
//

View File

@ -221,26 +221,24 @@ IsPortConnect (
}
/**
Judge if the port is connected with a low-speed usb device or not.
Get device speed according to port status.
@param PortStatus The usb port status gotten.
@param PortStatus The usb port status gotten.
@retval TRUE A low-speed usb device is connected with the port.
@retval FALSE No low-speed usb device is connected with the port.
@return Device speed value.
**/
UINTN
IsPortLowSpeedDeviceAttached (
IN UINT16 PortStatus
PeiUsbGetDeviceSpeed (
IN UINT16 PortStatus
)
{
//
// return the bit 9 value of PortStatus
//
if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
return EFI_USB_SPEED_LOW;
} else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){
return EFI_USB_SPEED_HIGH;
} else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
return EFI_USB_SPEED_SUPER;
} else {
return EFI_USB_SPEED_FULL;
}

View File

@ -70,6 +70,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_HUB 0x29
#define USB_DT_SUPERSPEED_HUB 0x2A
#define USB_DT_HID 0x21
//
@ -202,17 +203,16 @@ IsPortConnect (
);
/**
Judge if the port is connected with a low-speed usb device or not.
Get device speed according to port status.
@param PortStatus The usb port status gotten.
@param PortStatus The usb port status gotten.
@retval TRUE A low-speed usb device is connected with the port.
@retval FALSE No low-speed usb device is connected with the port.
@return Device speed value.
**/
UINTN
IsPortLowSpeedDeviceAttached (
IN UINT16 PortStatus
PeiUsbGetDeviceSpeed (
IN UINT16 PortStatus
);
/**

View File

@ -105,7 +105,7 @@ PeiUsbControlTransfer (
PeiUsbDev->UsbHcPpi,
PeiUsbDev->DeviceAddress,
PeiUsbDev->DeviceSpeed,
PeiUsbDev->MaxPacketSize0,
(UINT8) PeiUsbDev->MaxPacketSize0,
Request,
Direction,
Data,
@ -126,6 +126,7 @@ PeiUsbControlTransfer (
}
}
DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));
return Status;
}
@ -238,6 +239,7 @@ PeiUsbBulkTransfer (
PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
}
DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));
return Status;
}

View File

@ -228,6 +228,8 @@ PeiHubEnumeration (
UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));
for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
Status = PeiHubGetPortStatus (
@ -241,25 +243,14 @@ PeiHubEnumeration (
continue;
}
if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
EfiUsbPortConnectChange
);
MicroSecondDelay (100 * 1000);
DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
//
// Only handle connection/enable/overcurrent/reset change.
//
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
continue;
} else {
if (IsPortConnect (PortStatus.PortStatus)) {
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
(UINT32 *) &PortStatus
);
//
// Begin to deal with the new device
//
@ -294,19 +285,44 @@ PeiHubEnumeration (
NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1);
NewPeiUsbDevice->IsHub = 0x0;
NewPeiUsbDevice->DownStreamPortNo = 0x0;
PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
//
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
//
PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
(UINT32 *) &PortStatus
);
} else {
PeiHubClearPortFeature (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
EfiUsbPortResetChange
);
}
PeiHubGetPortStatus (
PeiServices,
UsbIoPpi,
(UINT8) (Index + 1),
(UINT32 *) &PortStatus
);
NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
NewPeiUsbDevice->MaxPacketSize0 = 512;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
NewPeiUsbDevice->MaxPacketSize0 = 64;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
NewPeiUsbDevice->MaxPacketSize0 = 8;
} else {
NewPeiUsbDevice->MaxPacketSize0 = 8;
}
if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
@ -330,6 +346,7 @@ PeiHubEnumeration (
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));
Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
@ -435,6 +452,8 @@ PeiUsbEnumeration (
return EFI_INVALID_PARAMETER;
}
DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
for (Index = 0; Index < NumOfRootPort; Index++) {
//
// First get root port status to detect changes happen
@ -454,48 +473,14 @@ PeiUsbEnumeration (
&PortStatus
);
}
DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));
if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
//
// Changes happen, first clear this change status
//
if (Usb2HcPpi != NULL) {
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
(UINT8) Index,
EfiUsbPortConnectChange
);
} else {
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,
(UINT8) Index,
EfiUsbPortConnectChange
);
}
MicroSecondDelay (100 * 1000);
DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
//
// Only handle connection/enable/overcurrent/reset change.
//
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
continue;
} else {
if (IsPortConnect (PortStatus.PortStatus)) {
if (Usb2HcPpi != NULL) {
Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
(UINT8) Index,
&PortStatus
);
} else {
UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
(UINT8) Index,
&PortStatus
);
}
//
// Connect change happen
//
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
@ -530,33 +515,65 @@ PeiUsbEnumeration (
PeiUsbDevice->IsHub = 0x0;
PeiUsbDevice->DownStreamPortNo = 0x0;
ResetRootPort (
PeiServices,
PeiUsbDevice->UsbHcPpi,
PeiUsbDevice->Usb2HcPpi,
Index,
0
);
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
//
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
//
ResetRootPort (
PeiServices,
PeiUsbDevice->UsbHcPpi,
PeiUsbDevice->Usb2HcPpi,
Index,
0
);
if (Usb2HcPpi != NULL) {
Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
(UINT8) Index,
&PortStatus
);
if (Usb2HcPpi != NULL) {
Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
(UINT8) Index,
&PortStatus
);
} else {
UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
(UINT8) Index,
&PortStatus
);
}
} else {
UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
(UINT8) Index,
&PortStatus
);
if (Usb2HcPpi != NULL) {
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
(UINT8) Index,
EfiUsbPortResetChange
);
} else {
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,
(UINT8) Index,
EfiUsbPortResetChange
);
}
}
PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
PeiUsbDevice->MaxPacketSize0 = 512;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 64;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 8;
} else {
PeiUsbDevice->MaxPacketSize0 = 8;
}
//
// Configure that Usb Device
//
@ -570,7 +587,7 @@ PeiUsbEnumeration (
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));
DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
@ -665,9 +682,6 @@ PeiConfigureUsbDevice (
//
for (Retry = 0; Retry < 3; Retry ++) {
PeiUsbDevice->MaxPacketSize0 = 8;
Status = PeiUsbGetDescriptor (
PeiServices,
UsbIoPpi,
@ -678,17 +692,21 @@ PeiConfigureUsbDevice (
);
if (!EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));
DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));
break;
}
}
if (Retry == 3) {
DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));
DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));
return Status;
}
PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
if ((DeviceDescriptor.BcdUSB == 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {
PeiUsbDevice->MaxPacketSize0 = 1 << 9;
} else {
PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
}
(*DeviceAddress) ++;
@ -699,7 +717,7 @@ PeiConfigureUsbDevice (
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));
DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));
return Status;
}
@ -995,6 +1013,8 @@ ResetRootPort (
)
{
EFI_STATUS Status;
UINTN Index;
EFI_USB_PORT_STATUS PortStatus;
if (Usb2HcPpi != NULL) {
@ -1015,8 +1035,12 @@ ResetRootPort (
return;
}
MicroSecondDelay (200 * 1000);
//
// Drive the reset signal for at least 50ms. Check USB 2.0 Spec
// section 7.1.7.5 for timing requirements.
//
MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
//
// clear reset root port
//
@ -1031,9 +1055,45 @@ ResetRootPort (
DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
return;
}
MicroSecondDelay (1 * 1000);
MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
//
// USB host controller won't clear the RESET bit until
// reset is actually finished.
//
ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
Status = Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
PortNum,
&PortStatus
);
if (EFI_ERROR (Status)) {
return;
}
if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
break;
}
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
}
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
return;
}
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
PortNum,
EfiUsbPortResetChange
);
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
@ -1077,7 +1137,11 @@ ResetRootPort (
return;
}
MicroSecondDelay (200 * 1000);
//
// Drive the reset signal for at least 50ms. Check USB 2.0 Spec
// section 7.1.7.5 for timing requirements.
//
MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
//
// clear reset root port
@ -1094,8 +1158,44 @@ ResetRootPort (
return;
}
MicroSecondDelay (1 * 1000);
MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
//
// USB host controller won't clear the RESET bit until
// reset is actually finished.
//
ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
Status = UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
PortNum,
&PortStatus
);
if (EFI_ERROR (Status)) {
return;
}
if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
break;
}
MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
}
if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
return;
}
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,
PortNum,
EfiUsbPortResetChange
);
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,

View File

@ -33,25 +33,20 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <IndustryStandard/Usb.h>
#define MAX_ROOT_PORT 2
#define MAX_INTERFACE 8
#define MAX_ENDPOINT 16
#define USB_SLOW_SPEED_DEVICE 0x01
#define USB_FULL_SPEED_DEVICE 0x02
#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')
typedef struct {
UINTN Signature;
PEI_USB_IO_PPI UsbIoPpi;
EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;
UINT16 MaxPacketSize0;
UINT16 DataToggle;
UINT8 DeviceAddress;
UINT8 MaxPacketSize0;
UINT8 DeviceSpeed;
UINT8 IsHub;
UINT16 DataToggle;
UINT8 DownStreamPortNo;
UINT8 Reserved; // Padding for IPF
UINTN AllocateAddress;
PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
@ -61,11 +56,48 @@ typedef struct {
EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescList[MAX_INTERFACE];
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];
EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescList[MAX_INTERFACE][MAX_ENDPOINT];
EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
UINT8 Tier;
} PEI_USB_DEVICE;
#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)
#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
#define USB_BUS_1_MILLISECOND 1000
//
// Wait for port reset, refers to specification
// [USB20-7.1.7.5, it says 10ms for hub and 50ms for
// root hub]
//
// According to USB2.0, Chapter 11.5.1.5 Resetting,
// the worst case for TDRST is 20ms
//
#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND)
//
// Wait for clear roothub port reset, set by experience
//
#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND)
//
// Wait for port statue reg change, set by experience
//
#define USB_WAIT_PORT_STS_CHANGE_STALL (100)
//
// Host software return timeout if port status doesn't change
// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience
//
#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000
//
// Wait for hub port power-on, refers to specification
// [USB20-11.23.2]
//
#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND)
/**
Submits control transfer to a target USB device.

View File

@ -2,7 +2,7 @@
Define APIs to retrieve USB Host Controller Info such as controller type and
I/O Port Base Address.
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
@ -49,6 +49,12 @@ typedef struct _PEI_USB_CONTROLLER_PPI PEI_USB_CONTROLLER_PPI;
///
#define PEI_EHCI_CONTROLLER 0x03
///
/// This bit is used in the ControllerType return parameter of GetUsbController()
/// to identify the USB Host Controller type as XHCI
///
#define PEI_XHCI_CONTROLLER 0x04
/**
Retrieve USB Host Controller Info such as controller type and I/O Base Address.

View File

@ -202,6 +202,7 @@
MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf
MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf
MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
MdeModulePkg/Bus/Pci/IdeBusPei/IdeBusPei.inf
MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf
MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf