]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add DebugCommunicationLibUsb3 for USB3.0 source level debug support.
authorElvin Li <elvin.li@intel.com>
Wed, 22 Oct 2014 05:01:58 +0000 (05:01 +0000)
committerli-elvin <li-elvin@Edk2>
Wed, 22 Oct 2014 05:01:58 +0000 (05:01 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Elvin Li <elvin.li@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16224 6f19259b-4bc3-4df7-8a09-765794883524

SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni [new file with mode: 0644]
SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c [new file with mode: 0644]
SourceLevelDebugPkg/SourceLevelDebugPkg.dec
SourceLevelDebugPkg/SourceLevelDebugPkg.dsc

diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
new file mode 100644 (file)
index 0000000..fe6aec1
--- /dev/null
@@ -0,0 +1,1236 @@
+/** @file\r
+  Debug Port Library implementation based on usb3 debug port.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DebugCommunicationLibUsb3Internal.h"\r
+\r
+//\r
+// The global variable which can be used after memory is ready.\r
+//\r
+USB3_DEBUG_PORT_HANDLE     mDebugCommunicationLibUsb3DebugPortHandle;\r
+\r
+UINT16   mString0Desc[] = {\r
+  //  String Descriptor Type + Length\r
+  ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,\r
+  0x0409\r
+};\r
+\r
+UINT16   mManufacturerStrDesc[] = {\r
+  //  String Descriptor Type + Length\r
+  ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,\r
+  'I', 'n', 't', 'e', 'l'\r
+};\r
+\r
+UINT16   mProductStrDesc[] = {\r
+  //  String Descriptor Type + Length\r
+  ( USB_DESC_TYPE_STRING << 8 ) +  PRODUCT_DESC_LEN,\r
+  'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'\r
+};\r
+\r
+UINT16   mSerialNumberStrDesc[] = {\r
+  //  String Descriptor Type + Length\r
+  ( USB_DESC_TYPE_STRING << 8 ) +  SERIAL_DESC_LEN,\r
+  '1'\r
+};\r
+\r
+/**\r
+  Sets bits as per the enabled bit positions in the mask.\r
+\r
+  @param[in, out] Register    UINTN register\r
+  @param[in]      BitMask     32-bit mask\r
+**/\r
+VOID\r
+XhcSetR32Bit(\r
+  IN OUT  UINTN  Register, \r
+  IN      UINT32 BitMask\r
+  )\r
+{\r
+  UINT32    RegisterValue;\r
+\r
+  RegisterValue = MmioRead32 (Register);\r
+  RegisterValue |= (UINT32)(BitMask);\r
+  MmioWrite32 (Register, RegisterValue);\r
+}\r
+\r
+/**\r
+  Clears bits as per the enabled bit positions in the mask.\r
+\r
+  @param[in, out] Register    UINTN register\r
+  @param[in]      BitMask     32-bit mask\r
+**/\r
+VOID\r
+XhcClearR32Bit(\r
+  IN OUT  UINTN  Register, \r
+  IN      UINT32 BitMask\r
+  )\r
+{\r
+  UINT32    RegisterValue;\r
+\r
+  RegisterValue = MmioRead32 (Register);\r
+  RegisterValue &= ~BitMask;\r
+  MmioWrite32 (Register, RegisterValue);\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI debug register.\r
+\r
+  @param  Handle       Debug port handle.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteDebugReg (\r
+  IN USB3_DEBUG_PORT_HANDLE  *Handle,\r
+  IN UINT32                   Offset,\r
+  IN UINT32                   Data\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  DebugCapabilityBase;\r
+  \r
+  DebugCapabilityBase = Handle->DebugCapabilityBase;\r
+  MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);\r
+  \r
+  return;\r
+}\r
+\r
+/**\r
+  Read XHCI debug register.\r
+\r
+  @param  Handle       Debug port handle.\r
+  @param  Offset       The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadDebugReg (\r
+  IN  USB3_DEBUG_PORT_HANDLE *Handle,\r
+  IN  UINT32                   Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_PHYSICAL_ADDRESS    DebugCapabilityBase;\r
+  \r
+  DebugCapabilityBase = Handle->DebugCapabilityBase;\r
+  Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Set one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Handle       Debug port handle.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetDebugRegBit (\r
+  IN USB3_DEBUG_PORT_HANDLE *Handle,\r
+  IN UINT32                   Offset,\r
+  IN UINT32                   Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = XhcReadDebugReg (Handle, Offset);\r
+  Data |= Bit;\r
+  XhcWriteDebugReg (Handle, Offset, Data);\r
+}\r
+\r
+/**\r
+  Program and eanble XHCI MMIO base address.\r
+\r
+  @return XHCI MMIO base address.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+ProgramXhciBaseAddress (\r
+  VOID\r
+  )\r
+{\r
+  UINT16                      PciCmd;\r
+  UINT32                      Low;\r
+  UINT32                      High;\r
+  EFI_PHYSICAL_ADDRESS        XhciMmioBase;\r
+  \r
+  Low = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);\r
+  High = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);\r
+  XhciMmioBase = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);\r
+  XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;\r
+\r
+  if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {\r
+    XhciMmioBase = PcdGet64(PcdUsbXhciMemorySpaceBase);\r
+    PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);\r
+    PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));\r
+  }\r
+\r
+  PciCmd = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);\r
+  if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {\r
+    PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;\r
+    PciWrite16(PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);\r
+  }\r
+\r
+  return XhciMmioBase;\r
+}\r
+\r
+/**\r
+  Check if the timer is timeout.\r
+  \r
+  @param[in] UsbDebugPortHandle  Pointer to USB Debug port handle\r
+  @param[in] Timer               The start timer from the begin.\r
+  @param[in] TimeoutTicker       Ticker number need time out.\r
+\r
+  @return TRUE  Timer time out occurs.\r
+  @retval FALSE Timer does not time out.\r
+\r
+**/\r
+BOOLEAN\r
+IsTimerTimeout (\r
+  IN USB3_DEBUG_PORT_HANDLE  *UsbDebugPortHandle,\r
+  IN UINT64                  Timer,\r
+  IN UINT64                  TimeoutTicker\r
+  )\r
+{\r
+  UINT64  CurrentTimer;\r
+  UINT64  Delta;\r
+\r
+  CurrentTimer = GetPerformanceCounter ();\r
+\r
+  if (UsbDebugPortHandle->TimerCountDown) {\r
+    //\r
+    // The timer counter counts down.  Check for roll over condition.\r
+    //\r
+    if (CurrentTimer < Timer) {\r
+      Delta = Timer - CurrentTimer;\r
+    } else {\r
+      //\r
+      // Handle one roll-over. \r
+      //\r
+      Delta = UsbDebugPortHandle->TimerCycle - (CurrentTimer - Timer);\r
+    }\r
+  } else {\r
+    //\r
+    // The timer counter counts up.  Check for roll over condition.\r
+    //\r
+    if (CurrentTimer > Timer) {\r
+      Delta = CurrentTimer - Timer;\r
+    } else {\r
+      //\r
+      // Handle one roll-over. \r
+      //\r
+      Delta = UsbDebugPortHandle->TimerCycle - (Timer - CurrentTimer);\r
+    }\r
+  }\r
\r
+  return (BOOLEAN) (Delta >= TimeoutTicker);\r
+}\r
+\r
+/**\r
+  Update XHC MMIO base address when MMIO base address is changed.\r
+\r
+  @param  Handle          Debug port handle.\r
+  @param  XhciMmioBase    XHCI MMIO base address.\r
+\r
+**/\r
+VOID\r
+UpdateXhcResource (\r
+  IN OUT USB3_DEBUG_PORT_HANDLE            *Handle,\r
+  IN EFI_PHYSICAL_ADDRESS                   XhciMmioBase\r
+  )\r
+{\r
+  if ((Handle == NULL) || (Handle->XhciMmioBase == XhciMmioBase)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Need fix Handle data according to new XHCI MMIO base address.\r
+  //\r
+  Handle->XhciMmioBase        = XhciMmioBase;\r
+  Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;\r
+  Handle->XhciOpRegister      = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);\r
+}\r
+\r
+/**\r
+  Calculate the usb debug port bar address.\r
+\r
+  @param  Handle             Debug port handle.\r
+\r
+  @retval RETURN_UNSUPPORTED The usb host controller does not supported usb debug port capability.\r
+  @retval RETURN_SUCCESS     Get bar and offset successfully.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+CalculateUsbDebugPortMmioBase (\r
+  USB3_DEBUG_PORT_HANDLE          *Handle\r
+ )\r
+{\r
+  UINT16                          VendorId;\r
+  UINT16                          DeviceId;\r
+  UINT8                           ProgInterface;\r
+  UINT8                           SubClassCode;\r
+  UINT8                           BaseCode;\r
+  BOOLEAN                         Flag;\r
+  UINT32                          Capability;\r
+  EFI_PHYSICAL_ADDRESS            CapabilityPointer;\r
+  UINT8                           CapLength;\r
+\r
+  VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);\r
+  DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);\r
+  \r
+  if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {\r
+    goto Done;\r
+  }\r
+\r
+  ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);\r
+  SubClassCode  = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);\r
+  BaseCode      = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);\r
+  \r
+  if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {\r
+    goto Done;\r
+  }\r
+\r
+  CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);\r
+\r
+  //\r
+  // Get capability pointer from HCCPARAMS at offset 0x10\r
+  //\r
+  CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;\r
\r
+  //\r
+  // Search XHCI debug capability\r
+  //\r
+  Flag = FALSE;\r
+  Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
+  while (TRUE) {\r
+    if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {\r
+      Flag = TRUE;\r
+      break;\r
+    }\r
+    if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {\r
+      //\r
+      // Reach the end of capability list, quit\r
+      //\r
+      break;\r
+    }\r
+    CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;\r
+    Capability = MmioRead32 ((UINTN)CapabilityPointer);\r
+  }\r
+\r
+  if (!Flag) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // USB3 debug capability is supported.\r
+  //\r
+  Handle->DebugCapabilityBase   = CapabilityPointer;\r
+  Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;\r
+  Handle->XhciOpRegister        = Handle->XhciMmioBase + CapLength;\r
+  Handle->Initialized = USB3DBG_DBG_CAB;\r
+  return RETURN_SUCCESS;\r
+\r
+Done:\r
+  Handle->Initialized = USB3DBG_NO_DBG_CAB;\r
+  return RETURN_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Check if it needs to re-initialize usb debug port hardware.\r
+\r
+  During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check\r
+  whether the usb debug port hardware configuration is changed. Such case can be triggerred by\r
+  Pci bus resource allocation and so on.\r
+\r
+  @param  Handle           Debug port handle.\r
+\r
+  @retval TRUE             The usb debug port hardware configuration is changed.\r
+  @retval FALSE            The usb debug port hardware configuration is not changed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+NeedReinitializeHardware(\r
+  IN USB3_DEBUG_PORT_HANDLE *Handle\r
+  )\r
+{\r
+  BOOLEAN                 Result;\r
+  volatile UINT32         Dcctrl;\r
+\r
+  Result = FALSE;\r
+\r
+  //\r
+  // If DCE bit, it means USB3 debug is not enabled.\r
+  //\r
+  Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
+  if ((Dcctrl & BIT0) == 0) {\r
+    Result = TRUE;\r
+  }\r
+\r
+  return Result;\r
+}\r
+\r
+/**\r
+  Create XHCI event ring.\r
+\r
+  @param  Handle              Debug port handle.\r
+  @param  EventRing           The created event ring.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateEventRing (\r
+  IN  USB3_DEBUG_PORT_HANDLE     *Handle,\r
+  OUT EVENT_RING                 *EventRing\r
+  )\r
+{\r
+  VOID                        *Buf;\r
+  EVENT_RING_SEG_TABLE_ENTRY  *ERSTBase;\r
+\r
+  ASSERT (EventRing != NULL);\r
+  \r
+  //\r
+  // Allocate Event Ring\r
+  //\r
+  Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+  ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
+\r
+  EventRing->EventRingSeg0    = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
+  EventRing->TrbNumber        = EVENT_RING_TRB_NUMBER;\r
+  EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
+  EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;\r
+  \r
+  //\r
+  // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
+  // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
+  //\r
+  EventRing->EventRingCCS = 1;\r
+\r
+  //\r
+  // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table\r
+  //\r
+  Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+  ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
+\r
+  ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
+  EventRing->ERSTBase   = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;\r
+\r
+  //\r
+  // Fill Event Segment address\r
+  //\r
+  ERSTBase->PtrLo       = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
+  ERSTBase->PtrHi       = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
+  ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
+\r
+  //\r
+  // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)\r
+  //\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCERDP,\r
+    XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
+    );\r
+\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCERDP + 4,\r
+    XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)\r
+    );\r
+\r
+  //\r
+  // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)\r
+  //\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCERSTBA,\r
+    XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)\r
+    );\r
+\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCERSTBA + 4,\r
+    XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)\r
+    );\r
+\r
+  //\r
+  // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)\r
+  //\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCERSTSZ,\r
+    ERST_NUMBER\r
+    );\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create XHCI transfer ring.\r
+\r
+  @param  Handle            Debug port handle.\r
+  @param  TrbNum            The number of TRB in the ring.\r
+  @param  TransferRing      The created transfer ring.\r
+\r
+**/\r
+VOID\r
+CreateTransferRing (\r
+  IN  USB3_DEBUG_PORT_HANDLE      *Handle,\r
+  IN  UINT32                      TrbNum,\r
+  OUT TRANSFER_RING               *TransferRing\r
+  )\r
+{\r
+  VOID                  *Buf;\r
+  LINK_TRB              *EndTrb;\r
\r
+  Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0xF) == 0);\r
+  ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
+\r
+  TransferRing->RingSeg0     = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;\r
+  TransferRing->TrbNumber    = TrbNum;\r
+  TransferRing->RingEnqueue  = TransferRing->RingSeg0;\r
+  TransferRing->RingDequeue  = TransferRing->RingSeg0;\r
+  TransferRing->RingPCS      = 1;\r
+  //\r
+  // 4.9.2 Transfer Ring Management\r
+  // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
+  // point to the first TRB in the ring.\r
+  //\r
+  EndTrb        = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
+  EndTrb->Type  = TRB_TYPE_LINK;\r
+  EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
+  EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
+  //\r
+  // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
+  //\r
+  EndTrb->TC    = 1;\r
+  //\r
+  // Set Cycle bit as other TRB PCS init value\r
+  //\r
+  EndTrb->CycleBit = 0;\r
+}\r
+\r
+/**\r
+  Create debug capability context for XHC debug device.\r
+\r
+  @param  Handle       Debug port handle.\r
+\r
+  @retval EFI_SUCCESS  The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT  The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateDebugCapabilityContext (\r
+  IN  USB3_DEBUG_PORT_HANDLE   *Handle\r
+  )\r
+{\r
+  VOID                        *Buf;\r
+  XHC_DC_CONTEXT              *DebugCapabilityContext;\r
+  UINT8                       *String0Desc;\r
+  UINT8                       *ManufacturerStrDesc;\r
+  UINT8                       *ProductStrDesc;\r
+  UINT8                       *SerialNumberStrDesc;\r
+  \r
+  //\r
+  // Allocate debug device context\r
+  //\r
+  Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0xF) == 0);\r
+  ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));\r
+  \r
+  DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;\r
+  Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;\r
+  \r
+  //\r
+  // Initialize DbcInfoContext.\r
+  //\r
+  DebugCapabilityContext->DbcInfoContext.String0Length         = STRING0_DESC_LEN;\r
+  DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;\r
+  DebugCapabilityContext->DbcInfoContext.ProductStrLength      = PRODUCT_DESC_LEN;\r
+  DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;\r
+\r
+  //\r
+  // Initialize EpOutContext.\r
+  //\r
+  DebugCapabilityContext->EpOutContext.CErr             = 0x3;\r
+  DebugCapabilityContext->EpOutContext.EPType           = ED_BULK_OUT;\r
+  DebugCapabilityContext->EpOutContext.MaxPacketSize    = 0x400;\r
+  DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;\r
+  \r
+  //\r
+  // Initialize EpInContext.\r
+  //\r
+  DebugCapabilityContext->EpInContext.CErr             = 0x3;\r
+  DebugCapabilityContext->EpInContext.EPType           = ED_BULK_IN;\r
+  DebugCapabilityContext->EpInContext.MaxPacketSize    = 0x400;\r
+  DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;\r
+  \r
+  //\r
+  // Update string descriptor address\r
+  //\r
+  String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
+  ASSERT (String0Desc != NULL);\r
+  ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);\r
+  CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);\r
+  DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;\r
+  \r
+  ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;\r
+  CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);\r
+  DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;\r
+  \r
+  ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;\r
+  CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);\r
+  DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;\r
+  \r
+  SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;\r
+  CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);\r
+  DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;\r
+  \r
+  //\r
+  // Allocate and initialize the Transfer Ring for the Input Endpoint Context.\r
+  //\r
+  ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));\r
+  CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);\r
+  DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;\r
+  DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);\r
+\r
+  //\r
+  // Allocate and initialize the Transfer Ring for the Output Endpoint Context.\r
+  //\r
+  ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));\r
+  CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);\r
+  DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;\r
+  DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);\r
+\r
+  //\r
+  // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)\r
+  //\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCCP,\r
+    XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
+    );\r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCCP + 4,\r
+    XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)\r
+    );\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if debug device is running.\r
+\r
+  @param  Handle       Debug port handle.\r
+\r
+**/\r
+VOID\r
+XhcDetectDebugCapabilityReady (\r
+  IN USB3_DEBUG_PORT_HANDLE *Handle\r
+  )\r
+{\r
+  UINT64                          TimeOut;\r
+  volatile UINT32                 Dcctrl;\r
+\r
+  TimeOut = 1;\r
+  if (Handle->Initialized == USB3DBG_DBG_CAB) {\r
+    //\r
+    // As detection is slow in seconds, wait for longer timeout for the first time.\r
+    // If first initialization is failed, we will try to enable debug device in the\r
+    // Poll function invoked by timer.\r
+    //\r
+    TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;\r
+  }\r
+\r
+  do {\r
+    //\r
+    // Check if debug device is in configured state\r
+    //\r
+    Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);\r
+    if ((Dcctrl & BIT0) != 0) {\r
+      //\r
+      // Set the flag to indicate debug device is in configured state\r
+      //\r
+      Handle->Ready = TRUE;\r
+      break;\r
+    }\r
+    MicroSecondDelay (XHC_POLL_DELAY);\r
+    TimeOut--;\r
+  } while (TimeOut != 0);\r
+}\r
+\r
+/**\r
+  Initialize usb debug port hardware.\r
+\r
+  @param  Handle           Debug port handle.\r
+\r
+  @retval TRUE             The usb debug port hardware configuration is changed.\r
+  @retval FALSE            The usb debug port hardware configuration is not changed.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+InitializeUsbDebugHardware (\r
+  IN USB3_DEBUG_PORT_HANDLE *Handle\r
+  )\r
+{\r
+  RETURN_STATUS                   Status;\r
+  UINT8                           *Buffer;\r
+  UINTN                           Index;\r
+  UINT8                           TotalUsb3Port;\r
+  EFI_PHYSICAL_ADDRESS            XhciOpRegister;\r
+\r
+  XhciOpRegister = Handle->XhciOpRegister;\r
+  TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;\r
+\r
+  if (Handle->Initialized == USB3DBG_NOT_ENABLED) {\r
+    //\r
+    // If XHCI supports debug capability, hardware resource has been allocated, \r
+    // but it has not been enabled, try to enable again.\r
+    //\r
+    goto Enable;\r
+  }\r
+\r
+  //\r
+  // Initialize for PEI phase when AllocatePages can work\r
+  //\r
+  Buffer = AllocateAlignBuffer (XHC_DEBUG_PORT_DATA_LENGTH);\r
+  if (Buffer == NULL) {\r
+    //\r
+    // AllocatePages can not still work now, return fail and do not initialize now.\r
+    //\r
+    return RETURN_NOT_READY;\r
+  }\r
+\r
+  //\r
+  // Reset port to get debug device discovered\r
+  //  \r
+  for (Index = 0; Index < TotalUsb3Port; Index++) {\r
+    XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);\r
+    MicroSecondDelay (10 * 1000);\r
+  }\r
+\r
+  //\r
+  // Construct the buffer for URB in and URB out\r
+  //\r
+  Handle->UrbIn.Data  = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;\r
+  Handle->UrbOut.Data = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHC_DEBUG_PORT_DATA_LENGTH;\r
+   \r
+  //\r
+  // Initialize event ring\r
+  //\r
+  ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));\r
+  Status = CreateEventRing (Handle, &Handle->EventRing);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Init IN and OUT endpoint context\r
+  //\r
+  Status = CreateDebugCapabilityContext (Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Init DCDDI1 and DCDDI2\r
+  //\r
+  XhcWriteDebugReg (\r
+   Handle,\r
+   XHC_DC_DCDDI1,\r
+   (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)\r
+   ); \r
+\r
+  XhcWriteDebugReg (\r
+   Handle,\r
+   XHC_DC_DCDDI2,\r
+   (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)\r
+   );\r
+\r
+Enable:\r
+  if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {\r
+    //\r
+    // If the first time detection is failed, turn port power off and on in order to \r
+    // reset port status this time, then try to check if debug device is ready again.\r
+    //\r
+    for (Index = 0; Index < TotalUsb3Port; Index++) {\r
+      XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
+      MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
+      XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);\r
+      MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);\r
+      Handle->ChangePortPower = TRUE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization\r
+  //\r
+  XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);\r
+  \r
+  XhcDetectDebugCapabilityReady (Handle);\r
+  \r
+  Status = RETURN_SUCCESS;\r
+  if (!Handle->Ready) {\r
+    Handle->Initialized = USB3DBG_NOT_ENABLED;\r
+    Status = RETURN_NOT_READY;\r
+  } else {\r
+    Handle->Initialized = USB3DBG_ENABLED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read data from debug device and save the data in buffer.\r
+\r
+  Reads NumberOfBytes data bytes from a debug device into the buffer\r
+  specified by Buffer. The number of bytes actually read is returned.\r
+  If the return value is less than NumberOfBytes, then the rest operation failed.\r
+  If NumberOfBytes is zero, then return 0.\r
+\r
+  @param  Handle           Debug port handle.\r
+  @param  Buffer           Pointer to the data buffer to store the data read from the debug device.\r
+  @param  NumberOfBytes    Number of bytes which will be read.\r
+  @param  Timeout          Timeout value for reading from debug device. It unit is Microsecond.\r
+\r
+  @retval 0                Read data failed, no data is to be read.\r
+  @retval >0               Actual number of bytes read from debug device.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+DebugPortReadBuffer (\r
+  IN   DEBUG_PORT_HANDLE        Handle,\r
+  IN   UINT8                    *Buffer,\r
+  IN   UINTN                    NumberOfBytes,\r
+  IN   UINTN                    Timeout\r
+  )\r
+{\r
+  USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;\r
+  RETURN_STATUS             Status;\r
+  UINTN                     Received;\r
+  UINTN                     Total;\r
+  UINTN                     Remaining;\r
+  UINT8                     Index;\r
+  UINTN                     Length;\r
+  UINT64                    Begin;\r
+  UINT64                    TimeoutTicker;\r
+  UINT64                    TimerRound;\r
+  EFI_PHYSICAL_ADDRESS      XhciMmioBase;\r
+\r
+  if (NumberOfBytes == 0 || Buffer == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Received  = 0;\r
+  Total     = 0;\r
+  Remaining = 0;\r
+\r
+  //\r
+  // If Handle is NULL, it means memory is ready for use.\r
+  // Use global variable to store handle value.\r
+  //\r
+  if (Handle == NULL) {\r
+    UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+  } else {\r
+    UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+  }\r
+  \r
+  if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+    return 0;\r
+  }\r
+  \r
+  XhciMmioBase = ProgramXhciBaseAddress ();\r
+  UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+  \r
+  if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+    Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
+    if (RETURN_ERROR(Status)) {\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // First read data from buffer, then read debug port hw to get received data.\r
+  //\r
+  if (UsbDebugPortHandle->DataCount > 0) {\r
+    if (NumberOfBytes <= UsbDebugPortHandle->DataCount) {\r
+      Total = NumberOfBytes;\r
+    } else {\r
+      Total = UsbDebugPortHandle->DataCount;\r
+    }\r
+\r
+    for (Index = 0; Index < Total; Index++) {\r
+      Buffer[Index] = UsbDebugPortHandle->Data[Index];\r
+    }\r
+\r
+    for (Index = 0; Index < UsbDebugPortHandle->DataCount - Total; Index++) {\r
+      if (Total + Index >= 8) {\r
+        return 0;\r
+      }\r
+      UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Total + Index];\r
+    }\r
+    UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - (UINT8)Total);\r
+  }\r
+\r
+  //\r
+  // If Timeout is equal to 0, then it means it should always wait until all data required are received.\r
+  //\r
+  Begin         = 0;\r
+  TimeoutTicker = 0;  \r
+  TimerRound    = 0;\r
+  if (Timeout != 0) {\r
+    Begin = GetPerformanceCounter ();\r
+    TimeoutTicker = DivU64x32 (\r
+                      MultU64x64 (\r
+                        UsbDebugPortHandle->TimerFrequency,\r
+                        Timeout\r
+                        ),\r
+                      1000000u\r
+                      );\r
+    TimerRound = DivU64x64Remainder (\r
+                   TimeoutTicker,\r
+                   DivU64x32 (UsbDebugPortHandle->TimerCycle, 2),\r
+                   &TimeoutTicker\r
+                   );\r
+  }\r
+\r
+  //\r
+  // Read remaining data by executing one or more usb debug transfer transactions at usb debug port hw.\r
+  //\r
+  while (Total < NumberOfBytes) {\r
+    if (Timeout != 0) {\r
+      if (TimerRound == 0) {\r
+        if (IsTimerTimeout (UsbDebugPortHandle, Begin, TimeoutTicker)) {\r
+          //\r
+          // If time out occurs.\r
+          //\r
+          return 0;\r
+        }\r
+      } else {\r
+        if (IsTimerTimeout (UsbDebugPortHandle, Begin, DivU64x32 (UsbDebugPortHandle->TimerCycle, 2))) {\r
+          TimerRound --;\r
+        }\r
+      }\r
+    }\r
+    Remaining = NumberOfBytes - Total;\r
+    if (Remaining >= USB3_DEBUG_PORT_MAX_PACKET_SIZE) {\r
+      Received = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+      Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, Buffer + Total, &Received, DATA_TRANSFER_READ_TIMEOUT);\r
+    } else {\r
+      Received = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+      Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, &UsbDebugPortHandle->Data[0], &Received, DATA_TRANSFER_READ_TIMEOUT);\r
+      UsbDebugPortHandle->DataCount = (UINT8) Received;\r
+\r
+      if (Remaining <= Received) {\r
+        //\r
+        // The data received are more than required\r
+        //\r
+        Length = (UINT8)Remaining;\r
+      } else {\r
+        //\r
+        // The data received are less than the remaining bytes\r
+        //\r
+        Length = (UINT8)Received;\r
+      }\r
+\r
+      //\r
+      // Copy required data from the data buffer to user buffer.\r
+      //\r
+      for (Index = 0; Index < Length; Index++) {\r
+        (Buffer + Total)[Index] = UsbDebugPortHandle->Data[Index];\r
+        UsbDebugPortHandle->DataCount--;\r
+      }\r
+\r
+      //\r
+      // reorder the data buffer to make available data arranged from the beginning of the data buffer.\r
+      //\r
+      for (Index = 0; Index < Received - Length; Index++) {\r
+        if (Length + Index >= 8) {\r
+          return 0;\r
+        }\r
+        UsbDebugPortHandle->Data[Index] = UsbDebugPortHandle->Data[Length + Index];\r
+      }\r
+      //\r
+      // fixup the real required length of data.\r
+      //\r
+      Received = Length;\r
+    }\r
+    Total += Received;\r
+  }\r
+  return Total;\r
+}\r
+\r
+/**\r
+  Write data from buffer to debug device.\r
+\r
+  Writes NumberOfBytes data bytes from Buffer to the debug device.\r
+  The number of bytes actually written to the debug device is returned.\r
+  If the return value is less than NumberOfBytes, then the write operation failed.\r
+  If NumberOfBytes is zero, then return 0.\r
+\r
+  @param  Handle           Debug port handle.\r
+  @param  Buffer           Pointer to the data buffer to be written.\r
+  @param  NumberOfBytes    Number of bytes to written to the debug device.\r
+\r
+  @retval 0                NumberOfBytes is 0.\r
+  @retval >0               The number of bytes written to the debug device.\r
+                           If this value is less than NumberOfBytes, then the read operation failed.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+DebugPortWriteBuffer (\r
+  IN   DEBUG_PORT_HANDLE    Handle,\r
+  IN   UINT8                *Buffer,\r
+  IN   UINTN                NumberOfBytes\r
+  )\r
+{\r
+  USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;\r
+  RETURN_STATUS             Status;\r
+  UINTN                     Sent;\r
+  UINTN                     Total;\r
+  EFI_PHYSICAL_ADDRESS      XhciMmioBase;\r
+  UINTN                     Index;\r
+\r
+  if (NumberOfBytes == 0 || Buffer == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Sent  = 0;\r
+  Total = 0;\r
+\r
+  //\r
+  // If Handle is NULL, it means memory is ready for use.\r
+  // Use global variable to store handle value.\r
+  //\r
+  if (Handle == NULL) {\r
+    UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+  } else {\r
+    UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+  }\r
+  \r
+  if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // MMIO base address is possible to clear, set it if it is cleared. (XhciMemorySpaceClose in PchUsbCommon.c)\r
+  //\r
+  XhciMmioBase = ProgramXhciBaseAddress ();\r
+\r
+  UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+\r
+  if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+    Status = InitializeUsbDebugHardware (UsbDebugPortHandle);\r
+    if (RETURN_ERROR(Status)) {\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // When host is trying to send data, write will be blocked.\r
+  // Poll to see if there is any data sent by host at first.\r
+  //\r
+  DebugPortPollBuffer (Handle);\r
+\r
+  Index = 0;\r
+  while ((Total < NumberOfBytes)) {\r
+    if (NumberOfBytes - Total > USB3_DEBUG_PORT_MAX_PACKET_SIZE) {\r
+      Sent = USB3_DEBUG_PORT_MAX_PACKET_SIZE;\r
+    } else {\r
+      Sent = (UINT8)(NumberOfBytes - Total);\r
+    }\r
+    Status = XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);\r
+    Total += Sent;\r
+  }\r
+  \r
+  return Total;\r
+}\r
+\r
+/**\r
+  Polls a debug device to see if there is any data waiting to be read.\r
+\r
+  Polls a debug device to see if there is any data waiting to be read.\r
+  If there is data waiting to be read from the debug device, then TRUE is returned.\r
+  If there is no data waiting to be read from the debug device, then FALSE is returned.\r
+\r
+  @param  Handle           Debug port handle.\r
+\r
+  @retval TRUE             Data is waiting to be read from the debug device.\r
+  @retval FALSE            There is no data waiting to be read from the serial device.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+DebugPortPollBuffer (\r
+  IN DEBUG_PORT_HANDLE      Handle\r
+  )\r
+{\r
+  USB3_DEBUG_PORT_HANDLE     *UsbDebugPortHandle;\r
+  UINTN                     Length;\r
+  RETURN_STATUS             Status;\r
+  UINT8                     Buffer[XHC_DEBUG_PORT_DATA_LENGTH];\r
+  EFI_PHYSICAL_ADDRESS      XhciMmioBase;\r
+\r
+  //\r
+  // If Handle is NULL, it means memory is ready for use.\r
+  // Use global variable to store handle value.\r
+  //\r
+  if (Handle == NULL) {\r
+    UsbDebugPortHandle = &mDebugCommunicationLibUsb3DebugPortHandle;\r
+  } else {\r
+    UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;\r
+  }\r
+\r
+  if (UsbDebugPortHandle->Initialized == USB3DBG_NO_DBG_CAB) {\r
+    return 0;\r
+  }\r
+\r
+  XhciMmioBase = ProgramXhciBaseAddress ();\r
+  UpdateXhcResource (UsbDebugPortHandle, XhciMmioBase);\r
+  \r
+  if (NeedReinitializeHardware(UsbDebugPortHandle)) {\r
+    Status = InitializeUsbDebugHardware(UsbDebugPortHandle);\r
+    if (RETURN_ERROR(Status)) {\r
+      return FALSE;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // If the data buffer is not empty, then return TRUE directly.\r
+  // Otherwise initialize a usb read transaction and read data to internal data buffer.\r
+  //\r
+  if (UsbDebugPortHandle->DataCount != 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Read most 8-bytes data\r
+  //\r
+  Length = XHC_DEBUG_PORT_DATA_LENGTH;\r
+  XhcDataTransfer (Handle, EfiUsbDataIn, Buffer, &Length, DATA_TRANSFER_POLL_TIMEOUT);\r
+\r
+  if (Length > 8) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (Length == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Store data into internal buffer for use later\r
+  //\r
+  CopyMem (UsbDebugPortHandle->Data, Buffer, Length);\r
+  UsbDebugPortHandle->DataCount = (UINT8) Length;\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Initialize the debug port.\r
+\r
+  If Function is not NULL, Debug Communication Libary will call this function\r
+  by passing in the Context to be the first parameter. If needed, Debug Communication\r
+  Library will create one debug port handle to be the second argument passing in\r
+  calling the Function, otherwise it will pass NULL to be the second argument of\r
+  Function.\r
+\r
+  If Function is NULL, and Context is not NULL, the Debug Communication Library could\r
+    a) Return the same handle as passed in (as Context parameter).\r
+    b) Ignore the input Context parameter and create new hanlde to be returned.\r
+\r
+  If parameter Function is NULL and Context is NULL, Debug Communication Library could\r
+  created a new handle if needed and return it, otherwise it will return NULL.\r
+\r
+  @param[in] Context      Context needed by callback function; it was optional.\r
+  @param[in] Function     Continue function called by Debug Communication library;\r
+                          it was optional.\r
+\r
+  @return  The debug port handle created by Debug Communication Library if Function\r
+           is not NULL.\r
+\r
+**/\r
+DEBUG_PORT_HANDLE\r
+EFIAPI\r
+DebugPortInitialize (\r
+  IN VOID                 *Context,\r
+  IN DEBUG_PORT_CONTINUE  Function\r
+  )\r
+{\r
+  RETURN_STATUS             Status;\r
+  USB3_DEBUG_PORT_HANDLE    Handle;\r
+  USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;\r
+  UINT64                    TimerStartValue;\r
+  UINT64                    TimerEndValue;\r
+\r
+  //\r
+  // Validate the PCD PcdDebugPortHandleBufferSize value \r
+  //\r
+  ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));\r
+\r
+  if (Function == NULL && Context != NULL) {\r
+    UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Context;\r
+  } else {\r
+    ZeroMem(&Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
+    UsbDebugPortHandle = &Handle;\r
+  }\r
+\r
+  UsbDebugPortHandle->TimerFrequency = GetPerformanceCounterProperties (\r
+                                         &TimerStartValue,\r
+                                         &TimerEndValue\r
+                                         );\r
+\r
+  if (TimerEndValue < TimerStartValue) {\r
+    UsbDebugPortHandle->TimerCountDown = TRUE;\r
+    UsbDebugPortHandle->TimerCycle     = TimerStartValue - TimerEndValue;\r
+  } else {\r
+    UsbDebugPortHandle->TimerCountDown = FALSE;\r
+    UsbDebugPortHandle->TimerCycle     = TimerEndValue - TimerStartValue;\r
+  }   \r
+\r
+  if (Function == NULL && Context != NULL) {\r
+    return (DEBUG_PORT_HANDLE *) Context;\r
+  }\r
+  \r
+  //\r
+  // Read 64-bit MMIO base address\r
+  //\r
+  UsbDebugPortHandle->XhciMmioBase = ProgramXhciBaseAddress ();\r
+\r
+  Status = CalculateUsbDebugPortMmioBase (UsbDebugPortHandle);\r
+  if (RETURN_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (NeedReinitializeHardware(&Handle)) {\r
+    Status = InitializeUsbDebugHardware (&Handle);\r
+    if (RETURN_ERROR(Status)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+Exit:\r
+\r
+  if (Function != NULL) {\r
+    Function (Context, &Handle);\r
+  } else {\r
+    CopyMem(&mDebugCommunicationLibUsb3DebugPortHandle, &Handle, sizeof (USB3_DEBUG_PORT_HANDLE));\r
+  }\r
+\r
+  return (DEBUG_PORT_HANDLE)(UINTN)&mDebugCommunicationLibUsb3DebugPortHandle;\r
+}\r
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
new file mode 100644 (file)
index 0000000..c232323
--- /dev/null
@@ -0,0 +1,48 @@
+/** @file\r
+  Debug Port Library implementation based on usb3 debug port.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <PiDxe.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include "DebugCommunicationLibUsb3Internal.h"\r
+\r
+/**\r
+  Allocate aligned memory for XHC's usage.\r
+\r
+  @param  BufferSize      The size, in bytes, of the Buffer.\r
+  \r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID*\r
+AllocateAlignBuffer (\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  VOID      *Buf;\r
+  \r
+  Buf = NULL;\r
+  \r
+  if (gBS != NULL) {\r
+    Buf = (VOID *)(UINTN)0xFFFFFFFF;\r
+    gBS->AllocatePages (\r
+           AllocateMaxAddress,\r
+           EfiACPIMemoryNVS,\r
+           EFI_SIZE_TO_PAGES (BufferSize),\r
+           (EFI_PHYSICAL_ADDRESS *) &Buf\r
+           );\r
+  }\r
+\r
+  return Buf;\r
+}\r
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
new file mode 100644 (file)
index 0000000..e984623
--- /dev/null
@@ -0,0 +1,69 @@
+## @file\r
+#  Debug Communication Library instance based on usb3 debug port.\r
+#\r
+#  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DebugCommunicationLibUsb3Dxe\r
+  MODULE_UNI_FILE                = DebugCommunicationLibUsb3Dxe.uni\r
+  FILE_GUID                      = C41F8C82-B3E6-47e0-A61D-0F9E429E6996\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  DebugCommunicationLibUsb3Dxe.c\r
+  DebugCommunicationLibUsb3Transfer.c\r
+  DebugCommunicationLibUsb3Common.c\r
+  DebugCommunicationLibUsb3Internal.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  SourceLevelDebugPkg/SourceLevelDebugPkg.dec\r
+\r
+[Pcd]\r
+  ## The memory BAR of ehci host controller, in which usb debug feature is enabled.\r
+  ## Note that the memory BAR address is only used before Pci bus resource allocation.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase          ## SOMETIMES_CONSUMES\r
+\r
+  ## The pci address of ehci host controller, in which usb debug feature is enabled.\r
+  ## The format of pci address please refer to SourceLevelDebugPkg.dec\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress               ## CONSUMES\r
+\r
+  ## Per XHCI spec, software shall impose a timeout between the detection of the Debug Host \r
+  ## connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout       ## SOMETIMES_CONSUMES\r
+\r
+  ## The value of data buffer size used for USB debug port handle.\r
+  ## It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|256   ## SOMETIMES_CONSUMES\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  PcdLib\r
+  IoLib\r
+  PciLib\r
+  TimerLib\r
+  UefiBootServicesTableLib\r
+  UefiLib\r
+  BaseMemoryLib\r
+  
\ No newline at end of file
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
new file mode 100644 (file)
index 0000000..111cf79
Binary files /dev/null and b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni differ
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
new file mode 100644 (file)
index 0000000..2f20250
--- /dev/null
@@ -0,0 +1,763 @@
+/** @file\r
+  Debug Port Library implementation based on usb3 debug port.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__\r
+#define __USB3_DEBUG_PORT_LIB_INTERNAL__\r
+\r
+#include <Uefi.h>\r
+#include <Base.h>\r
+#include <IndustryStandard/Usb.h>\r
+#include <Library/IoLib.h>\r
+#include <IndustryStandard/Pci.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/DebugCommunicationLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/SerialPortLib.h>      // Todo: remove in future\r
+\r
+//\r
+// Internal serial debug - remove finally\r
+//\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+//\r
+// USB Debug GUID value\r
+//\r
+#define USB3_DBG_GUID \\r
+    { \\r
+      0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \\r
+    }\r
+\r
+//\r
+// The state machine of usb debug port\r
+//\r
+#define USB3DBG_NO_DBG_CAB    0   // The XHCI host controller does not support debug capability\r
+#define USB3DBG_DBG_CAB       1   // The XHCI host controller supports debug capability\r
+#define USB3DBG_ENABLED       2   // The XHCI debug device is enabled\r
+#define USB3DBG_NOT_ENABLED   4   // The XHCI debug device is not enabled\r
+\r
+#define USB3_DEBUG_PORT_MAX_PACKET_SIZE 0x08\r
+\r
+#define XHCI_DEBUG_DEVICE_VENDOR_ID   0x0525\r
+#define XHCI_DEBUG_DEVICE_PRODUCT_ID  0x127A\r
+#define XHCI_DEBUG_DEVICE_PROTOCOL    0xFF\r
+#define XHCI_DEBUG_DEVICE_REVISION    0x00\r
+\r
+#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL\r
+#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000\r
+\r
+#define PCI_CAPABILITY_ID_DEBUG_PORT  0x0A\r
+#define XHC_HCCPARAMS_OFFSET          0x10\r
+#define XHC_CAPABILITY_ID_MASK        0xFF\r
+#define XHC_NEXT_CAPABILITY_MASK      0xFF00\r
+\r
+#define XHC_HCSPARAMS1_OFFSET         0x4    // Structural Parameters 1\r
+#define XHC_USBCMD_OFFSET             0x0    // USB Command Register Offset\r
+#define XHC_USBSTS_OFFSET             0x4    // USB Status Register Offset\r
+#define XHC_PORTSC_OFFSET             0x400  // Port Status and Control Register Offset\r
+\r
+#define XHC_USBCMD_RUN                BIT0  // Run/Stop\r
+#define XHC_USBCMD_RESET              BIT1  // Host Controller Reset\r
+\r
+#define XHC_USBSTS_HALT               BIT0\r
+\r
+//\r
+// Transfer the data of 8 bytes each time\r
+//\r
+#define XHC_DEBUG_PORT_DATA_LENGTH   8\r
+\r
+//\r
+// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout.\r
+//\r
+#define DATA_TRANSFER_WRITE_TIMEOUT      0\r
+#define DATA_TRANSFER_READ_TIMEOUT       50000\r
+#define DATA_TRANSFER_POLL_TIMEOUT       1000\r
+\r
+//\r
+// XHCI port power off/on delay\r
+//\r
+#define XHC_DEBUG_PORT_ON_OFF_DELAY    100000\r
+\r
+//\r
+// USB debug device string descritpor (header size + unicode string length)\r
+//\r
+#define STRING0_DESC_LEN      4\r
+#define MANU_DESC_LEN         12\r
+#define PRODUCT_DESC_LEN      40\r
+#define SERIAL_DESC_LEN       4\r
+\r
+//\r
+// Debug Capability Register Offset\r
+//\r
+#define XHC_DC_DCID                  0x0\r
+#define XHC_DC_DCDB                  0x4\r
+#define XHC_DC_DCERSTSZ              0x8\r
+#define XHC_DC_DCERSTBA              0x10\r
+#define XHC_DC_DCERDP                0x18\r
+#define XHC_DC_DCCTRL                0x20\r
+#define XHC_DC_DCST                  0x24\r
+#define XHC_DC_DCPORTSC              0x28\r
+#define XHC_DC_DCCP                  0x30\r
+#define XHC_DC_DCDDI1                0x38\r
+#define XHC_DC_DCDDI2                0x3C\r
+\r
+#define TRB_TYPE_LINK                6\r
+\r
+#define ERST_NUMBER                  0x01\r
+#define TR_RING_TRB_NUMBER           0x100\r
+#define EVENT_RING_TRB_NUMBER        0x200\r
+\r
+#define ED_BULK_OUT                  2\r
+#define ED_BULK_IN                   6\r
+\r
+#define XHC_LOW_32BIT(Addr64)          ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))\r
+#define XHC_HIGH_32BIT(Addr64)         ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))\r
+#define XHC_BIT_IS_SET(Data, Bit)      ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+//\r
+// Endpoint Type (EP Type).\r
+//\r
+#define ED_NOT_VALID                          0\r
+#define ED_ISOCH_OUT                          1\r
+#define ED_BULK_OUT                           2\r
+#define ED_INTERRUPT_OUT                      3\r
+#define ED_CONTROL_BIDIR                      4\r
+#define ED_ISOCH_IN                           5\r
+#define ED_BULK_IN                            6\r
+#define ED_INTERRUPT_IN                       7\r
+\r
+//\r
+// 6.4.5 TRB Completion Codes\r
+//\r
+#define TRB_COMPLETION_INVALID                0\r
+#define TRB_COMPLETION_SUCCESS                1\r
+#define TRB_COMPLETION_DATA_BUFFER_ERROR      2\r
+#define TRB_COMPLETION_BABBLE_ERROR           3\r
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR  4\r
+#define TRB_COMPLETION_TRB_ERROR              5\r
+#define TRB_COMPLETION_STALL_ERROR            6\r
+#define TRB_COMPLETION_SHORT_PACKET           13\r
+\r
+//\r
+// 6.4.6 TRB Types\r
+//\r
+#define TRB_TYPE_NORMAL                       1\r
+#define TRB_TYPE_SETUP_STAGE                  2\r
+#define TRB_TYPE_DATA_STAGE                   3\r
+#define TRB_TYPE_STATUS_STAGE                 4\r
+#define TRB_TYPE_ISOCH                        5\r
+#define TRB_TYPE_LINK                         6\r
+#define TRB_TYPE_EVENT_DATA                   7\r
+#define TRB_TYPE_NO_OP                        8\r
+#define TRB_TYPE_EN_SLOT                      9\r
+#define TRB_TYPE_DIS_SLOT                     10\r
+#define TRB_TYPE_ADDRESS_DEV                  11\r
+#define TRB_TYPE_CON_ENDPOINT                 12\r
+#define TRB_TYPE_EVALU_CONTXT                 13\r
+#define TRB_TYPE_RESET_ENDPOINT               14\r
+#define TRB_TYPE_STOP_ENDPOINT                15\r
+#define TRB_TYPE_SET_TR_DEQUE                 16\r
+#define TRB_TYPE_RESET_DEV                    17\r
+#define TRB_TYPE_GET_PORT_BANW                21\r
+#define TRB_TYPE_FORCE_HEADER                 22\r
+#define TRB_TYPE_NO_OP_COMMAND                23\r
+#define TRB_TYPE_TRANS_EVENT                  32\r
+#define TRB_TYPE_COMMAND_COMPLT_EVENT         33\r
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT     34\r
+#define TRB_TYPE_HOST_CONTROLLER_EVENT        37\r
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT          38\r
+#define TRB_TYPE_MFINDEX_WRAP_EVENT           39\r
+\r
+//\r
+// Convert millisecond to microsecond.\r
+//\r
+#define XHC_1_MILLISECOND                     (1000)\r
+#define XHC_POLL_DELAY                        (1000)\r
+#define XHC_GENERIC_TIMEOUT                   (10 * 1000)\r
+\r
+#define EFI_USB_SPEED_FULL                    0x0000  ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.\r
+#define EFI_USB_SPEED_LOW                     0x0001  ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.\r
+#define EFI_USB_SPEED_HIGH                    0x0002  ///< 480 Mb/s, USB 2.0 EHCI HC.\r
+#define EFI_USB_SPEED_SUPER                   0x0003  ///< 4.8 Gb/s, USB 3.0 XHCI HC.\r
+\r
+//\r
+// Transfer types, used in URB to identify the transfer type\r
+//\r
+#define XHC_CTRL_TRANSFER                     0x01\r
+#define XHC_BULK_TRANSFER                     0x02\r
+#define XHC_INT_TRANSFER_SYNC                 0x04\r
+#define XHC_INT_TRANSFER_ASYNC                0x08\r
+#define XHC_INT_ONLY_TRANSFER_ASYNC           0x10\r
+\r
+//\r
+// USB Transfer Results\r
+//\r
+#define EFI_USB_NOERROR             0x00\r
+#define EFI_USB_ERR_NOTEXECUTE      0x01\r
+#define EFI_USB_ERR_STALL           0x02\r
+#define EFI_USB_ERR_BUFFER          0x04\r
+#define EFI_USB_ERR_BABBLE          0x08\r
+#define EFI_USB_ERR_NAK             0x10\r
+#define EFI_USB_ERR_CRC             0x20\r
+#define EFI_USB_ERR_TIMEOUT         0x40\r
+#define EFI_USB_ERR_BITSTUFF        0x80\r
+#define EFI_USB_ERR_SYSTEM          0x100\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// 7.6.9 OUT/IN EP Context: 64 bytes\r
+// 7.6.9.2 When used by the DbC it is always a 64 byte data structure\r
+//\r
+typedef struct _ENDPOINT_CONTEXT_64 {\r
+  UINT32                  EPState:3;\r
+  UINT32                  RsvdZ1:5;\r
+  UINT32                  Mult:2;         // set to 0\r
+  UINT32                  MaxPStreams:5;  // set to 0\r
+  UINT32                  LSA:1;          // set to 0\r
+  UINT32                  Interval:8;     // set to 0\r
+  UINT32                  RsvdZ2:8;\r
+\r
+  UINT32                  RsvdZ3:1;\r
+  UINT32                  CErr:2;\r
+  UINT32                  EPType:3;\r
+  UINT32                  RsvdZ4:1;\r
+  UINT32                  HID:1;          // set to 0\r
+  UINT32                  MaxBurstSize:8;\r
+  UINT32                  MaxPacketSize:16;\r
+\r
+  UINT32                  PtrLo;\r
+\r
+  UINT32                  PtrHi;\r
+\r
+  UINT32                  AverageTRBLength:16;\r
+  UINT32                  MaxESITPayload:16;  // set to 0\r
+\r
+  UINT32                  RsvdZ5;             // Reserved\r
+  UINT32                  RsvdZ6;\r
+  UINT32                  RsvdZ7;\r
+  \r
+  UINT32                  RsvdZ8;\r
+  UINT32                  RsvdZ9;\r
+  UINT32                  RsvdZ10;\r
+  UINT32                  RsvdZ11;\r
+  \r
+  UINT32                  RsvdZ12;\r
+  UINT32                  RsvdZ13;\r
+  UINT32                  RsvdZ14;\r
+  UINT32                  RsvdZ15;\r
+} ENDPOINT_CONTEXT_64;\r
+\r
+//\r
+// 6.4.1.1 Normal TRB: 16 bytes\r
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and\r
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer\r
+// Rings, and to define the Data stage information for Control Transfer Rings.\r
+//\r
+typedef struct _TRANSFER_TRB_NORMAL {\r
+  UINT32                  TRBPtrLo;\r
+\r
+  UINT32                  TRBPtrHi;\r
+\r
+  UINT32                  Length:17;\r
+  UINT32                  TDSize:5;\r
+  UINT32                  IntTarget:10;\r
+\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  ENT:1;\r
+  UINT32                  ISP:1;\r
+  UINT32                  NS:1;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  IDT:1;\r
+  UINT32                  RsvdZ1:2;\r
+  UINT32                  BEI:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ2:16;\r
+} TRANSFER_TRB_NORMAL;\r
+\r
+//\r
+// 6.4.2.1 Transfer Event TRB: 16 bytes\r
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1\r
+// for more information on the use and operation of Transfer Events.\r
+//\r
+typedef struct _EVT_TRB_TRANSFER {\r
+  UINT32                  TRBPtrLo;\r
+\r
+  UINT32                  TRBPtrHi;\r
+\r
+  UINT32                  Length:24;\r
+  UINT32                  Completecode:8;\r
+\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ1:1;\r
+  UINT32                  ED:1;\r
+  UINT32                  RsvdZ2:7;\r
+  UINT32                  Type:6;\r
+  UINT32                  EndpointId:5;\r
+  UINT32                  RsvdZ3:3;\r
+  UINT32                  SlotId:8;\r
+} EVT_TRB_TRANSFER;\r
+\r
+//\r
+// 6.4.4.1 Link TRB: 16 bytes\r
+// A Link TRB provides support for non-contiguous TRB Rings.\r
+//\r
+typedef struct _LINK_TRB {\r
+  UINT32                  PtrLo;\r
+\r
+  UINT32                  PtrHi;\r
+\r
+  UINT32                  RsvdZ1:22;\r
+  UINT32                  InterTarget:10;\r
+\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  TC:1;\r
+  UINT32                  RsvdZ2:2;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  RsvdZ3:4;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:16;\r
+} LINK_TRB;\r
+\r
+//\r
+// TRB Template: 16 bytes\r
+//\r
+typedef struct _TRB_TEMPLATE {\r
+  UINT32                    Parameter1;\r
+\r
+  UINT32                    Parameter2;\r
+\r
+  UINT32                    Status;\r
+\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ1:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    Control:16;\r
+} TRB_TEMPLATE;\r
+\r
+//\r
+// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes\r
+//\r
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RingTrbSize:16;\r
+  UINT32                  RsvdZ1:16;\r
+  UINT32                  RsvdZ2;\r
+} EVENT_RING_SEG_TABLE_ENTRY;\r
+\r
+//\r
+// Size: 40 bytes\r
+//\r
+typedef struct _EVENT_RING {\r
+  EFI_PHYSICAL_ADDRESS      ERSTBase;\r
+  EFI_PHYSICAL_ADDRESS      EventRingSeg0;\r
+  UINT32                    TrbNumber;\r
+  EFI_PHYSICAL_ADDRESS      EventRingEnqueue;\r
+  EFI_PHYSICAL_ADDRESS      EventRingDequeue;\r
+  UINT32                    EventRingCCS;\r
+} EVENT_RING;\r
+\r
+// Size: 32 bytes\r
+typedef struct _TRANSFER_RING {\r
+  EFI_PHYSICAL_ADDRESS      RingSeg0;\r
+  UINT32                    TrbNumber;\r
+  EFI_PHYSICAL_ADDRESS      RingEnqueue;\r
+  EFI_PHYSICAL_ADDRESS      RingDequeue;\r
+  UINT32                    RingPCS;\r
+} TRANSFER_RING;\r
+\r
+//\r
+// Size: 64 bytes\r
+//\r
+typedef struct _DBC_INFO_CONTEXT {\r
+  UINT64        String0DescAddress;\r
+  UINT64        ManufacturerStrDescAddress;\r
+  UINT64        ProductStrDescAddress;\r
+  UINT64        SerialNumberStrDescAddress;\r
+  UINT64        String0Length:8;\r
+  UINT64        ManufacturerStrLength:8;\r
+  UINT64        ProductStrLength:8;\r
+  UINT64        SerialNumberStrLength:8;\r
+  UINT64        RsvdZ1:32;\r
+  UINT64        RsvdZ2;\r
+  UINT64        RsvdZ3;\r
+  UINT64        RsvdZ4;  \r
+} DBC_INFO_CONTEXT;\r
+\r
+//\r
+// Debug Capability Context Data Structure: 192 bytes\r
+//\r
+typedef struct _XHC_DC_CONTEXT {\r
+  DBC_INFO_CONTEXT      DbcInfoContext;\r
+  ENDPOINT_CONTEXT_64   EpOutContext;\r
+  ENDPOINT_CONTEXT_64   EpInContext;\r
+} XHC_DC_CONTEXT;\r
+\r
+//\r
+// Size: 16 bytes\r
+//\r
+typedef union _TRB {\r
+  TRB_TEMPLATE                TrbTemplate;\r
+  TRANSFER_TRB_NORMAL         TrbNormal;\r
+} TRB;\r
+\r
+///\r
+/// USB data transfer direction\r
+///\r
+typedef enum {\r
+  EfiUsbDataIn,\r
+  EfiUsbDataOut,\r
+  EfiUsbNoData\r
+} EFI_USB_DATA_DIRECTION;\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of\r
+// usb requests.\r
+//\r
+typedef struct _URB {\r
+  //\r
+  // Transfer data buffer\r
+  //\r
+  EFI_PHYSICAL_ADDRESS            Data;\r
+  UINT32                          DataLen;\r
+\r
+  //\r
+  // Execute result\r
+  //\r
+  UINT32                          Result;\r
+  //\r
+  // Completed data length\r
+  //\r
+  UINT32                          Completed;\r
+  //\r
+  // Tranfer Ring info\r
+  //\r
+  EFI_PHYSICAL_ADDRESS            Ring;\r
+  EFI_PHYSICAL_ADDRESS            Trb;\r
+  BOOLEAN                         Finished;\r
+  EFI_USB_DATA_DIRECTION          Direction;\r
+} URB;\r
+\r
+typedef struct _USB3_DEBUG_PORT_INSTANCE {\r
+  UINT8                                   Initialized;\r
+\r
+  //\r
+  // The flag indicates debug device is ready\r
+  //\r
+  BOOLEAN                                 DebugSupport;\r
+  \r
+  //\r
+  // The flag indicates debug device is ready\r
+  //\r
+  BOOLEAN                                 Ready;\r
+\r
+  //\r
+  // The flag indicates if USB 3.0 ports has been turn off/on power\r
+  //  \r
+  BOOLEAN                                 ChangePortPower;\r
+\r
+  //\r
+  // XHCI MMIO Base address\r
+  //\r
+  EFI_PHYSICAL_ADDRESS                    XhciMmioBase;\r
+\r
+  //\r
+  // XHCI OP RegisterBase address\r
+  //  \r
+  EFI_PHYSICAL_ADDRESS                    XhciOpRegister;\r
+  \r
+  //\r
+  // XHCI Debug Register Base Address\r
+  //\r
+  EFI_PHYSICAL_ADDRESS                    DebugCapabilityBase;\r
+  \r
+  //\r
+  // XHCI Debug Capability offset\r
+  //\r
+  UINT64                                  DebugCapabilityOffset;  \r
+  \r
+  //\r
+  // XHCI Debug Context Address\r
+  //\r
+  EFI_PHYSICAL_ADDRESS                    DebugCapabilityContext;\r
+  \r
+  //\r
+  // Transfer Ring\r
+  //\r
+  TRANSFER_RING                           TransferRingOut;\r
+  TRANSFER_RING                           TransferRingIn;\r
+\r
+  //\r
+  // EventRing\r
+  //\r
+  EVENT_RING                              EventRing;\r
+  \r
+  //\r
+  // URB - Read\r
+  //\r
+  URB                                     UrbOut;\r
+\r
+  //\r
+  // URB - Write\r
+  //\r
+  URB                                     UrbIn;\r
+\r
+  //\r
+  // The available data length in the following data buffer.\r
+  //\r
+  UINT8                                   DataCount;\r
+  //\r
+  // The data buffer. Maximum length is 8 bytes.\r
+  //\r
+  UINT8                                   Data[8];\r
+  //\r
+  // Timter settings\r
+  //\r
+  UINT64                                  TimerFrequency;\r
+  UINT64                                  TimerCycle;\r
+  BOOLEAN                                 TimerCountDown;\r
+\r
+} USB3_DEBUG_PORT_HANDLE;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+  Read XHCI debug register.\r
+\r
+ @param  Handle        Debug port handle.\r
+  @param  Offset       The offset of the debug register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadDebugReg (\r
+  IN  USB3_DEBUG_PORT_HANDLE    *Handle,\r
+  IN  UINT32                      Offset\r
+  );\r
+\r
+/**\r
+  Set one bit of the debug register while keeping other bits.\r
+\r
+  @param  Handle       Debug port handle.\r
+  @param  Offset       The offset of the debug register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetDebugRegBit (\r
+  IN USB3_DEBUG_PORT_HANDLE  *Handle,\r
+  IN UINT32                   Offset,\r
+  IN UINT32                   Bit\r
+  );\r
+  \r
+/**\r
+  Write the data to the debug register.\r
+\r
+  @param  Handle       Debug port handle.\r
+  @param  Offset       The offset of the debug register.\r
+  @param  Data         The data to write.\r
+\r
+**/  \r
+VOID\r
+XhcWriteDebugReg (\r
+  IN USB3_DEBUG_PORT_HANDLE     *Handle,\r
+  IN UINT32                     Offset,\r
+  IN UINT32                     Data\r
+  );\r
+\r
+/**\r
+  Discover the USB3 debug device.\r
+  \r
+  @param  Handle                Debug port handle.\r
+  \r
+  @retval RETURN_SUCCESS        The serial device was initialized.\r
+  @retval RETURN_DEVICE_ERROR   The serial device could not be initialized.\r
+\r
+**/\r
+RETURN_STATUS\r
+DiscoverUsb3DebugPort(\r
+  USB3_DEBUG_PORT_HANDLE  *Handle\r
+  );\r
+  \r
+/**\r
+  Initialize the Serial Device hardware.\r
+  \r
+  @param  Handle            Debug port handle.\r
+\r
+  @retval RETURN_SUCCESS    The serial device was initialized successfully.\r
+  @retval !RETURN_SUCCESS   Error.\r
+\r
+**/\r
+RETURN_STATUS\r
+InitializeUsb3DebugPort (\r
+  USB3_DEBUG_PORT_HANDLE  *Handle\r
+  );\r
+\r
+/**\r
+  Return XHCI MMIO base address.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+GetXhciBaseAddress (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Verifies if the bit positions specified by a mask are set in a register.\r
+\r
+  @param[in, out] Register    UNITN register\r
+  @param[in]      BitMask     32-bit mask\r
+\r
+  @return  BOOLEAN  - TRUE  if all bits specified by the mask are enabled.\r
+                    - FALSE even if one of the bits specified by the mask \r
+                            is not enabled.\r
+**/\r
+BOOLEAN\r
+XhcIsBitSet(\r
+  UINTN   Register, \r
+  UINT32  BitMask\r
+  );\r
+\r
+/**\r
+  Sets bits as per the enabled bit positions in the mask.\r
+\r
+  @param[in, out] Register    UINTN register\r
+  @param[in]      BitMask     32-bit mask\r
+**/\r
+VOID\r
+XhcSetR32Bit(\r
+  UINTN   Register, \r
+  UINT32  BitMask\r
+  );\r
+\r
+/**\r
+  Clears bits as per the enabled bit positions in the mask.\r
+\r
+  @param[in, out] Register    UINTN register\r
+  @param[in]      BitMask     32-bit mask\r
+**/\r
+VOID\r
+XhcClearR32Bit(\r
+  IN OUT  UINTN  Register, \r
+  IN      UINT32 BitMask\r
+  );\r
+\r
+/**\r
+  Initialize USB3 debug port.\r
+  \r
+  This method invokes various internal functions to facilitate\r
+  detection and initialization of USB3 debug port.\r
+\r
+  @retval RETURN_SUCCESS        The serial device was initialized.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+USB3Initialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Return command register value in XHCI controller.\r
+\r
+**/\r
+UINT16\r
+GetXhciPciCommand (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Allocate aligned memory for XHC's usage.\r
+\r
+  @param  BufferSize      The size, in bytes, of the Buffer.\r
+  \r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID*\r
+AllocateAlignBuffer (\r
+  IN UINTN                    BufferSize\r
+  );\r
+\r
+/**\r
+  The real function to initialize USB3 debug port.\r
+  \r
+  This method invokes various internal functions to facilitate\r
+  detection and initialization of USB3 debug port.\r
+\r
+  @retval RETURN_SUCCESS        The serial device was initialized.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+USB3InitializeReal (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  @param  Handle                The instance of debug device.\r
+  @param  Direction             The direction of data transfer.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit\r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  Timeout               Indicates the maximum time, in millisecond, which\r
+                                the transfer is allowed to complete.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDataTransfer (\r
+  IN     USB3_DEBUG_PORT_HANDLE              *Handle,\r
+  IN     EFI_USB_DATA_DIRECTION              Direction,\r
+  IN OUT VOID                                *Data,\r
+  IN OUT UINTN                               *DataLength,\r
+  IN     UINTN                               Timeout\r
+  );\r
+\r
+/**\r
+  Check if the timer is timeout.\r
+  \r
+  @param[in] UsbDebugPortHandle  Pointer to USB Debug port handle\r
+  @param[in] Timer               The start timer from the begin.\r
+  @param[in] TimeoutTicker       Ticker number need time out.\r
+\r
+  @return TRUE  Timer time out occurs.\r
+  @retval FALSE Timer does not time out.\r
+\r
+**/\r
+BOOLEAN\r
+IsTimerTimeout (\r
+  IN USB3_DEBUG_PORT_HANDLE  *UsbDebugPortHandle,\r
+  IN UINT64                  Timer,\r
+  IN UINT64                  TimeoutTicker\r
+  );\r
+\r
+#endif //__SERIAL_PORT_LIB_USB__\r
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
new file mode 100644 (file)
index 0000000..be3174e
--- /dev/null
@@ -0,0 +1,45 @@
+/** @file\r
+  Debug Port Library implementation based on usb3 debug port.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include "DebugCommunicationLibUsb3Internal.h"\r
+\r
+/**\r
+  Allocate aligned memory for XHC's usage.\r
+\r
+  @param  BufferSize      The size, in bytes, of the Buffer.\r
+  \r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID*\r
+AllocateAlignBuffer (\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  VOID                     *Buf;\r
+  EFI_PHYSICAL_ADDRESS     Address;\r
+  EFI_STATUS               Status;\r
+  \r
+  Buf = NULL;  \r
+  Status = PeiServicesAllocatePages (EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (BufferSize), &Address);\r
+  if (EFI_ERROR (Status)) {\r
+    Buf = NULL;\r
+  } else {\r
+    Buf = (VOID *)(UINTN) Address;\r
+  }\r
+  return Buf;\r
+}\r
+\r
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
new file mode 100644 (file)
index 0000000..24cd4a0
--- /dev/null
@@ -0,0 +1,70 @@
+## @file\r
+#  Debug Communication Library instance based on usb3 debug port.\r
+#\r
+#  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DebugCommunicationLibUsb3Pei\r
+  MODULE_UNI_FILE                = DebugCommunicationLibUsb3Pei.uni\r
+  FILE_GUID                      = 106C877F-C2BA-4c46-876C-BDFE6171CD7E\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = DebugCommunicationLib|PEIM PEI_CORE\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  DebugCommunicationLibUsb3Pei.c\r
+  DebugCommunicationLibUsb3Transfer.c\r
+  DebugCommunicationLibUsb3Common.c\r
+  DebugCommunicationLibUsb3Internal.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  SourceLevelDebugPkg/SourceLevelDebugPkg.dec\r
+\r
+[Pcd]\r
+  ## The memory BAR of ehci host controller, in which usb debug feature is enabled.\r
+  ## Note that the memory BAR address is only used before Pci bus resource allocation.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase          ## SOMETIMES_CONSUMES\r
+\r
+  ## The pci address of ehci host controller, in which usb debug feature is enabled.\r
+  ## The format of pci address please refer to SourceLevelDebugPkg.dec\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress               ## CONSUMES\r
+\r
+  ## Per XHCI spec, software shall impose a timeout between the detection of the Debug Host \r
+  ## connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout       ## SOMETIMES_CONSUMES\r
+\r
+  ## The value of data buffer size used for USB debug port handle.\r
+  ## It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|256   ## SOMETIMES_CONSUMES\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  PcdLib\r
+  IoLib\r
+  PciLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeiServicesLib\r
+  \r
+[Depex.common.PEIM]\r
+  gEfiPeiMemoryDiscoveredPpiGuid\r
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
new file mode 100644 (file)
index 0000000..074b686
Binary files /dev/null and b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni differ
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
new file mode 100644 (file)
index 0000000..73963e1
--- /dev/null
@@ -0,0 +1,606 @@
+/** @file\r
+  Debug Port Library implementation based on usb3 debug port.\r
+\r
+  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "DebugCommunicationLibUsb3Internal.h"\r
+\r
+/**\r
+  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Handle      Debug port handle.\r
+  @param  TrsRing     The transfer ring to sync.\r
+\r
+  @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncTrsRing (\r
+  IN USB3_DEBUG_PORT_HANDLE    *Handle,\r
+  IN TRANSFER_RING             *TrsRing\r
+  )\r
+{\r
+  UINTN               Index;\r
+  TRB_TEMPLATE        *TrsTrb;\r
+  UINT32              CycleBit;\r
+\r
+  ASSERT (TrsRing != NULL);\r
+\r
+  //\r
+  // Calculate the latest RingEnqueue and RingPCS\r
+  //\r
+  TrsTrb = (TRB_TEMPLATE *)(UINTN) TrsRing->RingEnqueue;\r
+\r
+  ASSERT (TrsTrb != NULL);\r
+  \r
+  for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
+    if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
+      break;\r
+    }\r
+    TrsTrb++;\r
+    if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
+      ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
+      //\r
+      // set cycle bit in Link TRB as normal\r
+      //\r
+      ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
+      //\r
+      // Toggle PCS maintained by software\r
+      //\r
+      TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
+      TrsTrb           = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);\r
+    }\r
+  }\r
+  ASSERT (Index != TrsRing->TrbNumber);\r
+\r
+  if ((EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb != TrsRing->RingEnqueue) {\r
+    TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) TrsTrb;\r
+  }\r
+\r
+  //\r
+  // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.\r
+  //\r
+  CycleBit = TrsTrb->CycleBit;\r
+  ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));\r
+  TrsTrb->CycleBit = CycleBit;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Handle      Debug port handle.\r
+  @param  EvtRing     The event ring to sync.\r
+\r
+  @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncEventRing (\r
+  IN USB3_DEBUG_PORT_HANDLE  *Handle,\r
+  IN EVENT_RING                *EvtRing\r
+  )\r
+{\r
+  UINTN               Index;\r
+  TRB_TEMPLATE        *EvtTrb1;\r
+\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  //\r
+  // Calculate the EventRingEnqueue and EventRingCCS.\r
+  // Note: only support single Segment\r
+  //\r
+  EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;\r
+\r
+  for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
+    if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
+      break;\r
+    }\r
+\r
+    EvtTrb1++;\r
+\r
+    if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+      EvtTrb1 = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingSeg0;\r
+      EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
+    }\r
+  }\r
+\r
+  if (Index < EvtRing->TrbNumber) {\r
+    EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;\r
+  } else {\r
+    ASSERT (FALSE);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if there is a new generated event.\r
+\r
+  @param  Handle        Debug port handle.\r
+  @param  EvtRing       The event ring to check.\r
+  @param  NewEvtTrb     The new event TRB found.\r
+\r
+  @retval EFI_SUCCESS   Found a new event TRB at the event ring.\r
+  @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcCheckNewEvent (\r
+  IN  USB3_DEBUG_PORT_HANDLE   *Handle,\r
+  IN  EVENT_RING               *EvtRing,\r
+  OUT TRB_TEMPLATE             **NewEvtTrb\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  TRB_TEMPLATE        *EvtTrb;\r
+\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  EvtTrb     = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;\r
+  *NewEvtTrb = (TRB_TEMPLATE *)(UINTN) EvtRing->EventRingDequeue;\r
+\r
+  if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);\r
+  //\r
+  // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
+  //\r
+  if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
+    EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check if the Trb is a transaction of the URB.\r
+\r
+  @param Ring   The transfer ring to be checked.\r
+  @param Trb    The TRB to be checked.\r
+\r
+  @retval TRUE  It is a transaction of the URB.\r
+  @retval FALSE It is not any transaction of the URB.\r
+\r
+**/\r
+BOOLEAN\r
+IsTrbInTrsRing (\r
+  IN  TRANSFER_RING       *Ring,\r
+  IN  TRB_TEMPLATE        *Trb\r
+  )\r
+{\r
+  TRB_TEMPLATE  *CheckedTrb;\r
+  UINTN         Index;\r
+  \r
+  CheckedTrb = (TRB_TEMPLATE *)(UINTN) Ring->RingSeg0;\r
+  \r
+  ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
+\r
+  for (Index = 0; Index < Ring->TrbNumber; Index++) {\r
+    if (Trb == CheckedTrb) {\r
+      return TRUE;\r
+    }\r
+    CheckedTrb++;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check the URB's execution result and update the URB's\r
+  result accordingly.\r
+\r
+  @param  Handle          Debug port handle.\r
+  @param  Urb             The URB to check result.\r
+\r
+**/\r
+VOID\r
+XhcCheckUrbResult (\r
+  IN  USB3_DEBUG_PORT_HANDLE *Handle,\r
+  IN  URB                      *Urb\r
+  )\r
+{\r
+  EVT_TRB_TRANSFER        *EvtTrb;\r
+  TRB_TEMPLATE            *TRBPtr;\r
+  UINTN                   Index;\r
+  EFI_STATUS              Status;\r
+  URB                     *CheckedUrb;\r
+  UINT64                  XhcDequeue;\r
+  UINT32                  High;\r
+  UINT32                  Low;\r
+  \r
+  ASSERT ((Handle != NULL) && (Urb != NULL));\r
+\r
+  if (Urb->Finished) {\r
+    goto EXIT;\r
+  }\r
+\r
+  EvtTrb = NULL;\r
+  \r
+  //\r
+  // Traverse the event ring to find out all new events from the previous check.\r
+  //\r
+  XhcSyncEventRing (Handle, &Handle->EventRing);\r
+  \r
+  for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {\r
+\r
+    Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
+    if (Status == EFI_NOT_READY) {\r
+      //\r
+      // All new events are handled, return directly.\r
+      //\r
+      goto EXIT;\r
+    }\r
+    \r
+    if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
+      continue;\r
+    }\r
+    \r
+    TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
+    \r
+    if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {\r
+      CheckedUrb = Urb;\r
+    } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {\r
+      //\r
+      // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.\r
+      // Internal buffer is used by next read.\r
+      //\r
+      Handle->DataCount = (UINT8) (Handle->UrbIn.DataLen - EvtTrb->Length);\r
+      CopyMem (Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);\r
+      //\r
+      // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.\r
+      //\r
+      TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;\r
+      continue;\r
+    } else {\r
+      continue;\r
+    }\r
+    \r
+    if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||\r
+        (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS)) {\r
+      //\r
+      // The length of data which were transferred.\r
+      //\r
+      CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Length);\r
+    } else {\r
+      CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;\r
+    }\r
+    //\r
+    // This Urb has been processed\r
+    //\r
+    CheckedUrb->Finished = TRUE;\r
+  }\r
+\r
+EXIT:\r
+  //\r
+  // Advance event ring to last available entry\r
+  //\r
+  // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+  // So divide it to two 32-bytes width register access.\r
+  //\r
+  Low  = XhcReadDebugReg (Handle, XHC_DC_DCERDP);\r
+  High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);\r
+  XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);\r
+\r
+  if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {\r
+    //\r
+    // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
+    // So divide it to two 32-bytes width register access.\r
+    //\r
+    XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));\r
+    XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));\r
+  }\r
+}\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+  @param  Handle        Debug port handle.\r
+  @param  Urb           The pointer to URB.\r
+\r
+  @retval EFI_SUCCESS   Successfully ring the door bell.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcRingDoorBell (\r
+  IN USB3_DEBUG_PORT_HANDLE    *Handle,\r
+  IN URB                       *Urb\r
+  )\r
+{\r
+  UINT32      Dcdb;\r
+\r
+  //\r
+  // 7.6.8.2 DCDB Register\r
+  //  \r
+  Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;\r
+  \r
+  XhcWriteDebugReg (\r
+    Handle,\r
+    XHC_DC_DCDB,\r
+    Dcdb\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+  @param  Handle            Debug port handle.\r
+  @param  Urb               The URB to execute.\r
+  @param  Timeout           The time to wait before abort, in microsecond.\r
+\r
+**/\r
+VOID\r
+XhcExecTransfer (\r
+  IN  USB3_DEBUG_PORT_HANDLE   *Handle,\r
+  IN  URB                      *Urb,\r
+  IN  UINTN                    Timeout\r
+  )\r
+{\r
+  TRANSFER_RING           *Ring;\r
+  UINT64                  Begin;\r
+  UINT64                  TimeoutTicker;\r
+  UINT64                  TimerRound;\r
+  TRB_TEMPLATE            *Trb;\r
+\r
+  Begin         = 0;\r
+  TimeoutTicker = 0;  \r
+  TimerRound    = 0;\r
+\r
+  XhcRingDoorBell (Handle, Urb);\r
+\r
+  if (Timeout != 0) {\r
+    Begin = GetPerformanceCounter ();\r
+    TimeoutTicker = DivU64x32 (\r
+                      MultU64x64 (\r
+                        Handle->TimerFrequency,\r
+                        Timeout\r
+                        ),\r
+                      1000000u\r
+                      );\r
+    TimerRound = DivU64x64Remainder (\r
+                   TimeoutTicker,\r
+                   DivU64x32 (Handle->TimerCycle, 2),\r
+                   &TimeoutTicker\r
+                   );\r
+  }\r
+\r
+  //\r
+  // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.\r
+  //\r
+  while (TRUE) {\r
+    if (Timeout != 0) {\r
+      if (TimerRound == 0) {\r
+        if (IsTimerTimeout (Handle, Begin, TimeoutTicker)) {\r
+          //\r
+          // If time out occurs.\r
+          //\r
+          Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+          break;\r
+        }\r
+      } else {\r
+        if (IsTimerTimeout (Handle, Begin, DivU64x32 (Handle->TimerCycle, 2))) {\r
+          TimerRound --;\r
+        }\r
+      }\r
+    }\r
+    XhcCheckUrbResult (Handle, Urb);\r
+    if (Urb->Finished) {\r
+      break;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // If URB transfer is error, restore transfer ring to original value before URB transfer\r
+  // This will make the current transfer TRB is always at the latest unused one in transfer ring.\r
+  //\r
+  Ring = (TRANSFER_RING *)(UINTN) Urb->Ring;\r
+  if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {\r
+    //\r
+    // Adjust Enqueue pointer\r
+    //\r
+    Ring->RingEnqueue = Urb->Trb;\r
+    //\r
+    // Clear CCS flag for next use\r
+    //\r
+    Trb = (TRB_TEMPLATE *)(UINTN) Urb->Trb;\r
+    Trb->CycleBit = ((~Ring->RingPCS) & BIT0);\r
+  } else {\r
+    //\r
+    // Update transfer ring for next transfer.\r
+    //\r
+    XhcSyncTrsRing (Handle, Ring);\r
+  }\r
+}\r
+\r
+/**\r
+  Create a transfer TRB.\r
+\r
+  @param  Handle  Debug port handle.\r
+  @param  Urb     The urb used to construct the transfer TRB.\r
+\r
+  @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcCreateTransferTrb (\r
+  IN USB3_DEBUG_PORT_HANDLE   *Handle,\r
+  IN URB                        *Urb\r
+  )\r
+{\r
+  TRANSFER_RING                 *EPRing;\r
+  TRB                           *Trb;\r
+\r
+  if (Urb->Direction == EfiUsbDataIn) {\r
+    EPRing = &Handle->TransferRingIn;\r
+  } else {\r
+    EPRing = &Handle->TransferRingOut;\r
+  }\r
+  \r
+  Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN) EPRing;\r
+  XhcSyncTrsRing (Handle, EPRing);\r
+\r
+  Urb->Trb = EPRing->RingEnqueue;\r
+  Trb = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+  Trb = (TRB *)(UINTN)EPRing->RingEnqueue;\r
+  Trb->TrbNormal.TRBPtrLo  = XHC_LOW_32BIT (Urb->Data);\r
+  Trb->TrbNormal.TRBPtrHi  = XHC_HIGH_32BIT (Urb->Data);\r
+  Trb->TrbNormal.Length    = Urb->DataLen;\r
+  Trb->TrbNormal.TDSize    = 0;\r
+  Trb->TrbNormal.IntTarget = 0;\r
+  Trb->TrbNormal.ISP       = 1;\r
+  Trb->TrbNormal.IOC       = 1;\r
+  Trb->TrbNormal.Type      = TRB_TYPE_NORMAL;\r
+  \r
+  //\r
+  // Update the cycle bit to indicate this TRB has been consumed.\r
+  //\r
+  Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a new URB for a new transaction.\r
+\r
+  @param  Handle     Debug port handle.\r
+  @param  Direction  The direction of data flow.\r
+  @param  Data       The user data to transfer\r
+  @param  DataLen    The length of data buffer\r
+\r
+  @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcCreateUrb (\r
+  IN USB3_DEBUG_PORT_HANDLE             *Handle,\r
+  IN EFI_USB_DATA_DIRECTION             Direction,\r
+  IN VOID                               *Data,\r
+  IN UINTN                              DataLen\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  URB                           *Urb;\r
+  EFI_PHYSICAL_ADDRESS          UrbData;\r
+  \r
+  if (Direction == EfiUsbDataIn) {\r
+    Urb = &Handle->UrbIn;\r
+  } else {\r
+    Urb = &Handle->UrbOut;\r
+  }\r
+\r
+  UrbData  = Urb->Data;\r
+  \r
+  ZeroMem (Urb, sizeof (URB));\r
+  Urb->Direction = Direction;\r
+  \r
+  //\r
+  // Allocate memory to move data from CAR or SMRAM to normal memory\r
+  // to make XHCI DMA successfully\r
+  // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready\r
+  //\r
+  Urb->Data  = UrbData;\r
+  \r
+  if (Direction == EfiUsbDataIn) {\r
+    //\r
+    // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC\r
+    //\r
+    Urb->DataLen  = (UINT32) DataLen;\r
+  } else {\r
+    //\r
+    // Put data into URB data out buffer which will create TRBs\r
+    //\r
+    ZeroMem ((VOID*)(UINTN) Urb->Data, DataLen);\r
+    CopyMem ((VOID*)(UINTN) Urb->Data, Data, DataLen);\r
+    Urb->DataLen  = (UINT32) DataLen;\r
+  }\r
+  \r
+  Status = XhcCreateTransferTrb (Handle, Urb);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Urb;\r
+}\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  @param  Handle                Debug port handle.\r
+  @param  Direction             The direction of data transfer.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit\r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  Timeout               Indicates the maximum time, in microsecond, which\r
+                                the transfer is allowed to complete.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDataTransfer (\r
+  IN     USB3_DEBUG_PORT_HANDLE              *Handle,\r
+  IN     EFI_USB_DATA_DIRECTION              Direction,\r
+  IN OUT VOID                                *Data,\r
+  IN OUT UINTN                               *DataLength,\r
+  IN     UINTN                               Timeout\r
+  )\r
+{\r
+  URB                     *Urb;\r
+  EFI_STATUS              Status;\r
+  \r
+  //\r
+  // Validate the parameters\r
+  //\r
+  if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  //\r
+  Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);\r
+  ASSERT (Urb != NULL);\r
+\r
+  XhcExecTransfer (Handle, Urb, Timeout);\r
+\r
+  *DataLength     = Urb->Completed;\r
+\r
+  Status = EFI_TIMEOUT;\r
+  if (Urb->Result == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  \r
+  if (Direction == EfiUsbDataIn) {\r
+    //\r
+    // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)\r
+    // SMRAM does not allow to do DMA, so we create an internal buffer.\r
+    //\r
+    CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
index 5c28e2934e1cbe98442d02ded85b713e9bf87fc3..e634ca7638fdae004c96dc1f7b0053751cb153fe 100644 (file)
   # @Prompt Assign debug port buffer size.\r
   gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|0x0|UINT16|0x00000006\r
 \r
+  ## The memory BAR of xhci host controller, in which usb debug feature is enabled.\r
+  ## Note that the memory BAR address is only used before Pci bus resource allocation.\r
+  # @Prompt Configure ehci host controller memory BAR.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase|0xD0000000|UINT64|0x00000007\r
+  \r
+  ## The pci address of xhci host controller, in which usb debug feature is enabled.\r
+  #  The format of pci address is :<BR>\r
+  #      -----------------------------------------------------------------------<BR>\r
+  #      | Bits 28..31 | Bits 20..27 | Bits 15..19 | Bits 12..14 | Bits 00..11 |<BR>\r
+  #      -----------------------------------------------------------------------<BR>\r
+  #      |      0      |     Bus     |   Device    |   Function  |      0      |<BR>\r
+  #      -----------------------------------------------------------------------<BR>\r
+  #  For the value 0x000A0000, it means the pci address at bus 0x0, device 0x14, function 0x0.\r
+  # @Prompt Configure xhci host controller pci address.\r
+  # @Expression  0x80000001 | (gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress & 0xF0000FFF) == 0\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress|0x000A0000|UINT32|0x00000008\r
+  \r
+  ## Per XHCI spec, software shall impose a timeout between the detection of the Debug Host \r
+  ## connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.\r
+  # @Prompt Configure debug device detection timeout value.\r
+  gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout|3000000|UINT64|0x00000009\r
+\r
 [UserExtensions.TianoCore."ExtraFiles"]\r
   SourceLevelDebugPkgExtra.uni\r
index a7be9ad51c3ec6d09d14dfe25e8f68ca3be6a816..7f17cd37c1d4068dee9484abe580892f49345fbe 100644 (file)
 !ifdef $(SOURCE_DEBUG_USE_USB)\r
   DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf\r
 !else\r
+!ifndef $(SOURCE_DEBUG_USE_USB3)\r
   DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf\r
 !endif\r
+!endif\r
 \r
 [LibraryClasses.common.PEIM]\r
   PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
@@ -61,6 +63,9 @@
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf\r
+!ifdef $(SOURCE_DEBUG_USE_USB3)\r
+  DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf\r
+!endif\r
 \r
 [LibraryClasses.common.DXE_DRIVER]\r
   UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
@@ -71,6 +76,9 @@
   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
   DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf\r
+!ifdef $(SOURCE_DEBUG_USE_USB3)\r
+  DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf\r
+!endif\r
 \r
 ###################################################################################################\r
 #\r