From d987459f8e0b78831c95188b5b0d712ed6a54c88 Mon Sep 17 00:00:00 2001
From: Star Zeng <star.zeng@intel.com>
Date: Wed, 2 Jul 2014 03:20:49 +0000
Subject: [PATCH] MdeModulePkg XhciPei/UsbBusPei: Add XHCI recovery support.

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

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15611 6f19259b-4bc3-4df7-8a09-765794883524
---
 MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c    |  662 +++++
 MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h    |  142 +
 MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c     | 1513 +++++++++++
 MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h     |  240 ++
 MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf   |   59 +
 MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h     |  471 ++++
 MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c   | 2761 ++++++++++++++++++++
 MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h   | 1228 +++++++++
 MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c   |  325 ++-
 MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h   |    4 +-
 MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c |   16 +-
 MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h |   12 +-
 MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c |    4 +-
 MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c   |  308 ++-
 MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h   |   48 +-
 MdeModulePkg/Include/Ppi/UsbController.h   |    8 +-
 MdeModulePkg/MdeModulePkg.dsc              |    1 +
 17 files changed, 7576 insertions(+), 226 deletions(-)
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhciReg.h
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
 create mode 100644 MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h

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