diff options
Diffstat (limited to 'SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3')
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; +} |
