https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com>
		
			
				
	
	
		
			1141 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1141 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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 eanble 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;
 | 
						|
}
 |