MdeModulePkg XhciPei/UsbBusPei: Add XHCI recovery support.
authorStar Zeng <star.zeng@intel.com>
Wed, 2 Jul 2014 03:20:49 +0000 (03:20 +0000)
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 2 Jul 2014 03:20:49 +0000 (03:20 +0000)
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

17 files changed:
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
MdeModulePkg/Include/Ppi/UsbController.h
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
new file mode 100644 (file)
index 0000000..b9ea51b
--- /dev/null
@@ -0,0 +1,662 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool.\r
+\r
+  @param  Pages         How many pages to allocate.\r
+\r
+  @return Pointer to the allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+  IN UINTN              Pages\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Block;\r
+  EFI_STATUS            Status;\r
+  UINTN                 PageNumber;\r
+  EFI_PHYSICAL_ADDRESS  TempPtr;\r
+\r
+  PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_BLOCK));\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
+\r
+  //\r
+  // each bit in the bit array represents USBHC_MEM_UNIT\r
+  // bytes of memory in the memory block.\r
+  //\r
+  ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+  Block = (USBHC_MEM_BLOCK *) (UINTN) TempPtr;\r
+  Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+\r
+  PageNumber = EFI_SIZE_TO_PAGES (Block->BitsLen);\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
+\r
+  Block->Bits = (UINT8 *) (UINTN) TempPtr;\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             Pages,\r
+             &TempPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+  Block->BufHost = (UINT8 *) (UINTN) TempPtr;;\r
+  Block->Buf = (UINT8 *) (UINTN) TempPtr;\r
+  Block->Next = NULL;\r
+\r
+  return Block;\r
+}\r
+\r
+/**\r
+  Free the memory block from the memory pool.\r
+\r
+  @param  Pool          The memory pool to free the block from.\r
+  @param  Block         The memory block to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemBlock (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN USBHC_MEM_BLOCK    *Block\r
+  )\r
+{\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+  //\r
+  // No free memory in PEI.\r
+  //\r
+}\r
+\r
+/**\r
+  Alloc some memory from the block.\r
+\r
+  @param  Block         The memory block to allocate memory from.\r
+  @param  Units         Number of memory units to allocate.\r
+\r
+  @return The pointer to the allocated memory.\r
+          If couldn't allocate the needed memory, the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+  IN USBHC_MEM_BLOCK    *Block,\r
+  IN UINTN              Units\r
+  )\r
+{\r
+  UINTN                 Byte;\r
+  UINT8                 Bit;\r
+  UINTN                 StartByte;\r
+  UINT8                 StartBit;\r
+  UINTN                 Available;\r
+  UINTN                 Count;\r
+\r
+  ASSERT ((Block != 0) && (Units != 0));\r
+\r
+  StartByte  = 0;\r
+  StartBit   = 0;\r
+  Available  = 0;\r
+\r
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+    //\r
+    // If current bit is zero, the corresponding memory unit is\r
+    // available, otherwise we need to restart our searching.\r
+    // Available counts the consective number of zero bit.\r
+    //\r
+    if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+      Available++;\r
+\r
+      if (Available >= Units) {\r
+        break;\r
+      }\r
+\r
+      NEXT_BIT (Byte, Bit);\r
+    } else {\r
+      NEXT_BIT (Byte, Bit);\r
+\r
+      Available  = 0;\r
+      StartByte  = Byte;\r
+      StartBit   = Bit;\r
+    }\r
+  }\r
+\r
+  if (Available < Units) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Mark the memory as allocated\r
+  //\r
+  Byte  = StartByte;\r
+  Bit   = StartBit;\r
+\r
+  for (Count = 0; Count < Units; Count++) {\r
+    ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
+    NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+/**\r
+  Calculate the corresponding pci bus address according to the Mem parameter.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The pointer to host memory.\r
+  @param  Size          The size of the memory region.\r
+\r
+  @return               The pci memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddrForHostAddr (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Head;\r
+  USBHC_MEM_BLOCK       *Block;\r
+  UINTN                 AllocSize;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+  UINTN                 Offset;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+\r
+  if (Mem == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the allocated memory.\r
+    //\r
+    if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT ((Block != NULL));\r
+  //\r
+  // calculate the pci memory address for host memory address.\r
+  //\r
+  Offset = (UINT8 *) Mem - Block->BufHost;\r
+  PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->Buf + Offset);\r
+  return PhyAddr;\r
+}\r
+\r
+/**\r
+  Calculate the corresponding host address according to the pci address.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The pointer to pci memory.\r
+  @param  Size          The size of the memory region.\r
+\r
+  @return               The host memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetHostAddrForPciAddr (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Head;\r
+  USBHC_MEM_BLOCK       *Block;\r
+  UINTN                 AllocSize;\r
+  EFI_PHYSICAL_ADDRESS  HostAddr;\r
+  UINTN                 Offset;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+\r
+  if (Mem == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the allocated memory.\r
+    //\r
+    if ((Block->Buf <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT ((Block != NULL));\r
+  //\r
+  // calculate the host memory address for pci memory address.\r
+  //\r
+  Offset = (UINT8 *) Mem - Block->Buf;\r
+  HostAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) (Block->BufHost + Offset);\r
+  return HostAddr;\r
+}\r
+\r
+/**\r
+  Insert the memory block to the pool's list of the blocks.\r
+\r
+  @param  Head          The head of the memory pool's block list.\r
+  @param  Block         The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+  IN USBHC_MEM_BLOCK    *Head,\r
+  IN USBHC_MEM_BLOCK    *Block\r
+  )\r
+{\r
+  ASSERT ((Head != NULL) && (Block != NULL));\r
+  Block->Next = Head->Next;\r
+  Head->Next  = Block;\r
+}\r
+\r
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block         The memory block to check.\r
+\r
+  @retval TRUE          The memory block is empty.\r
+  @retval FALSE         The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+  IN USBHC_MEM_BLOCK    *Block\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < Block->BitsLen; Index++) {\r
+    if (Block->Bits[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Unlink the memory block from the pool's list.\r
+\r
+  @param  Head          The block list head of the memory's pool.\r
+  @param  BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+  IN USBHC_MEM_BLOCK    *Head,\r
+  IN USBHC_MEM_BLOCK    *BlockToUnlink\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Block;\r
+\r
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    if (Block->Next == BlockToUnlink) {\r
+      Block->Next         = BlockToUnlink->Next;\r
+      BlockToUnlink->Next = NULL;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @return Pointer to the allocated memory pool or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  VOID\r
+  )\r
+{\r
+  USBHC_MEM_POOL        *Pool;\r
+  UINTN                 PageNumber;\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  TempPtr;\r
+\r
+  PageNumber = EFI_SIZE_TO_PAGES (sizeof (USBHC_MEM_POOL));\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (PageNumber));\r
+\r
+  Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);\r
+  Pool->Head = UsbHcAllocMemBlock (USBHC_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    //\r
+    // No free memory in PEI.\r
+    //\r
+    Pool = NULL;\r
+  }\r
+\r
+  return Pool;\r
+}\r
+\r
+/**\r
+  Release the memory management pool.\r
+\r
+  @param  Pool          The USB memory pool to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL     *Pool\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Block;\r
+\r
+  ASSERT (Pool->Head != NULL);\r
+\r
+  //\r
+  // Unlink all the memory blocks from the pool, then free them.\r
+  // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+  // first block.\r
+  //\r
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+    //UsbHcUnlinkMemBlock (Pool->Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  UsbHcFreeMemBlock (Pool, Pool->Head);\r
+}\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool          The host controller's memory pool.\r
+  @param  Size          Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN UINTN              Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Head;\r
+  USBHC_MEM_BLOCK       *Block;\r
+  USBHC_MEM_BLOCK       *NewBlock;\r
+  VOID                  *Mem;\r
+  UINTN                 AllocSize;\r
+  UINTN                 Pages;\r
+\r
+  Mem       = NULL;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+  Head      = Pool->Head;\r
+  ASSERT (Head != NULL);\r
+\r
+  //\r
+  // First check whether current memory blocks can satisfy the allocation.\r
+  //\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+    if (Mem != NULL) {\r
+      ZeroMem (Mem, Size);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Mem != NULL) {\r
+    return Mem;\r
+  }\r
+\r
+  //\r
+  // Create a new memory block if there is not enough memory\r
+  // in the pool. If the allocation size is larger than the\r
+  // default page number, just allocate a large enough memory\r
+  // block. Otherwise allocate default pages.\r
+  //\r
+  if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+    Pages = EFI_SIZE_TO_PAGES (AllocSize);\r
+  } else {\r
+    Pages = USBHC_MEM_DEFAULT_PAGES;\r
+  }\r
+  NewBlock = UsbHcAllocMemBlock (Pages);\r
+\r
+  if (NewBlock == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Add the new memory block to the pool, then allocate memory from it\r
+  //\r
+  UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+  Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+  if (Mem != NULL) {\r
+    ZeroMem (Mem, Size);\r
+  }\r
+\r
+  return Mem;\r
+}\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The memory to free.\r
+  @param  Size          The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK       *Head;\r
+  USBHC_MEM_BLOCK       *Block;\r
+  UINT8                 *ToFree;\r
+  UINTN                 AllocSize;\r
+  UINTN                 Byte;\r
+  UINTN                 Bit;\r
+  UINTN                 Count;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+  ToFree    = (UINT8 *) Mem;\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the memory to free.\r
+    //\r
+    if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
+      //\r
+      // compute the start byte and bit in the bit array\r
+      //\r
+      Byte  = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
+      Bit   = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+        ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
+        NEXT_BIT (Byte, Bit);\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If Block == NULL, it means that the current memory isn't\r
+  // in the host controller's pool. This is critical because\r
+  // the caller has passed in a wrong memory pointer\r
+  //\r
+  ASSERT (Block != NULL);\r
+\r
+  //\r
+  // Release the current memory block if it is empty and not the head\r
+  //\r
+  if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+    //UsbHcUnlinkMemBlock (Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+}\r
+\r
+/**\r
+  Allocates pages at a specified alignment.\r
+\r
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to\r
+                                use to access the hosts HostAddress.\r
+\r
+  @retval EFI_SUCCESS           Success to allocate aligned pages.\r
+  @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
+  @retval EFI_OUT_OF_RESOURCES  Do not have enough resources to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAllocateAlignedPages (\r
+  IN UINTN                      Pages,\r
+  IN UINTN                      Alignment,\r
+  OUT VOID                      **HostAddress,\r
+  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory;\r
+  UINTN                 AlignedMemory;\r
+  UINTN                 AlignmentMask;\r
+  UINTN                 RealPages;\r
+\r
+  //\r
+  // Alignment must be a power of two or zero.\r
+  //\r
+  ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+  if ((Alignment & (Alignment - 1)) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Pages == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Alignment > EFI_PAGE_SIZE) {\r
+    //\r
+    // Caculate the total number of pages since alignment is larger than page size.\r
+    //\r
+    AlignmentMask  = Alignment - 1;\r
+    RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
+    //\r
+    // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
+    //\r
+    ASSERT (RealPages > Pages);\r
+\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               Pages,\r
+               &Memory\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+  } else {\r
+    //\r
+    // Do not over-allocate pages in this case.\r
+    //\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               Pages,\r
+               &Memory\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    AlignedMemory = (UINTN) Memory;\r
+  }\r
+\r
+  *HostAddress = (VOID *) AlignedMemory;\r
+  *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
+\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  Pages                 The number of pages to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeAlignedPages (\r
+  IN VOID               *HostAddress,\r
+  IN UINTN              Pages\r
+  )\r
+{\r
+  ASSERT (Pages != 0);\r
+  //\r
+  // No free memory in PEI.\r
+  //\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
new file mode 100644 (file)
index 0000000..c314e92
--- /dev/null
@@ -0,0 +1,142 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_MEM_H_\r
+#define _EFI_PEI_XHCI_MEM_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#define USBHC_MEM_DEFAULT_PAGES 16\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+\r
+struct _USBHC_MEM_BLOCK {\r
+  UINT8                 *Bits;  // Bit array to record which unit is allocated\r
+  UINTN                 BitsLen;\r
+  UINT8                 *Buf;\r
+  UINT8                 *BufHost;\r
+  UINTN                 BufLen; // Memory size in bytes\r
+  USBHC_MEM_BLOCK       *Next;\r
+};\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT          64\r
+\r
+#define USBHC_MEM_UNIT_MASK     (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_ROUND(Len)    (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+#define USB_HC_BIT(a)           ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit)   \\r
+          ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit)  \\r
+          do {               \\r
+            (Bit)++;         \\r
+            if ((Bit) > 7) { \\r
+              (Byte)++;      \\r
+              (Bit) = 0;     \\r
+            }                \\r
+          } while (0)\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB\r
+// host controller. XHCI requires the control memory and transfer\r
+// data to be on the same 4G memory.\r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+  BOOLEAN               Check4G;\r
+  UINT32                Which4G;\r
+  USBHC_MEM_BLOCK       *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+/**\r
+  Calculate the corresponding pci bus address according to the Mem parameter.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The pointer to host memory.\r
+  @param  Size          The size of the memory region.\r
+\r
+  @return               The pci memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddrForHostAddr (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  );\r
+\r
+/**\r
+  Calculate the corresponding host address according to the pci address.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The pointer to pci memory.\r
+  @param  Size          The size of the memory region.\r
+\r
+  @return               The host memory address\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetHostAddrForPciAddr (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  );\r
+\r
+/**\r
+  Allocates pages at a specified alignment.\r
+\r
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to\r
+                                use to access the hosts HostAddress.\r
+\r
+  @retval EFI_SUCCESS           Success to allocate aligned pages.\r
+  @retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
+  @retval EFI_OUT_OF_RESOURCES  Do not have enough resources to allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAllocateAlignedPages (\r
+  IN UINTN                      Pages,\r
+  IN UINTN                      Alignment,\r
+  OUT VOID                      **HostAddress,\r
+  OUT EFI_PHYSICAL_ADDRESS      *DeviceAddress\r
+  );\r
+\r
+/**\r
+  Frees memory that was allocated with UsbHcAllocateAlignedPages().\r
+\r
+  @param  HostAddress           The system memory address to map to the PCI controller.\r
+  @param  Pages                 The number of pages to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeAlignedPages (\r
+  IN VOID               *HostAddress,\r
+  IN UINTN              Pages\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
new file mode 100644 (file)
index 0000000..9d9f53e
--- /dev/null
@@ -0,0 +1,1513 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+//\r
+// Two arrays used to translate the XHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP  mUsbPortStateMap[] = {\r
+  {XHC_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},\r
+  {XHC_PORTSC_PED,   USB_PORT_STAT_ENABLE},\r
+  {XHC_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},\r
+  {XHC_PORTSC_PP,    USB_PORT_STAT_POWER},\r
+  {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {\r
+  {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+  {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+  {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+  {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
+  {XHC_PORTSC_CSC, EfiUsbPortConnectChange},\r
+  {XHC_PORTSC_PEC, EfiUsbPortEnableChange},\r
+  {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+  {XHC_PORTSC_PRC, EfiUsbPortResetChange}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbHubPortStateMap[] = {\r
+  {XHC_HUB_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},\r
+  {XHC_HUB_PORTSC_PED,   USB_PORT_STAT_ENABLE},\r
+  {XHC_HUB_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},\r
+  {XHC_HUB_PORTSC_PP,    USB_PORT_STAT_POWER},\r
+  {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbHubPortChangeMap[] = {\r
+  {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+  {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+  {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+  {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
+  {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},\r
+  {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},\r
+  {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+  {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},\r
+  {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}\r
+};\r
+\r
+/**\r
+  Read XHCI Operation register.\r
+\r
+  @param Xhc            The XHCI device.\r
+  @param Offset         The operation register offset.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadOpReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI operation register.\r
+\r
+  @param Xhc            The XHCI device.\r
+  @param Offset         The operation register offset.\r
+  @param Data           The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteOpReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Data\r
+  )\r
+{\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);\r
+}\r
+\r
+/**\r
+  Set one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  Data  = XhcPeiReadOpReg (Xhc, Offset);\r
+  Data |= Bit;\r
+  XhcPeiWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Clear one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  Data  = XhcPeiReadOpReg (Xhc, Offset);\r
+  Data &= ~Bit;\r
+  XhcPeiWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Wait the operation register's bit as specified by Bit\r
+  to become set (or clear).\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to wait for.\r
+  @param  WaitToSet     Wait the bit to set or clear.\r
+  @param  Timeout       The time to wait before abort (in microsecond, us).\r
+\r
+  @retval EFI_SUCCESS   The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT   The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiWaitOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit,\r
+  IN BOOLEAN            WaitToSet,\r
+  IN UINT32             Timeout\r
+  )\r
+{\r
+  UINT32                Index;\r
+\r
+  for (Index = 0; Index < Timeout / XHC_POLL_DELAY + 1; Index++) {\r
+    if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    MicroSecondDelay (XHC_POLL_DELAY);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Read XHCI capability register.\r
+\r
+  @param Xhc        The XHCI device.\r
+  @param Offset     Capability register address.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadCapRegister (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Read XHCI door bell register.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  Offset    The offset of the door bell register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadDoorBellReg (\r
+  IN  PEI_XHC_DEV       *Xhc,\r
+  IN  UINT32            Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  ASSERT (Xhc->DBOff != 0);\r
+\r
+  Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset);\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI door bell register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the door bell register.\r
+  @param  Data          The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteDoorBellReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Data\r
+  )\r
+{\r
+  ASSERT (Xhc->DBOff != 0);\r
+\r
+  MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);\r
+}\r
+\r
+/**\r
+  Read XHCI runtime register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadRuntimeReg (\r
+  IN  PEI_XHC_DEV       *Xhc,\r
+  IN  UINT32            Offset\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI runtime register.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  Offset    The offset of the runtime register.\r
+  @param  Data      The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteRuntimeReg (\r
+  IN PEI_XHC_DEV          *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);\r
+}\r
+\r
+/**\r
+  Set one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetRuntimeRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  Data  = XhcPeiReadRuntimeReg (Xhc, Offset);\r
+  Data |= Bit;\r
+  XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Clear one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearRuntimeRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  )\r
+{\r
+  UINT32                Data;\r
+\r
+  Data  = XhcPeiReadRuntimeReg (Xhc, Offset);\r
+  Data &= ~Bit;\r
+  XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Check whether Xhc is halted.\r
+\r
+  @param  Xhc           The XHCI device.\r
+\r
+  @retval TRUE          The controller is halted.\r
+  @retval FALSE         The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsHalt (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  )\r
+{\r
+  return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);\r
+}\r
+\r
+/**\r
+  Check whether system error occurred.\r
+\r
+  @param  Xhc           The XHCI device.\r
+\r
+  @retval TRUE          System error happened.\r
+  @retval FALSE         No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsSysError (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  )\r
+{\r
+  return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
+}\r
+\r
+/**\r
+  Reset the host controller.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort (in microsecond, us).\r
+\r
+  @retval EFI_TIMEOUT   The transfer failed due to time out.\r
+  @retval Others        Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiResetHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  // Host can only be reset when it is halt. If not so, halt it\r
+  //\r
+  if (!XhcPeiIsHalt (Xhc)) {\r
+    Status = XhcPeiHaltHC (Xhc, Timeout);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
+  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
+ON_EXIT:\r
+  DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Halt the host controller.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort.\r
+\r
+  @retval EFI_TIMEOUT   Failed to halt the controller before Timeout.\r
+  @retval EFI_SUCCESS   The XHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiHaltHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the XHCI to run.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort.\r
+\r
+  @retval EFI_SUCCESS   The XHCI is running.\r
+  @retval Others        Failed to set the XHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRunHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+  Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+\r
+  @param  PeiServices               The pointer of EFI_PEI_SERVICES.\r
+  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress             The target device address.\r
+  @param  DeviceSpeed               Target device speed.\r
+  @param  MaximumPacketLength       Maximum packet size the default control transfer\r
+                                    endpoint is capable of sending or receiving.\r
+  @param  Request                   USB device request to send.\r
+  @param  TransferDirection         Specifies the data direction for the data stage.\r
+  @param  Data                      Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength                The size (in bytes) of the data buffer.\r
+  @param  TimeOut                   Indicates the maximum timeout, in millisecond.\r
+                                    If Timeout is 0, then the caller must wait for the function\r
+                                    to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
+  @param  Translator                Transaction translator to be used by this device.\r
+  @param  TransferResult            Return the result of this control transfer.\r
+\r
+  @retval EFI_SUCCESS               Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES      The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER     Some parameters are invalid.\r
+  @retval EFI_TIMEOUT               Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR          Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiControlTransfer (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  IN UINT8                                  DeviceAddress,\r
+  IN UINT8                                  DeviceSpeed,\r
+  IN UINTN                                  MaximumPacketLength,\r
+  IN EFI_USB_DEVICE_REQUEST                 *Request,\r
+  IN EFI_USB_DATA_DIRECTION                 TransferDirection,\r
+  IN OUT VOID                               *Data,\r
+  IN OUT UINTN                              *DataLength,\r
+  IN UINTN                                  TimeOut,\r
+  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,\r
+  OUT UINT32                                *TransferResult\r
+  )\r
+{\r
+  PEI_XHC_DEV                   *Xhc;\r
+  URB                           *Urb;\r
+  UINT8                         Endpoint;\r
+  UINT8                         Index;\r
+  UINT8                         DescriptorType;\r
+  UINT8                         SlotId;\r
+  UINT8                         TTT;\r
+  UINT8                         MTT;\r
+  UINT32                        MaxPacket0;\r
+  EFI_USB_HUB_DESCRIPTOR        *HubDesc;\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    RecoveryStatus;\r
+  UINTN                         MapSize;\r
+  EFI_USB_PORT_STATUS           PortStatus;\r
+  UINT32                        State;\r
+  EFI_USB_DEVICE_REQUEST        ClearPortRequest;\r
+  UINTN                         Len;\r
+\r
+  //\r
+  // Validate parameters\r
+  //\r
+  if ((Request == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection != EfiUsbDataIn) &&\r
+      (TransferDirection != EfiUsbDataOut) &&\r
+      (TransferDirection != EfiUsbNoData)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection == EfiUsbNoData) &&\r
+      ((Data != NULL) || (*DataLength != 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection != EfiUsbNoData) &&\r
+     ((Data == NULL) || (*DataLength == 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&\r
+      (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&\r
+      (MaximumPacketLength != 512)\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+  Status          = EFI_DEVICE_ERROR;\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Len             = 0;\r
+\r
+  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Hook the Set_Address request from UsbBus.\r
+  // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
+  //\r
+  if ((Request->Request     == USB_REQ_SET_ADDRESS) &&\r
+      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
+    //\r
+    // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
+    // This way is used to clean the history to avoid using wrong device address afterwards.\r
+    //\r
+    for (Index = 0; Index < 255; Index++) {\r
+      if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
+          (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
+          (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {\r
+        Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
+      }\r
+    }\r
+\r
+    if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // The actual device address has been assigned by XHCI during initializing the device slot.\r
+    // So we just need establish the mapping relationship between the device address requested from UsbBus\r
+    // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface\r
+    // can find out the actual device address by it.\r
+    //\r
+    Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  // Note that we encode the direction in address although default control\r
+  // endpoint is bidirectional. XhcPeiCreateUrb expects this\r
+  // combination of Ep addr and its direction.\r
+  //\r
+  Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
+  Urb = XhcPeiCreateUrb (\r
+          Xhc,\r
+          DeviceAddress,\r
+          Endpoint,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_CTRL_TRANSFER,\r
+          Request,\r
+          Data,\r
+          *DataLength,\r
+          NULL,\r
+          NULL\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+  //\r
+  // Get the status from URB. The result is updated in XhcPeiCheckUrbResult\r
+  // which is called by XhcPeiExecTransfer\r
+  //\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+    RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR (RecoveryStatus)) {\r
+      DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+    }\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto FREE_URB;\r
+  } else {\r
+    goto FREE_URB;\r
+  }\r
+\r
+  //\r
+  // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
+  // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
+  // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+  //\r
+  if ((Request->Request     == USB_REQ_GET_DESCRIPTOR) &&\r
+      ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
+      ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
+    DescriptorType = (UINT8) (Request->Value >> 8);\r
+    if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
+      ASSERT (Data != NULL);\r
+      //\r
+      // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
+      //\r
+      CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
+      if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
+        //\r
+        // If it's a usb3.0 device, then its max packet size is a 2^n.\r
+        //\r
+        MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+      } else {\r
+        MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+      }\r
+      Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
+      if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto FREE_URB;\r
+      }\r
+      if (Xhc->HcCParams.Data.Csz == 0) {\r
+        Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
+      } else {\r
+        Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
+      }\r
+    } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
+      ASSERT (Data != NULL);\r
+      if (*DataLength == ((UINT16 *) Data)[1]) {\r
+        //\r
+        // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.\r
+        //\r
+        Index = (UINT8) Request->Value;\r
+        ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
+        Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
+        if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto FREE_URB;\r
+        }\r
+        CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
+      }\r
+    } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
+               (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {\r
+      ASSERT (Data != NULL);\r
+      HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;\r
+      ASSERT (HubDesc->NumPorts <= 15);\r
+      //\r
+      // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
+      //\r
+      TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
+      if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
+        //\r
+        // Don't support multi-TT feature for super speed hub now.\r
+        //\r
+        MTT = 0;\r
+        DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
+      } else {\r
+        MTT = 0;\r
+      }\r
+\r
+      if (Xhc->HcCParams.Data.Csz == 0) {\r
+        Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+      } else {\r
+        Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+      }\r
+    }\r
+  } else if ((Request->Request     == USB_REQ_SET_CONFIG) &&\r
+             (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
+    //\r
+    // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+    //\r
+    for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+      if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
+        if (Xhc->HcCParams.Data.Csz == 0) {\r
+          Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+        } else {\r
+          Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+        }\r
+        break;\r
+      }\r
+    }\r
+  } else if ((Request->Request     == USB_REQ_GET_STATUS) &&\r
+             (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {\r
+    ASSERT (Data != NULL);\r
+    //\r
+    // Hook Get_Status request from UsbBus to keep track of the port status change.\r
+    //\r
+    State                       = *(UINT32 *) Data;\r
+    PortStatus.PortStatus       = 0;\r
+    PortStatus.PortChangeStatus = 0;\r
+\r
+    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+      //\r
+      // For super speed hub, its bit10~12 presents the attached device speed.\r
+      //\r
+      if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+      }\r
+    } else {\r
+      //\r
+      // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
+      //\r
+      if (XHC_BIT_IS_SET (State, BIT9)) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+      } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Convert the XHCI port/port change state to UEFI status\r
+    //\r
+    MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
+        PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
+      }\r
+    }\r
+\r
+    MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
+        PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
+      }\r
+    }\r
+\r
+    MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
+        ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+        ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
+        ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;\r
+        ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;\r
+        ClearPortRequest.Index        = Request->Index;\r
+        ClearPortRequest.Length       = 0;\r
+\r
+        XhcPeiControlTransfer (\r
+          PeiServices,\r
+          This,\r
+          DeviceAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          &ClearPortRequest,\r
+          EfiUsbNoData,\r
+          NULL,\r
+          &Len,\r
+          TimeOut,\r
+          Translator,\r
+          TransferResult\r
+          );\r
+      }\r
+    }\r
+\r
+    XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
+\r
+    *(UINT32 *) Data = *(UINT32 *) &PortStatus;\r
+  }\r
+\r
+FREE_URB:\r
+  XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.\r
+  @param  DeviceSpeed           Device speed, Low speed device doesn't support\r
+                                bulk transfer.\r
+  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of\r
+                                sending or receiving.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit\r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  DataToggle            On input, the initial data toggle for the transfer;\r
+                                On output, it is updated to to next data toggle to use of\r
+                                the subsequent bulk transfer.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+                                If Timeout is 0, then the caller must wait for the function\r
+                                to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
+  @param  Translator            A pointr to the transaction translator data.\r
+  @param  TransferResult        A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiBulkTransfer (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  IN UINT8                                  DeviceAddress,\r
+  IN UINT8                                  EndPointAddress,\r
+  IN UINT8                                  DeviceSpeed,\r
+  IN UINTN                                  MaximumPacketLength,\r
+  IN OUT VOID                               *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+  IN OUT UINTN                              *DataLength,\r
+  IN OUT UINT8                              *DataToggle,\r
+  IN UINTN                                  TimeOut,\r
+  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR     *Translator,\r
+  OUT UINT32                                *TransferResult\r
+  )\r
+{\r
+  PEI_XHC_DEV                   *Xhc;\r
+  URB                           *Urb;\r
+  UINT8                         SlotId;\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    RecoveryStatus;\r
+\r
+  //\r
+  // Validate the parameters\r
+  //\r
+  if ((DataLength == NULL) || (*DataLength == 0) ||\r
+      (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Xhc             = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  //\r
+  Urb = XhcPeiCreateUrb (\r
+          Xhc,\r
+          DeviceAddress,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_BULK_TRANSFER,\r
+          NULL,\r
+          Data[0],\r
+          *DataLength,\r
+          NULL,\r
+          NULL\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+    RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR (RecoveryStatus)) {\r
+      DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+    }\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices           The pointer to the PEI Services Table.\r
+  @param[in]  This                  The pointer to this instance of the\r
+                                    PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber            The pointer to the number of the root hub ports.\r
+\r
+  @retval EFI_SUCCESS               The port number was retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER     PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiGetRootHubPortNumber (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  OUT UINT8                         *PortNumber\r
+  )\r
+{\r
+  PEI_XHC_DEV           *XhcDev;\r
+  XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+  if (PortNumber == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;\r
+  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param  PeiServices               The pointer of EFI_PEI_SERVICES.\r
+  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber                Specifies the root hub port whose feature\r
+                                    is requested to be cleared.\r
+  @param  PortFeature               Indicates the feature selector associated with the\r
+                                    feature clear request.\r
+\r
+  @retval EFI_SUCCESS               The feature specified by PortFeature was cleared\r
+                                    for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiClearRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  )\r
+{\r
+  PEI_XHC_DEV           *Xhc;\r
+  UINT32                Offset;\r
+  UINT32                State;\r
+  EFI_STATUS            Status;\r
+\r
+  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+  State = XhcPeiReadOpReg (Xhc, Offset);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
+\r
+  //\r
+  // Mask off the port status change bits, these bits are\r
+  // write clean bits\r
+  //\r
+  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+  switch (PortFeature) {\r
+    case EfiUsbPortEnable:\r
+      //\r
+      // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+      // A port may be disabled by software writing a '1' to this flag.\r
+      //\r
+      State |= XHC_PORTSC_PED;\r
+      State &= ~XHC_PORTSC_RESET;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortSuspend:\r
+      State |= XHC_PORTSC_LWS;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      State &= ~XHC_PORTSC_PLS;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortReset:\r
+      //\r
+      // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
+      // Register bits indicate status when read, a clear bit may be set by\r
+      // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
+      //\r
+      break;\r
+\r
+    case EfiUsbPortPower:\r
+      if (Xhc->HcCParams.Data.Ppc) {\r
+        //\r
+        // Port Power Control supported\r
+        //\r
+        State &= ~XHC_PORTSC_PP;\r
+        XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortOwner:\r
+      //\r
+      // XHCI root hub port don't has the owner bit, ignore the operation\r
+      //\r
+      break;\r
+\r
+    case EfiUsbPortConnectChange:\r
+      //\r
+      // Clear connect status change\r
+      //\r
+      State |= XHC_PORTSC_CSC;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortEnableChange:\r
+      //\r
+      // Clear enable status change\r
+      //\r
+      State |= XHC_PORTSC_PEC;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortOverCurrentChange:\r
+      //\r
+      // Clear PortOverCurrent change\r
+      //\r
+      State |= XHC_PORTSC_OCC;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortResetChange:\r
+      //\r
+      // Clear Port Reset change\r
+      //\r
+      State |= XHC_PORTSC_PRC;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortSuspendChange:\r
+      //\r
+      // Not supported or not related operation\r
+      //\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_INVALID_PARAMETER;\r
+      break;\r
+  }\r
+\r
+ON_EXIT:\r
+  DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+\r
+  @param  PeiServices               The pointer of EFI_PEI_SERVICES\r
+  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
+  @param  PortNumber                Root hub port to set.\r
+  @param  PortFeature               Feature to set.\r
+\r
+  @retval EFI_SUCCESS               The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER     PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_TIMEOUT               The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiSetRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  )\r
+{\r
+  PEI_XHC_DEV           *Xhc;\r
+  UINT32                Offset;\r
+  UINT32                State;\r
+  EFI_STATUS            Status;\r
+\r
+  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+  State = XhcPeiReadOpReg (Xhc, Offset);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
+\r
+  //\r
+  // Mask off the port status change bits, these bits are\r
+  // write clean bits\r
+  //\r
+  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+  switch (PortFeature) {\r
+    case EfiUsbPortEnable:\r
+      //\r
+      // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+      // A port may be disabled by software writing a '1' to this flag.\r
+      //\r
+      break;\r
+\r
+    case EfiUsbPortSuspend:\r
+      State |= XHC_PORTSC_LWS;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      State &= ~XHC_PORTSC_PLS;\r
+      State |= (3 << 5) ;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      break;\r
+\r
+    case EfiUsbPortReset:\r
+      //\r
+      // Make sure Host Controller not halt before reset it\r
+      //\r
+      if (XhcPeiIsHalt (Xhc)) {\r
+        Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+        if (EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // 4.3.1 Resetting a Root Hub Port\r
+      // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
+      // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)\r
+      //    bit in the PORTSC field is set to '1'.\r
+      //\r
+      State |= XHC_PORTSC_RESET;\r
+      XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
+      break;\r
+\r
+    case EfiUsbPortPower:\r
+      if (Xhc->HcCParams.Data.Ppc) {\r
+        //\r
+        // Port Power Control supported\r
+        //\r
+        State |= XHC_PORTSC_PP;\r
+        XhcPeiWriteOpReg (Xhc, Offset, State);\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortOwner:\r
+      //\r
+      // XHCI root hub port don't has the owner bit, ignore the operation\r
+      //\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+ON_EXIT:\r
+  DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  @param  PeiServices               The pointer of EFI_PEI_SERVICES.\r
+  @param  This                      The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber                The root hub port to retrieve the state from.\r
+  @param  PortStatus                Variable to receive the port state.\r
+\r
+  @retval EFI_SUCCESS               The status of the USB root hub port specified.\r
+                                    by PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER     PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiGetRootHubPortStatus (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  IN UINT8                          PortNumber,\r
+  OUT EFI_USB_PORT_STATUS           *PortStatus\r
+  )\r
+{\r
+  PEI_XHC_DEV               *Xhc;\r
+  UINT32                    Offset;\r
+  UINT32                    State;\r
+  UINTN                     Index;\r
+  UINTN                     MapSize;\r
+  USB_DEV_ROUTE             ParentRouteChart;\r
+\r
+  if (PortStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
+\r
+  if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Clear port status.\r
+  //\r
+  PortStatus->PortStatus        = 0;\r
+  PortStatus->PortChangeStatus  = 0;\r
+\r
+  Offset                        = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+  State                         = XhcPeiReadOpReg (Xhc, Offset);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));\r
+\r
+  //\r
+  // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
+  //\r
+  switch ((State & XHC_PORTSC_PS) >> 10) {\r
+    case 2:\r
+      PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+      break;\r
+\r
+    case 3:\r
+      PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+      break;\r
+\r
+    case 4:\r
+      PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+  }\r
+\r
+  //\r
+  // Convert the XHCI port/port change state to UEFI status\r
+  //\r
+  MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+      PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
+    }\r
+  }\r
+  //\r
+  // Bit5~8 reflects its current link state.\r
+  //\r
+  if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+  }\r
+\r
+  MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+      PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+    }\r
+  }\r
+\r
+  MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
+      XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
+  // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
+  //\r
+  ParentRouteChart.Dword = 0;\r
+  XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  @param FileHandle     Handle of the file being invoked.\r
+  @param PeiServices    Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS   PPI successfully installed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeimEntry (\r
+  IN EFI_PEI_FILE_HANDLE    FileHandle,\r
+  IN CONST EFI_PEI_SERVICES **PeiServices\r
+  )\r
+{\r
+  PEI_USB_CONTROLLER_PPI      *UsbControllerPpi;\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Index;\r
+  UINTN                       ControllerType;\r
+  UINTN                       BaseAddress;\r
+  UINTN                       MemPages;\r
+  PEI_XHC_DEV                 *XhcDev;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+  UINT32                      PageSize;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory.\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = PeiServicesLocatePpi (\r
+             &gPeiUsbControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &UsbControllerPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Index = 0;\r
+  while (TRUE) {\r
+    Status = UsbControllerPpi->GetUsbController (\r
+                                 (EFI_PEI_SERVICES **) PeiServices,\r
+                                 UsbControllerPpi,\r
+                                 Index,\r
+                                 &ControllerType,\r
+                                 &BaseAddress\r
+                                 );\r
+    //\r
+    // When status is error, it means no controller is found.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // This PEIM is for XHC type controller.\r
+    //\r
+    if (ControllerType != PEI_XHCI_CONTROLLER) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               MemPages,\r
+               &TempPtr\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));\r
+    XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);\r
+\r
+    XhcDev->Signature = USB_XHC_DEV_SIGNATURE;\r
+    XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+    XhcDev->CapLength           = XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+    XhcDev->HcSParams1.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);\r
+    XhcDev->HcSParams2.Dword    = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);\r
+    XhcDev->HcCParams.Dword     = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);\r
+    XhcDev->DBOff               = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);\r
+    XhcDev->RTSOff              = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);\r
+\r
+    //\r
+    // This PageSize field defines the page size supported by the xHC implementation.\r
+    // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
+    // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
+    //\r
+    PageSize         = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
+    XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
+\r
+    DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: CapLength:                    %x\n", XhcDev->CapLength));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1:                   %x\n", XhcDev->HcSParams1.Dword));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2:                   %x\n", XhcDev->HcSParams2.Dword));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: HcCParams:                    %x\n", XhcDev->HcCParams.Dword));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: DBOff:                        %x\n", XhcDev->DBOff));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: RTSOff:                       %x\n", XhcDev->RTSOff));\r
+    DEBUG ((EFI_D_INFO, "XhciPei: PageSize:                     %x\n", XhcDev->PageSize));\r
+\r
+    XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);\r
+    ASSERT (XhcPeiIsHalt (XhcDev));\r
+\r
+    //\r
+    // Initialize the schedule\r
+    //\r
+    XhcPeiInitSched (XhcDev);\r
+\r
+    //\r
+    // Start the Host Controller\r
+    //\r
+    XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);\r
+\r
+    //\r
+    // Wait for root port state stable\r
+    //\r
+    MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);\r
+\r
+    XhcDev->Usb2HostControllerPpi.ControlTransfer           = XhcPeiControlTransfer;\r
+    XhcDev->Usb2HostControllerPpi.BulkTransfer              = XhcPeiBulkTransfer;\r
+    XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber      = XhcPeiGetRootHubPortNumber;\r
+    XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus      = XhcPeiGetRootHubPortStatus;\r
+    XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature     = XhcPeiSetRootHubPortFeature;\r
+    XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature   = XhcPeiClearRootHubPortFeature;\r
+\r
+    XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
+    XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
+\r
+    PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
+\r
+    Index++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
new file mode 100644 (file)
index 0000000..3b77f2a
--- /dev/null
@@ -0,0 +1,240 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _RECOVERY_XHC_H_\r
+#define _RECOVERY_XHC_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+typedef struct _PEI_XHC_DEV PEI_XHC_DEV;\r
+typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;\r
+\r
+#include "UsbHcMem.h"\r
+#include "XhciReg.h"\r
+#include "XhciSched.h"\r
+\r
+#define CMD_RING_TRB_NUMBER         0x100\r
+#define TR_RING_TRB_NUMBER          0x100\r
+#define ERST_NUMBER                 0x01\r
+#define EVENT_RING_TRB_NUMBER       0x200\r
+\r
+#define XHC_1_MICROSECOND           1\r
+#define XHC_1_MILLISECOND           (1000 * XHC_1_MICROSECOND)\r
+#define XHC_1_SECOND                (1000 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// XHC reset timeout experience values.\r
+// The unit is microsecond, setting it as 1s.\r
+//\r
+#define XHC_RESET_TIMEOUT           (1 * XHC_1_SECOND)\r
+//\r
+// XHC delay experience value for polling operation.\r
+// The unit is microsecond, set it as 1ms.\r
+//\r
+#define XHC_POLL_DELAY              (1 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// Wait for root port state stable.\r
+//\r
+#define XHC_ROOT_PORT_STATE_STABLE  (200 * XHC_1_MILLISECOND)\r
+\r
+#define XHC_GENERIC_TIMEOUT         (10 * XHC_1_MILLISECOND)\r
+\r
+#define XHC_LOW_32BIT(Addr64)       ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))\r
+#define XHC_HIGH_32BIT(Addr64)      ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+#define XHC_BIT_IS_SET(Data, Bit)   ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define XHC_REG_BIT_IS_SET(XHC, Offset, Bit) \\r
+          (XHC_BIT_IS_SET(XhcPeiReadOpReg ((XHC), (Offset)), (Bit)))\r
+\r
+#define USB_DESC_TYPE_HUB              0x29\r
+#define USB_DESC_TYPE_HUB_SUPER_SPEED  0x2a\r
+\r
+//\r
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of\r
+// three fields: One bit direction, 2 bit type, and 5 bit\r
+// target.\r
+//\r
+#define USB_REQUEST_TYPE(Dir, Type, Target) \\r
+          ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))\r
+\r
+struct _USB_DEV_CONTEXT {\r
+  //\r
+  // Whether this entry in UsbDevContext array is used or not.\r
+  //\r
+  BOOLEAN                           Enabled;\r
+  //\r
+  // The slot id assigned to the new device through XHCI's Enable_Slot cmd.\r
+  //\r
+  UINT8                             SlotId;\r
+  //\r
+  // The route string presented an attached usb device.\r
+  //\r
+  USB_DEV_ROUTE                     RouteString;\r
+  //\r
+  // The route string of parent device if it exists. Otherwise it's zero.\r
+  //\r
+  USB_DEV_ROUTE                     ParentRouteString;\r
+  //\r
+  // The actual device address assigned by XHCI through Address_Device command.\r
+  //\r
+  UINT8                             XhciDevAddr;\r
+  //\r
+  // The requested device address from UsbBus driver through Set_Address standard usb request.\r
+  // As XHCI spec replaces this request with Address_Device command, we have to record the\r
+  // requested device address and establish a mapping relationship with the actual device address.\r
+  // Then UsbBus driver just need to be aware of the requested device address to access usb device\r
+  // through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual\r
+  // device address and access the actual device.\r
+  //\r
+  UINT8                             BusDevAddr;\r
+  //\r
+  // The pointer to the input device context.\r
+  //\r
+  VOID                              *InputContext;\r
+  //\r
+  // The pointer to the output device context.\r
+  //\r
+  VOID                              *OutputContext;\r
+  //\r
+  // The transfer queue for every endpoint.\r
+  //\r
+  VOID                              *EndpointTransferRing[31];\r
+  //\r
+  // The device descriptor which is stored to support XHCI's Evaluate_Context cmd.\r
+  //\r
+  EFI_USB_DEVICE_DESCRIPTOR         DevDesc;\r
+  //\r
+  // As a usb device may include multiple configuration descriptors, we dynamically allocate an array\r
+  // to store them.\r
+  // Note that every configuration descriptor stored here includes those lower level descriptors,\r
+  // such as Interface descriptor, Endpoint descriptor, and so on.\r
+  // These information is used to support XHCI's Config_Endpoint cmd.\r
+  //\r
+  EFI_USB_CONFIG_DESCRIPTOR         **ConfDesc;\r
+};\r
+\r
+#define USB_XHC_DEV_SIGNATURE       SIGNATURE_32 ('x', 'h', 'c', 'i')\r
+\r
+struct _PEI_XHC_DEV {\r
+  UINTN                             Signature;\r
+  PEI_USB2_HOST_CONTROLLER_PPI      Usb2HostControllerPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR            PpiDescriptor;\r
+  UINT32                            UsbHostControllerBaseAddress;\r
+  USBHC_MEM_POOL                    *MemPool;\r
+\r
+  //\r
+  // XHCI configuration data\r
+  //\r
+  UINT8                             CapLength;    ///< Capability Register Length\r
+  XHC_HCSPARAMS1                    HcSParams1;   ///< Structural Parameters 1\r
+  XHC_HCSPARAMS2                    HcSParams2;   ///< Structural Parameters 2\r
+  XHC_HCCPARAMS                     HcCParams;    ///< Capability Parameters\r
+  UINT32                            DBOff;        ///< Doorbell Offset\r
+  UINT32                            RTSOff;       ///< Runtime Register Space Offset\r
+  UINT32                            PageSize;\r
+  UINT32                            MaxScratchpadBufs;\r
+  UINT64                            *ScratchBuf;\r
+  UINT64                            *ScratchEntry;\r
+  UINT64                            *DCBAA;\r
+  UINT32                            MaxSlotsEn;\r
+  //\r
+  // Cmd Transfer Ring\r
+  //\r
+  TRANSFER_RING                     CmdRing;\r
+  //\r
+  // EventRing\r
+  //\r
+  EVENT_RING                        EventRing;\r
+\r
+  //\r
+  // Store device contexts managed by XHCI device\r
+  // The array supports up to 255 devices, entry 0 is reserved and should not be used.\r
+  //\r
+  USB_DEV_CONTEXT                   UsbDevContext[256];\r
+};\r
+\r
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @return Pointer to the allocated memory pool or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  VOID\r
+  )\r
+;\r
+\r
+/**\r
+  Release the memory management pool.\r
+\r
+  @param  Pool          The USB memory pool to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL     *Pool\r
+  )\r
+;\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool          The host controller's memory pool.\r
+  @param  Size          Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN UINTN              Size\r
+  )\r
+;\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool          The memory pool of the host controller.\r
+  @param  Mem           The memory to free.\r
+  @param  Size          The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL     *Pool,\r
+  IN VOID               *Mem,\r
+  IN UINTN              Size\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf b/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
new file mode 100644 (file)
index 0000000..9883f0b
--- /dev/null
@@ -0,0 +1,59 @@
+## @file\r
+# Component description file for XhcPeim PEIM to produce gPeiUsb2HostControllerPpiGuid\r
+# based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers.\r
+#\r
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution.  The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = XhciPei\r
+  FILE_GUID                      = 65E5746E-9C14-467d-B5B3-932A66D59F79\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = XhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  XhcPeim.c\r
+  XhcPeim.h\r
+  XhciSched.c\r
+  UsbHcMem.c\r
+  XhciReg.h\r
+  XhciSched.h\r
+  UsbHcMem.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  MemoryAllocationLib\r
+\r
+[Ppis]\r
+  gPeiUsb2HostControllerPpiGuid                 ## PRODUCES\r
+  gPeiUsbControllerPpiGuid                      ## CONSUMES\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h b/MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h
new file mode 100644 (file)
index 0000000..1a62560
--- /dev/null
@@ -0,0 +1,471 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_REG_H_\r
+#define _EFI_PEI_XHCI_REG_H_\r
+\r
+//\r
+// Capability registers offset\r
+//\r
+#define XHC_CAPLENGTH_OFFSET            0x00    // Capability register length offset\r
+#define XHC_HCIVERSION_OFFSET           0x02    // Interface Version Number 02-03h\r
+#define XHC_HCSPARAMS1_OFFSET           0x04    // Structural Parameters 1\r
+#define XHC_HCSPARAMS2_OFFSET           0x08    // Structural Parameters 2\r
+#define XHC_HCSPARAMS3_OFFSET           0x0c    // Structural Parameters 3\r
+#define XHC_HCCPARAMS_OFFSET            0x10    // Capability Parameters\r
+#define XHC_DBOFF_OFFSET                0x14    // Doorbell Offset\r
+#define XHC_RTSOFF_OFFSET               0x18    // Runtime Register Space Offset\r
+\r
+//\r
+// Operational registers offset\r
+//\r
+#define XHC_USBCMD_OFFSET               0x0000  // USB Command Register Offset\r
+#define XHC_USBSTS_OFFSET               0x0004  // USB Status Register Offset\r
+#define XHC_PAGESIZE_OFFSET             0x0008  // USB Page Size Register Offset\r
+#define XHC_DNCTRL_OFFSET               0x0014  // Device Notification Control Register Offset\r
+#define XHC_CRCR_OFFSET                 0x0018  // Command Ring Control Register Offset\r
+#define XHC_DCBAAP_OFFSET               0x0030  // Device Context Base Address Array Pointer Register Offset\r
+#define XHC_CONFIG_OFFSET               0x0038  // Configure Register Offset\r
+#define XHC_PORTSC_OFFSET               0x0400  // Port Status and Control Register Offset\r
+\r
+//\r
+// Runtime registers offset\r
+//\r
+#define XHC_MFINDEX_OFFSET              0x00    // Microframe Index Register Offset\r
+#define XHC_IMAN_OFFSET                 0x20    // Interrupter X Management Register Offset\r
+#define XHC_IMOD_OFFSET                 0x24    // Interrupter X Moderation Register Offset\r
+#define XHC_ERSTSZ_OFFSET               0x28    // Event Ring Segment Table Size Register Offset\r
+#define XHC_ERSTBA_OFFSET               0x30    // Event Ring Segment Table Base Address Register Offset\r
+#define XHC_ERDP_OFFSET                 0x38    // Event Ring Dequeue Pointer Register Offset\r
+\r
+//\r
+// Register Bit Definition\r
+//\r
+#define XHC_USBCMD_RUN                  BIT0    // Run/Stop\r
+#define XHC_USBCMD_RESET                BIT1    // Host Controller Reset\r
+#define XHC_USBCMD_INTE                 BIT2    // Interrupter Enable\r
+#define XHC_USBCMD_HSEE                 BIT3    // Host System Error Enable\r
+\r
+#define XHC_USBSTS_HALT                 BIT0    // Host Controller Halted\r
+#define XHC_USBSTS_HSE                  BIT2    // Host System Error\r
+#define XHC_USBSTS_EINT                 BIT3    // Event Interrupt\r
+#define XHC_USBSTS_PCD                  BIT4    // Port Change Detect\r
+#define XHC_USBSTS_SSS                  BIT8    // Save State Status\r
+#define XHC_USBSTS_RSS                  BIT9    // Restore State Status\r
+#define XHC_USBSTS_SRE                  BIT10   // Save/Restore Error\r
+#define XHC_USBSTS_CNR                  BIT11   // Host Controller Not Ready\r
+#define XHC_USBSTS_HCE                  BIT12   // Host Controller Error\r
+\r
+#define XHC_PAGESIZE_MASK               0xFFFF  // Page Size\r
+\r
+#define XHC_CRCR_RCS                    BIT0    // Ring Cycle State\r
+#define XHC_CRCR_CS                     BIT1    // Command Stop\r
+#define XHC_CRCR_CA                     BIT2    // Command Abort\r
+#define XHC_CRCR_CRR                    BIT3    // Command Ring Running\r
+\r
+#define XHC_CONFIG_MASK                 0xFF    // Max Device Slots Enabled\r
+\r
+#define XHC_PORTSC_CCS                  BIT0    // Current Connect Status\r
+#define XHC_PORTSC_PED                  BIT1    // Port Enabled/Disabled\r
+#define XHC_PORTSC_OCA                  BIT3    // Over-current Active\r
+#define XHC_PORTSC_RESET                BIT4    // Port Reset\r
+#define XHC_PORTSC_PLS                  (BIT5|BIT6|BIT7|BIT8)   // Port Link State\r
+#define XHC_PORTSC_PP                   BIT9    // Port Power\r
+#define XHC_PORTSC_PS                   (BIT10|BIT11|BIT12)     // Port Speed\r
+#define XHC_PORTSC_LWS                  BIT16   // Port Link State Write Strobe\r
+#define XHC_PORTSC_CSC                  BIT17   // Connect Status Change\r
+#define XHC_PORTSC_PEC                  BIT18   // Port Enabled/Disabled Change\r
+#define XHC_PORTSC_WRC                  BIT19   // Warm Port Reset Change\r
+#define XHC_PORTSC_OCC                  BIT20   // Over-Current Change\r
+#define XHC_PORTSC_PRC                  BIT21   // Port Reset Change\r
+#define XHC_PORTSC_PLC                  BIT22   // Port Link State Change\r
+#define XHC_PORTSC_CEC                  BIT23   // Port Config Error Change\r
+#define XHC_PORTSC_CAS                  BIT24   // Cold Attach Status\r
+\r
+#define XHC_HUB_PORTSC_CCS              BIT0    // Hub's Current Connect Status\r
+#define XHC_HUB_PORTSC_PED              BIT1    // Hub's Port Enabled/Disabled\r
+#define XHC_HUB_PORTSC_OCA              BIT3    // Hub's Over-current Active\r
+#define XHC_HUB_PORTSC_RESET            BIT4    // Hub's Port Reset\r
+#define XHC_HUB_PORTSC_PP               BIT9    // Hub's Port Power\r
+#define XHC_HUB_PORTSC_CSC              BIT16   // Hub's Connect Status Change\r
+#define XHC_HUB_PORTSC_PEC              BIT17   // Hub's Port Enabled/Disabled Change\r
+#define XHC_HUB_PORTSC_OCC              BIT19   // Hub's Over-Current Change\r
+#define XHC_HUB_PORTSC_PRC              BIT20   // Hub's Port Reset Change\r
+#define XHC_HUB_PORTSC_BHRC             BIT21   // Hub's Port Warm Reset Change\r
+\r
+#define XHC_IMAN_IP                     BIT0    // Interrupt Pending\r
+#define XHC_IMAN_IE                     BIT1    // Interrupt Enable\r
+\r
+#define XHC_IMODI_MASK                  0x0000FFFF  // Interrupt Moderation Interval\r
+#define XHC_IMODC_MASK                  0xFFFF0000  // Interrupt Moderation Counter\r
+\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+  UINT8                 MaxSlots;       // Number of Device Slots\r
+  UINT16                MaxIntrs:11;    // Number of Interrupters\r
+  UINT16                Rsvd:5;\r
+  UINT8                 MaxPorts;       // Number of Ports\r
+} HCSPARAMS1;\r
+\r
+//\r
+// Structural Parameters 1 Register Bitmap Definition\r
+//\r
+typedef union {\r
+  UINT32                Dword;\r
+  HCSPARAMS1            Data;\r
+} XHC_HCSPARAMS1;\r
+\r
+typedef struct {\r
+  UINT32                Ist:4;          // Isochronous Scheduling Threshold\r
+  UINT32                Erst:4;         // Event Ring Segment Table Max\r
+  UINT32                Rsvd:13;\r
+  UINT32                ScratchBufHi:5; // Max Scratchpad Buffers Hi\r
+  UINT32                Spr:1;          // Scratchpad Restore\r
+  UINT32                ScratchBufLo:5; // Max Scratchpad Buffers Lo\r
+} HCSPARAMS2;\r
+\r
+//\r
+// Structural Parameters 2 Register Bitmap Definition\r
+//\r
+typedef union {\r
+  UINT32                Dword;\r
+  HCSPARAMS2            Data;\r
+} XHC_HCSPARAMS2;\r
+\r
+typedef struct {\r
+  UINT16                Ac64:1;        // 64-bit Addressing Capability\r
+  UINT16                Bnc:1;         // BW Negotiation Capability\r
+  UINT16                Csz:1;         // Context Size\r
+  UINT16                Ppc:1;         // Port Power Control\r
+  UINT16                Pind:1;        // Port Indicators\r
+  UINT16                Lhrc:1;        // Light HC Reset Capability\r
+  UINT16                Ltc:1;         // Latency Tolerance Messaging Capability\r
+  UINT16                Nss:1;         // No Secondary SID Support\r
+  UINT16                Pae:1;         // Parse All Event Data\r
+  UINT16                Rsvd:3;\r
+  UINT16                MaxPsaSize:4;  // Maximum Primary Stream Array Size\r
+  UINT16                ExtCapReg;     // xHCI Extended Capabilities Pointer\r
+} HCCPARAMS;\r
+\r
+//\r
+// Capability Parameters Register Bitmap Definition\r
+//\r
+typedef union {\r
+  UINT32                Dword;\r
+  HCCPARAMS             Data;\r
+} XHC_HCCPARAMS;\r
+\r
+#pragma pack ()\r
+\r
+//\r
+// XHCi Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                   Pi;\r
+  UINT8                   SubClassCode;\r
+  UINT8                   BaseCode;\r
+} USB_CLASSC;\r
+\r
+typedef struct {\r
+  UINT8                     Length;\r
+  UINT8                     DescType;\r
+  UINT8                     NumPorts;\r
+  UINT16                    HubCharacter;\r
+  UINT8                     PwrOn2PwrGood;\r
+  UINT8                     HubContrCurrent;\r
+  UINT8                     Filler[16];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+#pragma pack()\r
+\r
+//\r
+//  Hub Class Feature Selector for Clear Port Feature Request\r
+//  It's the extension of hub class feature selector of USB 2.0 in USB 3.0 Spec.\r
+//  For more details, Please refer to USB 3.0 Spec Table 10-7.\r
+//\r
+typedef enum {\r
+  Usb3PortBHPortReset          = 28,\r
+  Usb3PortBHPortResetChange    = 29\r
+} XHC_PORT_FEATURE;\r
+\r
+//\r
+// Structure to map the hardware port states to the\r
+// UEFI's port states.\r
+//\r
+typedef struct {\r
+  UINT32                  HwState;\r
+  UINT16                  UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+//\r
+// Structure to map the hardware port states to feature selector for clear port feature request.\r
+//\r
+typedef struct {\r
+  UINT32                  HwState;\r
+  UINT16                  Selector;\r
+} USB_CLEAR_PORT_MAP;\r
+\r
+/**\r
+  Read XHCI Operation register.\r
+\r
+  @param Xhc            The XHCI device.\r
+  @param Offset         The operation register offset.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadOpReg (\r
+  IN  PEI_XHC_DEV       *Xhc,\r
+  IN  UINT32            Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI operation register.\r
+\r
+  @param Xhc            The XHCI device.\r
+  @param Offset         The operation register offset.\r
+  @param Data           The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteOpReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Data\r
+  );\r
+\r
+/**\r
+  Set one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  );\r
+\r
+/**\r
+  Clear one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  );\r
+\r
+/**\r
+  Wait the operation register's bit as specified by Bit\r
+  to be set (or clear).\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit of the register to wait for.\r
+  @param  WaitToSet     Wait the bit to set or clear.\r
+  @param  Timeout       The time to wait before abort (in microsecond, us).\r
+\r
+  @retval EFI_SUCCESS   The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT   The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiWaitOpRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit,\r
+  IN BOOLEAN            WaitToSet,\r
+  IN UINT32             Timeout\r
+  );\r
+\r
+/**\r
+  Read XHCI door bell register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the door bell register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadDoorBellReg (\r
+  IN  PEI_XHC_DEV       *Xhc,\r
+  IN  UINT32            Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI door bell register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the door bell register.\r
+  @param  Data          The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteDoorBellReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Data\r
+  );\r
+\r
+/**\r
+  Read XHCI runtime register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcPeiReadRuntimeReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN  UINT32            Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI runtime register.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the runtime register.\r
+  @param  Data          The data to write.\r
+\r
+**/\r
+VOID\r
+XhcPeiWriteRuntimeReg (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Data\r
+  );\r
+\r
+/**\r
+  Set one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the runtime register.\r
+  @param  Bit           The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiSetRuntimeRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  );\r
+\r
+/**\r
+  Clear one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Offset        The offset of the runtime register.\r
+  @param  Bit           The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcPeiClearRuntimeRegBit (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Offset,\r
+  IN UINT32             Bit\r
+  );\r
+\r
+/**\r
+  Check whether Xhc is halted.\r
+\r
+  @param  Xhc           The XHCI device.\r
+\r
+  @retval TRUE          The controller is halted.\r
+  @retval FALSE         The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsHalt (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  );\r
+\r
+/**\r
+  Check whether system error occurred.\r
+\r
+  @param  Xhc           The XHCI device.\r
+\r
+  @retval TRUE          System error happened.\r
+  @retval FALSE         No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsSysError (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  );\r
+\r
+/**\r
+  Reset the host controller.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT   The transfer failed due to time out.\r
+  @retval Others        Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiResetHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  );\r
+\r
+/**\r
+  Halt the host controller.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort.\r
+\r
+  @retval EFI_TIMEOUT   Failed to halt the controller before Timeout.\r
+  @retval EFI_SUCCESS   The XHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiHaltHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  );\r
+\r
+/**\r
+  Set the XHCI to run.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Timeout       Time to wait before abort.\r
+\r
+  @retval EFI_SUCCESS   The XHCI is running.\r
+  @retval Others        Failed to set the XHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRunHC (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT32             Timeout\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
new file mode 100644 (file)
index 0000000..3ae1511
--- /dev/null
@@ -0,0 +1,2761 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+/**\r
+  Create a command transfer TRB to support XHCI command interfaces.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  CmdTrb    The cmd TRB to be executed.\r
+\r
+  @return Created URB or NULL.\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateCmdTrb (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN TRB_TEMPLATE   *CmdTrb\r
+  )\r
+{\r
+  URB   *Urb;\r
+\r
+  Urb = AllocateZeroPool (sizeof (URB));\r
+  if (Urb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Urb->Signature  = XHC_URB_SIG;\r
+\r
+  Urb->Ring       = &Xhc->CmdRing;\r
+  XhcPeiSyncTrsRing (Xhc, Urb->Ring);\r
+  Urb->TrbNum     = 1;\r
+  Urb->TrbStart   = Urb->Ring->RingEnqueue;\r
+  CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
+  Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
+  Urb->TrbEnd             = Urb->TrbStart;\r
+\r
+  return Urb;\r
+}\r
+\r
+/**\r
+  Execute a XHCI cmd TRB pointed by CmdTrb.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  CmdTrb                The cmd TRB to be executed.\r
+  @param  Timeout               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+  @param  EvtTrb                The event TRB corresponding to the cmd TRB.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCmdTransfer (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN TRB_TEMPLATE               *CmdTrb,\r
+  IN UINTN                      Timeout,\r
+  OUT TRB_TEMPLATE              **EvtTrb\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  URB           *Urb;\r
+\r
+  //\r
+  // Validate the parameters\r
+  //\r
+  if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: HC is halted or has system error\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create a new URB, then poll the execution status.\r
+  //\r
+  Urb = XhcPeiCreateCmdTrb (Xhc, CmdTrb);\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiCmdTransfer: failed to create URB\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status  = XhcPeiExecTransfer (Xhc, TRUE, Urb, Timeout);\r
+  *EvtTrb = Urb->EvtTrb;\r
+\r
+  if (Urb->Result == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  XhcPeiFreeUrb (Xhc, Urb);\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Create a new URB for a new transaction.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  BusAddr   The logical device address assigned by UsbBus driver\r
+  @param  EpAddr    Endpoint addrress\r
+  @param  DevSpeed  The device speed\r
+  @param  MaxPacket The max packet length of the endpoint\r
+  @param  Type      The transaction type\r
+  @param  Request   The standard USB request for control transfer\r
+  @param  Data      The user data to transfer\r
+  @param  DataLen   The length of data buffer\r
+  @param  Callback  The function to call when data is transferred\r
+  @param  Context   The context to the callback\r
+\r
+  @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateUrb (\r
+  IN PEI_XHC_DEV                        *Xhc,\r
+  IN UINT8                              BusAddr,\r
+  IN UINT8                              EpAddr,\r
+  IN UINT8                              DevSpeed,\r
+  IN UINTN                              MaxPacket,\r
+  IN UINTN                              Type,\r
+  IN EFI_USB_DEVICE_REQUEST             *Request,\r
+  IN VOID                               *Data,\r
+  IN UINTN                              DataLen,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,\r
+  IN VOID                               *Context\r
+  )\r
+{\r
+  USB_ENDPOINT      *Ep;\r
+  EFI_STATUS        Status;\r
+  URB               *Urb;\r
+\r
+  Urb = AllocateZeroPool (sizeof (URB));\r
+  if (Urb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Urb->Signature = XHC_URB_SIG;\r
+\r
+  Ep            = &Urb->Ep;\r
+  Ep->BusAddr   = BusAddr;\r
+  Ep->EpAddr    = (UINT8) (EpAddr & 0x0F);\r
+  Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
+  Ep->DevSpeed  = DevSpeed;\r
+  Ep->MaxPacket = MaxPacket;\r
+  Ep->Type      = Type;\r
+\r
+  Urb->Request  = Request;\r
+  Urb->Data     = Data;\r
+  Urb->DataLen  = DataLen;\r
+  Urb->Callback = Callback;\r
+  Urb->Context  = Context;\r
+\r
+  Status = XhcPeiCreateTransferTrb (Xhc, Urb);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status));\r
+    FreePool (Urb);\r
+    Urb = NULL;\r
+  }\r
+\r
+  return Urb;\r
+}\r
+\r
+/**\r
+  Free an allocated URB.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  Urb       The URB to free.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeUrb (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN URB            *Urb\r
+  )\r
+{\r
+  if ((Xhc == NULL) || (Urb == NULL)) {\r
+    return;\r
+  }\r
+\r
+  FreePool (Urb);\r
+}\r
+\r
+/**\r
+  Create a transfer TRB.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  Urb       The urb used to construct the transfer TRB.\r
+\r
+  @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCreateTransferTrb (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN URB            *Urb\r
+  )\r
+{\r
+  VOID                          *OutputContext;\r
+  TRANSFER_RING                 *EPRing;\r
+  UINT8                         EPType;\r
+  UINT8                         SlotId;\r
+  UINT8                         Dci;\r
+  TRB                           *TrbStart;\r
+  UINTN                         TotalLen;\r
+  UINTN                         Len;\r
+  UINTN                         TrbNum;\r
+\r
+  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+  if (SlotId == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Urb->Finished  = FALSE;\r
+  Urb->StartDone = FALSE;\r
+  Urb->EndDone   = FALSE;\r
+  Urb->Completed = 0;\r
+  Urb->Result    = EFI_USB_NOERROR;\r
+\r
+  Dci       = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+  EPRing    = (TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
+  Urb->Ring = EPRing;\r
+  OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+  if (Xhc->HcCParams.Data.Csz == 0) {\r
+    EPType  = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
+  } else {\r
+    EPType  = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
+  }\r
+\r
+  Urb->DataPhy = Urb->Data;\r
+\r
+  //\r
+  // Construct the TRB\r
+  //\r
+  XhcPeiSyncTrsRing (Xhc, EPRing);\r
+  Urb->TrbStart = EPRing->RingEnqueue;\r
+  switch (EPType) {\r
+    case ED_CONTROL_BIDIR:\r
+      //\r
+      // For control transfer, create SETUP_STAGE_TRB first.\r
+      //\r
+      TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+      TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
+      TrbStart->TrbCtrSetup.bRequest      = Urb->Request->Request;\r
+      TrbStart->TrbCtrSetup.wValue        = Urb->Request->Value;\r
+      TrbStart->TrbCtrSetup.wIndex        = Urb->Request->Index;\r
+      TrbStart->TrbCtrSetup.wLength       = Urb->Request->Length;\r
+      TrbStart->TrbCtrSetup.Length        = 8;\r
+      TrbStart->TrbCtrSetup.IntTarget     = 0;\r
+      TrbStart->TrbCtrSetup.IOC           = 1;\r
+      TrbStart->TrbCtrSetup.IDT           = 1;\r
+      TrbStart->TrbCtrSetup.Type          = TRB_TYPE_SETUP_STAGE;\r
+      if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+        TrbStart->TrbCtrSetup.TRT = 3;\r
+      } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+        TrbStart->TrbCtrSetup.TRT = 2;\r
+      } else {\r
+        TrbStart->TrbCtrSetup.TRT = 0;\r
+      }\r
+      //\r
+      // Update the cycle bit\r
+      //\r
+      TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
+      Urb->TrbNum++;\r
+\r
+      //\r
+      // For control transfer, create DATA_STAGE_TRB.\r
+      //\r
+      if (Urb->DataLen > 0) {\r
+        XhcPeiSyncTrsRing (Xhc, EPRing);\r
+        TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+        TrbStart->TrbCtrData.TRBPtrLo  = XHC_LOW_32BIT (Urb->DataPhy);\r
+        TrbStart->TrbCtrData.TRBPtrHi  = XHC_HIGH_32BIT (Urb->DataPhy);\r
+        TrbStart->TrbCtrData.Length    = (UINT32) Urb->DataLen;\r
+        TrbStart->TrbCtrData.TDSize    = 0;\r
+        TrbStart->TrbCtrData.IntTarget = 0;\r
+        TrbStart->TrbCtrData.ISP       = 1;\r
+        TrbStart->TrbCtrData.IOC       = 1;\r
+        TrbStart->TrbCtrData.IDT       = 0;\r
+        TrbStart->TrbCtrData.CH        = 0;\r
+        TrbStart->TrbCtrData.Type      = TRB_TYPE_DATA_STAGE;\r
+        if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+          TrbStart->TrbCtrData.DIR = 1;\r
+        } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+          TrbStart->TrbCtrData.DIR = 0;\r
+        } else {\r
+          TrbStart->TrbCtrData.DIR = 0;\r
+        }\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
+        Urb->TrbNum++;\r
+      }\r
+      //\r
+      // For control transfer, create STATUS_STAGE_TRB.\r
+      // Get the pointer to next TRB for status stage use\r
+      //\r
+      XhcPeiSyncTrsRing (Xhc, EPRing);\r
+      TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+      TrbStart->TrbCtrStatus.IntTarget = 0;\r
+      TrbStart->TrbCtrStatus.IOC       = 1;\r
+      TrbStart->TrbCtrStatus.CH        = 0;\r
+      TrbStart->TrbCtrStatus.Type      = TRB_TYPE_STATUS_STAGE;\r
+      if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+        TrbStart->TrbCtrStatus.DIR = 0;\r
+      } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+        TrbStart->TrbCtrStatus.DIR = 1;\r
+      } else {\r
+        TrbStart->TrbCtrStatus.DIR = 0;\r
+      }\r
+      //\r
+      // Update the cycle bit\r
+      //\r
+      TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
+      //\r
+      // Update the enqueue pointer\r
+      //\r
+      XhcPeiSyncTrsRing (Xhc, EPRing);\r
+      Urb->TrbNum++;\r
+      Urb->TrbEnd = (TRB_TEMPLATE *) (UINTN) TrbStart;\r
+\r
+      break;\r
+\r
+    case ED_BULK_OUT:\r
+    case ED_BULK_IN:\r
+      TotalLen = 0;\r
+      Len      = 0;\r
+      TrbNum   = 0;\r
+      TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+      while (TotalLen < Urb->DataLen) {\r
+        if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+          Len = Urb->DataLen - TotalLen;\r
+        } else {\r
+          Len = 0x10000;\r
+        }\r
+        TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+        TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+        TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+        TrbStart->TrbNormal.Length    = (UINT32) Len;\r
+        TrbStart->TrbNormal.TDSize    = 0;\r
+        TrbStart->TrbNormal.IntTarget = 0;\r
+        TrbStart->TrbNormal.ISP       = 1;\r
+        TrbStart->TrbNormal.IOC       = 1;\r
+        TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+        XhcPeiSyncTrsRing (Xhc, EPRing);\r
+        TrbNum++;\r
+        TotalLen += Len;\r
+      }\r
+\r
+      Urb->TrbNum = TrbNum;\r
+      Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
+      break;\r
+\r
+    case ED_INTERRUPT_OUT:\r
+    case ED_INTERRUPT_IN:\r
+      TotalLen = 0;\r
+      Len      = 0;\r
+      TrbNum   = 0;\r
+      TrbStart = (TRB *) (UINTN) EPRing->RingEnqueue;\r
+      while (TotalLen < Urb->DataLen) {\r
+        if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+          Len = Urb->DataLen - TotalLen;\r
+        } else {\r
+          Len = 0x10000;\r
+        }\r
+        TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+        TrbStart->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+        TrbStart->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
+        TrbStart->TrbNormal.Length    = (UINT32) Len;\r
+        TrbStart->TrbNormal.TDSize    = 0;\r
+        TrbStart->TrbNormal.IntTarget = 0;\r
+        TrbStart->TrbNormal.ISP       = 1;\r
+        TrbStart->TrbNormal.IOC       = 1;\r
+        TrbStart->TrbNormal.Type      = TRB_TYPE_NORMAL;\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+        XhcPeiSyncTrsRing (Xhc, EPRing);\r
+        TrbNum++;\r
+        TotalLen += Len;\r
+      }\r
+\r
+      Urb->TrbNum = TrbNum;\r
+      Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
+      break;\r
+\r
+    default:\r
+      DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
+      ASSERT (FALSE);\r
+      break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+  condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+  Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+  reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+  Stopped to the Running state.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Urb           The urb which makes the endpoint halted.\r
+\r
+  @retval EFI_SUCCESS   The recovery is successful.\r
+  @retval Others        Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRecoverHaltedEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN URB                *Urb\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
+  CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;\r
+  CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;\r
+  UINT8                       Dci;\r
+  UINT8                       SlotId;\r
+  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
+\r
+  Status = EFI_SUCCESS;\r
+  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+  if (SlotId == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId, Dci));\r
+\r
+  //\r
+  // 1) Send Reset endpoint command to transit from halt to stop state\r
+  //\r
+  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+  CmdTrbResetED.CycleBit = 1;\r
+  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
+  CmdTrbResetED.EDID     = Dci;\r
+  CmdTrbResetED.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 2) Set dequeue pointer\r
+  //\r
+  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
+  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
+  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdSetTRDeq.CycleBit = 1;\r
+  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
+  CmdSetTRDeq.Endpoint = Dci;\r
+  CmdSetTRDeq.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 3) Ring the doorbell to transit from stop to active\r
+  //\r
+  XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check if the Trb is a transaction of the URB.\r
+\r
+  @param Trb        The TRB to be checked\r
+  @param Urb        The transfer ring to be checked.\r
+\r
+  @retval TRUE      It is a transaction of the URB.\r
+  @retval FALSE     It is not any transaction of the URB.\r
+\r
+**/\r
+BOOLEAN\r
+XhcPeiIsTransferRingTrb (\r
+  IN TRB_TEMPLATE   *Trb,\r
+  IN URB            *Urb\r
+  )\r
+{\r
+  TRB_TEMPLATE  *CheckedTrb;\r
+  UINTN         Index;\r
+\r
+  CheckedTrb = Urb->Ring->RingSeg0;\r
+\r
+  ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
+\r
+  for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
+    if (Trb == CheckedTrb) {\r
+      return TRUE;\r
+    }\r
+    CheckedTrb++;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check the URB's execution result and update the URB's\r
+  result accordingly.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  Urb               The URB to check result.\r
+\r
+  @return Whether the result of URB transfer is finialized.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckUrbResult (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN URB                    *Urb\r
+  )\r
+{\r
+  EVT_TRB_TRANSFER          *EvtTrb;\r
+  TRB_TEMPLATE              *TRBPtr;\r
+  UINTN                     Index;\r
+  UINT8                     TRBType;\r
+  EFI_STATUS                Status;\r
+  URB                       *CheckedUrb;\r
+  UINT64                    XhcDequeue;\r
+  UINT32                    High;\r
+  UINT32                    Low;\r
+  EFI_PHYSICAL_ADDRESS      PhyAddr;\r
+\r
+  ASSERT ((Xhc != NULL) && (Urb != NULL));\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (Urb->Finished) {\r
+    goto EXIT;\r
+  }\r
+\r
+  EvtTrb = NULL;\r
+\r
+  if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
+    Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+    Status       = EFI_DEVICE_ERROR;\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Traverse the event ring to find out all new events from the previous check.\r
+  //\r
+  XhcPeiSyncEventRing (Xhc, &Xhc->EventRing);\r
+  for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
+    Status = XhcPeiCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **) &EvtTrb));\r
+    if (Status == EFI_NOT_READY) {\r
+      //\r
+      // All new events are handled, return directly.\r
+      //\r
+      goto EXIT;\r
+    }\r
+\r
+    //\r
+    // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
+    //\r
+    if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Need convert pci device address to host address\r
+    //\r
+    PhyAddr = (EFI_PHYSICAL_ADDRESS) (EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
+    TRBPtr = (TRB_TEMPLATE *) (UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *) (UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
+\r
+    //\r
+    // Update the status of Urb according to the finished event regardless of whether\r
+    // the urb is current checked one or in the XHCI's async transfer list.\r
+    // This way is used to avoid that those completed async transfer events don't get\r
+    // handled in time and are flushed by newer coming events.\r
+    //\r
+    if (XhcPeiIsTransferRingTrb (TRBPtr, Urb)) {\r
+      CheckedUrb = Urb;\r
+    } else {\r
+      continue;\r
+    }\r
+\r
+    switch (EvtTrb->Completecode) {\r
+      case TRB_COMPLETION_STALL_ERROR:\r
+        CheckedUrb->Result  |= EFI_USB_ERR_STALL;\r
+        CheckedUrb->Finished = TRUE;\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+        goto EXIT;\r
+\r
+      case TRB_COMPLETION_BABBLE_ERROR:\r
+        CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;\r
+        CheckedUrb->Finished = TRUE;\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+        goto EXIT;\r
+\r
+      case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
+        CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;\r
+        CheckedUrb->Finished = TRUE;\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));\r
+        goto EXIT;\r
+\r
+      case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
+        CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;\r
+        CheckedUrb->Finished = TRUE;\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
+        goto EXIT;\r
+\r
+      case TRB_COMPLETION_SHORT_PACKET:\r
+      case TRB_COMPLETION_SUCCESS:\r
+        if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
+          DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: short packet happens!\n"));\r
+        }\r
+\r
+        TRBType = (UINT8) (TRBPtr->Type);\r
+        if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
+            (TRBType == TRB_TYPE_NORMAL) ||\r
+            (TRBType == TRB_TYPE_ISOCH)) {\r
+          CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Length);\r
+        }\r
+\r
+        break;\r
+\r
+      default:\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));\r
+        CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;\r
+        CheckedUrb->Finished = TRUE;\r
+        goto EXIT;\r
+    }\r
+\r
+    //\r
+    // Only check first and end Trb event address\r
+    //\r
+    if (TRBPtr == CheckedUrb->TrbStart) {\r
+      CheckedUrb->StartDone = TRUE;\r
+    }\r
+\r
+    if (TRBPtr == CheckedUrb->TrbEnd) {\r
+      CheckedUrb->EndDone = TRUE;\r
+    }\r
+\r
+    if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
+      CheckedUrb->Finished = TRUE;\r
+      CheckedUrb->EvtTrb   = (TRB_TEMPLATE *) EvtTrb;\r
+    }\r
+  }\r
+\r
+EXIT:\r
+\r
+  //\r
+  // Advance event ring to last available entry\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  Low  = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
+  High = XhcPeiReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
+  XhcDequeue = (UINT64) (LShiftU64((UINT64) High, 32) | Low);\r
+\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
+\r
+  if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
+    //\r
+    // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+    // So divide it to two 32-bytes width register access.\r
+    //\r
+    XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
+    XhcPeiWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  CmdTransfer       The executed URB is for cmd transfer or not.\r
+  @param  Urb               The URB to execute.\r
+  @param  Timeout           The time to wait before abort, in millisecond.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiExecTransfer (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN BOOLEAN                CmdTransfer,\r
+  IN URB                    *Urb,\r
+  IN UINTN                  Timeout\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINTN         Index;\r
+  UINTN         Loop;\r
+  UINT8         SlotId;\r
+  UINT8         Dci;\r
+\r
+  if (CmdTransfer) {\r
+    SlotId = 0;\r
+    Dci    = 0;\r
+  } else {\r
+    SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+    if (SlotId == 0) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    Dci  = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  Loop   = Timeout * XHC_1_MILLISECOND;\r
+  if (Timeout == 0) {\r
+    Loop = 0xFFFFFFFF;\r
+  }\r
+\r
+  XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+  for (Index = 0; Index < Loop; Index++) {\r
+    Status = XhcPeiCheckUrbResult (Xhc, Urb);\r
+    if (Urb->Finished) {\r
+      break;\r
+    }\r
+    MicroSecondDelay (XHC_1_MICROSECOND);\r
+  }\r
+\r
+  if (Index == Loop) {\r
+    Urb->Result = EFI_USB_ERR_TIMEOUT;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  ParentRouteChart  The route string pointed to the parent device if it exists.\r
+  @param  Port              The port to be polled.\r
+  @param  PortState         The port state.\r
+\r
+  @retval EFI_SUCCESS       Successfully enable/disable device slot according to port state.\r
+  @retval Others            Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiPollPortStatusChange (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN USB_DEV_ROUTE          ParentRouteChart,\r
+  IN UINT8                  Port,\r
+  IN EFI_USB_PORT_STATUS    *PortState\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINT8             Speed;\r
+  UINT8             SlotId;\r
+  USB_DEV_ROUTE     RouteChart;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState->PortChangeStatus, PortState->PortStatus));\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (ParentRouteChart.Dword == 0) {\r
+    RouteChart.Route.RouteString = 0;\r
+    RouteChart.Route.RootPortNum = Port + 1;\r
+    RouteChart.Route.TierNum     = 1;\r
+  } else {\r
+    if(Port < 14) {\r
+      RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
+    } else {\r
+      RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
+    }\r
+    RouteChart.Route.RootPortNum   = ParentRouteChart.Route.RootPortNum;\r
+    RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;\r
+  }\r
+\r
+  SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
+  if (SlotId != 0) {\r
+    if (Xhc->HcCParams.Data.Csz == 0) {\r
+      Status = XhcPeiDisableSlotCmd (Xhc, SlotId);\r
+    } else {\r
+      Status = XhcPeiDisableSlotCmd64 (Xhc, SlotId);\r
+    }\r
+  }\r
+\r
+  if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
+      ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
+    //\r
+    // Has a device attached, Identify device speed after port is enabled.\r
+    //\r
+    Speed = EFI_USB_SPEED_FULL;\r
+    if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_LOW;\r
+    } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_HIGH;\r
+    } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_SUPER;\r
+    }\r
+    //\r
+    // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
+    //\r
+    SlotId = XhcPeiRouteStringToSlotId (Xhc, RouteChart);\r
+    if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
+      if (Xhc->HcCParams.Data.Csz == 0) {\r
+        Status = XhcPeiInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
+      } else {\r
+        Status = XhcPeiInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
+      }\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Calculate the device context index by endpoint address and direction.\r
+\r
+  @param  EpAddr        The target endpoint number.\r
+  @param  Direction     The direction of the target endpoint.\r
+\r
+  @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcPeiEndpointToDci (\r
+  IN UINT8                      EpAddr,\r
+  IN EFI_USB_DATA_DIRECTION     Direction\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  ASSERT (EpAddr <= 15);\r
+\r
+  if (EpAddr == 0) {\r
+    return 1;\r
+  } else {\r
+    Index = (UINT8) (2 * EpAddr);\r
+    if (Direction == EfiUsbDataIn) {\r
+      Index += 1;\r
+    }\r
+    return Index;\r
+  }\r
+}\r
+\r
+/**\r
+  Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  BusDevAddr    The requested device address by UsbBus upper driver.\r
+\r
+  @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiBusDevAddrToSlotId (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              BusDevAddr\r
+  )\r
+{\r
+  UINT8   Index;\r
+\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
+        (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
+        (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == 255) {\r
+    return 0;\r
+  }\r
+\r
+  return Xhc->UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+  Find out the slot id according to the device's route string.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  RouteString   The route string described the device location.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiRouteStringToSlotId (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN USB_DEV_ROUTE      RouteString\r
+  )\r
+{\r
+  UINT8   Index;\r
+\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
+        (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
+        (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == 255) {\r
+    return 0;\r
+  }\r
+\r
+  return Xhc->UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+**/\r
+VOID\r
+XhcPeiRingDoorBell (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  )\r
+{\r
+  if (SlotId == 0) {\r
+    XhcPeiWriteDoorBellReg (Xhc, 0, 0);\r
+  } else {\r
+    XhcPeiWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
+  }\r
+}\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device.\r
+  @param  ParentPort            The port at which the device is located.\r
+  @param  RouteChart            The route string pointed to the device.\r
+  @param  DeviceSpeed           The device speed.\r
+\r
+  @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.\r
+  @retval Others                Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN USB_DEV_ROUTE              ParentRouteChart,\r
+  IN UINT16                     ParentPort,\r
+  IN USB_DEV_ROUTE              RouteChart,\r
+  IN UINT8                      DeviceSpeed\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT                 *InputContext;\r
+  DEVICE_CONTEXT                *OutputContext;\r
+  TRANSFER_RING                 *EndpointTransferRing;\r
+  CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;\r
+  UINT8                         DeviceAddress;\r
+  CMD_TRB_ENABLE_SLOT           CmdTrb;\r
+  UINT8                         SlotId;\r
+  UINT8                         ParentSlotId;\r
+  DEVICE_CONTEXT                *ParentDeviceContext;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
+  CmdTrb.CycleBit = 1;\r
+  CmdTrb.Type     = TRB_TYPE_EN_SLOT;\r
+\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
+  SlotId = (UINT8) EvtTrb->SlotId;\r
+  ASSERT (SlotId != 0);\r
+\r
+  ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
+  Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;\r
+  Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;\r
+  Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;\r
+  Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
+\r
+  //\r
+  // 4.3.3 Device Slot Initialization\r
+  // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
+  //\r
+  InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
+  ASSERT (InputContext != NULL);\r
+  ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+  Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
+\r
+  //\r
+  // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
+  //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
+  //    Context are affected by the command.\r
+  //\r
+  InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
+\r
+  //\r
+  // 3) Initialize the Input Slot Context data structure\r
+  //\r
+  InputContext->Slot.RouteString    = RouteChart.Route.RouteString;\r
+  InputContext->Slot.Speed          = DeviceSpeed + 1;\r
+  InputContext->Slot.ContextEntries = 1;\r
+  InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
+\r
+  if (RouteChart.Route.RouteString != 0) {\r
+    //\r
+    // The device is behind of hub device.\r
+    //\r
+    ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
+    ASSERT (ParentSlotId != 0);\r
+    //\r
+    // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context\r
+    //\r
+    ParentDeviceContext = (DEVICE_CONTEXT *) Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
+    if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
+        (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
+      if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
+        //\r
+        // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
+        // environment from Full/Low speed signaling environment for a device\r
+        //\r
+        InputContext->Slot.TTPortNum   = ParentPort;\r
+        InputContext->Slot.TTHubSlotId = ParentSlotId;\r
+      }\r
+    } else {\r
+      //\r
+      // Inherit the TT parameters from parent device.\r
+      //\r
+      InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;\r
+      InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
+      //\r
+      // If the device is a High speed device then down the speed to be the same as its parent Hub\r
+      //\r
+      if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+        InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
+  //\r
+  EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+  Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
+  XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
+  //\r
+  // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
+  //\r
+  InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
+\r
+  if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    InputContext->EP[0].MaxPacketSize = 512;\r
+  } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+    InputContext->EP[0].MaxPacketSize = 64;\r
+  } else {\r
+    InputContext->EP[0].MaxPacketSize = 8;\r
+  }\r
+  //\r
+  // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
+  // 1KB, and Bulk and Isoch endpoints 3KB.\r
+  //\r
+  InputContext->EP[0].AverageTRBLength = 8;\r
+  InputContext->EP[0].MaxBurstSize     = 0;\r
+  InputContext->EP[0].Interval         = 0;\r
+  InputContext->EP[0].MaxPStreams      = 0;\r
+  InputContext->EP[0].Mult             = 0;\r
+  InputContext->EP[0].CErr             = 3;\r
+\r
+  //\r
+  // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
+  //\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+              Xhc->MemPool,\r
+              ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
+              sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+              );\r
+  InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
+  InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+  //\r
+  // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
+  //\r
+  OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
+  ASSERT (OutputContext != NULL);\r
+  ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
+  ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
+\r
+  Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
+  //\r
+  // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
+  //    a pointer to the Output Device Context data structure (6.2.1).\r
+  //\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
+  //\r
+  // Fill DCBAA with PCI device address\r
+  //\r
+  Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
+\r
+  //\r
+  // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
+  //    Context data structure described above.\r
+  //\r
+  ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
+  CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbAddr.CycleBit = 1;\r
+  CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;\r
+  CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;\r
+    DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress));\r
+    Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device.\r
+  @param  ParentPort            The port at which the device is located.\r
+  @param  RouteChart            The route string pointed to the device.\r
+  @param  DeviceSpeed           The device speed.\r
+\r
+  @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.\r
+  @retval Others                Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN USB_DEV_ROUTE              ParentRouteChart,\r
+  IN UINT16                     ParentPort,\r
+  IN USB_DEV_ROUTE              RouteChart,\r
+  IN UINT8                      DeviceSpeed\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT_64              *InputContext;\r
+  DEVICE_CONTEXT_64             *OutputContext;\r
+  TRANSFER_RING                 *EndpointTransferRing;\r
+  CMD_TRB_ADDRESS_DEVICE        CmdTrbAddr;\r
+  UINT8                         DeviceAddress;\r
+  CMD_TRB_ENABLE_SLOT           CmdTrb;\r
+  UINT8                         SlotId;\r
+  UINT8                         ParentSlotId;\r
+  DEVICE_CONTEXT_64             *ParentDeviceContext;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
+  CmdTrb.CycleBit = 1;\r
+  CmdTrb.Type     = TRB_TYPE_EN_SLOT;\r
+\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
+  SlotId = (UINT8)EvtTrb->SlotId;\r
+  ASSERT (SlotId != 0);\r
+\r
+  ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
+  Xhc->UsbDevContext[SlotId].Enabled                 = TRUE;\r
+  Xhc->UsbDevContext[SlotId].SlotId                  = SlotId;\r
+  Xhc->UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;\r
+  Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
+\r
+  //\r
+  // 4.3.3 Device Slot Initialization\r
+  // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
+  //\r
+  InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
+  ASSERT (InputContext != NULL);\r
+  ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+  Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
+\r
+  //\r
+  // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
+  //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
+  //    Context are affected by the command.\r
+  //\r
+  InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
+\r
+  //\r
+  // 3) Initialize the Input Slot Context data structure\r
+  //\r
+  InputContext->Slot.RouteString    = RouteChart.Route.RouteString;\r
+  InputContext->Slot.Speed          = DeviceSpeed + 1;\r
+  InputContext->Slot.ContextEntries = 1;\r
+  InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
+\r
+  if (RouteChart.Route.RouteString != 0) {\r
+    //\r
+    // The device is behind of hub device.\r
+    //\r
+    ParentSlotId = XhcPeiRouteStringToSlotId (Xhc, ParentRouteChart);\r
+    ASSERT (ParentSlotId != 0);\r
+    //\r
+    //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
+    //\r
+    ParentDeviceContext = (DEVICE_CONTEXT_64 *) Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
+    if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
+        (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
+      if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
+        //\r
+        // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
+        // environment from Full/Low speed signaling environment for a device\r
+        //\r
+        InputContext->Slot.TTPortNum   = ParentPort;\r
+        InputContext->Slot.TTHubSlotId = ParentSlotId;\r
+      }\r
+    } else {\r
+      //\r
+      // Inherit the TT parameters from parent device.\r
+      //\r
+      InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;\r
+      InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
+      //\r
+      // If the device is a High speed device then down the speed to be the same as its parent Hub\r
+      //\r
+      if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+        InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
+  //\r
+  EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+  Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
+  XhcPeiCreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
+  //\r
+  // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
+  //\r
+  InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
+\r
+  if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    InputContext->EP[0].MaxPacketSize = 512;\r
+  } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+    InputContext->EP[0].MaxPacketSize = 64;\r
+  } else {\r
+    InputContext->EP[0].MaxPacketSize = 8;\r
+  }\r
+  //\r
+  // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
+  // 1KB, and Bulk and Isoch endpoints 3KB.\r
+  //\r
+  InputContext->EP[0].AverageTRBLength = 8;\r
+  InputContext->EP[0].MaxBurstSize     = 0;\r
+  InputContext->EP[0].Interval         = 0;\r
+  InputContext->EP[0].MaxPStreams      = 0;\r
+  InputContext->EP[0].Mult             = 0;\r
+  InputContext->EP[0].CErr             = 3;\r
+\r
+  //\r
+  // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
+  //\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+              Xhc->MemPool,\r
+              ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
+              sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+              );\r
+  InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
+  InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+  //\r
+  // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
+  //\r
+  OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
+  ASSERT (OutputContext != NULL);\r
+  ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
+  ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+\r
+  Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
+  //\r
+  // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
+  //    a pointer to the Output Device Context data structure (6.2.1).\r
+  //\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+  //\r
+  // Fill DCBAA with PCI device address\r
+  //\r
+  Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
+\r
+  //\r
+  // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
+  //    Context data structure described above.\r
+  //\r
+  ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
+  CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbAddr.CycleBit = 1;\r
+  CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;\r
+  CmdTrbAddr.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    DeviceAddress = (UINT8) OutputContext->Slot.DeviceAddress;\r
+    DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress));\r
+    Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd (\r
+  IN PEI_XHC_DEV               *Xhc,\r
+  IN UINT8                     SlotId\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  TRB_TEMPLATE          *EvtTrb;\r
+  CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;\r
+  UINT8                 Index;\r
+  VOID                  *RingSeg;\r
+\r
+  //\r
+  // Disable the device slots occupied by these devices on its downstream ports.\r
+  // Entry 0 is reserved.\r
+  //\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
+        (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
+        (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
+      continue;\r
+    }\r
+\r
+    Status = XhcPeiDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));\r
+      Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Construct the disable slot command\r
+  //\r
+  DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId));\r
+\r
+  ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
+  CmdTrbDisSlot.CycleBit = 1;\r
+  CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;\r
+  CmdTrbDisSlot.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Free the slot's device context entry\r
+  //\r
+  Xhc->DCBAA[SlotId] = 0;\r
+\r
+  //\r
+  // Free the slot related data structure\r
+  //\r
+  for (Index = 0; Index < 31; Index++) {\r
+    if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
+      RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
+      if (RingSeg != NULL) {\r
+        UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
+      }\r
+      FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
+      Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+    if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
+      FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+    }\r
+  }\r
+\r
+  if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
+    UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
+  }\r
+\r
+  if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
+    UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
+  }\r
+  //\r
+  // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
+  // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
+  // remove urb from XHCI's asynchronous transfer list.\r
+  //\r
+  Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
+  Xhc->UsbDevContext[SlotId].SlotId  = 0;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd64 (\r
+  IN PEI_XHC_DEV               *Xhc,\r
+  IN UINT8                     SlotId\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  TRB_TEMPLATE          *EvtTrb;\r
+  CMD_TRB_DISABLE_SLOT  CmdTrbDisSlot;\r
+  UINT8                 Index;\r
+  VOID                  *RingSeg;\r
+\r
+  //\r
+  // Disable the device slots occupied by these devices on its downstream ports.\r
+  // Entry 0 is reserved.\r
+  //\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
+        (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
+        (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
+      continue;\r
+    }\r
+\r
+    Status = XhcPeiDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));\r
+      Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Construct the disable slot command\r
+  //\r
+  DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId));\r
+\r
+  ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
+  CmdTrbDisSlot.CycleBit = 1;\r
+  CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;\r
+  CmdTrbDisSlot.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Free the slot's device context entry\r
+  //\r
+  Xhc->DCBAA[SlotId] = 0;\r
+\r
+  //\r
+  // Free the slot related data structure\r
+  //\r
+  for (Index = 0; Index < 31; Index++) {\r
+    if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
+      RingSeg = ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
+      if (RingSeg != NULL) {\r
+        UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
+      }\r
+      FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
+      Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+    if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
+      FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+    }\r
+  }\r
+\r
+  if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
+    UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
+  }\r
+\r
+  if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
+     UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
+  }\r
+  //\r
+  // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
+  // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
+  // remove urb from XHCI's asynchronous transfer list.\r
+  //\r
+  Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
+  Xhc->UsbDevContext[SlotId].SlotId  = 0;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR      *ConfigDesc\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  USB_INTERFACE_DESCRIPTOR      *IfDesc;\r
+  USB_ENDPOINT_DESCRIPTOR       *EpDesc;\r
+  UINT8                         Index;\r
+  UINTN                         NumEp;\r
+  UINTN                         EpIndex;\r
+  UINT8                         EpAddr;\r
+  EFI_USB_DATA_DIRECTION        Direction;\r
+  UINT8                         Dci;\r
+  UINT8                         MaxDci;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  UINT8                         Interval;\r
+\r
+  TRANSFER_RING                 *EndpointTransferRing;\r
+  CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;\r
+  INPUT_CONTEXT                 *InputContext;\r
+  DEVICE_CONTEXT                *OutputContext;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  //\r
+  // 4.6.6 Configure Endpoint\r
+  //\r
+  InputContext  = Xhc->UsbDevContext[SlotId].InputContext;\r
+  OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+  CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
+\r
+  ASSERT (ConfigDesc != NULL);\r
+\r
+  MaxDci = 0;\r
+\r
+  IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);\r
+  for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
+    while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
+      IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+    }\r
+\r
+    NumEp = IfDesc->NumEndpoints;\r
+\r
+    EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);\r
+    for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
+      while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
+        EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+      }\r
+\r
+      EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
+      Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+\r
+      Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
+      if (Dci > MaxDci) {\r
+        MaxDci = Dci;\r
+      }\r
+\r
+      InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
+      InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;\r
+\r
+      if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+        //\r
+        // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
+        //\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      } else {\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      }\r
+\r
+      switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
+        case USB_ENDPOINT_BULK:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
+          }\r
+\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+            Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+\r
+          break;\r
+        case USB_ENDPOINT_ISO:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
+          }\r
+          break;\r
+        case USB_ENDPOINT_INTERRUPT:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
+          }\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;\r
+          //\r
+          // Get the bInterval from descriptor and init the interval field of endpoint context\r
+          //\r
+          if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
+            Interval = EpDesc->Interval;\r
+            //\r
+            // Calculate through the bInterval field of Endpoint descriptor.\r
+            //\r
+            ASSERT (Interval != 0);\r
+            InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32 ((UINT32) Interval) + 3;\r
+          } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            //\r
+            // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
+            //\r
+            InputContext->EP[Dci-1].Interval = Interval - 1;\r
+          }\r
+\r
+          if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+            Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+          break;\r
+\r
+        case USB_ENDPOINT_CONTROL:\r
+        default:\r
+          ASSERT (FALSE);\r
+          break;\r
+      }\r
+\r
+      PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+                  Xhc->MemPool,\r
+                  ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
+                  sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+                  );\r
+      PhyAddr &= ~(0x0F);\r
+      PhyAddr |= ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+      InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+      InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+      EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+    }\r
+    IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+  }\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+  InputContext->Slot.ContextEntries         = MaxDci;\r
+  //\r
+  // configure endpoint\r
+  //\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "XhcSetConfigCmd: Configure Endpoint\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR      *ConfigDesc\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  USB_INTERFACE_DESCRIPTOR      *IfDesc;\r
+  USB_ENDPOINT_DESCRIPTOR       *EpDesc;\r
+  UINT8                         Index;\r
+  UINTN                         NumEp;\r
+  UINTN                         EpIndex;\r
+  UINT8                         EpAddr;\r
+  EFI_USB_DATA_DIRECTION        Direction;\r
+  UINT8                         Dci;\r
+  UINT8                         MaxDci;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  UINT8                         Interval;\r
+\r
+  TRANSFER_RING                 *EndpointTransferRing;\r
+  CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;\r
+  INPUT_CONTEXT_64              *InputContext;\r
+  DEVICE_CONTEXT_64             *OutputContext;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  //\r
+  // 4.6.6 Configure Endpoint\r
+  //\r
+  InputContext  = Xhc->UsbDevContext[SlotId].InputContext;\r
+  OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+  CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
+\r
+  ASSERT (ConfigDesc != NULL);\r
+\r
+  MaxDci = 0;\r
+\r
+  IfDesc = (USB_INTERFACE_DESCRIPTOR *) (ConfigDesc + 1);\r
+  for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
+    while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
+      IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN) IfDesc + IfDesc->Length);\r
+    }\r
+\r
+    NumEp = IfDesc->NumEndpoints;\r
+\r
+    EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDesc + 1);\r
+    for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
+      while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
+        EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN) EpDesc + EpDesc->Length);\r
+      }\r
+\r
+      EpAddr    = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
+      Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+\r
+      Dci = XhcPeiEndpointToDci (EpAddr, Direction);\r
+      ASSERT (Dci < 32);\r
+      if (Dci > MaxDci) {\r
+        MaxDci = Dci;\r
+      }\r
+\r
+      InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
+      InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;\r
+\r
+      if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+        //\r
+        // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
+        //\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      } else {\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      }\r
+\r
+      switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
+        case USB_ENDPOINT_BULK:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
+          }\r
+\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+            Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+\r
+          break;\r
+        case USB_ENDPOINT_ISO:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
+          }\r
+          break;\r
+        case USB_ENDPOINT_INTERRUPT:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
+          }\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;\r
+          //\r
+          // Get the bInterval from descriptor and init the the interval field of endpoint context\r
+          //\r
+          if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
+            Interval = EpDesc->Interval;\r
+            //\r
+            // Calculate through the bInterval field of Endpoint descriptor.\r
+            //\r
+            ASSERT (Interval != 0);\r
+            InputContext->EP[Dci-1].Interval = (UINT32) HighBitSet32( (UINT32) Interval) + 3;\r
+          } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            //\r
+            // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
+            //\r
+            InputContext->EP[Dci-1].Interval = Interval - 1;\r
+          }\r
+\r
+          if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
+            Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            XhcPeiCreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+          break;\r
+\r
+        case USB_ENDPOINT_CONTROL:\r
+        default:\r
+          ASSERT (0);\r
+          break;\r
+      }\r
+\r
+      PhyAddr = UsbHcGetPciAddrForHostAddr (\r
+                  Xhc->MemPool,\r
+                  ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
+                  sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
+                  );\r
+\r
+      PhyAddr &= ~(0x0F);\r
+      PhyAddr |= ((TRANSFER_RING *) (UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+\r
+      InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+      InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+\r
+      EpDesc = (USB_ENDPOINT_DESCRIPTOR *) ((UINTN)EpDesc + EpDesc->Length);\r
+    }\r
+    IfDesc = (USB_INTERFACE_DESCRIPTOR *) ((UINTN)IfDesc + IfDesc->Length);\r
+  }\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+  InputContext->Slot.ContextEntries         = MaxDci;\r
+  //\r
+  // configure endpoint\r
+  //\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  PhyAddr  = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "XhcSetConfigCmd64: Configure Endpoint\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT32                     MaxPacketSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT                 *InputContext;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT1;\r
+  InputContext->EP[0].MaxPacketSize         = MaxPacketSize;\r
+\r
+  ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+  CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbEvalu.CycleBit = 1;\r
+  CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;\r
+  CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "XhcEvaluateContext: Evaluate context\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT32                     MaxPacketSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  CMD_TRB_EVALUATE_CONTEXT      CmdTrbEvalu;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT_64              *InputContext;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT1;\r
+  InputContext->EP[0].MaxPacketSize         = MaxPacketSize;\r
+\r
+  ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+  CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbEvalu.CycleBit = 1;\r
+  CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;\r
+  CmdTrbEvalu.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "XhcEvaluateContext64: Evaluate context 64\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      PortNum,\r
+  IN UINT8                      TTT,\r
+  IN UINT8                      MTT\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT                 *InputContext;\r
+  DEVICE_CONTEXT                *OutputContext;\r
+  CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+  InputContext  = Xhc->UsbDevContext[SlotId].InputContext;\r
+  OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+\r
+  //\r
+  // Copy the slot context from OutputContext to Input context\r
+  //\r
+  CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
+  InputContext->Slot.Hub     = 1;\r
+  InputContext->Slot.PortNum = PortNum;\r
+  InputContext->Slot.TTT     = TTT;\r
+  InputContext->Slot.MTT     = MTT;\r
+\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      PortNum,\r
+  IN UINT8                      TTT,\r
+  IN UINT8                      MTT\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  INPUT_CONTEXT_64              *InputContext;\r
+  DEVICE_CONTEXT_64             *OutputContext;\r
+  CMD_TRB_CONFIG_ENDPOINT       CmdTrbCfgEP;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
+  InputContext  = Xhc->UsbDevContext[SlotId].InputContext;\r
+  OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+\r
+  //\r
+  // Copy the slot context from OutputContext to Input context\r
+  //\r
+  CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
+  InputContext->Slot.Hub     = 1;\r
+  InputContext->Slot.PortNum = PortNum;\r
+  InputContext->Slot.TTT     = TTT;\r
+  InputContext->Slot.MTT     = MTT;\r
+\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = Xhc->UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "Configure Hub Slot Context 64\n"));\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check if there is a new generated event.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EvtRing       The event ring to check.\r
+  @param  NewEvtTrb     The new event TRB found.\r
+\r
+  @retval EFI_SUCCESS   Found a new event TRB at the event ring.\r
+  @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckNewEvent (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN EVENT_RING         *EvtRing,\r
+  OUT TRB_TEMPLATE      **NewEvtTrb\r
+  )\r
+{\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  *NewEvtTrb = EvtRing->EventRingDequeue;\r
+\r
+  if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  EvtRing->EventRingDequeue++;\r
+  //\r
+  // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
+  //\r
+  if ((UINTN) EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+    EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  EvtRing   The event ring to sync.\r
+\r
+  @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncEventRing (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN EVENT_RING     *EvtRing\r
+  )\r
+{\r
+  UINTN             Index;\r
+  TRB_TEMPLATE      *EvtTrb;\r
+\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  //\r
+  // Calculate the EventRingEnqueue and EventRingCCS.\r
+  // Note: only support single Segment\r
+  //\r
+  EvtTrb = EvtRing->EventRingDequeue;\r
+\r
+  for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
+    if (EvtTrb->CycleBit != EvtRing->EventRingCCS) {\r
+      break;\r
+    }\r
+\r
+    EvtTrb++;\r
+\r
+    if ((UINTN) EvtTrb >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+      EvtTrb = EvtRing->EventRingSeg0;\r
+      EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
+    }\r
+  }\r
+\r
+  if (Index < EvtRing->TrbNumber) {\r
+    EvtRing->EventRingEnqueue = EvtTrb;\r
+  } else {\r
+    ASSERT (FALSE);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free XHCI event ring.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EventRing     The event ring to be freed.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeEventRing (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN EVENT_RING         *EventRing\r
+  )\r
+{\r
+  if(EventRing->EventRingSeg0 == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Free EventRing Segment 0\r
+  //\r
+  UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+\r
+  //\r
+  // Free ERST table\r
+  //\r
+  UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+}\r
+\r
+/**\r
+  Create XHCI event ring.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EventRing     The created event ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateEventRing (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  OUT EVENT_RING        *EventRing\r
+  )\r
+{\r
+  VOID                          *Buf;\r
+  EVENT_RING_SEG_TABLE_ENTRY    *ERSTBase;\r
+  UINTN                         Size;\r
+  EFI_PHYSICAL_ADDRESS          ERSTPhy;\r
+  EFI_PHYSICAL_ADDRESS          DequeuePhy;\r
+\r
+  ASSERT (EventRing != NULL);\r
+\r
+  Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
+  Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+  ZeroMem (Buf, Size);\r
+\r
+  DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
+\r
+  EventRing->EventRingSeg0      = Buf;\r
+  EventRing->TrbNumber          = EVENT_RING_TRB_NUMBER;\r
+  EventRing->EventRingDequeue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
+  EventRing->EventRingEnqueue   = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
+\r
+  //\r
+  // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
+  // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
+  //\r
+  EventRing->EventRingCCS = 1;\r
+\r
+  Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
+  Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+  ZeroMem (Buf, Size);\r
+\r
+  ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
+  EventRing->ERSTBase   = ERSTBase;\r
+  ERSTBase->PtrLo       = XHC_LOW_32BIT (DequeuePhy);\r
+  ERSTBase->PtrHi       = XHC_HIGH_32BIT (DequeuePhy);\r
+  ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
+\r
+  ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
+\r
+  //\r
+  // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
+  //\r
+  XhcPeiWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERSTSZ_OFFSET,\r
+    ERST_NUMBER\r
+    );\r
+  //\r
+  // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  XhcPeiWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERDP_OFFSET,\r
+    XHC_LOW_32BIT ((UINT64) (UINTN) DequeuePhy)\r
+    );\r
+  XhcPeiWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERDP_OFFSET + 4,\r
+    XHC_HIGH_32BIT ((UINT64) (UINTN) DequeuePhy)\r
+    );\r
+  //\r
+  // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  XhcPeiWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERSTBA_OFFSET,\r
+    XHC_LOW_32BIT ((UINT64) (UINTN) ERSTPhy)\r
+    );\r
+  XhcPeiWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERSTBA_OFFSET + 4,\r
+    XHC_HIGH_32BIT ((UINT64) (UINTN) ERSTPhy)\r
+    );\r
+  //\r
+  // Need set IMAN IE bit to enable the ring interrupt\r
+  //\r
+  XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
+}\r
+\r
+/**\r
+  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  TrsRing   The transfer ring to sync.\r
+\r
+  @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncTrsRing (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN TRANSFER_RING  *TrsRing\r
+  )\r
+{\r
+  UINTN             Index;\r
+  TRB_TEMPLATE      *TrsTrb;\r
+\r
+  ASSERT (TrsRing != NULL);\r
+  //\r
+  // Calculate the latest RingEnqueue and RingPCS\r
+  //\r
+  TrsTrb = TrsRing->RingEnqueue;\r
+  ASSERT (TrsTrb != NULL);\r
+\r
+  for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
+    if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
+      break;\r
+    }\r
+    TrsTrb++;\r
+    if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
+      ASSERT (((LINK_TRB *) TrsTrb)->TC != 0);\r
+      //\r
+      // set cycle bit in Link TRB as normal\r
+      //\r
+      ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
+      //\r
+      // Toggle PCS maintained by software\r
+      //\r
+      TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
+      TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0;  // Use host address\r
+    }\r
+  }\r
+\r
+  ASSERT (Index != TrsRing->TrbNumber);\r
+\r
+  if (TrsTrb != TrsRing->RingEnqueue) {\r
+    TrsRing->RingEnqueue = TrsTrb;\r
+  }\r
+\r
+  //\r
+  // Clear the Trb context for enqueue, but reserve the PCS bit\r
+  //\r
+  TrsTrb->Parameter1 = 0;\r
+  TrsTrb->Parameter2 = 0;\r
+  TrsTrb->Status     = 0;\r
+  TrsTrb->RsvdZ1     = 0;\r
+  TrsTrb->Type       = 0;\r
+  TrsTrb->Control    = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create XHCI transfer ring.\r
+\r
+  @param  Xhc               The XHCI Device.\r
+  @param  TrbNum            The number of TRB in the ring.\r
+  @param  TransferRing      The created transfer ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateTransferRing (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN UINTN                  TrbNum,\r
+  OUT TRANSFER_RING         *TransferRing\r
+  )\r
+{\r
+  VOID                  *Buf;\r
+  LINK_TRB              *EndTrb;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+\r
+  Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+  ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+\r
+  TransferRing->RingSeg0     = Buf;\r
+  TransferRing->TrbNumber    = TrbNum;\r
+  TransferRing->RingEnqueue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
+  TransferRing->RingDequeue  = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
+  TransferRing->RingPCS      = 1;\r
+  //\r
+  // 4.9.2 Transfer Ring Management\r
+  // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
+  // point to the first TRB in the ring.\r
+  //\r
+  EndTrb        = (LINK_TRB *) ((UINTN) Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
+  EndTrb->Type  = TRB_TYPE_LINK;\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+  EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
+  EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+  //\r
+  // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
+  //\r
+  EndTrb->TC    = 1;\r
+  //\r
+  // Set Cycle bit as other TRB PCS init value\r
+  //\r
+  EndTrb->CycleBit = 0;\r
+}\r
+\r
+/**\r
+  Initialize the XHCI host controller for schedule.\r
+\r
+  @param  Xhc       The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcPeiInitSched (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  )\r
+{\r
+  VOID                  *Dcbaa;\r
+  EFI_PHYSICAL_ADDRESS  DcbaaPhy;\r
+  UINTN                 Size;\r
+  EFI_PHYSICAL_ADDRESS  CmdRingPhy;\r
+  UINT32                MaxScratchpadBufs;\r
+  UINT64                *ScratchBuf;\r
+  EFI_PHYSICAL_ADDRESS  ScratchPhy;\r
+  UINT64                *ScratchEntry;\r
+  EFI_PHYSICAL_ADDRESS  ScratchEntryPhy;\r
+  UINT32                Index;\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  // Initialize memory management.\r
+  //\r
+  Xhc->MemPool = UsbHcInitMemPool ();\r
+  ASSERT (Xhc->MemPool != NULL);\r
+\r
+  //\r
+  // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
+  // to enable the device slots that system software is going to use.\r
+  //\r
+  Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
+  ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
+  XhcPeiWriteOpReg (Xhc, XHC_CONFIG_OFFSET, (XhcPeiReadOpReg (Xhc, XHC_CONFIG_OFFSET) & ~XHC_CONFIG_MASK) | Xhc->MaxSlotsEn);\r
+\r
+  //\r
+  // The Device Context Base Address Array entry associated with each allocated Device Slot\r
+  // shall contain a 64-bit pointer to the base of the associated Device Context.\r
+  // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
+  // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
+  //\r
+  Size = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);\r
+  Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Size);\r
+  ASSERT (Dcbaa != NULL);\r
+\r
+  //\r
+  // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
+  // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
+  // mode (Run/Stop(R/S) ='1').\r
+  //\r
+  MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
+  Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
+  ASSERT (MaxScratchpadBufs <= 1023);\r
+  if (MaxScratchpadBufs != 0) {\r
+    //\r
+    // Allocate the buffer to record the host address for each entry\r
+    //\r
+    ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
+    ASSERT (ScratchEntry != NULL);\r
+    Xhc->ScratchEntry = ScratchEntry;\r
+\r
+    Status = UsbHcAllocateAlignedPages (\r
+               EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
+               Xhc->PageSize,\r
+               (VOID **) &ScratchBuf,\r
+               &ScratchPhy\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
+    Xhc->ScratchBuf = ScratchBuf;\r
+\r
+    //\r
+    // Allocate each scratch buffer\r
+    //\r
+    for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
+      Status = UsbHcAllocateAlignedPages (\r
+                 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
+                 Xhc->PageSize,\r
+                 (VOID **) &ScratchEntry[Index],\r
+                 &ScratchEntryPhy\r
+                 );\r
+      ASSERT_EFI_ERROR (Status);\r
+      ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);\r
+      //\r
+      // Fill with the PCI device address\r
+      //\r
+      *ScratchBuf++ = ScratchEntryPhy;\r
+    }\r
+    //\r
+    // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
+    // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
+    //\r
+    *(UINT64 *) Dcbaa = (UINT64) (UINTN) ScratchPhy;\r
+  }\r
+\r
+  //\r
+  // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
+  // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
+  //\r
+  Xhc->DCBAA = (UINT64 *) (UINTN) Dcbaa;\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Size);\r
+  XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));\r
+  XhcPeiWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc->DCBAA));\r
+\r
+  //\r
+  // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
+  // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
+  // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
+  // always be '0'.\r
+  //\r
+  XhcPeiCreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
+  //\r
+  // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
+  // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
+  // So we set RCS as inverted PCS init value to let Command Ring empty\r
+  //\r
+  CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
+  ASSERT ((CmdRingPhy & 0x3F) == 0);\r
+  CmdRingPhy |= XHC_CRCR_RCS;\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));\r
+  XhcPeiWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
+\r
+  //\r
+  // Disable the 'interrupter enable' bit in USB_CMD\r
+  // and clear IE & IP bit in all Interrupter X Management Registers.\r
+  //\r
+  XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
+  for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
+    XhcPeiClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
+    XhcPeiSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
+  }\r
+\r
+  //\r
+  // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
+  //\r
+  XhcPeiCreateEventRing (Xhc, &Xhc->EventRing);\r
+  DEBUG ((EFI_D_INFO, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
+}\r
+\r
+/**\r
+  Free the resouce allocated at initializing schedule.\r
+\r
+  @param  Xhc       The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeSched (\r
+  IN PEI_XHC_DEV    *Xhc\r
+  )\r
+{\r
+  UINT32                  Index;\r
+  UINT64                  *ScratchEntry;\r
+\r
+  if (Xhc->ScratchBuf != NULL) {\r
+    ScratchEntry = Xhc->ScratchEntry;\r
+    for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
+      //\r
+      // Free Scratchpad Buffers\r
+      //\r
+      UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
+    }\r
+    //\r
+    // Free Scratchpad Buffer Array\r
+    //\r
+    UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
+    FreePool (Xhc->ScratchEntry);\r
+  }\r
+\r
+  if (Xhc->CmdRing.RingSeg0 != NULL) {\r
+    UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
+    Xhc->CmdRing.RingSeg0 = NULL;\r
+  }\r
+\r
+  XhcPeiFreeEventRing (Xhc,&Xhc->EventRing);\r
+\r
+  if (Xhc->DCBAA != NULL) {\r
+    UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));\r
+    Xhc->DCBAA = NULL;\r
+  }\r
+\r
+  //\r
+  // Free memory pool at last\r
+  //\r
+  if (Xhc->MemPool != NULL) {\r
+    UsbHcFreeMemPool (Xhc->MemPool);\r
+    Xhc->MemPool = NULL;\r
+  }\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
new file mode 100644 (file)
index 0000000..19672d0
--- /dev/null
@@ -0,0 +1,1228 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_PEI_XHCI_SCHED_H_\r
+#define _EFI_PEI_XHCI_SCHED_H_\r
+\r
+//\r
+// Transfer types, used in URB to identify the transfer type\r
+//\r
+#define XHC_CTRL_TRANSFER                       0x01\r
+#define XHC_BULK_TRANSFER                       0x02\r
+\r
+//\r
+// 6.4.6 TRB Types\r
+//\r
+#define TRB_TYPE_NORMAL                         1\r
+#define TRB_TYPE_SETUP_STAGE                    2\r
+#define TRB_TYPE_DATA_STAGE                     3\r
+#define TRB_TYPE_STATUS_STAGE                   4\r
+#define TRB_TYPE_ISOCH                          5\r
+#define TRB_TYPE_LINK                           6\r
+#define TRB_TYPE_EVENT_DATA                     7\r
+#define TRB_TYPE_NO_OP                          8\r
+#define TRB_TYPE_EN_SLOT                        9\r
+#define TRB_TYPE_DIS_SLOT                       10\r
+#define TRB_TYPE_ADDRESS_DEV                    11\r
+#define TRB_TYPE_CON_ENDPOINT                   12\r
+#define TRB_TYPE_EVALU_CONTXT                   13\r
+#define TRB_TYPE_RESET_ENDPOINT                 14\r
+#define TRB_TYPE_STOP_ENDPOINT                  15\r
+#define TRB_TYPE_SET_TR_DEQUE                   16\r
+#define TRB_TYPE_RESET_DEV                      17\r
+#define TRB_TYPE_GET_PORT_BANW                  21\r
+#define TRB_TYPE_FORCE_HEADER                   22\r
+#define TRB_TYPE_NO_OP_COMMAND                  23\r
+#define TRB_TYPE_TRANS_EVENT                    32\r
+#define TRB_TYPE_COMMAND_COMPLT_EVENT           33\r
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT       34\r
+#define TRB_TYPE_HOST_CONTROLLER_EVENT          37\r
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT            38\r
+#define TRB_TYPE_MFINDEX_WRAP_EVENT             39\r
+\r
+//\r
+// Endpoint Type (EP Type).\r
+//\r
+#define ED_NOT_VALID                            0\r
+#define ED_ISOCH_OUT                            1\r
+#define ED_BULK_OUT                             2\r
+#define ED_INTERRUPT_OUT                        3\r
+#define ED_CONTROL_BIDIR                        4\r
+#define ED_ISOCH_IN                             5\r
+#define ED_BULK_IN                              6\r
+#define ED_INTERRUPT_IN                         7\r
+\r
+//\r
+// 6.4.5 TRB Completion Codes\r
+//\r
+#define TRB_COMPLETION_INVALID                  0\r
+#define TRB_COMPLETION_SUCCESS                  1\r
+#define TRB_COMPLETION_DATA_BUFFER_ERROR        2\r
+#define TRB_COMPLETION_BABBLE_ERROR             3\r
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR    4\r
+#define TRB_COMPLETION_TRB_ERROR                5\r
+#define TRB_COMPLETION_STALL_ERROR              6\r
+#define TRB_COMPLETION_SHORT_PACKET             13\r
+\r
+//\r
+// The topology string used to present usb device location\r
+//\r
+typedef struct _USB_DEV_TOPOLOGY {\r
+  //\r
+  // The tier concatenation of down stream port.\r
+  //\r
+  UINT32 RouteString:20;\r
+  //\r
+  // The root port number of the chain.\r
+  //\r
+  UINT32 RootPortNum:8;\r
+  //\r
+  // The Tier the device reside.\r
+  //\r
+  UINT32 TierNum:4;\r
+} USB_DEV_TOPOLOGY;\r
+\r
+//\r
+// USB Device's RouteChart\r
+//\r
+typedef union _USB_DEV_ROUTE {\r
+  UINT32                    Dword;\r
+  USB_DEV_TOPOLOGY          Route;\r
+} USB_DEV_ROUTE;\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+  //\r
+  // Store logical device address assigned by UsbBus\r
+  // It's because some XHCI host controllers may assign the same physcial device\r
+  // address for those devices inserted at different root port.\r
+  //\r
+  UINT8                     BusAddr;\r
+  UINT8                     DevAddr;\r
+  UINT8                     EpAddr;\r
+  EFI_USB_DATA_DIRECTION    Direction;\r
+  UINT8                     DevSpeed;\r
+  UINTN                     MaxPacket;\r
+  UINTN                     Type;\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// TRB Template\r
+//\r
+typedef struct _TRB_TEMPLATE {\r
+  UINT32                    Parameter1;\r
+\r
+  UINT32                    Parameter2;\r
+\r
+  UINT32                    Status;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ1:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    Control:16;\r
+} TRB_TEMPLATE;\r
+\r
+typedef struct _TRANSFER_RING {\r
+  VOID                      *RingSeg0;\r
+  UINTN                     TrbNumber;\r
+  TRB_TEMPLATE              *RingEnqueue;\r
+  TRB_TEMPLATE              *RingDequeue;\r
+  UINT32                    RingPCS;\r
+} TRANSFER_RING;\r
+\r
+typedef struct _EVENT_RING {\r
+  VOID                      *ERSTBase;\r
+  VOID                      *EventRingSeg0;\r
+  UINTN                     TrbNumber;\r
+  TRB_TEMPLATE              *EventRingEnqueue;\r
+  TRB_TEMPLATE              *EventRingDequeue;\r
+  UINT32                    EventRingCCS;\r
+} EVENT_RING;\r
+\r
+#define XHC_URB_SIG                 SIGNATURE_32 ('U', 'S', 'B', 'R')\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of\r
+// usb requests.\r
+//\r
+typedef struct _URB {\r
+  UINT32                            Signature;\r
+  //\r
+  // Usb Device URB related information\r
+  //\r
+  USB_ENDPOINT                      Ep;\r
+  EFI_USB_DEVICE_REQUEST            *Request;\r
+  VOID                              *Data;\r
+  UINTN                             DataLen;\r
+  VOID                              *DataPhy;\r
+  EFI_ASYNC_USB_TRANSFER_CALLBACK   Callback;\r
+  VOID                              *Context;\r
+  //\r
+  // Execute result\r
+  //\r
+  UINT32                            Result;\r
+  //\r
+  // completed data length\r
+  //\r
+  UINTN                             Completed;\r
+  //\r
+  // Command/Tranfer Ring info\r
+  //\r
+  TRANSFER_RING                     *Ring;\r
+  TRB_TEMPLATE                      *TrbStart;\r
+  TRB_TEMPLATE                      *TrbEnd;\r
+  UINTN                             TrbNum;\r
+  BOOLEAN                           StartDone;\r
+  BOOLEAN                           EndDone;\r
+  BOOLEAN                           Finished;\r
+\r
+  TRB_TEMPLATE                      *EvtTrb;\r
+} URB;\r
+\r
+//\r
+// 6.5 Event Ring Segment Table\r
+// The Event Ring Segment Table is used to define multi-segment Event Rings and to enable runtime\r
+// expansion and shrinking of the Event Ring. The location of the Event Ring Segment Table is defined by the\r
+// Event Ring Segment Table Base Address Register (5.5.2.3.2). The size of the Event Ring Segment Table\r
+// is defined by the Event Ring Segment Table Base Size Register (5.5.2.3.1).\r
+//\r
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {\r
+  UINT32                    PtrLo;\r
+  UINT32                    PtrHi;\r
+  UINT32                    RingTrbSize:16;\r
+  UINT32                    RsvdZ1:16;\r
+  UINT32                    RsvdZ2;\r
+} EVENT_RING_SEG_TABLE_ENTRY;\r
+\r
+//\r
+// 6.4.1.1 Normal TRB\r
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and\r
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer\r
+// Rings, and to define the Data stage information for Control Transfer Rings.\r
+//\r
+typedef struct _TRANSFER_TRB_NORMAL {\r
+  UINT32                    TRBPtrLo;\r
+\r
+  UINT32                    TRBPtrHi;\r
+\r
+  UINT32                    Length:17;\r
+  UINT32                    TDSize:5;\r
+  UINT32                    IntTarget:10;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    ENT:1;\r
+  UINT32                    ISP:1;\r
+  UINT32                    NS:1;\r
+  UINT32                    CH:1;\r
+  UINT32                    IOC:1;\r
+  UINT32                    IDT:1;\r
+  UINT32                    RsvdZ1:2;\r
+  UINT32                    BEI:1;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ2:16;\r
+} TRANSFER_TRB_NORMAL;\r
+\r
+//\r
+// 6.4.1.2.1 Setup Stage TRB\r
+// A Setup Stage TRB is created by system software to initiate a USB Setup packet on a control endpoint.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_SETUP {\r
+  UINT32                    bmRequestType:8;\r
+  UINT32                    bRequest:8;\r
+  UINT32                    wValue:16;\r
+\r
+  UINT32                    wIndex:16;\r
+  UINT32                    wLength:16;\r
+\r
+  UINT32                    Length:17;\r
+  UINT32                    RsvdZ1:5;\r
+  UINT32                    IntTarget:10;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ2:4;\r
+  UINT32                    IOC:1;\r
+  UINT32                    IDT:1;\r
+  UINT32                    RsvdZ3:3;\r
+  UINT32                    Type:6;\r
+  UINT32                    TRT:2;\r
+  UINT32                    RsvdZ4:14;\r
+} TRANSFER_TRB_CONTROL_SETUP;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_DATA {\r
+  UINT32                    TRBPtrLo;\r
+\r
+  UINT32                    TRBPtrHi;\r
+\r
+  UINT32                    Length:17;\r
+  UINT32                    TDSize:5;\r
+  UINT32                    IntTarget:10;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    ENT:1;\r
+  UINT32                    ISP:1;\r
+  UINT32                    NS:1;\r
+  UINT32                    CH:1;\r
+  UINT32                    IOC:1;\r
+  UINT32                    IDT:1;\r
+  UINT32                    RsvdZ1:3;\r
+  UINT32                    Type:6;\r
+  UINT32                    DIR:1;\r
+  UINT32                    RsvdZ2:15;\r
+} TRANSFER_TRB_CONTROL_DATA;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_STATUS {\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    RsvdZ3:22;\r
+  UINT32                    IntTarget:10;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    ENT:1;\r
+  UINT32                    RsvdZ4:2;\r
+  UINT32                    CH:1;\r
+  UINT32                    IOC:1;\r
+  UINT32                    RsvdZ5:4;\r
+  UINT32                    Type:6;\r
+  UINT32                    DIR:1;\r
+  UINT32                    RsvdZ6:15;\r
+} TRANSFER_TRB_CONTROL_STATUS;\r
+\r
+//\r
+// 6.4.2.1 Transfer Event TRB\r
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1\r
+// for more information on the use and operation of Transfer Events.\r
+//\r
+typedef struct _EVT_TRB_TRANSFER {\r
+  UINT32                    TRBPtrLo;\r
+\r
+  UINT32                    TRBPtrHi;\r
+\r
+  UINT32                    Length:24;\r
+  UINT32                    Completecode:8;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ1:1;\r
+  UINT32                    ED:1;\r
+  UINT32                    RsvdZ2:7;\r
+  UINT32                    Type:6;\r
+  UINT32                    EndpointId:5;\r
+  UINT32                    RsvdZ3:3;\r
+  UINT32                    SlotId:8;\r
+} EVT_TRB_TRANSFER;\r
+\r
+//\r
+// 6.4.2.2 Command Completion Event TRB\r
+// A Command Completion Event TRB shall be generated by the xHC when a command completes on the\r
+// Command Ring. Refer to section 4.11.4 for more information on the use of Command Completion Events.\r
+//\r
+typedef struct _EVT_TRB_COMMAND_COMPLETION {\r
+  UINT32                    TRBPtrLo;\r
+\r
+  UINT32                    TRBPtrHi;\r
+\r
+  UINT32                    RsvdZ2:24;\r
+  UINT32                    Completecode:8;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    VFID:8;\r
+  UINT32                    SlotId:8;\r
+} EVT_TRB_COMMAND_COMPLETION;\r
+\r
+typedef union _TRB {\r
+  TRB_TEMPLATE                  TrbTemplate;\r
+  TRANSFER_TRB_NORMAL           TrbNormal;\r
+  TRANSFER_TRB_CONTROL_SETUP    TrbCtrSetup;\r
+  TRANSFER_TRB_CONTROL_DATA     TrbCtrData;\r
+  TRANSFER_TRB_CONTROL_STATUS   TrbCtrStatus;\r
+} TRB;\r
+\r
+//\r
+// 6.4.3.1 No Op Command TRB\r
+// The No Op Command TRB provides a simple means for verifying the operation of the Command Ring\r
+// mechanisms offered by the xHCI.\r
+//\r
+typedef struct _CMD_TRB_NO_OP {\r
+  UINT32                    RsvdZ0;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ4:16;\r
+} CMD_TRB_NO_OP;\r
+\r
+//\r
+// 6.4.3.2 Enable Slot Command TRB\r
+// The Enable Slot Command TRB causes the xHC to select an available Device Slot and return the ID of the\r
+// selected slot to the host in a Command Completion Event.\r
+//\r
+typedef struct _CMD_TRB_ENABLE_SLOT {\r
+  UINT32                    RsvdZ0;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ4:16;\r
+} CMD_TRB_ENABLE_SLOT;\r
+\r
+//\r
+// 6.4.3.3 Disable Slot Command TRB\r
+// The Disable Slot Command TRB releases any bandwidth assigned to the disabled slot and frees any\r
+// internal xHC resources assigned to the slot.\r
+//\r
+typedef struct _CMD_TRB_DISABLE_SLOT {\r
+  UINT32                    RsvdZ0;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ4:8;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_DISABLE_SLOT;\r
+\r
+//\r
+// 6.4.3.4 Address Device Command TRB\r
+// The Address Device Command TRB transitions the selected Device Context from the Default to the\r
+// Addressed state and causes the xHC to select an address for the USB device in the Default State and\r
+// issue a SET_ADDRESS request to the USB device.\r
+//\r
+typedef struct _CMD_TRB_ADDRESS_DEVICE {\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    RsvdZ1;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ2:8;\r
+  UINT32                    BSR:1;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ3:8;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_ADDRESS_DEVICE;\r
+\r
+//\r
+// 6.4.3.5 Configure Endpoint Command TRB\r
+// The Configure Endpoint Command TRB evaluates the bandwidth and resource requirements of the\r
+// endpoints selected by the command.\r
+//\r
+typedef struct _CMD_TRB_CONFIG_ENDPOINT {\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    RsvdZ1;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ2:8;\r
+  UINT32                    DC:1;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ3:8;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_CONFIG_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.6 Evaluate Context Command TRB\r
+// The Evaluate Context Command TRB is used by system software to inform the xHC that the selected\r
+// Context data structures in the Device Context have been modified by system software and that the xHC\r
+// shall evaluate any changes\r
+//\r
+typedef struct _CMD_TRB_EVALUATE_CONTEXT {\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    RsvdZ1;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ2:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ3:8;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_EVALUATE_CONTEXT;\r
+\r
+//\r
+// 6.4.3.7 Reset Endpoint Command TRB\r
+// The Reset Endpoint Command TRB is used by system software to reset a specified Transfer Ring\r
+//\r
+typedef struct _CMD_TRB_RESET_ENDPOINT {\r
+  UINT32                    RsvdZ0;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:8;\r
+  UINT32                    TSP:1;\r
+  UINT32                    Type:6;\r
+  UINT32                    EDID:5;\r
+  UINT32                    RsvdZ4:3;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_RESET_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.8 Stop Endpoint Command TRB\r
+// The Stop Endpoint Command TRB command allows software to stop the xHC execution of the TDs on a\r
+// Transfer Ring and temporarily take ownership of TDs that had previously been passed to the xHC.\r
+//\r
+typedef struct _CMD_TRB_STOP_ENDPOINT {\r
+  UINT32                    RsvdZ0;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ3:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    EDID:5;\r
+  UINT32                    RsvdZ4:2;\r
+  UINT32                    SP:1;\r
+  UINT32                    SlotId:8;\r
+} CMD_TRB_STOP_ENDPOINT;\r
+\r
+//\r
+// 6.4.3.9 Set TR Dequeue Pointer Command TRB\r
+// The Set TR Dequeue Pointer Command TRB is used by system software to modify the TR Dequeue\r
+// Pointer and DCS fields of an Endpoint or Stream Context.\r
+//\r
+typedef struct _CMD_SET_TR_DEQ_POINTER {\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    RsvdZ1:16;\r
+  UINT32                    StreamID:16;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ2:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    Endpoint:5;\r
+  UINT32                    RsvdZ3:3;\r
+  UINT32                    SlotId:8;\r
+} CMD_SET_TR_DEQ_POINTER;\r
+\r
+//\r
+// 6.4.4.1 Link TRB\r
+// A Link TRB provides support for non-contiguous TRB Rings.\r
+//\r
+typedef struct _LINK_TRB {\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    RsvdZ1:22;\r
+  UINT32                    InterTarget:10;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    TC:1;\r
+  UINT32                    RsvdZ2:2;\r
+  UINT32                    CH:1;\r
+  UINT32                    IOC:1;\r
+  UINT32                    RsvdZ3:4;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ4:16;\r
+} LINK_TRB;\r
+\r
+//\r
+// 6.2.2 Slot Context\r
+//\r
+typedef struct _SLOT_CONTEXT {\r
+  UINT32                    RouteString:20;\r
+  UINT32                    Speed:4;\r
+  UINT32                    RsvdZ1:1;\r
+  UINT32                    MTT:1;\r
+  UINT32                    Hub:1;\r
+  UINT32                    ContextEntries:5;\r
+\r
+  UINT32                    MaxExitLatency:16;\r
+  UINT32                    RootHubPortNum:8;\r
+  UINT32                    PortNum:8;\r
+\r
+  UINT32                    TTHubSlotId:8;\r
+  UINT32                    TTPortNum:8;\r
+  UINT32                    TTT:2;\r
+  UINT32                    RsvdZ2:4;\r
+  UINT32                    InterTarget:10;\r
+\r
+  UINT32                    DeviceAddress:8;\r
+  UINT32                    RsvdZ3:19;\r
+  UINT32                    SlotState:5;\r
+\r
+  UINT32                    RsvdZ4;\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+  UINT32                    RsvdZ7;\r
+} SLOT_CONTEXT;\r
+\r
+typedef struct _SLOT_CONTEXT_64 {\r
+  UINT32                    RouteString:20;\r
+  UINT32                    Speed:4;\r
+  UINT32                    RsvdZ1:1;\r
+  UINT32                    MTT:1;\r
+  UINT32                    Hub:1;\r
+  UINT32                    ContextEntries:5;\r
+\r
+  UINT32                    MaxExitLatency:16;\r
+  UINT32                    RootHubPortNum:8;\r
+  UINT32                    PortNum:8;\r
+\r
+  UINT32                    TTHubSlotId:8;\r
+  UINT32                    TTPortNum:8;\r
+  UINT32                    TTT:2;\r
+  UINT32                    RsvdZ2:4;\r
+  UINT32                    InterTarget:10;\r
+\r
+  UINT32                    DeviceAddress:8;\r
+  UINT32                    RsvdZ3:19;\r
+  UINT32                    SlotState:5;\r
+\r
+  UINT32                    RsvdZ4;\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+  UINT32                    RsvdZ7;\r
+\r
+  UINT32                    RsvdZ8;\r
+  UINT32                    RsvdZ9;\r
+  UINT32                    RsvdZ10;\r
+  UINT32                    RsvdZ11;\r
+\r
+  UINT32                    RsvdZ12;\r
+  UINT32                    RsvdZ13;\r
+  UINT32                    RsvdZ14;\r
+  UINT32                    RsvdZ15;\r
+\r
+} SLOT_CONTEXT_64;\r
+\r
+\r
+//\r
+// 6.2.3 Endpoint Context\r
+//\r
+typedef struct _ENDPOINT_CONTEXT {\r
+  UINT32                    EPState:3;\r
+  UINT32                    RsvdZ1:5;\r
+  UINT32                    Mult:2;\r
+  UINT32                    MaxPStreams:5;\r
+  UINT32                    LSA:1;\r
+  UINT32                    Interval:8;\r
+  UINT32                    RsvdZ2:8;\r
+\r
+  UINT32                    RsvdZ3:1;\r
+  UINT32                    CErr:2;\r
+  UINT32                    EPType:3;\r
+  UINT32                    RsvdZ4:1;\r
+  UINT32                    HID:1;\r
+  UINT32                    MaxBurstSize:8;\r
+  UINT32                    MaxPacketSize:16;\r
+\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    AverageTRBLength:16;\r
+  UINT32                    MaxESITPayload:16;\r
+\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+  UINT32                    RsvdZ7;\r
+} ENDPOINT_CONTEXT;\r
+\r
+typedef struct _ENDPOINT_CONTEXT_64 {\r
+  UINT32                    EPState:3;\r
+  UINT32                    RsvdZ1:5;\r
+  UINT32                    Mult:2;\r
+  UINT32                    MaxPStreams:5;\r
+  UINT32                    LSA:1;\r
+  UINT32                    Interval:8;\r
+  UINT32                    RsvdZ2:8;\r
+\r
+  UINT32                    RsvdZ3:1;\r
+  UINT32                    CErr:2;\r
+  UINT32                    EPType:3;\r
+  UINT32                    RsvdZ4:1;\r
+  UINT32                    HID:1;\r
+  UINT32                    MaxBurstSize:8;\r
+  UINT32                    MaxPacketSize:16;\r
+\r
+  UINT32                    PtrLo;\r
+\r
+  UINT32                    PtrHi;\r
+\r
+  UINT32                    AverageTRBLength:16;\r
+  UINT32                    MaxESITPayload:16;\r
+\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+  UINT32                    RsvdZ7;\r
+\r
+  UINT32                    RsvdZ8;\r
+  UINT32                    RsvdZ9;\r
+  UINT32                    RsvdZ10;\r
+  UINT32                    RsvdZ11;\r
+\r
+  UINT32                    RsvdZ12;\r
+  UINT32                    RsvdZ13;\r
+  UINT32                    RsvdZ14;\r
+  UINT32                    RsvdZ15;\r
+\r
+} ENDPOINT_CONTEXT_64;\r
+\r
+\r
+//\r
+// 6.2.5.1 Input Control Context\r
+//\r
+typedef struct _INPUT_CONTRL_CONTEXT {\r
+  UINT32                    Dword1;\r
+  UINT32                    Dword2;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+  UINT32                    RsvdZ3;\r
+  UINT32                    RsvdZ4;\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+} INPUT_CONTRL_CONTEXT;\r
+\r
+typedef struct _INPUT_CONTRL_CONTEXT_64 {\r
+  UINT32                    Dword1;\r
+  UINT32                    Dword2;\r
+  UINT32                    RsvdZ1;\r
+  UINT32                    RsvdZ2;\r
+  UINT32                    RsvdZ3;\r
+  UINT32                    RsvdZ4;\r
+  UINT32                    RsvdZ5;\r
+  UINT32                    RsvdZ6;\r
+  UINT32                    RsvdZ7;\r
+  UINT32                    RsvdZ8;\r
+  UINT32                    RsvdZ9;\r
+  UINT32                    RsvdZ10;\r
+  UINT32                    RsvdZ11;\r
+  UINT32                    RsvdZ12;\r
+  UINT32                    RsvdZ13;\r
+  UINT32                    RsvdZ14;\r
+} INPUT_CONTRL_CONTEXT_64;\r
+\r
+//\r
+// 6.2.1 Device Context\r
+//\r
+typedef struct _DEVICE_CONTEXT {\r
+  SLOT_CONTEXT              Slot;\r
+  ENDPOINT_CONTEXT          EP[31];\r
+} DEVICE_CONTEXT;\r
+\r
+typedef struct _DEVICE_CONTEXT_64 {\r
+  SLOT_CONTEXT_64           Slot;\r
+  ENDPOINT_CONTEXT_64       EP[31];\r
+} DEVICE_CONTEXT_64;\r
+\r
+//\r
+// 6.2.5 Input Context\r
+//\r
+typedef struct _INPUT_CONTEXT {\r
+  INPUT_CONTRL_CONTEXT      InputControlContext;\r
+  SLOT_CONTEXT              Slot;\r
+  ENDPOINT_CONTEXT          EP[31];\r
+} INPUT_CONTEXT;\r
+\r
+typedef struct _INPUT_CONTEXT_64 {\r
+  INPUT_CONTRL_CONTEXT_64   InputControlContext;\r
+  SLOT_CONTEXT_64           Slot;\r
+  ENDPOINT_CONTEXT_64       EP[31];\r
+} INPUT_CONTEXT_64;\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  CmdTransfer       The executed URB is for cmd transfer or not.\r
+  @param  Urb               The URB to execute.\r
+  @param  Timeout           The time to wait before abort, in millisecond.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiExecTransfer (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN BOOLEAN                CmdTransfer,\r
+  IN URB                    *Urb,\r
+  IN UINTN                  Timeout\r
+  );\r
+\r
+/**\r
+  Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  BusDevAddr    The requested device address by UsbBus upper driver.\r
+\r
+  @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiBusDevAddrToSlotId (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              BusDevAddr\r
+  );\r
+\r
+/**\r
+  Find out the slot id according to the device's route string.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  RouteString   The route string described the device location.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+XhcPeiRouteStringToSlotId (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN USB_DEV_ROUTE      RouteString\r
+  );\r
+\r
+/**\r
+  Calculate the device context index by endpoint address and direction.\r
+\r
+  @param  EpAddr        The target endpoint number.\r
+  @param  Direction     The direction of the target endpoint.\r
+\r
+  @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcPeiEndpointToDci (\r
+  IN UINT8                      EpAddr,\r
+  IN EFI_USB_DATA_DIRECTION     Direction\r
+  );\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+**/\r
+VOID\r
+XhcPeiRingDoorBell (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  );\r
+\r
+/**\r
+  Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  ParentRouteChart  The route string pointed to the parent device if it exists.\r
+  @param  Port              The port to be polled.\r
+  @param  PortState         The port state.\r
+\r
+  @retval EFI_SUCCESS       Successfully enable/disable device slot according to port state.\r
+  @retval Others            Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiPollPortStatusChange (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN USB_DEV_ROUTE          ParentRouteChart,\r
+  IN UINT8                  Port,\r
+  IN EFI_USB_PORT_STATUS    *PortState\r
+  );\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      PortNum,\r
+  IN UINT8                      TTT,\r
+  IN UINT8                      MTT\r
+  );\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiConfigHubContext64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      PortNum,\r
+  IN UINT8                      TTT,\r
+  IN UINT8                      MTT\r
+  );\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR      *ConfigDesc\r
+  );\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSetConfigCmd64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT8                      DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR      *ConfigDesc\r
+  );\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device.\r
+  @param  ParentPort            The port at which the device is located.\r
+  @param  RouteChart            The route string pointed to the device.\r
+  @param  DeviceSpeed           The device speed.\r
+\r
+  @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.\r
+  @retval Others                Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN USB_DEV_ROUTE              ParentRouteChart,\r
+  IN UINT16                     ParentPort,\r
+  IN USB_DEV_ROUTE              RouteChart,\r
+  IN UINT8                      DeviceSpeed\r
+  );\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device.\r
+  @param  ParentPort            The port at which the device is located.\r
+  @param  RouteChart            The route string pointed to the device.\r
+  @param  DeviceSpeed           The device speed.\r
+\r
+  @retval EFI_SUCCESS           Successfully assign a slot to the device and assign an address to it.\r
+  @retval Others                Fail to initialize device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiInitializeDeviceSlot64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN USB_DEV_ROUTE              ParentRouteChart,\r
+  IN UINT16                     ParentPort,\r
+  IN USB_DEV_ROUTE              RouteChart,\r
+  IN UINT8                      DeviceSpeed\r
+  );\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT32                     MaxPacketSize\r
+  );\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiEvaluateContext64 (\r
+  IN PEI_XHC_DEV                *Xhc,\r
+  IN UINT8                      SlotId,\r
+  IN UINT32                     MaxPacketSize\r
+  );\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd (\r
+  IN PEI_XHC_DEV              *Xhc,\r
+  IN UINT8                    SlotId\r
+  );\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDisableSlotCmd64 (\r
+  IN PEI_XHC_DEV              *Xhc,\r
+  IN UINT8                    SlotId\r
+  );\r
+\r
+/**\r
+  System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+  condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+  Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+  reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+  Stopped to the Running state.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Urb           The urb which makes the endpoint halted.\r
+\r
+  @retval EFI_SUCCESS   The recovery is successful.\r
+  @retval Others        Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiRecoverHaltedEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN URB                *Urb\r
+  );\r
+\r
+/**\r
+  Create a new URB for a new transaction.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  DevAddr   The device address\r
+  @param  EpAddr    Endpoint addrress\r
+  @param  DevSpeed  The device speed\r
+  @param  MaxPacket The max packet length of the endpoint\r
+  @param  Type      The transaction type\r
+  @param  Request   The standard USB request for control transfer\r
+  @param  Data      The user data to transfer\r
+  @param  DataLen   The length of data buffer\r
+  @param  Callback  The function to call when data is transferred\r
+  @param  Context   The context to the callback\r
+\r
+  @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcPeiCreateUrb (\r
+  IN PEI_XHC_DEV                        *Xhc,\r
+  IN UINT8                              DevAddr,\r
+  IN UINT8                              EpAddr,\r
+  IN UINT8                              DevSpeed,\r
+  IN UINTN                              MaxPacket,\r
+  IN UINTN                              Type,\r
+  IN EFI_USB_DEVICE_REQUEST             *Request,\r
+  IN VOID                               *Data,\r
+  IN UINTN                              DataLen,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,\r
+  IN VOID                               *Context\r
+  );\r
+\r
+/**\r
+  Free an allocated URB.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  Urb       The URB to free.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeUrb (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN URB            *Urb\r
+  );\r
+\r
+/**\r
+  Create a transfer TRB.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  Urb       The urb used to construct the transfer TRB.\r
+\r
+  @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCreateTransferTrb (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN URB            *Urb\r
+  );\r
+\r
+/**\r
+  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  TrsRing   The transfer ring to sync.\r
+\r
+  @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncTrsRing (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN TRANSFER_RING  *TrsRing\r
+  );\r
+\r
+/**\r
+  Create XHCI transfer ring.\r
+\r
+  @param  Xhc               The XHCI Device.\r
+  @param  TrbNum            The number of TRB in the ring.\r
+  @param  TransferRing      The created transfer ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateTransferRing (\r
+  IN PEI_XHC_DEV            *Xhc,\r
+  IN UINTN                  TrbNum,\r
+  OUT TRANSFER_RING         *TransferRing\r
+  );\r
+\r
+/**\r
+  Check if there is a new generated event.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EvtRing       The event ring to check.\r
+  @param  NewEvtTrb     The new event TRB found.\r
+\r
+  @retval EFI_SUCCESS   Found a new event TRB at the event ring.\r
+  @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiCheckNewEvent (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN EVENT_RING         *EvtRing,\r
+  OUT TRB_TEMPLATE      **NewEvtTrb\r
+  );\r
+\r
+/**\r
+  Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  EvtRing   The event ring to sync.\r
+\r
+  @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiSyncEventRing (\r
+  IN PEI_XHC_DEV    *Xhc,\r
+  IN EVENT_RING     *EvtRing\r
+  );\r
+\r
+/**\r
+  Create XHCI event ring.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EventRing     The created event ring.\r
+\r
+**/\r
+VOID\r
+XhcPeiCreateEventRing (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  OUT EVENT_RING        *EventRing\r
+  );\r
+\r
+/**\r
+  Initialize the XHCI host controller for schedule.\r
+\r
+  @param  Xhc       The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcPeiInitSched (\r
+  IN PEI_XHC_DEV        *Xhc\r
+  );\r
+\r
+/**\r
+  Free the resouce allocated at initializing schedule.\r
+\r
+  @param  Xhc       The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcPeiFreeSched (\r
+  IN PEI_XHC_DEV    *Xhc\r
+  );\r
+\r
+#endif\r
index 5b7ebfa..16a7b58 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Usb Hub Request Support In PEI Phase\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
   \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -319,6 +319,139 @@ PeiGetHubDescriptor (
                       );\r
 }\r
 \r
+/**\r
+  Get a given SuperSpeed hub descriptor.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if\r
+                            successfully returned.\r
+\r
+  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetSuperSpeedHubDesc (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_USB_IO_PPI            *UsbIoPpi,\r
+  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST        DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DevReq.RequestType = USB_RT_HUB | 0x80;\r
+  DevReq.Request     = USB_HUB_GET_DESCRIPTOR;\r
+  DevReq.Value       = USB_DT_SUPERSPEED_HUB << 8;\r
+  DevReq.Length      = 12;\r
+\r
+  return  UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DevReq,\r
+                      EfiUsbDataIn,\r
+                      PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                      HubDescriptor,\r
+                      12\r
+                      );\r
+}\r
+\r
+/**\r
+  Read the whole usb hub descriptor. It is necessary\r
+  to do it in two steps because hub descriptor is of\r
+  variable length.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice      Indicates the hub controller device.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if\r
+                            successfully returned.\r
+\r
+  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubReadDesc (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN PEI_USB_DEVICE             *PeiUsbDevice,\r
+  IN PEI_USB_IO_PPI             *UsbIoPpi,\r
+  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    //\r
+    // Get the super speed hub descriptor\r
+    //\r
+    Status = PeiGetSuperSpeedHubDesc (PeiServices, UsbIoPpi, HubDescriptor);\r
+  } else {\r
+\r
+    //\r
+    // First get the hub descriptor length\r
+    //\r
+    Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, 2, HubDescriptor);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get the whole hub descriptor\r
+    //\r
+    Status = PeiGetHubDescriptor (PeiServices, UsbIoPpi, HubDescriptor->Length, HubDescriptor);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  USB hub control transfer to set the hub depth.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice      Indicates the hub controller device.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       Depth of the hub is set.\r
+  @retval Others            Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubCtrlSetHubDepth (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN PEI_USB_DEVICE             *PeiUsbDevice,\r
+  IN PEI_USB_IO_PPI             *UsbIoPpi\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST        DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DevReq.RequestType = USB_RT_HUB;\r
+  DevReq.Request     = USB_HUB_REQ_SET_DEPTH;\r
+  DevReq.Value       = PeiUsbDevice->Tier;\r
+  DevReq.Length      = 0;\r
+\r
+  return  UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DevReq,\r
+                      EfiUsbNoData,\r
+                      PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                      NULL,\r
+                      0\r
+                      );\r
+}\r
+\r
 /**\r
   Configure a given hub.\r
 \r
@@ -339,32 +472,18 @@ PeiDoHubConfig (
   EFI_STATUS              Status;\r
   EFI_USB_HUB_STATUS      HubStatus;\r
   UINTN                   Index;\r
-  UINT32                  PortStatus;\r
   PEI_USB_IO_PPI          *UsbIoPpi;\r
 \r
   ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
   UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
 \r
   //\r
-  // First get the hub descriptor length\r
-  //\r
-  Status = PeiGetHubDescriptor (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            2,\r
-            &HubDescriptor\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-  //\r
-  // First get the whole descriptor, then\r
-  // get the number of hub ports\r
+  // Get the hub descriptor \r
   //\r
-  Status = PeiGetHubDescriptor (\r
+  Status = PeiUsbHubReadDesc (\r
             PeiServices,\r
+            PeiUsbDevice,\r
             UsbIoPpi,\r
-            HubDescriptor.Length,\r
             &HubDescriptor\r
             );\r
   if (EFI_ERROR (Status)) {\r
@@ -373,74 +492,66 @@ PeiDoHubConfig (
 \r
   PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
 \r
-  Status = PeiHubGetHubStatus (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (UINT32 *) &HubStatus\r
-            );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-  //\r
-  //  Get all hub ports status\r
-  //\r
-  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-\r
-    Status = PeiHubGetPortStatus (\r
-              PeiServices,\r
-              UsbIoPpi,\r
-              (UINT8) (Index + 1),\r
-              &PortStatus\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-  }\r
-  //\r
-  //  Power all the hub ports\r
-  //\r
-  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-    Status = PeiHubSetPortFeature (\r
-              PeiServices,\r
-              UsbIoPpi,\r
-              (UINT8) (Index + 1),\r
-              EfiUsbPortPower\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-  }\r
-  //\r
-  // Clear Hub Status Change\r
-  //\r
-  Status = PeiHubGetHubStatus (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (UINT32 *) &HubStatus\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+  if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));\r
+    PeiUsbHubCtrlSetHubDepth (\r
+      PeiServices,\r
+      PeiUsbDevice,\r
+      UsbIoPpi\r
+      );\r
   } else {\r
     //\r
-    // Hub power supply change happens\r
+    //  Power all the hub ports\r
     //\r
-    if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
-      PeiHubClearHubFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        C_HUB_LOCAL_POWER\r
-        );\r
+    for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+      Status = PeiHubSetPortFeature (\r
+                PeiServices,\r
+                UsbIoPpi,\r
+                (UINT8) (Index + 1),\r
+                EfiUsbPortPower\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));\r
+        continue;\r
+      }\r
     }\r
+\r
+    DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor.PwrOn2PwrGood));\r
+    if (HubDescriptor.PwrOn2PwrGood > 0) {\r
+      MicroSecondDelay (HubDescriptor.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
+    }\r
+\r
     //\r
-    // Hub change overcurrent happens\r
+    // Clear Hub Status Change\r
     //\r
-    if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
-      PeiHubClearHubFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        C_HUB_OVER_CURRENT\r
-        );\r
+    Status = PeiHubGetHubStatus (\r
+              PeiServices,\r
+              UsbIoPpi,\r
+              (UINT32 *) &HubStatus\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    } else {\r
+      //\r
+      // Hub power supply change happens\r
+      //\r
+      if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+        PeiHubClearHubFeature (\r
+          PeiServices,\r
+          UsbIoPpi,\r
+          C_HUB_LOCAL_POWER\r
+          );\r
+      }\r
+      //\r
+      // Hub change overcurrent happens\r
+      //\r
+      if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+        PeiHubClearHubFeature (\r
+          PeiServices,\r
+          UsbIoPpi,\r
+          C_HUB_OVER_CURRENT\r
+          );\r
+      }\r
     }\r
   }\r
 \r
@@ -462,10 +573,10 @@ PeiResetHubPort (
   IN UINT8               PortNum\r
   )\r
 {\r
-  UINT8               Try;\r
+  EFI_STATUS          Status;\r
+  UINTN               Index;\r
   EFI_USB_PORT_STATUS HubPortStatus;\r
 \r
-\r
   MicroSecondDelay (100 * 1000);\r
 \r
   //\r
@@ -478,27 +589,49 @@ PeiResetHubPort (
     EfiUsbPortReset\r
     );\r
 \r
-  Try = 10;\r
-  do {\r
-    PeiHubGetPortStatus (\r
-      PeiServices,\r
-      UsbIoPpi,\r
-      PortNum,\r
-      (UINT32 *) &HubPortStatus\r
-      );\r
+  //\r
+  // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
+  // section 7.1.7.5 for timing requirements.\r
+  //\r
+  MicroSecondDelay (USB_SET_PORT_RESET_STALL);\r
 \r
-    MicroSecondDelay (2 * 1000);\r
-    Try -= 1;\r
-  } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+  //\r
+  // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
+  //\r
+  ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+  for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+    Status = PeiHubGetPortStatus (\r
+               PeiServices,\r
+               UsbIoPpi,\r
+               PortNum,\r
+               (UINT32 *) &HubPortStatus\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return;\r
+    }\r
+\r
+    if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+      break;\r
+    }\r
+\r
+    MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+  }\r
+\r
+  if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+    DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));\r
+    return;\r
+  }\r
 \r
   //\r
-  // clear reset root port\r
+  // clear reset change root port\r
   //\r
   PeiHubClearPortFeature (\r
     PeiServices,\r
     UsbIoPpi,\r
     PortNum,\r
-    EfiUsbPortReset\r
+    EfiUsbPortResetChange\r
     );\r
 \r
   MicroSecondDelay (1 * 1000);\r
index 273a26c..f50bc63 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Constants definitions for Usb Hub Peim\r
 \r
-Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
   \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -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)\r
 #define USB_RT_PORT       (USB_TYPE_CLASS | USB_RECIP_OTHER)\r
 \r
+#define USB_HUB_REQ_SET_DEPTH               12\r
+\r
 #define MAXBYTES  8\r
 #pragma pack(1)\r
 //\r
index 6fef61e..42be13a 100644 (file)
@@ -221,26 +221,24 @@ IsPortConnect (
 }\r
 \r
 /**\r
-  Judge if the port is connected with a low-speed usb device or not.\r
+  Get device speed according to port status.\r
 \r
-  @param  PortStatus  The usb port status gotten.\r
+  @param    PortStatus  The usb port status gotten.\r
 \r
-  @retval TRUE        A low-speed usb device is connected with the port.\r
-  @retval FALSE       No low-speed usb device is connected with the port.\r
+  @return   Device speed value.\r
 \r
 **/\r
 UINTN\r
-IsPortLowSpeedDeviceAttached (\r
-  IN UINT16  PortStatus\r
+PeiUsbGetDeviceSpeed (\r
+  IN UINT16 PortStatus\r
   )\r
 {\r
-  //\r
-  // return the bit 9 value of PortStatus\r
-  //\r
   if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
     return EFI_USB_SPEED_LOW;\r
   } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){\r
     return EFI_USB_SPEED_HIGH;\r
+  } else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
+    return EFI_USB_SPEED_SUPER;\r
   } else {\r
     return EFI_USB_SPEED_FULL;\r
   }\r
index e0557f8..1ace89f 100644 (file)
@@ -70,6 +70,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define USB_DT_INTERFACE  0x04\r
 #define USB_DT_ENDPOINT   0x05\r
 #define USB_DT_HUB        0x29\r
+#define USB_DT_SUPERSPEED_HUB 0x2A\r
 #define USB_DT_HID        0x21\r
 \r
 //\r
@@ -202,17 +203,16 @@ IsPortConnect (
   );\r
 \r
 /**\r
-  Judge if the port is connected with a low-speed usb device or not.\r
+  Get device speed according to port status.\r
 \r
-  @param  PortStatus  The usb port status gotten.\r
+  @param    PortStatus  The usb port status gotten.\r
 \r
-  @retval TRUE        A low-speed usb device is connected with the port.\r
-  @retval FALSE       No low-speed usb device is connected with the port.\r
+  @return   Device speed value.\r
 \r
 **/\r
 UINTN\r
-IsPortLowSpeedDeviceAttached (\r
-  IN UINT16  PortStatus\r
+PeiUsbGetDeviceSpeed (\r
+  IN UINT16 PortStatus\r
   );\r
 \r
 /**\r
index 492f124..d13a7ee 100644 (file)
@@ -105,7 +105,7 @@ PeiUsbControlTransfer (
                         PeiUsbDev->UsbHcPpi,\r
                         PeiUsbDev->DeviceAddress,\r
                         PeiUsbDev->DeviceSpeed,\r
-                        PeiUsbDev->MaxPacketSize0,\r
+                        (UINT8) PeiUsbDev->MaxPacketSize0,\r
                         Request,\r
                         Direction,\r
                         Data,\r
@@ -126,6 +126,7 @@ PeiUsbControlTransfer (
     }\r
   }\r
 \r
+  DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));\r
   return Status;\r
 }\r
 \r
@@ -238,6 +239,7 @@ PeiUsbBulkTransfer (
     PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
   }\r
 \r
+  DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));\r
   return Status;\r
 }\r
 \r
index 23090f6..947864b 100644 (file)
@@ -228,6 +228,8 @@ PeiHubEnumeration (
 \r
   UsbIoPpi    = &PeiUsbDevice->UsbIoPpi;\r
 \r
+  DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));\r
+\r
   for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
 \r
     Status = PeiHubGetPortStatus (\r
@@ -241,25 +243,14 @@ PeiHubEnumeration (
       continue;\r
     }\r
 \r
-    if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
-      PeiHubClearPortFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        (UINT8) (Index + 1),\r
-        EfiUsbPortConnectChange\r
-        );\r
-\r
-      MicroSecondDelay (100 * 1000);\r
-\r
+    DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+    //\r
+    // Only handle connection/enable/overcurrent/reset change.\r
+    //\r
+    if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+      continue;\r
+    } else {\r
       if (IsPortConnect (PortStatus.PortStatus)) {\r
-\r
-        PeiHubGetPortStatus (\r
-          PeiServices,\r
-          UsbIoPpi,\r
-          (UINT8) (Index + 1),\r
-          (UINT32 *) &PortStatus\r
-          );\r
-\r
         //\r
         // Begin to deal with the new device\r
         //\r
@@ -294,19 +285,44 @@ PeiHubEnumeration (
         NewPeiUsbDevice->AllocateAddress  = (UINTN) AllocateAddress;\r
         NewPeiUsbDevice->UsbHcPpi         = PeiUsbDevice->UsbHcPpi;\r
         NewPeiUsbDevice->Usb2HcPpi        = PeiUsbDevice->Usb2HcPpi;\r
+        NewPeiUsbDevice->Tier             = (UINT8) (PeiUsbDevice->Tier + 1);\r
         NewPeiUsbDevice->IsHub            = 0x0;\r
         NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
 \r
-        PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+        if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || \r
+             ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {\r
+          //\r
+          // If the port already has reset change flag and is connected and enabled, skip the port reset logic. \r
+          //\r
+          PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+  \r
+          PeiHubGetPortStatus (\r
+             PeiServices,\r
+             UsbIoPpi,\r
+             (UINT8) (Index + 1),\r
+             (UINT32 *) &PortStatus\r
+             );\r
+        } else {\r
+          PeiHubClearPortFeature (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            (UINT8) (Index + 1),\r
+            EfiUsbPortResetChange\r
+            );\r
+        }<