summaryrefslogtreecommitdiff
path: root/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3
diff options
context:
space:
mode:
Diffstat (limited to 'SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3')
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c2302
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c1072
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf148
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni32
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h1474
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c548
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf138
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni32
-rw-r--r--SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c1168
9 files changed, 3457 insertions, 3457 deletions
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
index 3a3d16e4b9..cc25b2ff34 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Common.c
@@ -1,1151 +1,1151 @@
-/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DebugCommunicationLibUsb3Internal.h"
-
-UINT16 mString0Desc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + STRING0_DESC_LEN,
- 0x0409
-};
-
-UINT16 mManufacturerStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + MANU_DESC_LEN,
- 'I', 'n','t', 'e', 'l'
-};
-
-UINT16 mProductStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + PRODUCT_DESC_LEN,
- 'U', 'S','B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
-};
-
-UINT16 mSerialNumberStrDesc[] = {
- // String Descriptor Type + Length
- (USB_DESC_TYPE_STRING << 8) + SERIAL_DESC_LEN,
- '1'
-};
-
-/**
- Sets bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcSetR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- )
-{
- UINT32 RegisterValue;
-
- RegisterValue = MmioRead32 (Register);
- RegisterValue |= (UINT32)(BitMask);
- MmioWrite32 (Register, RegisterValue);
-}
-
-/**
- Clears bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcClearR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- )
-{
- UINT32 RegisterValue;
-
- RegisterValue = MmioRead32 (Register);
- RegisterValue &= ~BitMask;
- MmioWrite32 (Register, RegisterValue);
-}
-
-/**
- Write the data to the XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Data The data to write.
-
-**/
-VOID
-XhcWriteDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Data
- )
-{
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- DebugCapabilityBase = Handle->DebugCapabilityBase;
- MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
-
- return;
-}
-
-/**
- Read XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the runtime register.
-
- @return The register content read
-
-**/
-UINT32
-XhcReadDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset
- )
-{
- UINT32 Data;
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- DebugCapabilityBase = Handle->DebugCapabilityBase;
- Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
-
- return Data;
-}
-
-/**
- Set one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to set.
-
-**/
-VOID
-XhcSetDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- )
-{
- UINT32 Data;
-
- Data = XhcReadDebugReg (Handle, Offset);
- Data |= Bit;
- XhcWriteDebugReg (Handle, Offset, Data);
-}
-
-/**
- Clear one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to clear.
-
-**/
-VOID
-XhcClearDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- )
-{
- UINT32 Data;
-
- Data = XhcReadDebugReg (Handle, Offset);
- Data &= ~Bit;
- XhcWriteDebugReg (Handle, Offset, Data);
-}
-
-/**
- Program and enable XHCI MMIO base address.
-
- @return XHCI MMIO base address.
-
-**/
-EFI_PHYSICAL_ADDRESS
-ProgramXhciBaseAddress (
- VOID
- )
-{
- UINT16 PciCmd;
- UINT32 Low;
- UINT32 High;
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- Low = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
- High = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);
- XhciMmioBase = (EFI_PHYSICAL_ADDRESS)(LShiftU64 ((UINT64)High, 32) | Low);
- XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;
-
- if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
- XhciMmioBase = PcdGet64 (PcdUsbXhciMemorySpaceBase);
- PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);
- PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));
- }
-
- PciCmd = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);
- if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
- PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
- PciWrite16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
- }
-
- return XhciMmioBase;
-}
-
-/**
- Update XHC MMIO base address when MMIO base address is changed.
-
- @param Handle Debug port handle.
- @param XhciMmioBase XHCI MMIO base address.
-
-**/
-VOID
-UpdateXhcResource (
- IN OUT USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_PHYSICAL_ADDRESS XhciMmioBase
- )
-{
- if (Handle == NULL) {
- return;
- }
-
- //
- // Need fix Handle data according to new XHCI MMIO base address.
- //
- Handle->XhciMmioBase = XhciMmioBase;
- Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
- Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
-}
-
-/**
- Calculate the usb debug port bar address.
-
- @param Handle Debug port handle.
-
- @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability.
- @retval RETURN_SUCCESS Get bar and offset successfully.
-
-**/
-RETURN_STATUS
-EFIAPI
-CalculateUsbDebugPortMmioBase (
- USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- UINT16 VendorId;
- UINT16 DeviceId;
- UINT8 ProgInterface;
- UINT8 SubClassCode;
- UINT8 BaseCode;
- BOOLEAN Flag;
- UINT32 Capability;
- EFI_PHYSICAL_ADDRESS CapabilityPointer;
- UINT8 CapLength;
-
- if (Handle->Initialized != USB3DBG_UNINITIALIZED) {
- if (Handle->Initialized == USB3DBG_NO_DBG_CAB) {
- return RETURN_UNSUPPORTED;
- } else {
- return RETURN_SUCCESS;
- }
- }
-
- VendorId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
- DeviceId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
-
- if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
- goto Done;
- }
-
- ProgInterface = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
- SubClassCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
- BaseCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
-
- if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
- goto Done;
- }
-
- CapLength = MmioRead8 ((UINTN)Handle->XhciMmioBase);
-
- //
- // Get capability pointer from HCCPARAMS at offset 0x10
- //
- CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
-
- //
- // Search XHCI debug capability
- //
- Flag = FALSE;
- Capability = MmioRead32 ((UINTN)CapabilityPointer);
- while (TRUE) {
- if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
- Flag = TRUE;
- break;
- }
-
- if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
- //
- // Reach the end of capability list, quit
- //
- break;
- }
-
- CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
- Capability = MmioRead32 ((UINTN)CapabilityPointer);
- }
-
- if (!Flag) {
- goto Done;
- }
-
- //
- // USB3 debug capability is supported.
- //
- Handle->DebugCapabilityBase = CapabilityPointer;
- Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
- Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;
- Handle->DebugSupport = TRUE;
- Handle->Initialized = USB3DBG_DBG_CAB;
- return RETURN_SUCCESS;
-
-Done:
- Handle->Initialized = USB3DBG_NO_DBG_CAB;
- return RETURN_UNSUPPORTED;
-}
-
-/**
- Check if it needs to re-initialize usb debug port hardware.
-
- During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
- whether the usb debug port hardware configuration is changed. Such case can be triggered by
- Pci bus resource allocation and so on.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-BOOLEAN
-EFIAPI
-NeedReinitializeHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- BOOLEAN Result;
- volatile UINT32 Dcctrl;
-
- Result = FALSE;
-
- //
- // If DCE bit, it means USB3 debug is not enabled.
- //
- Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
- if ((Dcctrl & BIT0) == 0) {
- Result = TRUE;
- } else if (!Handle->Ready) {
- Handle->Ready = TRUE;
- Handle->Initialized = USB3DBG_ENABLED;
- }
-
- return Result;
-}
-
-/**
- Create XHCI event ring.
-
- @param Handle Debug port handle.
- @param EventRing The created event ring.
-
-**/
-EFI_STATUS
-CreateEventRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- OUT EVENT_RING *EventRing
- )
-{
- VOID *Buf;
- EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
-
- ASSERT (EventRing != NULL);
-
- //
- // Allocate Event Ring
- //
- Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0x3F) == 0);
- ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
-
- EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
- EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
- EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
- EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
-
- //
- // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
- // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
- //
- EventRing->EventRingCCS = 1;
-
- //
- // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
- //
- Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0x3F) == 0);
- ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
-
- ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;
- EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ERSTBase;
-
- //
- // Fill Event Segment address
- //
- ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
- ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
- ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
-
- //
- // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERDP,
- XHC_LOW_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERDP + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
- );
-
- //
- // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTBA,
- XHC_LOW_32BIT ((UINT64)(UINTN)ERSTBase)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTBA + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTBase)
- );
-
- //
- // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCERSTSZ,
- ERST_NUMBER
- );
- return EFI_SUCCESS;
-}
-
-/**
- Create XHCI transfer ring.
-
- @param Handle Debug port handle.
- @param TrbNum The number of TRB in the ring.
- @param TransferRing The created transfer ring.
-
-**/
-VOID
-CreateTransferRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 TrbNum,
- OUT TRANSFER_RING *TransferRing
- )
-{
- VOID *Buf;
- LINK_TRB *EndTrb;
-
- Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0xF) == 0);
- ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
-
- TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
- TransferRing->TrbNumber = TrbNum;
- TransferRing->RingEnqueue = TransferRing->RingSeg0;
- TransferRing->RingDequeue = TransferRing->RingSeg0;
- TransferRing->RingPCS = 1;
- //
- // 4.9.2 Transfer Ring Management
- // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
- // point to the first TRB in the ring.
- //
- EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
- EndTrb->Type = TRB_TYPE_LINK;
- EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
- EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
- //
- // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
- //
- EndTrb->TC = 1;
- //
- // Set Cycle bit as other TRB PCS init value
- //
- EndTrb->CycleBit = 0;
-}
-
-/**
- Create debug capability context for XHC debug device.
-
- @param Handle Debug port handle.
-
- @retval EFI_SUCCESS The bit successfully changed by host controller.
- @retval EFI_TIMEOUT The time out occurred.
-
-**/
-EFI_STATUS
-CreateDebugCapabilityContext (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- VOID *Buf;
- XHC_DC_CONTEXT *DebugCapabilityContext;
- UINT8 *String0Desc;
- UINT8 *ManufacturerStrDesc;
- UINT8 *ProductStrDesc;
- UINT8 *SerialNumberStrDesc;
-
- //
- // Allocate debug device context
- //
- Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
- ASSERT (Buf != NULL);
- ASSERT (((UINTN)Buf & 0xF) == 0);
- ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
-
- DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN)Buf;
- Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN)DebugCapabilityContext;
-
- //
- // Initialize DbcInfoContext.
- //
- DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;
- DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
-
- //
- // Initialize EpOutContext.
- //
- DebugCapabilityContext->EpOutContext.CErr = 0x3;
- DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;
- DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
-
- //
- // Initialize EpInContext.
- //
- DebugCapabilityContext->EpInContext.CErr = 0x3;
- DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;
- DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
-
- //
- // Update string descriptor address
- //
- String0Desc = (UINT8 *)AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
- ASSERT (String0Desc != NULL);
- ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
- CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
-
- ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
- CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
-
- ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
- CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
-
- SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
- CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
- DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
-
- //
- // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
- //
- ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
- CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
- DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
- DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
-
- //
- // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
- //
- ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
- CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
- DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
- DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
-
- //
- // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCCP,
- XHC_LOW_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
- );
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCCP + 4,
- XHC_HIGH_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
- );
- return EFI_SUCCESS;
-}
-
-/**
- Check if debug device is running.
-
- @param Handle Debug port handle.
-
-**/
-VOID
-XhcDetectDebugCapabilityReady (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- UINT64 TimeOut;
- volatile UINT32 Dcctrl;
-
- TimeOut = 1;
- if (Handle->Initialized == USB3DBG_DBG_CAB) {
- //
- // As detection is slow in seconds, wait for longer timeout for the first time.
- // If first initialization is failed, we will try to enable debug device in the
- // Poll function invoked by timer.
- //
- TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
- }
-
- do {
- //
- // Check if debug device is in configured state
- //
- Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
- if ((Dcctrl & BIT0) != 0) {
- //
- // Set the flag to indicate debug device is in configured state
- //
- Handle->Ready = TRUE;
- break;
- }
-
- MicroSecondDelay (XHC_POLL_DELAY);
- TimeOut--;
- } while (TimeOut != 0);
-}
-
-/**
- Initialize usb debug port hardware.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-RETURN_STATUS
-EFIAPI
-InitializeUsbDebugHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- RETURN_STATUS Status;
- UINT8 *Buffer;
- UINTN Index;
- UINT8 TotalUsb3Port;
- EFI_PHYSICAL_ADDRESS XhciOpRegister;
- UINT32 Dcddi1;
-
- XhciOpRegister = Handle->XhciOpRegister;
- TotalUsb3Port = MmioRead32 (((UINTN)Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
-
- if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
- Dcddi1 = XhcReadDebugReg (Handle, XHC_DC_DCDDI1);
- if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) {
- //
- // The debug capability has been reset by other code, return device error.
- //
- return EFI_DEVICE_ERROR;
- }
-
- //
- // If XHCI supports debug capability, hardware resource has been allocated,
- // but it has not been enabled, try to enable again.
- //
- goto Enable;
- }
-
- //
- // Initialize for PEI phase when AllocatePages can work.
- // Allocate data buffer with max packet size for data read and data poll.
- // Allocate data buffer for data write.
- //
- Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
- if (Buffer == NULL) {
- //
- // AllocatePages can not still work now, return fail and do not initialize now.
- //
- return RETURN_NOT_READY;
- }
-
- //
- // Reset port to get debug device discovered
- //
- for (Index = 0; Index < TotalUsb3Port; Index++) {
- XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
- MicroSecondDelay (10 * 1000);
- }
-
- //
- // Clear DCE bit and LSE bit in DCCTRL
- //
- if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
- XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
- }
-
- //
- // Construct the buffer for read, poll and write.
- //
- Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
- Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
-
- //
- // Initialize event ring
- //
- ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
- Status = CreateEventRing (Handle, &Handle->EventRing);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Init IN and OUT endpoint context
- //
- Status = CreateDebugCapabilityContext (Handle);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Init DCDDI1 and DCDDI2
- //
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDDI1,
- (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
- );
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDDI2,
- (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
- );
-
-Enable:
- if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
- //
- // If the first time detection is failed, turn port power off and on in order to
- // reset port status this time, then try to check if debug device is ready again.
- //
- for (Index = 0; Index < TotalUsb3Port; Index++) {
- XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
- MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
- XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
- MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
- Handle->ChangePortPower = TRUE;
- }
- }
-
- //
- // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
- //
- XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
-
- XhcDetectDebugCapabilityReady (Handle);
-
- Status = RETURN_SUCCESS;
- if (!Handle->Ready) {
- Handle->Initialized = USB3DBG_NOT_ENABLED;
- Status = RETURN_NOT_READY;
- } else {
- Handle->Initialized = USB3DBG_ENABLED;
- }
-
- return Status;
-}
-
-/**
- Discover and initialize usb debug port.
-
- @param Handle Debug port handle.
-
-**/
-VOID
-DiscoverInitializeUsbDebugPort (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- //
- // Read 64-bit MMIO base address
- //
- XhciMmioBase = ProgramXhciBaseAddress ();
- Handle->XhciMmioBase = XhciMmioBase;
-
- Status = CalculateUsbDebugPortMmioBase (Handle);
- if (!RETURN_ERROR (Status)) {
- UpdateXhcResource (Handle, XhciMmioBase);
- if (NeedReinitializeHardware (Handle)) {
- InitializeUsbDebugHardware (Handle);
- }
- }
-}
-
-/**
- Set USB3 debug instance address.
-
- @param[in] Instance Debug port instance.
-
-**/
-VOID
-SetUsb3DebugPortInstance (
- IN USB3_DEBUG_PORT_HANDLE *Instance
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
-
- AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
- ASSERT (AddrPtr != NULL);
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
-}
-
-/**
- Return USB3 debug instance address.
-
-**/
-USB3_DEBUG_PORT_HANDLE *
-GetUsb3DebugPortInstance (
- VOID
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
- ASSERT (AddrPtr != NULL);
-
- Instance = (USB3_DEBUG_PORT_HANDLE *)(UINTN)*AddrPtr;
-
- return Instance;
-}
-
-/**
- Read data from debug device and save the data in buffer.
-
- Reads NumberOfBytes data bytes from a debug device into the buffer
- specified by Buffer. The number of bytes actually read is returned.
- If the return value is less than NumberOfBytes, then the rest operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to store the data read from the debug device.
- @param NumberOfBytes Number of bytes which will be read.
- @param Timeout Timeout value for reading from debug device. Its unit is Microsecond.
-
- @retval 0 Read data failed, no data is to be read.
- @retval >0 Actual number of bytes read from debug device.
-
-**/
-UINTN
-EFIAPI
-DebugPortReadBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes,
- IN UINTN Timeout
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINT8 Index;
- UINT8 *Data;
-
- if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) {
- return 0;
- }
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return 0;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return 0;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return 0;
- }
-
- Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
-
- //
- // Read data from buffer
- //
- if (UsbDebugPortHandle->DataCount < 1) {
- return 0;
- } else {
- *Buffer = Data[0];
-
- for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
- if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
- return 0;
- }
-
- Data[Index] = Data[Index + 1];
- }
-
- UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
- return 1;
- }
-}
-
-/**
- Write data from buffer to debug device.
-
- Writes NumberOfBytes data bytes from Buffer to the debug device.
- The number of bytes actually written to the debug device is returned.
- If the return value is less than NumberOfBytes, then the write operation failed.
- If NumberOfBytes is zero, then return 0.
-
- @param Handle Debug port handle.
- @param Buffer Pointer to the data buffer to be written.
- @param NumberOfBytes Number of bytes to written to the debug device.
-
- @retval 0 NumberOfBytes is 0.
- @retval >0 The number of bytes written to the debug device.
- If this value is less than NumberOfBytes, then the write operation failed.
-
-**/
-UINTN
-EFIAPI
-DebugPortWriteBuffer (
- IN DEBUG_PORT_HANDLE Handle,
- IN UINT8 *Buffer,
- IN UINTN NumberOfBytes
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINTN Sent;
- UINTN Total;
-
- if ((NumberOfBytes == 0) || (Buffer == NULL)) {
- return 0;
- }
-
- Sent = 0;
- Total = 0;
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return 0;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return 0;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return 0;
- }
-
- //
- // When host is trying to send data, write will be blocked.
- // Poll to see if there is any data sent by host at first.
- //
- DebugPortPollBuffer (UsbDebugPortHandle);
-
- while ((Total < NumberOfBytes)) {
- if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
- Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
- } else {
- Sent = (UINT8)(NumberOfBytes - Total);
- }
-
- XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
- Total += Sent;
- }
-
- return Total;
-}
-
-/**
- Polls a debug device to see if there is any data waiting to be read.
-
- Polls a debug device to see if there is any data waiting to be read.
- If there is data waiting to be read from the debug device, then TRUE is returned.
- If there is no data waiting to be read from the debug device, then FALSE is returned.
-
- @param Handle Debug port handle.
-
- @retval TRUE Data is waiting to be read from the debug device.
- @retval FALSE There is no data waiting to be read from the debug device.
-
-**/
-BOOLEAN
-EFIAPI
-DebugPortPollBuffer (
- IN DEBUG_PORT_HANDLE Handle
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
- UINTN Length;
-
- //
- // If Handle is NULL, get own instance.
- // If Handle is not NULL, use it and set the instance.
- //
- if (Handle != NULL) {
- UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
- SetUsb3DebugPortInstance (UsbDebugPortHandle);
- } else {
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- }
-
- if (UsbDebugPortHandle == NULL) {
- return FALSE;
- }
-
- if (UsbDebugPortHandle->InNotify) {
- return FALSE;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
- return FALSE;
- }
-
- //
- // If the data buffer is not empty, then return TRUE directly.
- // Otherwise initialize a usb read transaction and read data to internal data buffer.
- //
- if (UsbDebugPortHandle->DataCount != 0) {
- return TRUE;
- }
-
- //
- // Read data as much as we can
- //
- Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
- XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
-
- if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
- return FALSE;
- }
-
- if (Length == 0) {
- return FALSE;
- }
-
- //
- // Store data into internal buffer for use later
- //
- UsbDebugPortHandle->DataCount = (UINT8)Length;
- return TRUE;
-}
-
-/**
- Initialize the debug port.
-
- If Function is not NULL, Debug Communication Library will call this function
- by passing in the Context to be the first parameter. If needed, Debug Communication
- Library will create one debug port handle to be the second argument passing in
- calling the Function, otherwise it will pass NULL to be the second argument of
- Function.
-
- If Function is NULL, and Context is not NULL, the Debug Communication Library could
- a) Return the same handle as passed in (as Context parameter).
- b) Ignore the input Context parameter and create new handle to be returned.
-
- If parameter Function is NULL and Context is NULL, Debug Communication Library could
- created a new handle if needed and return it, otherwise it will return NULL.
-
- @param[in] Context Context needed by callback function; it was optional.
- @param[in] Function Continue function called by Debug Communication library;
- it was optional.
-
- @return The debug port handle created by Debug Communication Library if Function
- is not NULL.
-
-**/
-DEBUG_PORT_HANDLE
-EFIAPI
-DebugPortInitialize (
- IN VOID *Context,
- IN DEBUG_PORT_CONTINUE Function
- )
-{
- USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
-
- //
- // Validate the PCD PcdDebugPortHandleBufferSize value
- //
- ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
-
- if ((Function == NULL) && (Context != NULL)) {
- SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *)Context);
- return (DEBUG_PORT_HANDLE)Context;
- }
-
- UsbDebugPortHandle = GetUsb3DebugPortInstance ();
- if (UsbDebugPortHandle == NULL) {
- return NULL;
- }
-
- DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
-
- if (Function != NULL) {
- Function (Context, (DEBUG_PORT_HANDLE)UsbDebugPortHandle);
- }
-
- return (DEBUG_PORT_HANDLE)UsbDebugPortHandle;
-}
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DebugCommunicationLibUsb3Internal.h"
+
+UINT16 mString0Desc[] = {
+ // String Descriptor Type + Length
+ (USB_DESC_TYPE_STRING << 8) + STRING0_DESC_LEN,
+ 0x0409
+};
+
+UINT16 mManufacturerStrDesc[] = {
+ // String Descriptor Type + Length
+ (USB_DESC_TYPE_STRING << 8) + MANU_DESC_LEN,
+ 'I', 'n','t', 'e', 'l'
+};
+
+UINT16 mProductStrDesc[] = {
+ // String Descriptor Type + Length
+ (USB_DESC_TYPE_STRING << 8) + PRODUCT_DESC_LEN,
+ 'U', 'S','B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
+};
+
+UINT16 mSerialNumberStrDesc[] = {
+ // String Descriptor Type + Length
+ (USB_DESC_TYPE_STRING << 8) + SERIAL_DESC_LEN,
+ '1'
+};
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit (
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue |= (UINT32)(BitMask);
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClearR32Bit (
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ )
+{
+ UINT32 RegisterValue;
+
+ RegisterValue = MmioRead32 (Register);
+ RegisterValue &= ~BitMask;
+ MmioWrite32 (Register, RegisterValue);
+}
+
+/**
+ Write the data to the XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Handle->DebugCapabilityBase;
+ MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
+
+ return;
+}
+
+/**
+ Read XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the runtime register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ DebugCapabilityBase = Handle->DebugCapabilityBase;
+ Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
+
+ return Data;
+}
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Handle, Offset);
+ Data |= Bit;
+ XhcWriteDebugReg (Handle, Offset, Data);
+}
+
+/**
+ Clear one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to clear.
+
+**/
+VOID
+XhcClearDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ )
+{
+ UINT32 Data;
+
+ Data = XhcReadDebugReg (Handle, Offset);
+ Data &= ~Bit;
+ XhcWriteDebugReg (Handle, Offset, Data);
+}
+
+/**
+ Program and enable XHCI MMIO base address.
+
+ @return XHCI MMIO base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+ProgramXhciBaseAddress (
+ VOID
+ )
+{
+ UINT16 PciCmd;
+ UINT32 Low;
+ UINT32 High;
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ Low = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
+ High = PciRead32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);
+ XhciMmioBase = (EFI_PHYSICAL_ADDRESS)(LShiftU64 ((UINT64)High, 32) | Low);
+ XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;
+
+ if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
+ XhciMmioBase = PcdGet64 (PcdUsbXhciMemorySpaceBase);
+ PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);
+ PciWrite32 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));
+ }
+
+ PciCmd = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);
+ if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
+ PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
+ PciWrite16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
+ }
+
+ return XhciMmioBase;
+}
+
+/**
+ Update XHC MMIO base address when MMIO base address is changed.
+
+ @param Handle Debug port handle.
+ @param XhciMmioBase XHCI MMIO base address.
+
+**/
+VOID
+UpdateXhcResource (
+ IN OUT USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_PHYSICAL_ADDRESS XhciMmioBase
+ )
+{
+ if (Handle == NULL) {
+ return;
+ }
+
+ //
+ // Need fix Handle data according to new XHCI MMIO base address.
+ //
+ Handle->XhciMmioBase = XhciMmioBase;
+ Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
+ Handle->XhciOpRegister = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
+}
+
+/**
+ Calculate the usb debug port bar address.
+
+ @param Handle Debug port handle.
+
+ @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability.
+ @retval RETURN_SUCCESS Get bar and offset successfully.
+
+**/
+RETURN_STATUS
+EFIAPI
+CalculateUsbDebugPortMmioBase (
+ USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 ProgInterface;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+ BOOLEAN Flag;
+ UINT32 Capability;
+ EFI_PHYSICAL_ADDRESS CapabilityPointer;
+ UINT8 CapLength;
+
+ if (Handle->Initialized != USB3DBG_UNINITIALIZED) {
+ if (Handle->Initialized == USB3DBG_NO_DBG_CAB) {
+ return RETURN_UNSUPPORTED;
+ } else {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ VendorId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
+ DeviceId = PciRead16 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
+
+ if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
+ goto Done;
+ }
+
+ ProgInterface = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
+ SubClassCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
+ BaseCode = PciRead8 (PcdGet32 (PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
+
+ if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
+ goto Done;
+ }
+
+ CapLength = MmioRead8 ((UINTN)Handle->XhciMmioBase);
+
+ //
+ // Get capability pointer from HCCPARAMS at offset 0x10
+ //
+ CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
+
+ //
+ // Search XHCI debug capability
+ //
+ Flag = FALSE;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ while (TRUE) {
+ if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
+ Flag = TRUE;
+ break;
+ }
+
+ if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
+ //
+ // Reach the end of capability list, quit
+ //
+ break;
+ }
+
+ CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
+ Capability = MmioRead32 ((UINTN)CapabilityPointer);
+ }
+
+ if (!Flag) {
+ goto Done;
+ }
+
+ //
+ // USB3 debug capability is supported.
+ //
+ Handle->DebugCapabilityBase = CapabilityPointer;
+ Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
+ Handle->XhciOpRegister = Handle->XhciMmioBase + CapLength;
+ Handle->DebugSupport = TRUE;
+ Handle->Initialized = USB3DBG_DBG_CAB;
+ return RETURN_SUCCESS;
+
+Done:
+ Handle->Initialized = USB3DBG_NO_DBG_CAB;
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Check if it needs to re-initialize usb debug port hardware.
+
+ During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
+ whether the usb debug port hardware configuration is changed. Such case can be triggered by
+ Pci bus resource allocation and so on.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+BOOLEAN
+EFIAPI
+NeedReinitializeHardware (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ BOOLEAN Result;
+ volatile UINT32 Dcctrl;
+
+ Result = FALSE;
+
+ //
+ // If DCE bit, it means USB3 debug is not enabled.
+ //
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) == 0) {
+ Result = TRUE;
+ } else if (!Handle->Ready) {
+ Handle->Ready = TRUE;
+ Handle->Initialized = USB3DBG_ENABLED;
+ }
+
+ return Result;
+}
+
+/**
+ Create XHCI event ring.
+
+ @param Handle Debug port handle.
+ @param EventRing The created event ring.
+
+**/
+EFI_STATUS
+CreateEventRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ OUT EVENT_RING *EventRing
+ )
+{
+ VOID *Buf;
+ EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
+
+ ASSERT (EventRing != NULL);
+
+ //
+ // Allocate Event Ring
+ //
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN)Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
+
+ EventRing->EventRingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
+ EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
+ EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
+ EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EventRing->EventRingSeg0;
+
+ //
+ // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
+ // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
+ //
+ EventRing->EventRingCCS = 1;
+
+ //
+ // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
+ //
+ Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN)Buf & 0x3F) == 0);
+ ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
+
+ ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;
+ EventRing->ERSTBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ERSTBase;
+
+ //
+ // Fill Event Segment address
+ //
+ ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
+ ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
+
+ //
+ // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERDP,
+ XHC_LOW_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERDP + 4,
+ XHC_HIGH_32BIT ((UINT64)(UINTN)EventRing->EventRingDequeue)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTBA,
+ XHC_LOW_32BIT ((UINT64)(UINTN)ERSTBase)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTBA + 4,
+ XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTBase)
+ );
+
+ //
+ // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCERSTSZ,
+ ERST_NUMBER
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Create XHCI transfer ring.
+
+ @param Handle Debug port handle.
+ @param TrbNum The number of TRB in the ring.
+ @param TransferRing The created transfer ring.
+
+**/
+VOID
+CreateTransferRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 TrbNum,
+ OUT TRANSFER_RING *TransferRing
+ )
+{
+ VOID *Buf;
+ LINK_TRB *EndTrb;
+
+ Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN)Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
+
+ TransferRing->RingSeg0 = (EFI_PHYSICAL_ADDRESS)(UINTN)Buf;
+ TransferRing->TrbNumber = TrbNum;
+ TransferRing->RingEnqueue = TransferRing->RingSeg0;
+ TransferRing->RingDequeue = TransferRing->RingSeg0;
+ TransferRing->RingPCS = 1;
+ //
+ // 4.9.2 Transfer Ring Management
+ // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
+ // point to the first TRB in the ring.
+ //
+ EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
+ EndTrb->Type = TRB_TYPE_LINK;
+ EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
+ EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
+ //
+ // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
+ //
+ EndTrb->TC = 1;
+ //
+ // Set Cycle bit as other TRB PCS init value
+ //
+ EndTrb->CycleBit = 0;
+}
+
+/**
+ Create debug capability context for XHC debug device.
+
+ @param Handle Debug port handle.
+
+ @retval EFI_SUCCESS The bit successfully changed by host controller.
+ @retval EFI_TIMEOUT The time out occurred.
+
+**/
+EFI_STATUS
+CreateDebugCapabilityContext (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ VOID *Buf;
+ XHC_DC_CONTEXT *DebugCapabilityContext;
+ UINT8 *String0Desc;
+ UINT8 *ManufacturerStrDesc;
+ UINT8 *ProductStrDesc;
+ UINT8 *SerialNumberStrDesc;
+
+ //
+ // Allocate debug device context
+ //
+ Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
+ ASSERT (Buf != NULL);
+ ASSERT (((UINTN)Buf & 0xF) == 0);
+ ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
+
+ DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN)Buf;
+ Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN)DebugCapabilityContext;
+
+ //
+ // Initialize DbcInfoContext.
+ //
+ DebugCapabilityContext->DbcInfoContext.String0Length = STRING0_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.ProductStrLength = PRODUCT_DESC_LEN;
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
+
+ //
+ // Initialize EpOutContext.
+ //
+ DebugCapabilityContext->EpOutContext.CErr = 0x3;
+ DebugCapabilityContext->EpOutContext.EPType = ED_BULK_OUT;
+ DebugCapabilityContext->EpOutContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
+
+ //
+ // Initialize EpInContext.
+ //
+ DebugCapabilityContext->EpInContext.CErr = 0x3;
+ DebugCapabilityContext->EpInContext.EPType = ED_BULK_IN;
+ DebugCapabilityContext->EpInContext.MaxPacketSize = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
+
+ //
+ // Update string descriptor address
+ //
+ String0Desc = (UINT8 *)AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ ASSERT (String0Desc != NULL);
+ ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
+ CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
+
+ ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
+ CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
+
+ ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
+ CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
+
+ SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
+ CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
+ DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
+
+ //
+ // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
+ //
+ ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
+ DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
+
+ //
+ // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
+ //
+ ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
+ CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
+ DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
+ DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
+
+ //
+ // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCCP,
+ XHC_LOW_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCCP + 4,
+ XHC_HIGH_32BIT ((UINT64)(UINTN)DebugCapabilityContext)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if debug device is running.
+
+ @param Handle Debug port handle.
+
+**/
+VOID
+XhcDetectDebugCapabilityReady (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ UINT64 TimeOut;
+ volatile UINT32 Dcctrl;
+
+ TimeOut = 1;
+ if (Handle->Initialized == USB3DBG_DBG_CAB) {
+ //
+ // As detection is slow in seconds, wait for longer timeout for the first time.
+ // If first initialization is failed, we will try to enable debug device in the
+ // Poll function invoked by timer.
+ //
+ TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
+ }
+
+ do {
+ //
+ // Check if debug device is in configured state
+ //
+ Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
+ if ((Dcctrl & BIT0) != 0) {
+ //
+ // Set the flag to indicate debug device is in configured state
+ //
+ Handle->Ready = TRUE;
+ break;
+ }
+
+ MicroSecondDelay (XHC_POLL_DELAY);
+ TimeOut--;
+ } while (TimeOut != 0);
+}
+
+/**
+ Initialize usb debug port hardware.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+RETURN_STATUS
+EFIAPI
+InitializeUsbDebugHardware (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ RETURN_STATUS Status;
+ UINT8 *Buffer;
+ UINTN Index;
+ UINT8 TotalUsb3Port;
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;
+ UINT32 Dcddi1;
+
+ XhciOpRegister = Handle->XhciOpRegister;
+ TotalUsb3Port = MmioRead32 (((UINTN)Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
+
+ if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
+ Dcddi1 = XhcReadDebugReg (Handle, XHC_DC_DCDDI1);
+ if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) {
+ //
+ // The debug capability has been reset by other code, return device error.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If XHCI supports debug capability, hardware resource has been allocated,
+ // but it has not been enabled, try to enable again.
+ //
+ goto Enable;
+ }
+
+ //
+ // Initialize for PEI phase when AllocatePages can work.
+ // Allocate data buffer with max packet size for data read and data poll.
+ // Allocate data buffer for data write.
+ //
+ Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
+ if (Buffer == NULL) {
+ //
+ // AllocatePages can not still work now, return fail and do not initialize now.
+ //
+ return RETURN_NOT_READY;
+ }
+
+ //
+ // Reset port to get debug device discovered
+ //
+ for (Index = 0; Index < TotalUsb3Port; Index++) {
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
+ MicroSecondDelay (10 * 1000);
+ }
+
+ //
+ // Clear DCE bit and LSE bit in DCCTRL
+ //
+ if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
+ XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
+ }
+
+ //
+ // Construct the buffer for read, poll and write.
+ //
+ Handle->UrbIn.Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ Handle->Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
+
+ //
+ // Initialize event ring
+ //
+ ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
+ Status = CreateEventRing (Handle, &Handle->EventRing);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init IN and OUT endpoint context
+ //
+ Status = CreateDebugCapabilityContext (Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init DCDDI1 and DCDDI2
+ //
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDDI1,
+ (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
+ );
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDDI2,
+ (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
+ );
+
+Enable:
+ if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
+ //
+ // If the first time detection is failed, turn port power off and on in order to
+ // reset port status this time, then try to check if debug device is ready again.
+ //
+ for (Index = 0; Index < TotalUsb3Port; Index++) {
+ XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
+ XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
+ MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
+ Handle->ChangePortPower = TRUE;
+ }
+ }
+
+ //
+ // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
+ //
+ XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
+
+ XhcDetectDebugCapabilityReady (Handle);
+
+ Status = RETURN_SUCCESS;
+ if (!Handle->Ready) {
+ Handle->Initialized = USB3DBG_NOT_ENABLED;
+ Status = RETURN_NOT_READY;
+ } else {
+ Handle->Initialized = USB3DBG_ENABLED;
+ }
+
+ return Status;
+}
+
+/**
+ Discover and initialize usb debug port.
+
+ @param Handle Debug port handle.
+
+**/
+VOID
+DiscoverInitializeUsbDebugPort (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ //
+ // Read 64-bit MMIO base address
+ //
+ XhciMmioBase = ProgramXhciBaseAddress ();
+ Handle->XhciMmioBase = XhciMmioBase;
+
+ Status = CalculateUsbDebugPortMmioBase (Handle);
+ if (!RETURN_ERROR (Status)) {
+ UpdateXhcResource (Handle, XhciMmioBase);
+ if (NeedReinitializeHardware (Handle)) {
+ InitializeUsbDebugHardware (Handle);
+ }
+ }
+}
+
+/**
+ Set USB3 debug instance address.
+
+ @param[in] Instance Debug port instance.
+
+**/
+VOID
+SetUsb3DebugPortInstance (
+ IN USB3_DEBUG_PORT_HANDLE *Instance
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+
+ AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
+ ASSERT (AddrPtr != NULL);
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
+}
+
+/**
+ Return USB3 debug instance address.
+
+**/
+USB3_DEBUG_PORT_HANDLE *
+GetUsb3DebugPortInstance (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
+ ASSERT (AddrPtr != NULL);
+
+ Instance = (USB3_DEBUG_PORT_HANDLE *)(UINTN)*AddrPtr;
+
+ return Instance;
+}
+
+/**
+ Read data from debug device and save the data in buffer.
+
+ Reads NumberOfBytes data bytes from a debug device into the buffer
+ specified by Buffer. The number of bytes actually read is returned.
+ If the return value is less than NumberOfBytes, then the rest operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to store the data read from the debug device.
+ @param NumberOfBytes Number of bytes which will be read.
+ @param Timeout Timeout value for reading from debug device. Its unit is Microsecond.
+
+ @retval 0 Read data failed, no data is to be read.
+ @retval >0 Actual number of bytes read from debug device.
+
+**/
+UINTN
+EFIAPI
+DebugPortReadBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN Timeout
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINT8 Index;
+ UINT8 *Data;
+
+ if ((NumberOfBytes != 1) || (Buffer == NULL) || (Timeout != 0)) {
+ return 0;
+ }
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+
+ if (UsbDebugPortHandle == NULL) {
+ return 0;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return 0;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return 0;
+ }
+
+ Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
+
+ //
+ // Read data from buffer
+ //
+ if (UsbDebugPortHandle->DataCount < 1) {
+ return 0;
+ } else {
+ *Buffer = Data[0];
+
+ for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
+ if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
+ return 0;
+ }
+
+ Data[Index] = Data[Index + 1];
+ }
+
+ UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
+ return 1;
+ }
+}
+
+/**
+ Write data from buffer to debug device.
+
+ Writes NumberOfBytes data bytes from Buffer to the debug device.
+ The number of bytes actually written to the debug device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+ If NumberOfBytes is zero, then return 0.
+
+ @param Handle Debug port handle.
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the debug device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the debug device.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+DebugPortWriteBuffer (
+ IN DEBUG_PORT_HANDLE Handle,
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINTN Sent;
+ UINTN Total;
+
+ if ((NumberOfBytes == 0) || (Buffer == NULL)) {
+ return 0;
+ }
+
+ Sent = 0;
+ Total = 0;
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+
+ if (UsbDebugPortHandle == NULL) {
+ return 0;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return 0;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return 0;
+ }
+
+ //
+ // When host is trying to send data, write will be blocked.
+ // Poll to see if there is any data sent by host at first.
+ //
+ DebugPortPollBuffer (UsbDebugPortHandle);
+
+ while ((Total < NumberOfBytes)) {
+ if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
+ Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
+ } else {
+ Sent = (UINT8)(NumberOfBytes - Total);
+ }
+
+ XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
+ Total += Sent;
+ }
+
+ return Total;
+}
+
+/**
+ Polls a debug device to see if there is any data waiting to be read.
+
+ Polls a debug device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the debug device, then TRUE is returned.
+ If there is no data waiting to be read from the debug device, then FALSE is returned.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE Data is waiting to be read from the debug device.
+ @retval FALSE There is no data waiting to be read from the debug device.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPortPollBuffer (
+ IN DEBUG_PORT_HANDLE Handle
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+ UINTN Length;
+
+ //
+ // If Handle is NULL, get own instance.
+ // If Handle is not NULL, use it and set the instance.
+ //
+ if (Handle != NULL) {
+ UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *)Handle;
+ SetUsb3DebugPortInstance (UsbDebugPortHandle);
+ } else {
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ }
+
+ if (UsbDebugPortHandle == NULL) {
+ return FALSE;
+ }
+
+ if (UsbDebugPortHandle->InNotify) {
+ return FALSE;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
+ return FALSE;
+ }
+
+ //
+ // If the data buffer is not empty, then return TRUE directly.
+ // Otherwise initialize a usb read transaction and read data to internal data buffer.
+ //
+ if (UsbDebugPortHandle->DataCount != 0) {
+ return TRUE;
+ }
+
+ //
+ // Read data as much as we can
+ //
+ Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
+ XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
+
+ if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
+ return FALSE;
+ }
+
+ if (Length == 0) {
+ return FALSE;
+ }
+
+ //
+ // Store data into internal buffer for use later
+ //
+ UsbDebugPortHandle->DataCount = (UINT8)Length;
+ return TRUE;
+}
+
+/**
+ Initialize the debug port.
+
+ If Function is not NULL, Debug Communication Library will call this function
+ by passing in the Context to be the first parameter. If needed, Debug Communication
+ Library will create one debug port handle to be the second argument passing in
+ calling the Function, otherwise it will pass NULL to be the second argument of
+ Function.
+
+ If Function is NULL, and Context is not NULL, the Debug Communication Library could
+ a) Return the same handle as passed in (as Context parameter).
+ b) Ignore the input Context parameter and create new handle to be returned.
+
+ If parameter Function is NULL and Context is NULL, Debug Communication Library could
+ created a new handle if needed and return it, otherwise it will return NULL.
+
+ @param[in] Context Context needed by callback function; it was optional.
+ @param[in] Function Continue function called by Debug Communication library;
+ it was optional.
+
+ @return The debug port handle created by Debug Communication Library if Function
+ is not NULL.
+
+**/
+DEBUG_PORT_HANDLE
+EFIAPI
+DebugPortInitialize (
+ IN VOID *Context,
+ IN DEBUG_PORT_CONTINUE Function
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *UsbDebugPortHandle;
+
+ //
+ // Validate the PCD PcdDebugPortHandleBufferSize value
+ //
+ ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
+
+ if ((Function == NULL) && (Context != NULL)) {
+ SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *)Context);
+ return (DEBUG_PORT_HANDLE)Context;
+ }
+
+ UsbDebugPortHandle = GetUsb3DebugPortInstance ();
+ if (UsbDebugPortHandle == NULL) {
+ return NULL;
+ }
+
+ DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
+
+ if (Function != NULL) {
+ Function (Context, (DEBUG_PORT_HANDLE)UsbDebugPortHandle);
+ }
+
+ return (DEBUG_PORT_HANDLE)UsbDebugPortHandle;
+}
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
index d37fb991f1..6f86ace58c 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
@@ -1,536 +1,536 @@
-/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Base.h>
-#include <PiDxe.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/HobLib.h>
-#include <Protocol/PciIo.h>
-#include <Protocol/IoMmu.h>
-#include <Protocol/DxeSmmReadyToLock.h>
-#include "DebugCommunicationLibUsb3Internal.h"
-
-GUID gUsb3DbgGuid = USB3_DBG_GUID;
-
-USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED };
-EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
-EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
-EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
-
-/**
- Creates a named event that can be signaled.
-
- This function creates an event using NotifyTpl, NotifyFunction.
- If Name is NULL, then ASSERT().
- If NotifyTpl is not a legal TPL value, then ASSERT().
- If NotifyFunction is NULL, then ASSERT().
-
- @param Name Supplies the GUID name of the event.
- @param NotifyTpl Supplies the task priority level of the event notifications.
- @param NotifyFunction Supplies the function to notify when the event is signaled.
- @param Event A pointer to the event created.
-
- @retval EFI_SUCCESS A named event was created.
- @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
-
-**/
-EFI_STATUS
-EFIAPI
-Usb3NamedEventListen (
- IN CONST EFI_GUID *Name,
- IN EFI_TPL NotifyTpl,
- IN EFI_EVENT_NOTIFY NotifyFunction,
- IN EFI_EVENT *Event
- )
-{
- EFI_STATUS Status;
- VOID *RegistrationLocal;
-
- ASSERT (Name != NULL);
- ASSERT (NotifyFunction != NULL);
- ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
-
- //
- // Create event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- NotifyTpl,
- NotifyFunction,
- NULL,
- Event
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for an installation of protocol interface
- //
- Status = gBS->RegisterProtocolNotify (
- (EFI_GUID *)Name,
- *Event,
- &RegistrationLocal
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
-
-/**
- USB3 map one DMA buffer.
-
- @param PciIo Pointer to PciIo for USB3 debug port.
- @param Address DMA buffer address to be mapped.
- @param NumberOfBytes Number of bytes to be mapped.
-
-**/
-VOID
-Usb3MapOneDmaBuffer (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfBytes
- )
-{
- EFI_STATUS Status;
- VOID *HostAddress;
- EFI_PHYSICAL_ADDRESS DeviceAddress;
- VOID *Mapping;
-
- HostAddress = (VOID *)(UINTN)Address;
- Status = PciIo->Map (
- PciIo,
- EfiPciIoOperationBusMasterCommonBuffer,
- HostAddress,
- &NumberOfBytes,
- &DeviceAddress,
- &Mapping
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
-}
-
-/**
- USB3 map DMA buffers.
-
- @param Instance Pointer to USB3 debug port instance.
- @param PciIo Pointer to PciIo for USB3 debug port.
-
-**/
-VOID
-Usb3MapDmaBuffers (
- IN USB3_DEBUG_PORT_HANDLE *Instance,
- IN EFI_PCI_IO_PROTOCOL *PciIo
- )
-{
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->UrbIn.Data,
- XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->TransferRingIn.RingSeg0,
- sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->TransferRingOut.RingSeg0,
- sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->EventRing.EventRingSeg0,
- sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->EventRing.ERSTBase,
- sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- Instance->DebugCapabilityContext,
- sizeof (XHC_DC_CONTEXT)
- );
-
- Usb3MapOneDmaBuffer (
- PciIo,
- ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
- STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
- );
-}
-
-/**
- Invoke a notification event
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-Usb3DxeSmmReadyToLockNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- Instance->InNotify = TRUE;
-
- //
- // For the case that the USB3 debug port instance and DMA buffers are
- // from PEI HOB with IOMMU enabled.
- // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
- // by SMM environment.
- //
- InitializeUsbDebugHardware (Instance);
-
- //
- // Wait some time for host to be ready after re-initialization.
- //
- MicroSecondDelay (1000000);
-
- Instance->InNotify = FALSE;
- gBS->CloseEvent (Event);
-}
-
-/**
- USB3 get IOMMU protocol.
-
- @return Pointer to IOMMU protocol.
-
-**/
-EDKII_IOMMU_PROTOCOL *
-Usb3GetIoMmu (
- VOID
- )
-{
- EFI_STATUS Status;
- EDKII_IOMMU_PROTOCOL *IoMmu;
-
- IoMmu = NULL;
- Status = gBS->LocateProtocol (
- &gEdkiiIoMmuProtocolGuid,
- NULL,
- (VOID **)&IoMmu
- );
- if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
- return IoMmu;
- }
-
- return NULL;
-}
-
-/**
- Invoke a notification event
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-Usb3PciIoNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- UINTN PciIoHandleCount;
- EFI_HANDLE *PciIoHandleBuffer;
- UINTN Index;
- EFI_PCI_IO_PROTOCOL *PciIo;
- UINTN PciSegment;
- UINTN PciBusNumber;
- UINTN PciDeviceNumber;
- UINTN PciFunctionNumber;
- UINT32 PciAddress;
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_EVENT SmmReadyToLockEvent;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiPciIoProtocolGuid,
- NULL,
- &PciIoHandleCount,
- &PciIoHandleBuffer
- );
- if (!EFI_ERROR (Status) &&
- (PciIoHandleBuffer != NULL) &&
- (PciIoHandleCount != 0))
- {
- for (Index = 0; Index < PciIoHandleCount; Index++) {
- Status = gBS->HandleProtocol (
- PciIoHandleBuffer[Index],
- &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo
- );
- ASSERT_EFI_ERROR (Status);
- Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
- ASSERT_EFI_ERROR (Status);
- PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
- if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) {
- //
- // Found the PciIo for USB3 debug port.
- //
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
- if (Usb3GetIoMmu () != NULL) {
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
- if (Instance->Ready) {
- Instance->InNotify = TRUE;
- Usb3MapDmaBuffers (Instance, PciIo);
- Instance->InNotify = FALSE;
-
- if (Instance->FromHob) {
- mUsb3PciIo = PciIo;
- Usb3NamedEventListen (
- &gEfiDxeSmmReadyToLockProtocolGuid,
- TPL_NOTIFY,
- Usb3DxeSmmReadyToLockNotify,
- &SmmReadyToLockEvent
- );
- }
- }
- }
-
- gBS->CloseEvent (Event);
- break;
- }
- }
-
- gBS->FreePool (PciIoHandleBuffer);
- }
-}
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- )
-{
- if (mUsb3InstanceAddrPtr == NULL) {
- //
- // Use the local variables temporarily.
- //
- mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance;
- mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
- }
-
- return mUsb3InstanceAddrPtr;
-}
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param PciIo Pointer to PciIo for USB3 debug port.
- @param Pages The number of pages to allocate.
- @param Address A pointer to store the base system memory address of the
- allocated range.
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-Usb3AllocateDmaBuffer (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINTN Pages,
- OUT VOID **Address
- )
-{
- EFI_STATUS Status;
-
- *Address = NULL;
- Status = PciIo->AllocateBuffer (
- PciIo,
- AllocateAnyPages,
- EfiRuntimeServicesData,
- Pages,
- Address,
- 0
- );
- if (!EFI_ERROR (Status)) {
- Usb3MapOneDmaBuffer (
- PciIo,
- (EFI_PHYSICAL_ADDRESS)(UINTN)*Address,
- EFI_PAGES_TO_SIZE (Pages)
- );
- }
-
- return Status;
-}
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- )
-{
- EFI_PHYSICAL_ADDRESS TmpAddr;
- EFI_STATUS Status;
- VOID *Buf;
-
- Buf = NULL;
-
- if (gBS != NULL) {
- if (mUsb3PciIo != NULL) {
- Usb3AllocateDmaBuffer (
- mUsb3PciIo,
- EFI_SIZE_TO_PAGES (BufferSize),
- &Buf
- );
- } else {
- TmpAddr = 0xFFFFFFFF;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (BufferSize),
- &TmpAddr
- );
- if (!EFI_ERROR (Status)) {
- Buf = (VOID *)(UINTN)TmpAddr;
- }
- }
- }
-
- return Buf;
-}
-
-/**
- The constructor function initialize USB3 debug port.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugCommunicationUsb3DxeConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_PHYSICAL_ADDRESS Address;
- EFI_STATUS Status;
- EFI_EVENT Event;
-
- Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr);
- if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
- //
- // Instead of using local variables, install system configuration table for
- // the local instance and the buffer to save instance address pointer.
- //
- Address = SIZE_4GB;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
- &Address
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address;
- ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
- Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
- CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
-
- Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- if (mUsb3InstanceAddrPtr != NULL) {
- *AddrPtr = *mUsb3InstanceAddrPtr;
- }
-
- mUsb3InstanceAddrPtr = AddrPtr;
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- if (Instance->PciIoEvent == 0) {
- Status = Usb3NamedEventListen (
- &gEfiPciIoProtocolGuid,
- TPL_NOTIFY,
- Usb3PciIoNotify,
- &Event
- );
- if (!EFI_ERROR (Status)) {
- Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The destructor function.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-DebugCommunicationUsb3DxeDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
-
- if (Instance->PciIoEvent != 0) {
- //
- // Close the event created.
- //
- gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent);
- Instance->PciIoEvent = 0;
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/IoMmu.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include "DebugCommunicationLibUsb3Internal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+USB3_DEBUG_PORT_HANDLE mUsb3Instance = { USB3DBG_UNINITIALIZED };
+EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
+EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
+EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
+
+/**
+ Creates a named event that can be signaled.
+
+ This function creates an event using NotifyTpl, NotifyFunction.
+ If Name is NULL, then ASSERT().
+ If NotifyTpl is not a legal TPL value, then ASSERT().
+ If NotifyFunction is NULL, then ASSERT().
+
+ @param Name Supplies the GUID name of the event.
+ @param NotifyTpl Supplies the task priority level of the event notifications.
+ @param NotifyFunction Supplies the function to notify when the event is signaled.
+ @param Event A pointer to the event created.
+
+ @retval EFI_SUCCESS A named event was created.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3NamedEventListen (
+ IN CONST EFI_GUID *Name,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ VOID *RegistrationLocal;
+
+ ASSERT (Name != NULL);
+ ASSERT (NotifyFunction != NULL);
+ ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NotifyTpl,
+ NotifyFunction,
+ NULL,
+ Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ (EFI_GUID *)Name,
+ *Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ USB3 map one DMA buffer.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Address DMA buffer address to be mapped.
+ @param NumberOfBytes Number of bytes to be mapped.
+
+**/
+VOID
+Usb3MapOneDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfBytes
+ )
+{
+ EFI_STATUS Status;
+ VOID *HostAddress;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *Mapping;
+
+ HostAddress = (VOID *)(UINTN)Address;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ HostAddress,
+ &NumberOfBytes,
+ &DeviceAddress,
+ &Mapping
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
+}
+
+/**
+ USB3 map DMA buffers.
+
+ @param Instance Pointer to USB3 debug port instance.
+ @param PciIo Pointer to PciIo for USB3 debug port.
+
+**/
+VOID
+Usb3MapDmaBuffers (
+ IN USB3_DEBUG_PORT_HANDLE *Instance,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->UrbIn.Data,
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingIn.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingOut.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.EventRingSeg0,
+ sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.ERSTBase,
+ sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->DebugCapabilityContext,
+ sizeof (XHC_DC_CONTEXT)
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ ((XHC_DC_CONTEXT *)(UINTN)Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
+ STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
+ );
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3DxeSmmReadyToLockNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ DEBUG ((DEBUG_INFO, "%a()\n", __func__));
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ Instance->InNotify = TRUE;
+
+ //
+ // For the case that the USB3 debug port instance and DMA buffers are
+ // from PEI HOB with IOMMU enabled.
+ // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
+ // by SMM environment.
+ //
+ InitializeUsbDebugHardware (Instance);
+
+ //
+ // Wait some time for host to be ready after re-initialization.
+ //
+ MicroSecondDelay (1000000);
+
+ Instance->InNotify = FALSE;
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB3 get IOMMU protocol.
+
+ @return Pointer to IOMMU protocol.
+
+**/
+EDKII_IOMMU_PROTOCOL *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PROTOCOL *IoMmu;
+
+ IoMmu = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiIoMmuProtocolGuid,
+ NULL,
+ (VOID **)&IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3PciIoNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN PciIoHandleCount;
+ EFI_HANDLE *PciIoHandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN PciSegment;
+ UINTN PciBusNumber;
+ UINTN PciDeviceNumber;
+ UINTN PciFunctionNumber;
+ UINT32 PciAddress;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_EVENT SmmReadyToLockEvent;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &PciIoHandleCount,
+ &PciIoHandleBuffer
+ );
+ if (!EFI_ERROR (Status) &&
+ (PciIoHandleBuffer != NULL) &&
+ (PciIoHandleCount != 0))
+ {
+ for (Index = 0; Index < PciIoHandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ PciIoHandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
+ ASSERT_EFI_ERROR (Status);
+ PciAddress = (UINT32)((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
+ if (PciAddress == PcdGet32 (PcdUsbXhciPciAddress)) {
+ //
+ // Found the PciIo for USB3 debug port.
+ //
+ DEBUG ((DEBUG_INFO, "%a()\n", __func__));
+ if (Usb3GetIoMmu () != NULL) {
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ if (Instance->Ready) {
+ Instance->InNotify = TRUE;
+ Usb3MapDmaBuffers (Instance, PciIo);
+ Instance->InNotify = FALSE;
+
+ if (Instance->FromHob) {
+ mUsb3PciIo = PciIo;
+ Usb3NamedEventListen (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ Usb3DxeSmmReadyToLockNotify,
+ &SmmReadyToLockEvent
+ );
+ }
+ }
+ }
+
+ gBS->CloseEvent (Event);
+ break;
+ }
+ }
+
+ gBS->FreePool (PciIoHandleBuffer);
+ }
+}
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ )
+{
+ if (mUsb3InstanceAddrPtr == NULL) {
+ //
+ // Use the local variables temporarily.
+ //
+ mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)&mUsb3Instance;
+ mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
+ }
+
+ return mUsb3InstanceAddrPtr;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Pages The number of pages to allocate.
+ @param Address A pointer to store the base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+Usb3AllocateDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ OUT VOID **Address
+ )
+{
+ EFI_STATUS Status;
+
+ *Address = NULL;
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ Pages,
+ Address,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)*Address,
+ EFI_PAGES_TO_SIZE (Pages)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TmpAddr;
+ EFI_STATUS Status;
+ VOID *Buf;
+
+ Buf = NULL;
+
+ if (gBS != NULL) {
+ if (mUsb3PciIo != NULL) {
+ Usb3AllocateDmaBuffer (
+ mUsb3PciIo,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buf
+ );
+ } else {
+ TmpAddr = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &TmpAddr
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN)TmpAddr;
+ }
+ }
+ }
+
+ return Buf;
+}
+
+/**
+ The constructor function initialize USB3 debug port.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **)&AddrPtr);
+ if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
+ //
+ // Instead of using local variables, install system configuration table for
+ // the local instance and the buffer to save instance address pointer.
+ //
+ Address = SIZE_4GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AddrPtr = (EFI_PHYSICAL_ADDRESS *)(UINTN)Address;
+ ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
+ Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
+ CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
+
+ Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (mUsb3InstanceAddrPtr != NULL) {
+ *AddrPtr = *mUsb3InstanceAddrPtr;
+ }
+
+ mUsb3InstanceAddrPtr = AddrPtr;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent == 0) {
+ Status = Usb3NamedEventListen (
+ &gEfiPciIoProtocolGuid,
+ TPL_NOTIFY,
+ Usb3PciIoNotify,
+ &Event
+ );
+ if (!EFI_ERROR (Status)) {
+ Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS)(UINTN)Event;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent != 0) {
+ //
+ // Close the event created.
+ //
+ gBS->CloseEvent ((EFI_EVENT)(UINTN)Instance->PciIoEvent);
+ Instance->PciIoEvent = 0;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
index 8f351fb2bc..abe37acfef 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.inf
@@ -1,74 +1,74 @@
-## @file
-# Debug Communication Library instance based on usb3 debug port.
-#
-# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibUsb3Dxe
- MODULE_UNI_FILE = DebugCommunicationLibUsb3Dxe.uni
- FILE_GUID = C41F8C82-B3E6-47e0-A61D-0F9E429E6996
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- LIBRARY_CLASS = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
- CONSTRUCTOR = DebugCommunicationUsb3DxeConstructor
- DESTRUCTOR = DebugCommunicationUsb3DxeDestructor
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- DebugCommunicationLibUsb3Dxe.c
- DebugCommunicationLibUsb3Transfer.c
- DebugCommunicationLibUsb3Common.c
- DebugCommunicationLibUsb3Internal.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[Pcd]
- # The memory BAR of ehci host controller, in which usb debug feature is enabled.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
-
- # The pci address of ehci host controller, in which usb debug feature is enabled.
- # The format of pci address please refer to SourceLevelDebugPkg.dec
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
-
- # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
- # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
-
- # The value of data buffer size used for USB debug port handle.
- # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
-
-[Protocols]
- ## NOTIFY
- ## SOMETIMES_CONSUMES
- gEfiPciIoProtocolGuid
- gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
- ## NOTIFY
- ## SOMETIMES_CONSUMES
- gEfiDxeSmmReadyToLockProtocolGuid
-
-[LibraryClasses]
- BaseLib
- PcdLib
- IoLib
- PciLib
- TimerLib
- UefiBootServicesTableLib
- UefiLib
- BaseMemoryLib
- HobLib
+## @file
+# Debug Communication Library instance based on usb3 debug port.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibUsb3Dxe
+ MODULE_UNI_FILE = DebugCommunicationLibUsb3Dxe.uni
+ FILE_GUID = C41F8C82-B3E6-47e0-A61D-0F9E429E6996
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugCommunicationLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DebugCommunicationUsb3DxeConstructor
+ DESTRUCTOR = DebugCommunicationUsb3DxeDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugCommunicationLibUsb3Dxe.c
+ DebugCommunicationLibUsb3Transfer.c
+ DebugCommunicationLibUsb3Common.c
+ DebugCommunicationLibUsb3Internal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[Pcd]
+ # The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
+
+ # The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address please refer to SourceLevelDebugPkg.dec
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
+
+ # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
+ # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
+
+ # The value of data buffer size used for USB debug port handle.
+ # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
+
+[Protocols]
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiLib
+ BaseMemoryLib
+ HobLib
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
index 244b25d771..b2cd0431cb 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.uni
@@ -1,16 +1,16 @@
-// /** @file
-// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
-//
-// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
-//
-// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules."
-
+// /** @file
+// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
+//
+// Debug Communication Library instance based on USB3 debug port for DXE and SMM modules.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for DXE and SMM modules."
+
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
index cc5f294f33..8fd9105b88 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Internal.h
@@ -1,737 +1,737 @@
-/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__
-#define __USB3_DEBUG_PORT_LIB_INTERNAL__
-
-#include <Uefi.h>
-#include <Base.h>
-#include <IndustryStandard/Usb.h>
-#include <Library/IoLib.h>
-#include <IndustryStandard/Pci.h>
-#include <Library/PcdLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/BaseLib.h>
-#include <Library/TimerLib.h>
-#include <Library/DebugCommunicationLib.h>
-#include <Library/PciLib.h>
-
-//
-// USB Debug GUID value
-//
-#define USB3_DBG_GUID \
- { \
- 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \
- }
-
-//
-// The state machine of usb debug port
-//
-#define USB3DBG_NO_DBG_CAB 0 // The XHCI host controller does not support debug capability
-#define USB3DBG_DBG_CAB 1 // The XHCI host controller supports debug capability
-#define USB3DBG_ENABLED 2 // The XHCI debug device is enabled
-#define USB3DBG_NOT_ENABLED 4 // The XHCI debug device is not enabled
-#define USB3DBG_UNINITIALIZED 255 // The XHCI debug device is uninitialized
-
-#define USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE 0x08
-
-//
-// MaxPacketSize for DbC Endpoint Descriptor IN and OUT
-//
-#define XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE 0x400
-
-#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x0525
-#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x127A
-#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF
-#define XHCI_DEBUG_DEVICE_REVISION 0x00
-
-#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL
-#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000
-
-#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
-#define XHC_HCCPARAMS_OFFSET 0x10
-#define XHC_CAPABILITY_ID_MASK 0xFF
-#define XHC_NEXT_CAPABILITY_MASK 0xFF00
-
-#define XHC_HCSPARAMS1_OFFSET 0x4 // Structural Parameters 1
-#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset
-#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset
-#define XHC_PORTSC_OFFSET 0x400 // Port Status and Control Register Offset
-
-#define XHC_USBCMD_RUN BIT0 // Run/Stop
-#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
-
-#define XHC_USBSTS_HALT BIT0
-
-//
-// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout.
-//
-#define DATA_TRANSFER_WRITE_TIMEOUT 0
-#define DATA_TRANSFER_READ_TIMEOUT 50000
-#define DATA_TRANSFER_POLL_TIMEOUT 1000
-#define XHC_DEBUG_PORT_1_MILLISECOND 1000
-//
-// XHCI port power off/on delay
-//
-#define XHC_DEBUG_PORT_ON_OFF_DELAY 100000
-
-//
-// USB debug device string descriptor (header size + unicode string length)
-//
-#define STRING0_DESC_LEN 4
-#define MANU_DESC_LEN 12
-#define PRODUCT_DESC_LEN 40
-#define SERIAL_DESC_LEN 4
-
-//
-// Debug Capability Register Offset
-//
-#define XHC_DC_DCID 0x0
-#define XHC_DC_DCDB 0x4
-#define XHC_DC_DCERSTSZ 0x8
-#define XHC_DC_DCERSTBA 0x10
-#define XHC_DC_DCERDP 0x18
-#define XHC_DC_DCCTRL 0x20
-#define XHC_DC_DCST 0x24
-#define XHC_DC_DCPORTSC 0x28
-#define XHC_DC_DCCP 0x30
-#define XHC_DC_DCDDI1 0x38
-#define XHC_DC_DCDDI2 0x3C
-
-#define TRB_TYPE_LINK 6
-
-#define ERST_NUMBER 0x01
-#define TR_RING_TRB_NUMBER 0x100
-#define EVENT_RING_TRB_NUMBER 0x200
-
-#define ED_BULK_OUT 2
-#define ED_BULK_IN 6
-
-#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
-#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
-#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
-
-//
-// Endpoint Type (EP Type).
-//
-#define ED_NOT_VALID 0
-#define ED_ISOCH_OUT 1
-#define ED_BULK_OUT 2
-#define ED_INTERRUPT_OUT 3
-#define ED_CONTROL_BIDIR 4
-#define ED_ISOCH_IN 5
-#define ED_BULK_IN 6
-#define ED_INTERRUPT_IN 7
-
-//
-// 6.4.5 TRB Completion Codes
-//
-#define TRB_COMPLETION_INVALID 0
-#define TRB_COMPLETION_SUCCESS 1
-#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
-#define TRB_COMPLETION_BABBLE_ERROR 3
-#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
-#define TRB_COMPLETION_TRB_ERROR 5
-#define TRB_COMPLETION_STALL_ERROR 6
-#define TRB_COMPLETION_SHORT_PACKET 13
-
-//
-// 6.4.6 TRB Types
-//
-#define TRB_TYPE_NORMAL 1
-#define TRB_TYPE_SETUP_STAGE 2
-#define TRB_TYPE_DATA_STAGE 3
-#define TRB_TYPE_STATUS_STAGE 4
-#define TRB_TYPE_ISOCH 5
-#define TRB_TYPE_LINK 6
-#define TRB_TYPE_EVENT_DATA 7
-#define TRB_TYPE_NO_OP 8
-#define TRB_TYPE_EN_SLOT 9
-#define TRB_TYPE_DIS_SLOT 10
-#define TRB_TYPE_ADDRESS_DEV 11
-#define TRB_TYPE_CON_ENDPOINT 12
-#define TRB_TYPE_EVALU_CONTXT 13
-#define TRB_TYPE_RESET_ENDPOINT 14
-#define TRB_TYPE_STOP_ENDPOINT 15
-#define TRB_TYPE_SET_TR_DEQUE 16
-#define TRB_TYPE_RESET_DEV 17
-#define TRB_TYPE_GET_PORT_BANW 21
-#define TRB_TYPE_FORCE_HEADER 22
-#define TRB_TYPE_NO_OP_COMMAND 23
-#define TRB_TYPE_TRANS_EVENT 32
-#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
-#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
-#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
-#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
-#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
-
-//
-// Convert millisecond to microsecond.
-//
-#define XHC_1_MILLISECOND (1000)
-#define XHC_POLL_DELAY (1000)
-#define XHC_GENERIC_TIMEOUT (10 * 1000)
-
-#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.
-#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.
-#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC.
-#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC.
-
-//
-// Transfer types, used in URB to identify the transfer type
-//
-#define XHC_CTRL_TRANSFER 0x01
-#define XHC_BULK_TRANSFER 0x02
-#define XHC_INT_TRANSFER_SYNC 0x04
-#define XHC_INT_TRANSFER_ASYNC 0x08
-#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
-
-//
-// USB Transfer Results
-//
-#define EFI_USB_NOERROR 0x00
-#define EFI_USB_ERR_NOTEXECUTE 0x01
-#define EFI_USB_ERR_STALL 0x02
-#define EFI_USB_ERR_BUFFER 0x04
-#define EFI_USB_ERR_BABBLE 0x08
-#define EFI_USB_ERR_NAK 0x10
-#define EFI_USB_ERR_CRC 0x20
-#define EFI_USB_ERR_TIMEOUT 0x40
-#define EFI_USB_ERR_BITSTUFF 0x80
-#define EFI_USB_ERR_SYSTEM 0x100
-
-#pragma pack(1)
-
-//
-// 7.6.9 OUT/IN EP Context: 64 bytes
-// 7.6.9.2 When used by the DbC it is always a 64 byte data structure
-//
-typedef struct _ENDPOINT_CONTEXT_64 {
- UINT32 EPState : 3;
- UINT32 RsvdZ1 : 5;
- UINT32 Mult : 2; // set to 0
- UINT32 MaxPStreams : 5; // set to 0
- UINT32 LSA : 1; // set to 0
- UINT32 Interval : 8; // set to 0
- UINT32 RsvdZ2 : 8;
-
- UINT32 RsvdZ3 : 1;
- UINT32 CErr : 2;
- UINT32 EPType : 3;
- UINT32 RsvdZ4 : 1;
- UINT32 HID : 1; // set to 0
- UINT32 MaxBurstSize : 8;
- UINT32 MaxPacketSize : 16;
-
- UINT32 PtrLo;
-
- UINT32 PtrHi;
-
- UINT32 AverageTRBLength : 16;
- UINT32 MaxESITPayload : 16; // set to 0
-
- UINT32 RsvdZ5; // Reserved
- UINT32 RsvdZ6;
- UINT32 RsvdZ7;
-
- UINT32 RsvdZ8;
- UINT32 RsvdZ9;
- UINT32 RsvdZ10;
- UINT32 RsvdZ11;
-
- UINT32 RsvdZ12;
- UINT32 RsvdZ13;
- UINT32 RsvdZ14;
- UINT32 RsvdZ15;
-} ENDPOINT_CONTEXT_64;
-
-//
-// 6.4.1.1 Normal TRB: 16 bytes
-// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
-// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
-// Rings, and to define the Data stage information for Control Transfer Rings.
-//
-typedef struct _TRANSFER_TRB_NORMAL {
- UINT32 TRBPtrLo;
-
- UINT32 TRBPtrHi;
-
- UINT32 Length : 17;
- UINT32 TDSize : 5;
- UINT32 IntTarget : 10;
-
- UINT32 CycleBit : 1;
- UINT32 ENT : 1;
- UINT32 ISP : 1;
- UINT32 NS : 1;
- UINT32 CH : 1;
- UINT32 IOC : 1;
- UINT32 IDT : 1;
- UINT32 RsvdZ1 : 2;
- UINT32 BEI : 1;
- UINT32 Type : 6;
- UINT32 RsvdZ2 : 16;
-} TRANSFER_TRB_NORMAL;
-
-//
-// 6.4.2.1 Transfer Event TRB: 16 bytes
-// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
-// for more information on the use and operation of Transfer Events.
-//
-typedef struct _EVT_TRB_TRANSFER {
- UINT32 TRBPtrLo;
-
- UINT32 TRBPtrHi;
-
- UINT32 Length : 24;
- UINT32 Completecode : 8;
-
- UINT32 CycleBit : 1;
- UINT32 RsvdZ1 : 1;
- UINT32 ED : 1;
- UINT32 RsvdZ2 : 7;
- UINT32 Type : 6;
- UINT32 EndpointId : 5;
- UINT32 RsvdZ3 : 3;
- UINT32 SlotId : 8;
-} EVT_TRB_TRANSFER;
-
-//
-// 6.4.4.1 Link TRB: 16 bytes
-// A Link TRB provides support for non-contiguous TRB Rings.
-//
-typedef struct _LINK_TRB {
- UINT32 PtrLo;
-
- UINT32 PtrHi;
-
- UINT32 RsvdZ1 : 22;
- UINT32 InterTarget : 10;
-
- UINT32 CycleBit : 1;
- UINT32 TC : 1;
- UINT32 RsvdZ2 : 2;
- UINT32 CH : 1;
- UINT32 IOC : 1;
- UINT32 RsvdZ3 : 4;
- UINT32 Type : 6;
- UINT32 RsvdZ4 : 16;
-} LINK_TRB;
-
-//
-// TRB Template: 16 bytes
-//
-typedef struct _TRB_TEMPLATE {
- UINT32 Parameter1;
-
- UINT32 Parameter2;
-
- UINT32 Status;
-
- UINT32 CycleBit : 1;
- UINT32 RsvdZ1 : 9;
- UINT32 Type : 6;
- UINT32 Control : 16;
-} TRB_TEMPLATE;
-
-//
-// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes
-//
-typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
- UINT32 PtrLo;
- UINT32 PtrHi;
- UINT32 RingTrbSize : 16;
- UINT32 RsvdZ1 : 16;
- UINT32 RsvdZ2;
-} EVENT_RING_SEG_TABLE_ENTRY;
-
-//
-// Size: 40 bytes
-//
-typedef struct _EVENT_RING {
- EFI_PHYSICAL_ADDRESS ERSTBase;
- EFI_PHYSICAL_ADDRESS EventRingSeg0;
- UINT32 TrbNumber;
- EFI_PHYSICAL_ADDRESS EventRingEnqueue;
- EFI_PHYSICAL_ADDRESS EventRingDequeue;
- UINT32 EventRingCCS;
-} EVENT_RING;
-
-// Size: 32 bytes
-typedef struct _TRANSFER_RING {
- EFI_PHYSICAL_ADDRESS RingSeg0;
- UINT32 TrbNumber;
- EFI_PHYSICAL_ADDRESS RingEnqueue;
- EFI_PHYSICAL_ADDRESS RingDequeue;
- UINT32 RingPCS;
-} TRANSFER_RING;
-
-//
-// Size: 64 bytes
-//
-typedef struct _DBC_INFO_CONTEXT {
- UINT64 String0DescAddress;
- UINT64 ManufacturerStrDescAddress;
- UINT64 ProductStrDescAddress;
- UINT64 SerialNumberStrDescAddress;
- UINT64 String0Length : 8;
- UINT64 ManufacturerStrLength : 8;
- UINT64 ProductStrLength : 8;
- UINT64 SerialNumberStrLength : 8;
- UINT64 RsvdZ1 : 32;
- UINT64 RsvdZ2;
- UINT64 RsvdZ3;
- UINT64 RsvdZ4;
-} DBC_INFO_CONTEXT;
-
-//
-// Debug Capability Context Data Structure: 192 bytes
-//
-typedef struct _XHC_DC_CONTEXT {
- DBC_INFO_CONTEXT DbcInfoContext;
- ENDPOINT_CONTEXT_64 EpOutContext;
- ENDPOINT_CONTEXT_64 EpInContext;
-} XHC_DC_CONTEXT;
-
-//
-// Size: 16 bytes
-//
-typedef union _TRB {
- TRB_TEMPLATE TrbTemplate;
- TRANSFER_TRB_NORMAL TrbNormal;
-} TRB;
-
-///
-/// USB data transfer direction
-///
-typedef enum {
- EfiUsbDataIn,
- EfiUsbDataOut,
- EfiUsbNoData
-} EFI_USB_DATA_DIRECTION;
-
-//
-// URB (Usb Request Block) contains information for all kinds of
-// usb requests.
-//
-typedef struct _URB {
- //
- // Transfer data buffer
- //
- EFI_PHYSICAL_ADDRESS Data;
- UINT32 DataLen;
-
- //
- // Execute result
- //
- UINT32 Result;
- //
- // Completed data length
- //
- UINT32 Completed;
- //
- // Tranfer Ring info
- //
- EFI_PHYSICAL_ADDRESS Ring;
- EFI_PHYSICAL_ADDRESS Trb;
- BOOLEAN Finished;
- EFI_USB_DATA_DIRECTION Direction;
-} URB;
-
-typedef struct _USB3_DEBUG_PORT_INSTANCE {
- UINT8 Initialized;
-
- //
- // The flag indicates debug capability is supported
- //
- BOOLEAN DebugSupport;
-
- //
- // The flag indicates debug device is ready
- //
- BOOLEAN Ready;
-
- //
- // The flag indicates the instance is from HOB
- //
- BOOLEAN FromHob;
-
- //
- // Prevent notification being interrupted by debug timer
- //
- BOOLEAN InNotify;
-
- //
- // PciIo protocol event
- //
- EFI_PHYSICAL_ADDRESS PciIoEvent;
-
- //
- // The flag indicates if USB 3.0 ports has been turn off/on power
- //
- BOOLEAN ChangePortPower;
-
- //
- // XHCI MMIO Base address
- //
- EFI_PHYSICAL_ADDRESS XhciMmioBase;
-
- //
- // XHCI OP RegisterBase address
- //
- EFI_PHYSICAL_ADDRESS XhciOpRegister;
-
- //
- // XHCI Debug Register Base Address
- //
- EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
-
- //
- // XHCI Debug Capability offset
- //
- UINT64 DebugCapabilityOffset;
-
- //
- // XHCI Debug Context Address
- //
- EFI_PHYSICAL_ADDRESS DebugCapabilityContext;
-
- //
- // Transfer Ring
- //
- TRANSFER_RING TransferRingOut;
- TRANSFER_RING TransferRingIn;
-
- //
- // EventRing
- //
- EVENT_RING EventRing;
-
- //
- // URB - Read
- //
- URB UrbOut;
-
- //
- // URB - Write
- //
- URB UrbIn;
-
- //
- // The available data length in the following data buffer.
- //
- UINT8 DataCount;
- //
- // The data buffer address for data read and poll.
- //
- EFI_PHYSICAL_ADDRESS Data;
-} USB3_DEBUG_PORT_HANDLE;
-
-#pragma pack()
-
-/**
- Read XHCI debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
-
- @return The register content read
-
-**/
-UINT32
-XhcReadDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset
- );
-
-/**
- Set one bit of the debug register while keeping other bits.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Bit The bit mask of the register to set.
-
-**/
-VOID
-XhcSetDebugRegBit (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Bit
- );
-
-/**
- Write the data to the debug register.
-
- @param Handle Debug port handle.
- @param Offset The offset of the debug register.
- @param Data The data to write.
-
-**/
-VOID
-XhcWriteDebugReg (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN UINT32 Offset,
- IN UINT32 Data
- );
-
-/**
- Verifies if the bit positions specified by a mask are set in a register.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-
- @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
- - FALSE even if one of the bits specified by the mask
- is not enabled.
-**/
-BOOLEAN
-XhcIsBitSet (
- UINTN Register,
- UINT32 BitMask
- );
-
-/**
- Sets bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcSetR32Bit (
- UINTN Register,
- UINT32 BitMask
- );
-
-/**
- Clears bits as per the enabled bit positions in the mask.
-
- @param[in, out] Register UINTN register
- @param[in] BitMask 32-bit mask
-**/
-VOID
-XhcClearR32Bit (
- IN OUT UINTN Register,
- IN UINT32 BitMask
- );
-
-/**
- Initialize USB3 debug port.
-
- This method invokes various internal functions to facilitate
- detection and initialization of USB3 debug port.
-
- @retval RETURN_SUCCESS The serial device was initialized.
-**/
-RETURN_STATUS
-EFIAPI
-USB3Initialize (
- VOID
- );
-
-/**
- Return command register value in XHCI controller.
-
-**/
-UINT16
-GetXhciPciCommand (
- VOID
- );
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- );
-
-/**
- The real function to initialize USB3 debug port.
-
- This method invokes various internal functions to facilitate
- detection and initialization of USB3 debug port.
-
- @retval RETURN_SUCCESS The serial device was initialized.
-**/
-RETURN_STATUS
-EFIAPI
-USB3InitializeReal (
- VOID
- );
-
-/**
- Submits bulk transfer to a bulk endpoint of a USB device.
-
- @param Handle The instance of debug device.
- @param Direction The direction of data transfer.
- @param Data Array of pointers to the buffers of data to transmit
- from or receive into.
- @param DataLength The length of the data buffer.
- @param Timeout Indicates the maximum time, in millisecond, which
- the transfer is allowed to complete.
-
- @retval EFI_SUCCESS The transfer was completed successfully.
- @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
- @retval EFI_INVALID_PARAMETER Some parameters are invalid.
- @retval EFI_TIMEOUT The transfer failed due to timeout.
- @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcDataTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN OUT VOID *Data,
- IN OUT UINTN *DataLength,
- IN UINTN Timeout
- );
-
-/**
- Initialize usb debug port hardware.
-
- @param Handle Debug port handle.
-
- @retval TRUE The usb debug port hardware configuration is changed.
- @retval FALSE The usb debug port hardware configuration is not changed.
-
-**/
-RETURN_STATUS
-EFIAPI
-InitializeUsbDebugHardware (
- IN USB3_DEBUG_PORT_HANDLE *Handle
- );
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- );
-
-/**
- Return USB3 debug instance address.
-
-**/
-USB3_DEBUG_PORT_HANDLE *
-GetUsb3DebugPortInstance (
- VOID
- );
-
-#endif //__SERIAL_PORT_LIB_USB__
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB3_DEBUG_PORT_LIB_INTERNAL__
+#define __USB3_DEBUG_PORT_LIB_INTERNAL__
+
+#include <Uefi.h>
+#include <Base.h>
+#include <IndustryStandard/Usb.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugCommunicationLib.h>
+#include <Library/PciLib.h>
+
+//
+// USB Debug GUID value
+//
+#define USB3_DBG_GUID \
+ { \
+ 0xb2a56f4d, 0x9177, 0x4fc8, { 0xa6, 0x77, 0xdd, 0x96, 0x3e, 0xb4, 0xcb, 0x1b } \
+ }
+
+//
+// The state machine of usb debug port
+//
+#define USB3DBG_NO_DBG_CAB 0 // The XHCI host controller does not support debug capability
+#define USB3DBG_DBG_CAB 1 // The XHCI host controller supports debug capability
+#define USB3DBG_ENABLED 2 // The XHCI debug device is enabled
+#define USB3DBG_NOT_ENABLED 4 // The XHCI debug device is not enabled
+#define USB3DBG_UNINITIALIZED 255 // The XHCI debug device is uninitialized
+
+#define USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE 0x08
+
+//
+// MaxPacketSize for DbC Endpoint Descriptor IN and OUT
+//
+#define XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE 0x400
+
+#define XHCI_DEBUG_DEVICE_VENDOR_ID 0x0525
+#define XHCI_DEBUG_DEVICE_PRODUCT_ID 0x127A
+#define XHCI_DEBUG_DEVICE_PROTOCOL 0xFF
+#define XHCI_DEBUG_DEVICE_REVISION 0x00
+
+#define XHCI_BASE_ADDRESS_64_BIT_MASK 0xFFFFFFFFFFFF0000ULL
+#define XHCI_BASE_ADDRESS_32_BIT_MASK 0xFFFF0000
+
+#define PCI_CAPABILITY_ID_DEBUG_PORT 0x0A
+#define XHC_HCCPARAMS_OFFSET 0x10
+#define XHC_CAPABILITY_ID_MASK 0xFF
+#define XHC_NEXT_CAPABILITY_MASK 0xFF00
+
+#define XHC_HCSPARAMS1_OFFSET 0x4 // Structural Parameters 1
+#define XHC_USBCMD_OFFSET 0x0 // USB Command Register Offset
+#define XHC_USBSTS_OFFSET 0x4 // USB Status Register Offset
+#define XHC_PORTSC_OFFSET 0x400 // Port Status and Control Register Offset
+
+#define XHC_USBCMD_RUN BIT0 // Run/Stop
+#define XHC_USBCMD_RESET BIT1 // Host Controller Reset
+
+#define XHC_USBSTS_HALT BIT0
+
+//
+// Indicate the timeout when data is transferred in microsecond. 0 means infinite timeout.
+//
+#define DATA_TRANSFER_WRITE_TIMEOUT 0
+#define DATA_TRANSFER_READ_TIMEOUT 50000
+#define DATA_TRANSFER_POLL_TIMEOUT 1000
+#define XHC_DEBUG_PORT_1_MILLISECOND 1000
+//
+// XHCI port power off/on delay
+//
+#define XHC_DEBUG_PORT_ON_OFF_DELAY 100000
+
+//
+// USB debug device string descriptor (header size + unicode string length)
+//
+#define STRING0_DESC_LEN 4
+#define MANU_DESC_LEN 12
+#define PRODUCT_DESC_LEN 40
+#define SERIAL_DESC_LEN 4
+
+//
+// Debug Capability Register Offset
+//
+#define XHC_DC_DCID 0x0
+#define XHC_DC_DCDB 0x4
+#define XHC_DC_DCERSTSZ 0x8
+#define XHC_DC_DCERSTBA 0x10
+#define XHC_DC_DCERDP 0x18
+#define XHC_DC_DCCTRL 0x20
+#define XHC_DC_DCST 0x24
+#define XHC_DC_DCPORTSC 0x28
+#define XHC_DC_DCCP 0x30
+#define XHC_DC_DCDDI1 0x38
+#define XHC_DC_DCDDI2 0x3C
+
+#define TRB_TYPE_LINK 6
+
+#define ERST_NUMBER 0x01
+#define TR_RING_TRB_NUMBER 0x100
+#define EVENT_RING_TRB_NUMBER 0x200
+
+#define ED_BULK_OUT 2
+#define ED_BULK_IN 6
+
+#define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))
+#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF))
+#define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
+
+//
+// Endpoint Type (EP Type).
+//
+#define ED_NOT_VALID 0
+#define ED_ISOCH_OUT 1
+#define ED_BULK_OUT 2
+#define ED_INTERRUPT_OUT 3
+#define ED_CONTROL_BIDIR 4
+#define ED_ISOCH_IN 5
+#define ED_BULK_IN 6
+#define ED_INTERRUPT_IN 7
+
+//
+// 6.4.5 TRB Completion Codes
+//
+#define TRB_COMPLETION_INVALID 0
+#define TRB_COMPLETION_SUCCESS 1
+#define TRB_COMPLETION_DATA_BUFFER_ERROR 2
+#define TRB_COMPLETION_BABBLE_ERROR 3
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR 4
+#define TRB_COMPLETION_TRB_ERROR 5
+#define TRB_COMPLETION_STALL_ERROR 6
+#define TRB_COMPLETION_SHORT_PACKET 13
+
+//
+// 6.4.6 TRB Types
+//
+#define TRB_TYPE_NORMAL 1
+#define TRB_TYPE_SETUP_STAGE 2
+#define TRB_TYPE_DATA_STAGE 3
+#define TRB_TYPE_STATUS_STAGE 4
+#define TRB_TYPE_ISOCH 5
+#define TRB_TYPE_LINK 6
+#define TRB_TYPE_EVENT_DATA 7
+#define TRB_TYPE_NO_OP 8
+#define TRB_TYPE_EN_SLOT 9
+#define TRB_TYPE_DIS_SLOT 10
+#define TRB_TYPE_ADDRESS_DEV 11
+#define TRB_TYPE_CON_ENDPOINT 12
+#define TRB_TYPE_EVALU_CONTXT 13
+#define TRB_TYPE_RESET_ENDPOINT 14
+#define TRB_TYPE_STOP_ENDPOINT 15
+#define TRB_TYPE_SET_TR_DEQUE 16
+#define TRB_TYPE_RESET_DEV 17
+#define TRB_TYPE_GET_PORT_BANW 21
+#define TRB_TYPE_FORCE_HEADER 22
+#define TRB_TYPE_NO_OP_COMMAND 23
+#define TRB_TYPE_TRANS_EVENT 32
+#define TRB_TYPE_COMMAND_COMPLT_EVENT 33
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT 34
+#define TRB_TYPE_HOST_CONTROLLER_EVENT 37
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT 38
+#define TRB_TYPE_MFINDEX_WRAP_EVENT 39
+
+//
+// Convert millisecond to microsecond.
+//
+#define XHC_1_MILLISECOND (1000)
+#define XHC_POLL_DELAY (1000)
+#define XHC_GENERIC_TIMEOUT (10 * 1000)
+
+#define EFI_USB_SPEED_FULL 0x0000 ///< 12 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_LOW 0x0001 ///< 1 Mb/s, USB 1.1 OHCI and UHCI HC.
+#define EFI_USB_SPEED_HIGH 0x0002 ///< 480 Mb/s, USB 2.0 EHCI HC.
+#define EFI_USB_SPEED_SUPER 0x0003 ///< 4.8 Gb/s, USB 3.0 XHCI HC.
+
+//
+// Transfer types, used in URB to identify the transfer type
+//
+#define XHC_CTRL_TRANSFER 0x01
+#define XHC_BULK_TRANSFER 0x02
+#define XHC_INT_TRANSFER_SYNC 0x04
+#define XHC_INT_TRANSFER_ASYNC 0x08
+#define XHC_INT_ONLY_TRANSFER_ASYNC 0x10
+
+//
+// USB Transfer Results
+//
+#define EFI_USB_NOERROR 0x00
+#define EFI_USB_ERR_NOTEXECUTE 0x01
+#define EFI_USB_ERR_STALL 0x02
+#define EFI_USB_ERR_BUFFER 0x04
+#define EFI_USB_ERR_BABBLE 0x08
+#define EFI_USB_ERR_NAK 0x10
+#define EFI_USB_ERR_CRC 0x20
+#define EFI_USB_ERR_TIMEOUT 0x40
+#define EFI_USB_ERR_BITSTUFF 0x80
+#define EFI_USB_ERR_SYSTEM 0x100
+
+#pragma pack(1)
+
+//
+// 7.6.9 OUT/IN EP Context: 64 bytes
+// 7.6.9.2 When used by the DbC it is always a 64 byte data structure
+//
+typedef struct _ENDPOINT_CONTEXT_64 {
+ UINT32 EPState : 3;
+ UINT32 RsvdZ1 : 5;
+ UINT32 Mult : 2; // set to 0
+ UINT32 MaxPStreams : 5; // set to 0
+ UINT32 LSA : 1; // set to 0
+ UINT32 Interval : 8; // set to 0
+ UINT32 RsvdZ2 : 8;
+
+ UINT32 RsvdZ3 : 1;
+ UINT32 CErr : 2;
+ UINT32 EPType : 3;
+ UINT32 RsvdZ4 : 1;
+ UINT32 HID : 1; // set to 0
+ UINT32 MaxBurstSize : 8;
+ UINT32 MaxPacketSize : 16;
+
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 AverageTRBLength : 16;
+ UINT32 MaxESITPayload : 16; // set to 0
+
+ UINT32 RsvdZ5; // Reserved
+ UINT32 RsvdZ6;
+ UINT32 RsvdZ7;
+
+ UINT32 RsvdZ8;
+ UINT32 RsvdZ9;
+ UINT32 RsvdZ10;
+ UINT32 RsvdZ11;
+
+ UINT32 RsvdZ12;
+ UINT32 RsvdZ13;
+ UINT32 RsvdZ14;
+ UINT32 RsvdZ15;
+} ENDPOINT_CONTEXT_64;
+
+//
+// 6.4.1.1 Normal TRB: 16 bytes
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer
+// Rings, and to define the Data stage information for Control Transfer Rings.
+//
+typedef struct _TRANSFER_TRB_NORMAL {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length : 17;
+ UINT32 TDSize : 5;
+ UINT32 IntTarget : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 ENT : 1;
+ UINT32 ISP : 1;
+ UINT32 NS : 1;
+ UINT32 CH : 1;
+ UINT32 IOC : 1;
+ UINT32 IDT : 1;
+ UINT32 RsvdZ1 : 2;
+ UINT32 BEI : 1;
+ UINT32 Type : 6;
+ UINT32 RsvdZ2 : 16;
+} TRANSFER_TRB_NORMAL;
+
+//
+// 6.4.2.1 Transfer Event TRB: 16 bytes
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1
+// for more information on the use and operation of Transfer Events.
+//
+typedef struct _EVT_TRB_TRANSFER {
+ UINT32 TRBPtrLo;
+
+ UINT32 TRBPtrHi;
+
+ UINT32 Length : 24;
+ UINT32 Completecode : 8;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ1 : 1;
+ UINT32 ED : 1;
+ UINT32 RsvdZ2 : 7;
+ UINT32 Type : 6;
+ UINT32 EndpointId : 5;
+ UINT32 RsvdZ3 : 3;
+ UINT32 SlotId : 8;
+} EVT_TRB_TRANSFER;
+
+//
+// 6.4.4.1 Link TRB: 16 bytes
+// A Link TRB provides support for non-contiguous TRB Rings.
+//
+typedef struct _LINK_TRB {
+ UINT32 PtrLo;
+
+ UINT32 PtrHi;
+
+ UINT32 RsvdZ1 : 22;
+ UINT32 InterTarget : 10;
+
+ UINT32 CycleBit : 1;
+ UINT32 TC : 1;
+ UINT32 RsvdZ2 : 2;
+ UINT32 CH : 1;
+ UINT32 IOC : 1;
+ UINT32 RsvdZ3 : 4;
+ UINT32 Type : 6;
+ UINT32 RsvdZ4 : 16;
+} LINK_TRB;
+
+//
+// TRB Template: 16 bytes
+//
+typedef struct _TRB_TEMPLATE {
+ UINT32 Parameter1;
+
+ UINT32 Parameter2;
+
+ UINT32 Status;
+
+ UINT32 CycleBit : 1;
+ UINT32 RsvdZ1 : 9;
+ UINT32 Type : 6;
+ UINT32 Control : 16;
+} TRB_TEMPLATE;
+
+//
+// Refer to XHCI 6.5 Event Ring Segment Table: 16 bytes
+//
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {
+ UINT32 PtrLo;
+ UINT32 PtrHi;
+ UINT32 RingTrbSize : 16;
+ UINT32 RsvdZ1 : 16;
+ UINT32 RsvdZ2;
+} EVENT_RING_SEG_TABLE_ENTRY;
+
+//
+// Size: 40 bytes
+//
+typedef struct _EVENT_RING {
+ EFI_PHYSICAL_ADDRESS ERSTBase;
+ EFI_PHYSICAL_ADDRESS EventRingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS EventRingEnqueue;
+ EFI_PHYSICAL_ADDRESS EventRingDequeue;
+ UINT32 EventRingCCS;
+} EVENT_RING;
+
+// Size: 32 bytes
+typedef struct _TRANSFER_RING {
+ EFI_PHYSICAL_ADDRESS RingSeg0;
+ UINT32 TrbNumber;
+ EFI_PHYSICAL_ADDRESS RingEnqueue;
+ EFI_PHYSICAL_ADDRESS RingDequeue;
+ UINT32 RingPCS;
+} TRANSFER_RING;
+
+//
+// Size: 64 bytes
+//
+typedef struct _DBC_INFO_CONTEXT {
+ UINT64 String0DescAddress;
+ UINT64 ManufacturerStrDescAddress;
+ UINT64 ProductStrDescAddress;
+ UINT64 SerialNumberStrDescAddress;
+ UINT64 String0Length : 8;
+ UINT64 ManufacturerStrLength : 8;
+ UINT64 ProductStrLength : 8;
+ UINT64 SerialNumberStrLength : 8;
+ UINT64 RsvdZ1 : 32;
+ UINT64 RsvdZ2;
+ UINT64 RsvdZ3;
+ UINT64 RsvdZ4;
+} DBC_INFO_CONTEXT;
+
+//
+// Debug Capability Context Data Structure: 192 bytes
+//
+typedef struct _XHC_DC_CONTEXT {
+ DBC_INFO_CONTEXT DbcInfoContext;
+ ENDPOINT_CONTEXT_64 EpOutContext;
+ ENDPOINT_CONTEXT_64 EpInContext;
+} XHC_DC_CONTEXT;
+
+//
+// Size: 16 bytes
+//
+typedef union _TRB {
+ TRB_TEMPLATE TrbTemplate;
+ TRANSFER_TRB_NORMAL TrbNormal;
+} TRB;
+
+///
+/// USB data transfer direction
+///
+typedef enum {
+ EfiUsbDataIn,
+ EfiUsbDataOut,
+ EfiUsbNoData
+} EFI_USB_DATA_DIRECTION;
+
+//
+// URB (Usb Request Block) contains information for all kinds of
+// usb requests.
+//
+typedef struct _URB {
+ //
+ // Transfer data buffer
+ //
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT32 DataLen;
+
+ //
+ // Execute result
+ //
+ UINT32 Result;
+ //
+ // Completed data length
+ //
+ UINT32 Completed;
+ //
+ // Tranfer Ring info
+ //
+ EFI_PHYSICAL_ADDRESS Ring;
+ EFI_PHYSICAL_ADDRESS Trb;
+ BOOLEAN Finished;
+ EFI_USB_DATA_DIRECTION Direction;
+} URB;
+
+typedef struct _USB3_DEBUG_PORT_INSTANCE {
+ UINT8 Initialized;
+
+ //
+ // The flag indicates debug capability is supported
+ //
+ BOOLEAN DebugSupport;
+
+ //
+ // The flag indicates debug device is ready
+ //
+ BOOLEAN Ready;
+
+ //
+ // The flag indicates the instance is from HOB
+ //
+ BOOLEAN FromHob;
+
+ //
+ // Prevent notification being interrupted by debug timer
+ //
+ BOOLEAN InNotify;
+
+ //
+ // PciIo protocol event
+ //
+ EFI_PHYSICAL_ADDRESS PciIoEvent;
+
+ //
+ // The flag indicates if USB 3.0 ports has been turn off/on power
+ //
+ BOOLEAN ChangePortPower;
+
+ //
+ // XHCI MMIO Base address
+ //
+ EFI_PHYSICAL_ADDRESS XhciMmioBase;
+
+ //
+ // XHCI OP RegisterBase address
+ //
+ EFI_PHYSICAL_ADDRESS XhciOpRegister;
+
+ //
+ // XHCI Debug Register Base Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityBase;
+
+ //
+ // XHCI Debug Capability offset
+ //
+ UINT64 DebugCapabilityOffset;
+
+ //
+ // XHCI Debug Context Address
+ //
+ EFI_PHYSICAL_ADDRESS DebugCapabilityContext;
+
+ //
+ // Transfer Ring
+ //
+ TRANSFER_RING TransferRingOut;
+ TRANSFER_RING TransferRingIn;
+
+ //
+ // EventRing
+ //
+ EVENT_RING EventRing;
+
+ //
+ // URB - Read
+ //
+ URB UrbOut;
+
+ //
+ // URB - Write
+ //
+ URB UrbIn;
+
+ //
+ // The available data length in the following data buffer.
+ //
+ UINT8 DataCount;
+ //
+ // The data buffer address for data read and poll.
+ //
+ EFI_PHYSICAL_ADDRESS Data;
+} USB3_DEBUG_PORT_HANDLE;
+
+#pragma pack()
+
+/**
+ Read XHCI debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+
+ @return The register content read
+
+**/
+UINT32
+XhcReadDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset
+ );
+
+/**
+ Set one bit of the debug register while keeping other bits.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Bit The bit mask of the register to set.
+
+**/
+VOID
+XhcSetDebugRegBit (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Bit
+ );
+
+/**
+ Write the data to the debug register.
+
+ @param Handle Debug port handle.
+ @param Offset The offset of the debug register.
+ @param Data The data to write.
+
+**/
+VOID
+XhcWriteDebugReg (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN UINT32 Offset,
+ IN UINT32 Data
+ );
+
+/**
+ Verifies if the bit positions specified by a mask are set in a register.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+
+ @return BOOLEAN - TRUE if all bits specified by the mask are enabled.
+ - FALSE even if one of the bits specified by the mask
+ is not enabled.
+**/
+BOOLEAN
+XhcIsBitSet (
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Sets bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcSetR32Bit (
+ UINTN Register,
+ UINT32 BitMask
+ );
+
+/**
+ Clears bits as per the enabled bit positions in the mask.
+
+ @param[in, out] Register UINTN register
+ @param[in] BitMask 32-bit mask
+**/
+VOID
+XhcClearR32Bit (
+ IN OUT UINTN Register,
+ IN UINT32 BitMask
+ );
+
+/**
+ Initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3Initialize (
+ VOID
+ );
+
+/**
+ Return command register value in XHCI controller.
+
+**/
+UINT16
+GetXhciPciCommand (
+ VOID
+ );
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ );
+
+/**
+ The real function to initialize USB3 debug port.
+
+ This method invokes various internal functions to facilitate
+ detection and initialization of USB3 debug port.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+**/
+RETURN_STATUS
+EFIAPI
+USB3InitializeReal (
+ VOID
+ );
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Handle The instance of debug device.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in millisecond, which
+ the transfer is allowed to complete.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ );
+
+/**
+ Initialize usb debug port hardware.
+
+ @param Handle Debug port handle.
+
+ @retval TRUE The usb debug port hardware configuration is changed.
+ @retval FALSE The usb debug port hardware configuration is not changed.
+
+**/
+RETURN_STATUS
+EFIAPI
+InitializeUsbDebugHardware (
+ IN USB3_DEBUG_PORT_HANDLE *Handle
+ );
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ );
+
+/**
+ Return USB3 debug instance address.
+
+**/
+USB3_DEBUG_PORT_HANDLE *
+GetUsb3DebugPortInstance (
+ VOID
+ );
+
+#endif //__SERIAL_PORT_LIB_USB__
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
index aa04442918..876be20f25 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.c
@@ -1,274 +1,274 @@
-/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiPei.h>
-#include <Library/PeiServicesLib.h>
-#include <Library/HobLib.h>
-#include <Ppi/MemoryDiscovered.h>
-#include <Ppi/IoMmu.h>
-#include "DebugCommunicationLibUsb3Internal.h"
-
-GUID gUsb3DbgGuid = USB3_DBG_GUID;
-
-/**
- USB3 IOMMU PPI notify.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
- caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_STATUS Always return EFI_SUCCESS
-**/
-EFI_STATUS
-EFIAPI
-Usb3IoMmuPpiNotify (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
- IN VOID *Ppi
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
-
- DEBUG ((DEBUG_INFO, "%a()\n", __func__));
-
- Instance = GetUsb3DebugPortInstance ();
- ASSERT (Instance != NULL);
- if (!Instance->Ready) {
- return EFI_SUCCESS;
- }
-
- Instance->InNotify = TRUE;
-
- //
- // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
- //
- InitializeUsbDebugHardware (Instance);
-
- //
- // Wait some time for host to be ready after re-initialization.
- //
- MicroSecondDelay (1000000);
-
- Instance->InNotify = FALSE;
-
- return EFI_SUCCESS;
-}
-
-EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEdkiiIoMmuPpiGuid,
- Usb3IoMmuPpiNotify
-};
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param IoMmu Pointer to IOMMU PPI.
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN EDKII_IOMMU_PPI *IoMmu,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINTN NumberOfBytes;
-
- *HostAddress = NULL;
- *DeviceAddress = 0;
- *Mapping = NULL;
-
- Status = IoMmu->AllocateBuffer (
- IoMmu,
- EfiRuntimeServicesData,
- Pages,
- HostAddress,
- 0
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
- Status = IoMmu->Map (
- IoMmu,
- EdkiiIoMmuOperationBusMasterCommonBuffer,
- *HostAddress,
- &NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
- *HostAddress = NULL;
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = IoMmu->SetAttribute (
- IoMmu,
- *Mapping,
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
- );
- if (EFI_ERROR (Status)) {
- IoMmu->Unmap (IoMmu, *Mapping);
- IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
- *Mapping = NULL;
- *HostAddress = NULL;
- return Status;
- }
-
- return Status;
-}
-
-/**
- USB3 get IOMMU PPI.
-
- @return Pointer to IOMMU PPI.
-
-**/
-EDKII_IOMMU_PPI *
-Usb3GetIoMmu (
- VOID
- )
-{
- EFI_STATUS Status;
- EDKII_IOMMU_PPI *IoMmu;
-
- IoMmu = NULL;
- Status = PeiServicesLocatePpi (
- &gEdkiiIoMmuPpiGuid,
- 0,
- NULL,
- (VOID **)&IoMmu
- );
- if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
- return IoMmu;
- }
-
- return NULL;
-}
-
-/**
- Return USB3 debug instance address pointer.
-
-**/
-EFI_PHYSICAL_ADDRESS *
-GetUsb3DebugPortInstanceAddrPtr (
- VOID
- )
-{
- USB3_DEBUG_PORT_HANDLE *Instance;
- EFI_PHYSICAL_ADDRESS *AddrPtr;
- EFI_PEI_HOB_POINTERS Hob;
- EFI_STATUS Status;
-
- Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
- if (Hob.Raw == NULL) {
- //
- // Build HOB for the local instance and the buffer to save instance address pointer.
- // Use the local instance in HOB temporarily.
- //
- AddrPtr = BuildGuidHob (
- &gUsb3DbgGuid,
- sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)
- );
- ASSERT (AddrPtr != NULL);
- ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
- Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
- *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
- Instance->FromHob = TRUE;
- Instance->Initialized = USB3DBG_UNINITIALIZED;
- if (Usb3GetIoMmu () == NULL) {
- Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
- ASSERT_EFI_ERROR (Status);
- }
- } else {
- AddrPtr = GET_GUID_HOB_DATA (Hob.Guid);
- }
-
- return AddrPtr;
-}
-
-/**
- Allocate aligned memory for XHC's usage.
-
- @param BufferSize The size, in bytes, of the Buffer.
-
- @return A pointer to the allocated buffer or NULL if allocation fails.
-
-**/
-VOID *
-AllocateAlignBuffer (
- IN UINTN BufferSize
- )
-{
- VOID *Buf;
- EFI_PHYSICAL_ADDRESS Address;
- EFI_STATUS Status;
- VOID *MemoryDiscoveredPpi;
- EDKII_IOMMU_PPI *IoMmu;
- VOID *HostAddress;
- VOID *Mapping;
-
- Buf = NULL;
-
- //
- // Make sure the allocated memory is physical memory.
- //
- Status = PeiServicesLocatePpi (
- &gEfiPeiMemoryDiscoveredPpiGuid,
- 0,
- NULL,
- (VOID **)&MemoryDiscoveredPpi
- );
- if (!EFI_ERROR (Status)) {
- IoMmu = Usb3GetIoMmu ();
- if (IoMmu != NULL) {
- Status = IoMmuAllocateBuffer (
- IoMmu,
- EFI_SIZE_TO_PAGES (BufferSize),
- &HostAddress,
- &Address,
- &Mapping
- );
- if (!EFI_ERROR (Status)) {
- ASSERT (Address == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
- Buf = (VOID *)(UINTN)Address;
- }
- } else {
- Status = PeiServicesAllocatePages (
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (BufferSize),
- &Address
- );
- if (!EFI_ERROR (Status)) {
- Buf = (VOID *)(UINTN)Address;
- }
- }
- }
-
- return Buf;
-}
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/IoMmu.h>
+#include "DebugCommunicationLibUsb3Internal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+/**
+ USB3 IOMMU PPI notify.
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+Usb3IoMmuPpiNotify (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ DEBUG ((DEBUG_INFO, "%a()\n", __func__));
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ if (!Instance->Ready) {
+ return EFI_SUCCESS;
+ }
+
+ Instance->InNotify = TRUE;
+
+ //
+ // Reinitialize USB3 debug port with granted DMA buffer from IOMMU PPI.
+ //
+ InitializeUsbDebugHardware (Instance);
+
+ //
+ // Wait some time for host to be ready after re-initialization.
+ //
+ MicroSecondDelay (1000000);
+
+ Instance->InNotify = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mUsb3IoMmuPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEdkiiIoMmuPpiGuid,
+ Usb3IoMmuPpiNotify
+};
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param IoMmu Pointer to IOMMU PPI.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PPI *IoMmu,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+ *Mapping = NULL;
+
+ Status = IoMmu->AllocateBuffer (
+ IoMmu,
+ EfiRuntimeServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
+ Status = IoMmu->Map (
+ IoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *HostAddress = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = IoMmu->SetAttribute (
+ IoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ IoMmu->Unmap (IoMmu, *Mapping);
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
+ *Mapping = NULL;
+ *HostAddress = NULL;
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ USB3 get IOMMU PPI.
+
+ @return Pointer to IOMMU PPI.
+
+**/
+EDKII_IOMMU_PPI *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PPI *IoMmu;
+
+ IoMmu = NULL;
+ Status = PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_STATUS Status;
+
+ Hob.Raw = GetFirstGuidHob (&gUsb3DbgGuid);
+ if (Hob.Raw == NULL) {
+ //
+ // Build HOB for the local instance and the buffer to save instance address pointer.
+ // Use the local instance in HOB temporarily.
+ //
+ AddrPtr = BuildGuidHob (
+ &gUsb3DbgGuid,
+ sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)
+ );
+ ASSERT (AddrPtr != NULL);
+ ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
+ Instance = (USB3_DEBUG_PORT_HANDLE *)(AddrPtr + 1);
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS)(UINTN)Instance;
+ Instance->FromHob = TRUE;
+ Instance->Initialized = USB3DBG_UNINITIALIZED;
+ if (Usb3GetIoMmu () == NULL) {
+ Status = PeiServicesNotifyPpi (&mUsb3IoMmuPpiNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ AddrPtr = GET_GUID_HOB_DATA (Hob.Guid);
+ }
+
+ return AddrPtr;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ VOID *Buf;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ VOID *MemoryDiscoveredPpi;
+ EDKII_IOMMU_PPI *IoMmu;
+ VOID *HostAddress;
+ VOID *Mapping;
+
+ Buf = NULL;
+
+ //
+ // Make sure the allocated memory is physical memory.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiMemoryDiscoveredPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&MemoryDiscoveredPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ IoMmu = Usb3GetIoMmu ();
+ if (IoMmu != NULL) {
+ Status = IoMmuAllocateBuffer (
+ IoMmu,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &HostAddress,
+ &Address,
+ &Mapping
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Address == ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress));
+ Buf = (VOID *)(UINTN)Address;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *)(UINTN)Address;
+ }
+ }
+ }
+
+ return Buf;
+}
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
index 89a7cfcd00..02638804af 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf
@@ -1,69 +1,69 @@
-## @file
-# Debug Communication Library instance based on usb3 debug port.
-#
-# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DebugCommunicationLibUsb3Pei
- MODULE_UNI_FILE = DebugCommunicationLibUsb3Pei.uni
- FILE_GUID = 106C877F-C2BA-4c46-876C-BDFE6171CD7E
- MODULE_TYPE = PEIM
- VERSION_STRING = 1.0
- LIBRARY_CLASS = DebugCommunicationLib|PEIM PEI_CORE
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64
-#
-
-[Sources]
- DebugCommunicationLibUsb3Pei.c
- DebugCommunicationLibUsb3Transfer.c
- DebugCommunicationLibUsb3Common.c
- DebugCommunicationLibUsb3Internal.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- SourceLevelDebugPkg/SourceLevelDebugPkg.dec
-
-[Ppis]
- gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
- gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES
-
-[Pcd]
- # The memory BAR of ehci host controller, in which usb debug feature is enabled.
- # Note that the memory BAR address is only used before Pci bus resource allocation.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
-
- # The pci address of ehci host controller, in which usb debug feature is enabled.
- # The format of pci address please refer to SourceLevelDebugPkg.dec
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
-
- # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
- # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
-
- # The value of data buffer size used for USB debug port handle.
- # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
- gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
-
-[LibraryClasses]
- BaseLib
- PcdLib
- IoLib
- PciLib
- TimerLib
- BaseMemoryLib
- PeiServicesLib
- HobLib
-
-[Depex.common.PEIM]
- gEfiPeiMemoryDiscoveredPpiGuid
+## @file
+# Debug Communication Library instance based on usb3 debug port.
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugCommunicationLibUsb3Pei
+ MODULE_UNI_FILE = DebugCommunicationLibUsb3Pei.uni
+ FILE_GUID = 106C877F-C2BA-4c46-876C-BDFE6171CD7E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugCommunicationLib|PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DebugCommunicationLibUsb3Pei.c
+ DebugCommunicationLibUsb3Transfer.c
+ DebugCommunicationLibUsb3Common.c
+ DebugCommunicationLibUsb3Internal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+
+[Ppis]
+ gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ # The memory BAR of ehci host controller, in which usb debug feature is enabled.
+ # Note that the memory BAR address is only used before Pci bus resource allocation.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciMemorySpaceBase ## SOMETIMES_CONSUMES
+
+ # The pci address of ehci host controller, in which usb debug feature is enabled.
+ # The format of pci address please refer to SourceLevelDebugPkg.dec
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciPciAddress ## CONSUMES
+
+ # Per XHCI spec, software shall impose a timeout between the detection of the Debug Host
+ # connection and the DbC Run transition to 1. This PCD specifies the timeout value in microsecond.
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdUsbXhciDebugDetectTimeout ## SOMETIMES_CONSUMES
+
+ # The value of data buffer size used for USB debug port handle.
+ # It should be equal to sizeof (USB3_DEBUG_PORT_HANDLE).
+ gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugPortHandleBufferSize|249 ## SOMETIMES_CONSUMES
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ IoLib
+ PciLib
+ TimerLib
+ BaseMemoryLib
+ PeiServicesLib
+ HobLib
+
+[Depex.common.PEIM]
+ gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
index 8252b660b6..3511de6788 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.uni
@@ -1,16 +1,16 @@
-// /** @file
-// Debug Communication Library instance based on USB3 debug port for PEI modules.
-//
-// Debug Communication Library instance based on USB3 debug port for PEI modules.
-//
-// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules."
-
+// /** @file
+// Debug Communication Library instance based on USB3 debug port for PEI modules.
+//
+// Debug Communication Library instance based on USB3 debug port for PEI modules.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Debug Communication Library instance based on USB3 debug port for PEI modules."
+
diff --git a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
index a651e88271..eadc8f5164 100644
--- a/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
+++ b/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Transfer.c
@@ -1,584 +1,584 @@
-/** @file
- Debug Port Library implementation based on usb3 debug port.
-
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-#include "DebugCommunicationLibUsb3Internal.h"
-
-/**
- Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
-
- @param Handle Debug port handle.
- @param TrsRing The transfer ring to sync.
-
- @retval EFI_SUCCESS The transfer ring is synchronized successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcSyncTrsRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN TRANSFER_RING *TrsRing
- )
-{
- UINTN Index;
- TRB_TEMPLATE *TrsTrb;
- UINT32 CycleBit;
-
- ASSERT (TrsRing != NULL);
-
- //
- // Calculate the latest RingEnqueue and RingPCS
- //
- TrsTrb = (TRB_TEMPLATE *)(UINTN)TrsRing->RingEnqueue;
-
- ASSERT (TrsTrb != NULL);
-
- for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
- if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
- break;
- }
-
- TrsTrb++;
- if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {
- ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);
- //
- // set cycle bit in Link TRB as normal
- //
- ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
- //
- // Toggle PCS maintained by software
- //
- TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
- TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
- }
- }
-
- ASSERT (Index != TrsRing->TrbNumber);
-
- if ((EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb != TrsRing->RingEnqueue) {
- TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb;
- }
-
- //
- // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
- //
- CycleBit = TrsTrb->CycleBit;
- ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
- TrsTrb->CycleBit = CycleBit;
-
- return EFI_SUCCESS;
-}
-
-/**
- Synchronize the specified event ring to update the enqueue and dequeue pointer.
-
- @param Handle Debug port handle.
- @param EvtRing The event ring to sync.
-
- @retval EFI_SUCCESS The event ring is synchronized successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcSyncEventRing (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EVENT_RING *EvtRing
- )
-{
- UINTN Index;
- TRB_TEMPLATE *EvtTrb1;
-
- ASSERT (EvtRing != NULL);
-
- //
- // Calculate the EventRingEnqueue and EventRingCCS.
- // Note: only support single Segment
- //
- EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
-
- for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
- if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
- break;
- }
-
- EvtTrb1++;
-
- if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
- EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingSeg0;
- EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
- }
- }
-
- if (Index < EvtRing->TrbNumber) {
- EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
- } else {
- ASSERT (FALSE);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Check if there is a new generated event.
-
- @param Handle Debug port handle.
- @param EvtRing The event ring to check.
- @param NewEvtTrb The new event TRB found.
-
- @retval EFI_SUCCESS Found a new event TRB at the event ring.
- @retval EFI_NOT_READY The event ring has no new event.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcCheckNewEvent (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EVENT_RING *EvtRing,
- OUT TRB_TEMPLATE **NewEvtTrb
- )
-{
- EFI_STATUS Status;
-
- ASSERT (EvtRing != NULL);
-
- *NewEvtTrb = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
-
- if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
- return EFI_NOT_READY;
- }
-
- Status = EFI_SUCCESS;
-
- EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
- //
- // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
- //
- if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
- EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
- }
-
- return Status;
-}
-
-/**
- Check if the Trb is a transaction of the URB.
-
- @param Ring The transfer ring to be checked.
- @param Trb The TRB to be checked.
-
- @retval TRUE It is a transaction of the URB.
- @retval FALSE It is not any transaction of the URB.
-
-**/
-BOOLEAN
-IsTrbInTrsRing (
- IN TRANSFER_RING *Ring,
- IN TRB_TEMPLATE *Trb
- )
-{
- TRB_TEMPLATE *CheckedTrb;
- UINTN Index;
-
- CheckedTrb = (TRB_TEMPLATE *)(UINTN)Ring->RingSeg0;
-
- ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
-
- for (Index = 0; Index < Ring->TrbNumber; Index++) {
- if (Trb == CheckedTrb) {
- return TRUE;
- }
-
- CheckedTrb++;
- }
-
- return FALSE;
-}
-
-/**
- Check the URB's execution result and update the URB's
- result accordingly.
-
- @param Handle Debug port handle.
- @param Urb The URB to check result.
-
-**/
-VOID
-XhcCheckUrbResult (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- EVT_TRB_TRANSFER *EvtTrb;
- TRB_TEMPLATE *TRBPtr;
- UINTN Index;
- EFI_STATUS Status;
- URB *CheckedUrb;
- UINT64 XhcDequeue;
- UINT32 High;
- UINT32 Low;
-
- ASSERT ((Handle != NULL) && (Urb != NULL));
-
- if (Urb->Finished) {
- goto EXIT;
- }
-
- EvtTrb = NULL;
-
- //
- // Traverse the event ring to find out all new events from the previous check.
- //
- XhcSyncEventRing (Handle, &Handle->EventRing);
-
- for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
- Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
- if (Status == EFI_NOT_READY) {
- //
- // All new events are handled, return directly.
- //
- goto EXIT;
- }
-
- if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
- continue;
- }
-
- TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));
-
- if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
- CheckedUrb = Urb;
- } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
- //
- // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
- // Internal buffer is used by next read.
- //
- Handle->DataCount = (UINT8)(Handle->UrbIn.DataLen - EvtTrb->Length);
- CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
- //
- // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
- //
- TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
- continue;
- } else {
- continue;
- }
-
- if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
- (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS))
- {
- //
- // The length of data which were transferred.
- //
- CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);
- } else {
- CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
- }
-
- //
- // This Urb has been processed
- //
- CheckedUrb->Finished = TRUE;
- }
-
-EXIT:
- //
- // Advance event ring to last available entry
- //
- // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
- // So divide it to two 32-bytes width register access.
- //
- Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
- High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
- XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);
-
- if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
- //
- // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
- // So divide it to two 32-bytes width register access.
- //
- XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
- XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
- }
-}
-
-/**
- Ring the door bell to notify XHCI there is a transaction to be executed.
-
- @param Handle Debug port handle.
- @param Urb The pointer to URB.
-
- @retval EFI_SUCCESS Successfully ring the door bell.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcRingDoorBell (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- UINT32 Dcdb;
-
- //
- // 7.6.8.2 DCDB Register
- //
- Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
-
- XhcWriteDebugReg (
- Handle,
- XHC_DC_DCDB,
- Dcdb
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Execute the transfer by polling the URB. This is a synchronous operation.
-
- @param Handle Debug port handle.
- @param Urb The URB to execute.
- @param Timeout The time to wait before abort, in microsecond.
-
-**/
-VOID
-XhcExecTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb,
- IN UINTN Timeout
- )
-{
- TRANSFER_RING *Ring;
- TRB_TEMPLATE *Trb;
- UINTN Loop;
- UINTN Index;
-
- Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
- if (Timeout == 0) {
- Loop = 0xFFFFFFFF;
- }
-
- XhcRingDoorBell (Handle, Urb);
- //
- // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
- //
- for (Index = 0; Index < Loop; Index++) {
- XhcCheckUrbResult (Handle, Urb);
- if (Urb->Finished) {
- break;
- }
-
- MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
- }
-
- if (Index == Loop) {
- //
- // If time out occurs.
- //
- Urb->Result |= EFI_USB_ERR_TIMEOUT;
- }
-
- //
- // If URB transfer is error, restore transfer ring to original value before URB transfer
- // This will make the current transfer TRB is always at the latest unused one in transfer ring.
- //
- Ring = (TRANSFER_RING *)(UINTN)Urb->Ring;
- if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
- //
- // Adjust Enqueue pointer
- //
- Ring->RingEnqueue = Urb->Trb;
- //
- // Clear CCS flag for next use
- //
- Trb = (TRB_TEMPLATE *)(UINTN)Urb->Trb;
- Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
- } else {
- //
- // Update transfer ring for next transfer.
- //
- XhcSyncTrsRing (Handle, Ring);
- }
-}
-
-/**
- Create a transfer TRB.
-
- @param Handle Debug port handle.
- @param Urb The urb used to construct the transfer TRB.
-
- @return Created TRB or NULL
-
-**/
-EFI_STATUS
-XhcCreateTransferTrb (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN URB *Urb
- )
-{
- TRANSFER_RING *EPRing;
- TRB *Trb;
-
- if (Urb->Direction == EfiUsbDataIn) {
- EPRing = &Handle->TransferRingIn;
- } else {
- EPRing = &Handle->TransferRingOut;
- }
-
- Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN)EPRing;
- XhcSyncTrsRing (Handle, EPRing);
-
- Urb->Trb = EPRing->RingEnqueue;
- Trb = (TRB *)(UINTN)EPRing->RingEnqueue;
- Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data);
- Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data);
- Trb->TrbNormal.Length = Urb->DataLen;
- Trb->TrbNormal.TDSize = 0;
- Trb->TrbNormal.IntTarget = 0;
- Trb->TrbNormal.ISP = 1;
- Trb->TrbNormal.IOC = 1;
- Trb->TrbNormal.Type = TRB_TYPE_NORMAL;
-
- //
- // Update the cycle bit to indicate this TRB has been consumed.
- //
- Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
-
- return EFI_SUCCESS;
-}
-
-/**
- Create a new URB for a new transaction.
-
- @param Handle Debug port handle.
- @param Direction The direction of data flow.
- @param Data The user data to transfer
- @param DataLen The length of data buffer
-
- @return Created URB or NULL
-
-**/
-URB *
-XhcCreateUrb (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN VOID *Data,
- IN UINTN DataLen
- )
-{
- EFI_STATUS Status;
- URB *Urb;
- EFI_PHYSICAL_ADDRESS UrbData;
-
- if (Direction == EfiUsbDataIn) {
- Urb = &Handle->UrbIn;
- } else {
- Urb = &Handle->UrbOut;
- }
-
- UrbData = Urb->Data;
-
- ZeroMem (Urb, sizeof (URB));
- Urb->Direction = Direction;
-
- //
- // Allocate memory to move data from CAR or SMRAM to normal memory
- // to make XHCI DMA successfully
- // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
- //
- Urb->Data = UrbData;
-
- if (Direction == EfiUsbDataIn) {
- //
- // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
- //
- Urb->DataLen = (UINT32)DataLen;
- } else {
- //
- // Put data into URB data out buffer which will create TRBs
- //
- ZeroMem ((VOID *)(UINTN)Urb->Data, DataLen);
- CopyMem ((VOID *)(UINTN)Urb->Data, Data, DataLen);
- Urb->DataLen = (UINT32)DataLen;
- }
-
- Status = XhcCreateTransferTrb (Handle, Urb);
- ASSERT_EFI_ERROR (Status);
-
- return Urb;
-}
-
-/**
- Submits bulk transfer to a bulk endpoint of a USB device.
-
- @param Handle Debug port handle.
- @param Direction The direction of data transfer.
- @param Data Array of pointers to the buffers of data to transmit
- from or receive into.
- @param DataLength The length of the data buffer.
- @param Timeout Indicates the maximum time, in microsecond, which
- the transfer is allowed to complete.
-
- @retval EFI_SUCCESS The transfer was completed successfully.
- @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
- @retval EFI_INVALID_PARAMETER Some parameters are invalid.
- @retval EFI_TIMEOUT The transfer failed due to timeout.
- @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
-
-**/
-EFI_STATUS
-EFIAPI
-XhcDataTransfer (
- IN USB3_DEBUG_PORT_HANDLE *Handle,
- IN EFI_USB_DATA_DIRECTION Direction,
- IN OUT VOID *Data,
- IN OUT UINTN *DataLength,
- IN UINTN Timeout
- )
-{
- URB *Urb;
- EFI_STATUS Status;
-
- //
- // Validate the parameters
- //
- if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Create a new URB, insert it into the asynchronous
- // schedule list, then poll the execution status.
- //
- Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
- ASSERT (Urb != NULL);
-
- XhcExecTransfer (Handle, Urb, Timeout);
-
- //
- // Make sure the data received from HW can fit in the received buffer.
- //
- if (Urb->Completed > *DataLength) {
- return EFI_DEVICE_ERROR;
- }
-
- *DataLength = Urb->Completed;
-
- Status = EFI_TIMEOUT;
- if (Urb->Result == EFI_USB_NOERROR) {
- Status = EFI_SUCCESS;
- }
-
- if (Direction == EfiUsbDataIn) {
- //
- // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
- // SMRAM does not allow to do DMA, so we create an internal buffer.
- //
- CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
- }
-
- return Status;
-}
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "DebugCommunicationLibUsb3Internal.h"
+
+/**
+ Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
+
+ @param Handle Debug port handle.
+ @param TrsRing The transfer ring to sync.
+
+ @retval EFI_SUCCESS The transfer ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncTrsRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN TRANSFER_RING *TrsRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *TrsTrb;
+ UINT32 CycleBit;
+
+ ASSERT (TrsRing != NULL);
+
+ //
+ // Calculate the latest RingEnqueue and RingPCS
+ //
+ TrsTrb = (TRB_TEMPLATE *)(UINTN)TrsRing->RingEnqueue;
+
+ ASSERT (TrsTrb != NULL);
+
+ for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
+ if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
+ break;
+ }
+
+ TrsTrb++;
+ if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {
+ ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);
+ //
+ // set cycle bit in Link TRB as normal
+ //
+ ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
+ //
+ // Toggle PCS maintained by software
+ //
+ TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
+ TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
+ }
+ }
+
+ ASSERT (Index != TrsRing->TrbNumber);
+
+ if ((EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb != TrsRing->RingEnqueue) {
+ TrsRing->RingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)TrsTrb;
+ }
+
+ //
+ // Clear the Trb context for enqueue, but reserve the PCS bit which indicates free Trb.
+ //
+ CycleBit = TrsTrb->CycleBit;
+ ZeroMem (TrsTrb, sizeof (TRB_TEMPLATE));
+ TrsTrb->CycleBit = CycleBit;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Synchronize the specified event ring to update the enqueue and dequeue pointer.
+
+ @param Handle Debug port handle.
+ @param EvtRing The event ring to sync.
+
+ @retval EFI_SUCCESS The event ring is synchronized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcSyncEventRing (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EVENT_RING *EvtRing
+ )
+{
+ UINTN Index;
+ TRB_TEMPLATE *EvtTrb1;
+
+ ASSERT (EvtRing != NULL);
+
+ //
+ // Calculate the EventRingEnqueue and EventRingCCS.
+ // Note: only support single Segment
+ //
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
+
+ for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
+ if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
+ break;
+ }
+
+ EvtTrb1++;
+
+ if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtTrb1 = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingSeg0;
+ EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
+ }
+ }
+
+ if (Index < EvtRing->TrbNumber) {
+ EvtRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN)EvtTrb1;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if there is a new generated event.
+
+ @param Handle Debug port handle.
+ @param EvtRing The event ring to check.
+ @param NewEvtTrb The new event TRB found.
+
+ @retval EFI_SUCCESS Found a new event TRB at the event ring.
+ @retval EFI_NOT_READY The event ring has no new event.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcCheckNewEvent (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EVENT_RING *EvtRing,
+ OUT TRB_TEMPLATE **NewEvtTrb
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (EvtRing != NULL);
+
+ *NewEvtTrb = (TRB_TEMPLATE *)(UINTN)EvtRing->EventRingDequeue;
+
+ if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
+ return EFI_NOT_READY;
+ }
+
+ Status = EFI_SUCCESS;
+
+ EvtRing->EventRingDequeue += sizeof (TRB_TEMPLATE);
+ //
+ // If the dequeue pointer is beyond the ring, then roll-back it to the beginning of the ring.
+ //
+ if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
+ EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
+ }
+
+ return Status;
+}
+
+/**
+ Check if the Trb is a transaction of the URB.
+
+ @param Ring The transfer ring to be checked.
+ @param Trb The TRB to be checked.
+
+ @retval TRUE It is a transaction of the URB.
+ @retval FALSE It is not any transaction of the URB.
+
+**/
+BOOLEAN
+IsTrbInTrsRing (
+ IN TRANSFER_RING *Ring,
+ IN TRB_TEMPLATE *Trb
+ )
+{
+ TRB_TEMPLATE *CheckedTrb;
+ UINTN Index;
+
+ CheckedTrb = (TRB_TEMPLATE *)(UINTN)Ring->RingSeg0;
+
+ ASSERT (Ring->TrbNumber == TR_RING_TRB_NUMBER);
+
+ for (Index = 0; Index < Ring->TrbNumber; Index++) {
+ if (Trb == CheckedTrb) {
+ return TRUE;
+ }
+
+ CheckedTrb++;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check the URB's execution result and update the URB's
+ result accordingly.
+
+ @param Handle Debug port handle.
+ @param Urb The URB to check result.
+
+**/
+VOID
+XhcCheckUrbResult (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ EVT_TRB_TRANSFER *EvtTrb;
+ TRB_TEMPLATE *TRBPtr;
+ UINTN Index;
+ EFI_STATUS Status;
+ URB *CheckedUrb;
+ UINT64 XhcDequeue;
+ UINT32 High;
+ UINT32 Low;
+
+ ASSERT ((Handle != NULL) && (Urb != NULL));
+
+ if (Urb->Finished) {
+ goto EXIT;
+ }
+
+ EvtTrb = NULL;
+
+ //
+ // Traverse the event ring to find out all new events from the previous check.
+ //
+ XhcSyncEventRing (Handle, &Handle->EventRing);
+
+ for (Index = 0; Index < Handle->EventRing.TrbNumber; Index++) {
+ Status = XhcCheckNewEvent (Handle, &Handle->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
+ if (Status == EFI_NOT_READY) {
+ //
+ // All new events are handled, return directly.
+ //
+ goto EXIT;
+ }
+
+ if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
+ continue;
+ }
+
+ TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));
+
+ if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Urb->Ring), TRBPtr)) {
+ CheckedUrb = Urb;
+ } else if (IsTrbInTrsRing ((TRANSFER_RING *)(UINTN)(Handle->UrbIn.Ring), TRBPtr)) {
+ //
+ // If it is read event and it should be generated by poll, and current operation is write, we need save data into internal buffer.
+ // Internal buffer is used by next read.
+ //
+ Handle->DataCount = (UINT8)(Handle->UrbIn.DataLen - EvtTrb->Length);
+ CopyMem ((VOID *)(UINTN)Handle->Data, (VOID *)(UINTN)Handle->UrbIn.Data, Handle->DataCount);
+ //
+ // Fill this TRB complete with CycleBit, otherwise next read will fail with old TRB.
+ //
+ TRBPtr->CycleBit = (TRBPtr->CycleBit & BIT0) ? 0 : 1;
+ continue;
+ } else {
+ continue;
+ }
+
+ if ((EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) ||
+ (EvtTrb->Completecode == TRB_COMPLETION_SUCCESS))
+ {
+ //
+ // The length of data which were transferred.
+ //
+ CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);
+ } else {
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ //
+ // This Urb has been processed
+ //
+ CheckedUrb->Finished = TRUE;
+ }
+
+EXIT:
+ //
+ // Advance event ring to last available entry
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ Low = XhcReadDebugReg (Handle, XHC_DC_DCERDP);
+ High = XhcReadDebugReg (Handle, XHC_DC_DCERDP + 4);
+ XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);
+
+ if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Handle->EventRing.EventRingDequeue & (~0x0F))) {
+ //
+ // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
+ // So divide it to two 32-bytes width register access.
+ //
+ XhcWriteDebugReg (Handle, XHC_DC_DCERDP, XHC_LOW_32BIT (Handle->EventRing.EventRingDequeue));
+ XhcWriteDebugReg (Handle, XHC_DC_DCERDP + 4, XHC_HIGH_32BIT (Handle->EventRing.EventRingDequeue));
+ }
+}
+
+/**
+ Ring the door bell to notify XHCI there is a transaction to be executed.
+
+ @param Handle Debug port handle.
+ @param Urb The pointer to URB.
+
+ @retval EFI_SUCCESS Successfully ring the door bell.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcRingDoorBell (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ UINT32 Dcdb;
+
+ //
+ // 7.6.8.2 DCDB Register
+ //
+ Dcdb = (Urb->Direction == EfiUsbDataIn) ? 0x100 : 0x0;
+
+ XhcWriteDebugReg (
+ Handle,
+ XHC_DC_DCDB,
+ Dcdb
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute the transfer by polling the URB. This is a synchronous operation.
+
+ @param Handle Debug port handle.
+ @param Urb The URB to execute.
+ @param Timeout The time to wait before abort, in microsecond.
+
+**/
+VOID
+XhcExecTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb,
+ IN UINTN Timeout
+ )
+{
+ TRANSFER_RING *Ring;
+ TRB_TEMPLATE *Trb;
+ UINTN Loop;
+ UINTN Index;
+
+ Loop = Timeout / XHC_DEBUG_PORT_1_MILLISECOND;
+ if (Timeout == 0) {
+ Loop = 0xFFFFFFFF;
+ }
+
+ XhcRingDoorBell (Handle, Urb);
+ //
+ // Event Ring Not Empty bit can only be set to 1 by XHC after ringing door bell with some delay.
+ //
+ for (Index = 0; Index < Loop; Index++) {
+ XhcCheckUrbResult (Handle, Urb);
+ if (Urb->Finished) {
+ break;
+ }
+
+ MicroSecondDelay (XHC_DEBUG_PORT_1_MILLISECOND);
+ }
+
+ if (Index == Loop) {
+ //
+ // If time out occurs.
+ //
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ //
+ // If URB transfer is error, restore transfer ring to original value before URB transfer
+ // This will make the current transfer TRB is always at the latest unused one in transfer ring.
+ //
+ Ring = (TRANSFER_RING *)(UINTN)Urb->Ring;
+ if ((Urb->Result != EFI_USB_NOERROR) && (Urb->Direction == EfiUsbDataIn)) {
+ //
+ // Adjust Enqueue pointer
+ //
+ Ring->RingEnqueue = Urb->Trb;
+ //
+ // Clear CCS flag for next use
+ //
+ Trb = (TRB_TEMPLATE *)(UINTN)Urb->Trb;
+ Trb->CycleBit = ((~Ring->RingPCS) & BIT0);
+ } else {
+ //
+ // Update transfer ring for next transfer.
+ //
+ XhcSyncTrsRing (Handle, Ring);
+ }
+}
+
+/**
+ Create a transfer TRB.
+
+ @param Handle Debug port handle.
+ @param Urb The urb used to construct the transfer TRB.
+
+ @return Created TRB or NULL
+
+**/
+EFI_STATUS
+XhcCreateTransferTrb (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN URB *Urb
+ )
+{
+ TRANSFER_RING *EPRing;
+ TRB *Trb;
+
+ if (Urb->Direction == EfiUsbDataIn) {
+ EPRing = &Handle->TransferRingIn;
+ } else {
+ EPRing = &Handle->TransferRingOut;
+ }
+
+ Urb->Ring = (EFI_PHYSICAL_ADDRESS)(UINTN)EPRing;
+ XhcSyncTrsRing (Handle, EPRing);
+
+ Urb->Trb = EPRing->RingEnqueue;
+ Trb = (TRB *)(UINTN)EPRing->RingEnqueue;
+ Trb->TrbNormal.TRBPtrLo = XHC_LOW_32BIT (Urb->Data);
+ Trb->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT (Urb->Data);
+ Trb->TrbNormal.Length = Urb->DataLen;
+ Trb->TrbNormal.TDSize = 0;
+ Trb->TrbNormal.IntTarget = 0;
+ Trb->TrbNormal.ISP = 1;
+ Trb->TrbNormal.IOC = 1;
+ Trb->TrbNormal.Type = TRB_TYPE_NORMAL;
+
+ //
+ // Update the cycle bit to indicate this TRB has been consumed.
+ //
+ Trb->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new URB for a new transaction.
+
+ @param Handle Debug port handle.
+ @param Direction The direction of data flow.
+ @param Data The user data to transfer
+ @param DataLen The length of data buffer
+
+ @return Created URB or NULL
+
+**/
+URB *
+XhcCreateUrb (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN VOID *Data,
+ IN UINTN DataLen
+ )
+{
+ EFI_STATUS Status;
+ URB *Urb;
+ EFI_PHYSICAL_ADDRESS UrbData;
+
+ if (Direction == EfiUsbDataIn) {
+ Urb = &Handle->UrbIn;
+ } else {
+ Urb = &Handle->UrbOut;
+ }
+
+ UrbData = Urb->Data;
+
+ ZeroMem (Urb, sizeof (URB));
+ Urb->Direction = Direction;
+
+ //
+ // Allocate memory to move data from CAR or SMRAM to normal memory
+ // to make XHCI DMA successfully
+ // re-use the pre-allocate buffer in PEI to avoid DXE memory service or gBS are not ready
+ //
+ Urb->Data = UrbData;
+
+ if (Direction == EfiUsbDataIn) {
+ //
+ // Do not break URB data in buffer as it may contain the data which were just put in via DMA by XHC
+ //
+ Urb->DataLen = (UINT32)DataLen;
+ } else {
+ //
+ // Put data into URB data out buffer which will create TRBs
+ //
+ ZeroMem ((VOID *)(UINTN)Urb->Data, DataLen);
+ CopyMem ((VOID *)(UINTN)Urb->Data, Data, DataLen);
+ Urb->DataLen = (UINT32)DataLen;
+ }
+
+ Status = XhcCreateTransferTrb (Handle, Urb);
+ ASSERT_EFI_ERROR (Status);
+
+ return Urb;
+}
+
+/**
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ @param Handle Debug port handle.
+ @param Direction The direction of data transfer.
+ @param Data Array of pointers to the buffers of data to transmit
+ from or receive into.
+ @param DataLength The length of the data buffer.
+ @param Timeout Indicates the maximum time, in microsecond, which
+ the transfer is allowed to complete.
+
+ @retval EFI_SUCCESS The transfer was completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_TIMEOUT The transfer failed due to timeout.
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
+
+**/
+EFI_STATUS
+EFIAPI
+XhcDataTransfer (
+ IN USB3_DEBUG_PORT_HANDLE *Handle,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout
+ )
+{
+ URB *Urb;
+ EFI_STATUS Status;
+
+ //
+ // Validate the parameters
+ //
+ if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a new URB, insert it into the asynchronous
+ // schedule list, then poll the execution status.
+ //
+ Urb = XhcCreateUrb (Handle, Direction, Data, *DataLength);
+ ASSERT (Urb != NULL);
+
+ XhcExecTransfer (Handle, Urb, Timeout);
+
+ //
+ // Make sure the data received from HW can fit in the received buffer.
+ //
+ if (Urb->Completed > *DataLength) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *DataLength = Urb->Completed;
+
+ Status = EFI_TIMEOUT;
+ if (Urb->Result == EFI_USB_NOERROR) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (Direction == EfiUsbDataIn) {
+ //
+ // Move data from internal buffer to outside buffer (outside buffer may be in SMRAM...)
+ // SMRAM does not allow to do DMA, so we create an internal buffer.
+ //
+ CopyMem (Data, (VOID *)(UINTN)Urb->Data, *DataLength);
+ }
+
+ return Status;
+}