From 6b4483cdbdcf5e74ee61b025116f86c4e15a4793 Mon Sep 17 00:00:00 2001 From: erictian Date: Fri, 25 Nov 2011 08:08:54 +0000 Subject: [PATCH] MdeModulePkg: The patch eliminates two assumptions 1) XHCI host controller hw always provides more than 5 interrupters. Now using interrupter 0 to accommodate all received events. 2) XHCI host controller hw always provides 32bytes context size. Now it dynamically detect context size and construct it. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit also solved several issues: 1) Divides 64byte width register access to two 32bit registers access because some XHCI chipsets cannot support a single 64bit access. 2) Remove halt host controller statement in UsbBusDriverBindingStop(). It has been done by host controller’s DriverBindingStop(). And XhciDriverBindingStop() need XHCI host controller is in running state because it need execute DISABLE_SLOT cmd to release h/w resource. signed-off-by: erictian Reviewed-by: li-elvin git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12785 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c | 93 +- MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h | 22 +- MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c | 103 -- MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h | 45 - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c | 1088 +++++++++++++++++----- MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h | 245 ++++- MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c | 1 - 7 files changed, 1122 insertions(+), 475 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c index 5ccb78e55b..8cbb7bab07 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c @@ -721,7 +721,6 @@ XhcControlTransfer ( URB *Urb; UINT8 Endpoint; UINT8 Index; - UINT8 XhciDevAddr; UINT8 DescriptorType; UINT8 SlotId; UINT8 TTT; @@ -793,11 +792,6 @@ XhcControlTransfer ( goto ON_EXIT; } - // - // Acquire the actual device address assigned by XHCI's Address_Device cmd. - // - XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr; - // // Hook the Set_Address request from UsbBus. // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd. @@ -810,7 +804,7 @@ XhcControlTransfer ( // for (Index = 0; Index < 255; Index++) { if (!Xhc->UsbDevContext[Index + 1].Enabled && - (Xhc->UsbDevContext[Index + 1].SlotId != 0) && + (Xhc->UsbDevContext[Index + 1].SlotId == 0) && (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) { Xhc->UsbDevContext[Index + 1].BusDevAddr = 0; } @@ -850,7 +844,7 @@ XhcControlTransfer ( Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0)); Urb = XhcCreateUrb ( Xhc, - XhciDevAddr, + DeviceAddress, Endpoint, DeviceSpeed, MaximumPacketLength, @@ -867,7 +861,7 @@ XhcControlTransfer ( Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } - ASSERT (Urb->EvtRing == &Xhc->CtrlTrEventRing); + ASSERT (Urb->EvtRing == &Xhc->EventRing); Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); // @@ -909,7 +903,11 @@ XhcControlTransfer ( MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0; } Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *)); - Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0); + if (Xhc->HcCParams.Data.Csz == 0) { + Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0); + } else { + Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0); + } ASSERT_EFI_ERROR (Status); } else if (DescriptorType == USB_DESC_TYPE_CONFIG) { ASSERT (Data != NULL); @@ -940,13 +938,12 @@ XhcControlTransfer ( MTT = 0; } - Status = XhcConfigHubContext ( - Xhc, - SlotId, - HubDesc->NumPorts, - TTT, - MTT - ); + if (Xhc->HcCParams.Data.Csz == 0) { + Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT); + } else { + Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT); + } + ASSERT_EFI_ERROR (Status); } } else if ((Request->Request == USB_REQ_SET_CONFIG) && (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) { @@ -955,7 +952,12 @@ XhcControlTransfer ( // for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) { - XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + if (Xhc->HcCParams.Data.Csz == 0) { + Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + } else { + Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + } + ASSERT_EFI_ERROR (Status); break; } } @@ -1073,7 +1075,6 @@ XhcBulkTransfer ( { USB_XHCI_INSTANCE *Xhc; URB *Urb; - UINT8 XhciDevAddr; UINT8 SlotId; EFI_STATUS Status; EFI_STATUS RecoveryStatus; @@ -1118,18 +1119,13 @@ XhcBulkTransfer ( goto ON_EXIT; } - // - // Acquire the actual device address assigned by XHCI's Address_Device cmd. - // - XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr; - // // Create a new URB, insert it into the asynchronous // schedule list, then poll the execution status. // Urb = XhcCreateUrb ( Xhc, - XhciDevAddr, + DeviceAddress, EndPointAddress, DeviceSpeed, MaximumPacketLength, @@ -1147,7 +1143,7 @@ XhcBulkTransfer ( goto ON_EXIT; } - ASSERT (Urb->EvtRing == &Xhc->BulkTrEventRing); + ASSERT (Urb->EvtRing == &Xhc->EventRing); Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); @@ -1223,7 +1219,6 @@ XhcAsyncInterruptTransfer ( USB_XHCI_INSTANCE *Xhc; URB *Urb; EFI_STATUS Status; - UINT8 XhciDevAddr; UINT8 SlotId; UINT8 Index; UINT8 *Data; @@ -1262,8 +1257,7 @@ XhcAsyncInterruptTransfer ( // The delete request may happen after device is detached. // for (Index = 0; Index < 255; Index++) { - if ((Xhc->UsbDevContext[Index + 1].SlotId != 0) && - (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress)) { + if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) { break; } } @@ -1273,12 +1267,7 @@ XhcAsyncInterruptTransfer ( goto ON_EXIT; } - // - // Acquire the actual device address assigned by XHCI's Address_Device cmd. - // - XhciDevAddr = Xhc->UsbDevContext[Index + 1].XhciDevAddr; - - Status = XhciDelAsyncIntTransfer (Xhc, XhciDevAddr, EndPointAddress); + Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress); DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status)); goto ON_EXIT; } @@ -1299,11 +1288,6 @@ XhcAsyncInterruptTransfer ( goto ON_EXIT; } - // - // Acquire the actual device address assigned by XHCI's Address_Device cmd. - // - XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr; - Data = AllocateZeroPool (DataLength); if (Data == NULL) { @@ -1314,7 +1298,7 @@ XhcAsyncInterruptTransfer ( Urb = XhcCreateUrb ( Xhc, - XhciDevAddr, + DeviceAddress, EndPointAddress, DeviceSpeed, MaximumPacketLength, @@ -1333,7 +1317,7 @@ XhcAsyncInterruptTransfer ( goto ON_EXIT; } - ASSERT (Urb->EvtRing == &Xhc->AsynIntTrEventRing); + ASSERT (Urb->EvtRing == &Xhc->EventRing); InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList); // @@ -1393,7 +1377,6 @@ XhcSyncInterruptTransfer ( { USB_XHCI_INSTANCE *Xhc; URB *Urb; - UINT8 XhciDevAddr; UINT8 SlotId; EFI_STATUS Status; EFI_STATUS RecoveryStatus; @@ -1441,14 +1424,9 @@ XhcSyncInterruptTransfer ( goto ON_EXIT; } - // - // Acquire the actual device address assigned by XHCI's Address_Device cmd. - // - XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr; - Urb = XhcCreateUrb ( Xhc, - XhciDevAddr, + DeviceAddress, EndPointAddress, DeviceSpeed, MaximumPacketLength, @@ -2072,8 +2050,11 @@ XhcDriverBindingStop ( (Xhc->UsbDevContext[Index + 1].SlotId == 0)) { continue; } - - XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + if (Xhc->HcCParams.Data.Csz == 0) { + XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + } else { + XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + } } XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT); @@ -2108,11 +2089,11 @@ XhcDriverBindingStop ( // Restore original PCI attributes // PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationSet, - Xhc->OriginalPciAttributes, - NULL - ); + PciIo, + EfiPciIoAttributeOperationSet, + Xhc->OriginalPciAttributes, + NULL + ); gBS->CloseProtocol ( Controller, diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h index 3793d9c1c2..f6da016bfb 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h +++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h @@ -93,7 +93,7 @@ typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT; #define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field) #define XHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF)) -#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0xFFFFFFFF)) +#define XHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINT64)(UINTN)(Addr64), 32) & 0xFFFFFFFF)) #define XHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit))) #define XHC_REG_BIT_IS_SET(Xhc, Offset, Bit) \ @@ -228,25 +228,9 @@ struct _USB_XHCI_INSTANCE { // TRANSFER_RING CmdRing; // - // CmdEventRing + // EventRing // - EVENT_RING CmdEventRing; - // - // ControlTREventRing - // - EVENT_RING CtrlTrEventRing; - // - // BulkTREventRing - // - EVENT_RING BulkTrEventRing; - // - // IntTREventRing - // - EVENT_RING IntTrEventRing; - // - // AsyncIntTREventRing - // - EVENT_RING AsynIntTrEventRing; + EVENT_RING EventRing; // // Misc // diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c index 874967974c..9d50ef8242 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c @@ -191,39 +191,6 @@ XhcWriteOpReg16 ( } } -/** - Write the data to the 8-bytes width XHCI operational register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width operational register. - @param Data The data to write. - -**/ -VOID -XhcWriteOpReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset, - IN UINT64 Data - ) -{ - EFI_STATUS Status; - - ASSERT (Xhc->CapLength != 0); - - Status = Xhc->PciIo->Mem.Write ( - Xhc->PciIo, - EfiPciIoWidthUint64, - XHC_BAR_INDEX, - (UINT64) (Xhc->CapLength + Offset), - 1, - &Data - ); - - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "XhcWriteOpReg64: Pci Io Write error: %r at %d\n", Status, Offset)); - } -} - /** Read XHCI door bell register. @@ -331,43 +298,6 @@ XhcReadRuntimeReg ( return Data; } -/** - Read 8-bytes width XHCI runtime register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width runtime register. - - @return The register content read - -**/ -UINT64 -XhcReadRuntimeReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset - ) -{ - UINT64 Data; - EFI_STATUS Status; - - ASSERT (Xhc->RTSOff != 0); - - Status = Xhc->PciIo->Mem.Read ( - Xhc->PciIo, - EfiPciIoWidthUint64, - XHC_BAR_INDEX, - (UINT64) (Xhc->RTSOff + Offset), - 1, - &Data - ); - - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg64: Pci Io Read error - %r at %d\n", Status, Offset)); - Data = 0xFFFFFFFFFFFFFFFFULL; - } - - return Data; -} - /** Write the data to the XHCI runtime register. @@ -401,39 +331,6 @@ XhcWriteRuntimeReg ( } } -/** - Write the data to the 8-bytes width XHCI runtime register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width runtime register. - @param Data The data to write. - -**/ -VOID -XhcWriteRuntimeReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset, - IN UINT64 Data - ) -{ - EFI_STATUS Status; - - ASSERT (Xhc->RTSOff != 0); - - Status = Xhc->PciIo->Mem.Write ( - Xhc->PciIo, - EfiPciIoWidthUint64, - XHC_BAR_INDEX, - (UINT64) (Xhc->RTSOff + Offset), - 1, - &Data - ); - - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg64: Pci Io Write error: %r at %d\n", Status, Offset)); - } -} - /** Read XHCI extended capability register. diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h index c1c086cf28..26ead70bb4 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h @@ -265,21 +265,6 @@ XhcWriteOpReg16 ( IN UINT16 Data ); -/** - Write the data to the 8-bytes width XHCI operational register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width operational register. - @param Data The data to write. - -**/ -VOID -XhcWriteOpReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset, - IN UINT64 Data - ); - /** Read XHCI runtime register. @@ -295,21 +280,6 @@ XhcReadRuntimeReg ( IN UINT32 Offset ); -/** - Read 8-bytes width XHCI runtime register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width runtime register. - - @return The register content read - -**/ -UINT64 -XhcReadRuntimeReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset - ); - /** Write the data to the XHCI runtime register. @@ -325,21 +295,6 @@ XhcWriteRuntimeReg ( IN UINT32 Data ); -/** - Write the data to the 8-bytes width XHCI runtime register. - - @param Xhc The XHCI Instance. - @param Offset The offset of the 8-bytes width runtime register. - @param Data The data to write. - -**/ -VOID -XhcWriteRuntimeReg64 ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT32 Offset, - IN UINT64 Data - ); - /** Read XHCI door bell register. diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c index 49cc2619eb..d0b616582e 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c @@ -47,7 +47,7 @@ XhcCreateCmdTrb ( Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0; Urb->TrbEnd = Urb->TrbStart; - Urb->EvtRing = &Xhc->CmdEventRing; + Urb->EvtRing = &Xhc->EventRing; XhcSyncEventRing (Xhc, Urb->EvtRing); Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue; @@ -106,7 +106,7 @@ XhcCmdTransfer ( goto ON_EXIT; } - ASSERT (Urb->EvtRing == &Xhc->CmdEventRing); + ASSERT (Urb->EvtRing == &Xhc->EventRing); Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout); *EvtTrb = Urb->EvtTrbStart; @@ -125,7 +125,7 @@ ON_EXIT: Create a new URB for a new transaction. @param Xhc The XHCI Instance - @param DevAddr The device address + @param BusAddr The logical device address assigned by UsbBus driver @param EpAddr Endpoint addrress @param DevSpeed The device speed @param MaxPacket The max packet length of the endpoint @@ -142,7 +142,7 @@ ON_EXIT: URB* XhcCreateUrb ( IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 DevAddr, + IN UINT8 BusAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINTN MaxPacket, @@ -167,7 +167,7 @@ XhcCreateUrb ( InitializeListHead (&Urb->UrbList); Ep = &Urb->Ep; - Ep->DevAddr = DevAddr; + Ep->BusAddr = BusAddr; Ep->EpAddr = (UINT8)(EpAddr & 0x0F); Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut; Ep->DevSpeed = DevSpeed; @@ -201,7 +201,7 @@ XhcCreateTransferTrb ( IN URB *Urb ) { - DEVICE_CONTEXT *OutputContext; + VOID *OutputContext; TRANSFER_RING *EPRing; UINT8 EPType; UINT8 SlotId; @@ -211,13 +211,21 @@ XhcCreateTransferTrb ( UINTN Len; UINTN TrbNum; - SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr); + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); + if (SlotId == 0) { + return EFI_DEVICE_ERROR; + } + Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); ASSERT (Dci < 32); EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]; Urb->Ring = EPRing; - OutputContext = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId]; - EPType = (UINT8) OutputContext->EP[Dci-1].EPType; + OutputContext = (VOID *)(UINTN)Xhc->DCBAA[SlotId]; + if (Xhc->HcCParams.Data.Csz == 0) { + EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType; + } else { + EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType; + } // // Construct the TRB @@ -226,7 +234,7 @@ XhcCreateTransferTrb ( Urb->TrbStart = EPRing->RingEnqueue; switch (EPType) { case ED_CONTROL_BIDIR: - Urb->EvtRing = &Xhc->CtrlTrEventRing; + Urb->EvtRing = &Xhc->EventRing; XhcSyncEventRing (Xhc, Urb->EvtRing); Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue; // @@ -239,7 +247,7 @@ XhcCreateTransferTrb ( TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index; TrbStart->TrbCtrSetup.wLength = Urb->Request->Length; TrbStart->TrbCtrSetup.Lenth = 8; - TrbStart->TrbCtrSetup.IntTarget = Urb->EvtRing->EventInterrupter; + TrbStart->TrbCtrSetup.IntTarget = 0; TrbStart->TrbCtrSetup.IOC = 1; TrbStart->TrbCtrSetup.IDT = 1; TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE; @@ -266,7 +274,7 @@ XhcCreateTransferTrb ( TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data); TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen; TrbStart->TrbCtrData.TDSize = 0; - TrbStart->TrbCtrData.IntTarget = Urb->EvtRing->EventInterrupter; + TrbStart->TrbCtrData.IntTarget = 0; TrbStart->TrbCtrData.ISP = 1; TrbStart->TrbCtrData.IOC = 1; TrbStart->TrbCtrData.IDT = 0; @@ -291,7 +299,7 @@ XhcCreateTransferTrb ( // XhcSyncTrsRing (Xhc, EPRing); TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; - TrbStart->TrbCtrStatus.IntTarget = Urb->EvtRing->EventInterrupter; + TrbStart->TrbCtrStatus.IntTarget = 0; TrbStart->TrbCtrStatus.IOC = 1; TrbStart->TrbCtrStatus.CH = 0; TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE; @@ -317,7 +325,7 @@ XhcCreateTransferTrb ( case ED_BULK_OUT: case ED_BULK_IN: - Urb->EvtRing = &Xhc->BulkTrEventRing; + Urb->EvtRing = &Xhc->EventRing; XhcSyncEventRing (Xhc, Urb->EvtRing); Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue; @@ -336,7 +344,7 @@ XhcCreateTransferTrb ( TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); TrbStart->TrbNormal.Lenth = (UINT32) Len; TrbStart->TrbNormal.TDSize = 0; - TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter; + TrbStart->TrbNormal.IntTarget = 0; TrbStart->TrbNormal.ISP = 1; TrbStart->TrbNormal.IOC = 1; TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL; @@ -356,14 +364,7 @@ XhcCreateTransferTrb ( case ED_INTERRUPT_OUT: case ED_INTERRUPT_IN: - if (Urb->Ep.Type == XHC_INT_TRANSFER_ASYNC) { - Urb->EvtRing = &Xhc->AsynIntTrEventRing; - } else if(Urb->Ep.Type == XHC_INT_TRANSFER_SYNC){ - Urb->EvtRing = &Xhc->IntTrEventRing; - } else { - DEBUG ((EFI_D_ERROR, "EP Interrupt type error!\n")); - ASSERT(FALSE); - } + Urb->EvtRing = &Xhc->EventRing; XhcSyncEventRing (Xhc, Urb->EvtRing); Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue; @@ -382,7 +383,7 @@ XhcCreateTransferTrb ( TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); TrbStart->TrbNormal.Lenth = (UINT32) Len; TrbStart->TrbNormal.TDSize = 0; - TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter; + TrbStart->TrbNormal.IntTarget = 0; TrbStart->TrbNormal.ISP = 1; TrbStart->TrbNormal.IOC = 1; TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL; @@ -481,7 +482,12 @@ XhcInitSched ( // a 64-bit address pointing to where the Device Context Base Address Array is located. // Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa; - XhcWriteOpReg64 (Xhc, XHC_DCBAAP_OFFSET, (UINT64)(UINTN)Xhc->DCBAA); + // + // Some 3rd party XHCI external cards don't support single 64-bytes width register access, + // So divide it to two 32-bytes width register access. + // + XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(Xhc->DCBAA)); + XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (Xhc->DCBAA)); DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA)); // @@ -499,7 +505,12 @@ XhcInitSched ( CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0; ASSERT ((CmdRing & 0x3F) == 0); CmdRing |= XHC_CRCR_RCS; - XhcWriteOpReg64 (Xhc, XHC_CRCR_OFFSET, CmdRing); + // + // 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. + // + XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRing)); + XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRing)); DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0)); @@ -516,11 +527,8 @@ XhcInitSched ( // // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer // - CreateEventRing (Xhc, CMD_INTER, &Xhc->CmdEventRing); - CreateEventRing (Xhc, CTRL_INTER, &Xhc->CtrlTrEventRing); - CreateEventRing (Xhc, BULK_INTER, &Xhc->BulkTrEventRing); - CreateEventRing (Xhc, INT_INTER, &Xhc->IntTrEventRing); - CreateEventRing (Xhc, INT_INTER_ASYNC, &Xhc->AsynIntTrEventRing); + CreateEventRing (Xhc, &Xhc->EventRing); + DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0)); } /** @@ -551,10 +559,14 @@ XhcRecoverHaltedEndpoint ( UINT8 Dci; UINT8 SlotId; - Status = EFI_SUCCESS; - SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); - + Status = EFI_SUCCESS; + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); + if (SlotId == 0) { + return EFI_DEVICE_ERROR; + } + Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); + ASSERT (Dci < 32); + DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci)); // @@ -603,14 +615,12 @@ XhcRecoverHaltedEndpoint ( Create XHCI event ring. @param Xhc The XHCI Instance. - @param EventInterrupter The interrupter of event. @param EventRing The created event ring. **/ VOID CreateEventRing ( IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 EventInterrupter, OUT EVENT_RING *EventRing ) { @@ -625,7 +635,6 @@ CreateEventRing ( ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER); EventRing->EventRingSeg0 = Buf; - EventRing->EventInterrupter = EventInterrupter; EventRing->TrbNumber = EVENT_RING_TRB_NUMBER; EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0; EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0; @@ -651,29 +660,45 @@ CreateEventRing ( // XhcWriteRuntimeReg ( Xhc, - XHC_ERSTSZ_OFFSET + (32 * EventRing->EventInterrupter), + XHC_ERSTSZ_OFFSET, ERST_NUMBER ); // // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3) // - XhcWriteRuntimeReg64 ( + // 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. + // + XhcWriteRuntimeReg ( + Xhc, + XHC_ERDP_OFFSET, + XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue) + ); + XhcWriteRuntimeReg ( Xhc, - XHC_ERDP_OFFSET + (32 * EventRing->EventInterrupter), - (UINT64)(UINTN)EventRing->EventRingDequeue + XHC_ERDP_OFFSET + 4, + XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue) ); // // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2) // - XhcWriteRuntimeReg64 ( + // 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. + // + XhcWriteRuntimeReg ( + Xhc, + XHC_ERSTBA_OFFSET, + XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase) + ); + XhcWriteRuntimeReg ( Xhc, - XHC_ERSTBA_OFFSET + (32 * EventRing->EventInterrupter), - (UINT64)(UINTN)ERSTBase + XHC_ERSTBA_OFFSET + 4, + XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase) ); // // Need set IMAN IE bit to enble the ring interrupt // - XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (32 * EventRing->EventInterrupter), XHC_IMAN_IE); + XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE); } /** @@ -800,11 +825,7 @@ XhcFreeSched ( Xhc->CmdRing.RingSeg0 = NULL; } - XhcFreeEventRing (Xhc,&Xhc->CmdEventRing); - XhcFreeEventRing (Xhc,&Xhc->CtrlTrEventRing); - XhcFreeEventRing (Xhc,&Xhc->BulkTrEventRing); - XhcFreeEventRing (Xhc,&Xhc->AsynIntTrEventRing); - XhcFreeEventRing (Xhc,&Xhc->IntTrEventRing); + XhcFreeEventRing (Xhc,&Xhc->EventRing); } /** @@ -894,74 +915,82 @@ XhcCheckUrbResult ( goto EXIT; } - TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32); + // + // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT. + // + if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) { + continue; + } - switch (EvtTrb->Completecode) { - case TRB_COMPLETION_STALL_ERROR: - Urb->Result |= EFI_USB_ERR_STALL; - Status = EFI_DEVICE_ERROR; - DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode)); - goto EXIT; - break; + TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32); + if (IsTransferRingTrb (Urb->Ring, TRBPtr)) { + switch (EvtTrb->Completecode) { + case TRB_COMPLETION_STALL_ERROR: + Urb->Result |= EFI_USB_ERR_STALL; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode)); + goto EXIT; + break; - case TRB_COMPLETION_BABBLE_ERROR: - Urb->Result |= EFI_USB_ERR_BABBLE; - Status = EFI_DEVICE_ERROR; - DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode)); - goto EXIT; - break; + case TRB_COMPLETION_BABBLE_ERROR: + Urb->Result |= EFI_USB_ERR_BABBLE; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode)); + goto EXIT; + break; - case TRB_COMPLETION_DATA_BUFFER_ERROR: - Urb->Result |= EFI_USB_ERR_BUFFER; - Status = EFI_DEVICE_ERROR; - DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode)); - goto EXIT; - break; + case TRB_COMPLETION_DATA_BUFFER_ERROR: + Urb->Result |= EFI_USB_ERR_BUFFER; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode)); + goto EXIT; + break; - case TRB_COMPLETION_USB_TRANSACTION_ERROR: - Urb->Result |= EFI_USB_ERR_TIMEOUT; - Status = EFI_DEVICE_ERROR; - DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode)); - goto EXIT; - break; + case TRB_COMPLETION_USB_TRANSACTION_ERROR: + Urb->Result |= EFI_USB_ERR_TIMEOUT; + Status = EFI_DEVICE_ERROR; + DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode)); + goto EXIT; + break; - case TRB_COMPLETION_SHORT_PACKET: - case TRB_COMPLETION_SUCCESS: - if (IsTransferRingTrb (Urb->Ring, TRBPtr)) { + case TRB_COMPLETION_SHORT_PACKET: + case TRB_COMPLETION_SUCCESS: if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) { DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n")); } + TRBType = (UINT8) (TRBPtr->Type); if ((TRBType == TRB_TYPE_DATA_STAGE) || (TRBType == TRB_TYPE_NORMAL) || (TRBType == TRB_TYPE_ISOCH)) { Urb->Completed += (Urb->DataLen - EvtTrb->Lenth); } - } - Status = EFI_SUCCESS; - break; - default: - DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode)); - Urb->Result |= EFI_USB_ERR_TIMEOUT; - Status = EFI_DEVICE_ERROR; - goto EXIT; - break; - } + Status = EFI_SUCCESS; + break; - // - // Only check first and end Trb event address - // - if (TRBPtr == Urb->TrbStart) { - StartDone = TRUE; - } + default: + DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode)); + Urb->Result |= EFI_USB_ERR_TIMEOUT; + Status = EFI_DEVICE_ERROR; + goto EXIT; + break; + } - if (TRBPtr == Urb->TrbEnd) { - EndDone = TRUE; - } + // + // Only check first and end Trb event address + // + if (TRBPtr == Urb->TrbStart) { + StartDone = TRUE; + } - if (StartDone && EndDone) { - break; + if (TRBPtr == Urb->TrbEnd) { + EndDone = TRUE; + } + + if (StartDone && EndDone) { + break; + } } } @@ -1001,8 +1030,12 @@ XhcExecTransfer ( SlotId = 0; Dci = 0; } else { - SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); + if (SlotId == 0) { + return EFI_DEVICE_ERROR; + } + Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); + ASSERT (Dci < 32); } Status = EFI_SUCCESS; @@ -1029,7 +1062,7 @@ XhcExecTransfer ( the device and endpoint. @param Xhc The XHCI Instance. - @param DevAddr The address of the target device. + @param BusAddr The logical device address assigned by UsbBus driver. @param EpNum The endpoint of the target. @retval EFI_SUCCESS An asynchronous transfer is removed. @@ -1039,7 +1072,7 @@ XhcExecTransfer ( EFI_STATUS XhciDelAsyncIntTransfer ( IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 DevAddr, + IN UINT8 BusAddr, IN UINT8 EpNum ) { @@ -1051,11 +1084,11 @@ XhciDelAsyncIntTransfer ( Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut; EpNum &= 0x0F; - Urb = NULL; + Urb = NULL; EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) { Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList); - if ((Urb->Ep.DevAddr == DevAddr) && + if ((Urb->Ep.BusAddr == BusAddr) && (Urb->Ep.EpAddr == EpNum) && (Urb->Ep.Direction == Direction)) { RemoveEntryList (&Urb->UrbList); @@ -1108,9 +1141,13 @@ XhcUpdateAsyncRequest ( if (Urb->Result == EFI_USB_NOERROR) { Status = XhcCreateTransferTrb (Xhc, Urb); - ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return; + } Status = RingIntTransferDoorBell (Xhc, Urb); - ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return; + } } } @@ -1148,7 +1185,7 @@ XhcMonitorAsyncRequests ( // // Make sure that the device is available before every check. // - SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr); + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); if (SlotId == 0) { continue; } @@ -1271,7 +1308,11 @@ XhcPollPortStatusChange ( // SlotId = XhcRouteStringToSlotId (Xhc, RouteChart); if (SlotId == 0) { - Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed); + if (Xhc->HcCParams.Data.Csz == 0) { + Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed); + } else { + Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed); + } ASSERT_EFI_ERROR (Status); } } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) { @@ -1280,7 +1321,11 @@ XhcPollPortStatusChange ( // SlotId = XhcRouteStringToSlotId (Xhc, RouteChart); if (SlotId != 0) { - Status = XhcDisableSlotCmd (Xhc, SlotId); + if (Xhc->HcCParams.Data.Csz == 0) { + Status = XhcDisableSlotCmd (Xhc, SlotId); + } else { + Status = XhcDisableSlotCmd64 (Xhc, SlotId); + } ASSERT_EFI_ERROR (Status); } } @@ -1316,38 +1361,6 @@ XhcEndpointToDci ( } } -/** - Find out the slot id according to device address assigned by XHCI's Address_Device cmd. - - @param Xhc The XHCI Instance. - @param DevAddr The device address of the target device. - - @return The slot id used by the device. - -**/ -UINT8 -XhcDevAddrToSlotId ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 DevAddr - ) -{ - UINT8 Index; - - for (Index = 0; Index < 255; Index++) { - if (Xhc->UsbDevContext[Index + 1].Enabled && - (Xhc->UsbDevContext[Index + 1].SlotId != 0) && - (Xhc->UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) { - break; - } - } - - if (Index == 255) { - return 0; - } - - return Xhc->UsbDevContext[Index + 1].SlotId; -} - /** Find out the actual device address according to the requested device address from UsbBus. @@ -1433,7 +1446,9 @@ XhcSyncEventRing ( UINTN Index; TRB_TEMPLATE *EvtTrb1; TRB_TEMPLATE *EvtTrb2; - TRB_TEMPLATE *XhcDequeue; + UINT64 XhcDequeue; + UINT32 High; + UINT32 Low; ASSERT (EvtRing != NULL); @@ -1462,17 +1477,20 @@ XhcSyncEventRing ( // // Apply the EventRingDequeue to Xhc // - XhcDequeue = (TRB_TEMPLATE *)(UINTN) XhcReadRuntimeReg64 ( - Xhc, - XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter) - ); - - if (((UINT64)(UINTN)XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)EvtRing->EventRingDequeue & (~0x0F))) { - XhcWriteRuntimeReg64 ( - Xhc, - XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter), - (UINT64)(UINTN)EvtRing->EventRingDequeue | BIT3 - ); + // 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 = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET); + High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4); + XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low); + + if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)EvtRing->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. + // + XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, Low | BIT3); + XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, High); } return EFI_SUCCESS; @@ -1635,8 +1653,8 @@ RingIntTransferDoorBell ( UINT8 SlotId; UINT8 Dci; - SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); + Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); XhcRingDoorBell (Xhc, SlotId, Dci); return EFI_SUCCESS; } @@ -1835,100 +1853,587 @@ XhcInitializeDeviceSlot ( } /** - Disable the specified device slot. + Assign and initialize the device slot for a new device. - @param Xhc The XHCI Instance. - @param SlotId The slot id to be disabled. + @param Xhc The XHCI Instance. + @param ParentRouteChart The route string pointed to the parent device. + @param ParentPort The port at which the device is located. + @param RouteChart The route string pointed to the device. + @param DeviceSpeed The device speed. - @retval EFI_SUCCESS Successfully disable the device slot. + @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it. **/ EFI_STATUS EFIAPI -XhcDisableSlotCmd ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 SlotId +XhcInitializeDeviceSlot64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN USB_DEV_ROUTE ParentRouteChart, + IN UINT16 ParentPort, + IN USB_DEV_ROUTE RouteChart, + IN UINT8 DeviceSpeed ) { - EFI_STATUS Status; - TRB_TEMPLATE *EvtTrb; - CMD_TRB_DISABLE_SLOT CmdTrbDisSlot; - UINT8 Index; - VOID *RingSeg; + EFI_STATUS Status; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT_64 *InputContext; + DEVICE_CONTEXT_64 *OutputContext; + TRANSFER_RING *EndpointTransferRing; + CMD_TRB_ADDRESS_DEVICE CmdTrbAddr; + UINT8 DeviceAddress; + CMD_TRB_ENABLE_SLOT CmdTrb; + UINT8 SlotId; + UINT8 ParentSlotId; + DEVICE_CONTEXT_64 *ParentDeviceContext; - // - // Disable the device slots occupied by these devices on its downstream ports. - // Entry 0 is reserved. - // - for (Index = 0; Index < 255; Index++) { - if (!Xhc->UsbDevContext[Index + 1].Enabled || - (Xhc->UsbDevContext[Index + 1].SlotId == 0) || - (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) { - continue; - } + ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT)); + CmdTrb.CycleBit = 1; + CmdTrb.Type = TRB_TYPE_EN_SLOT; - Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrb, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT_EFI_ERROR (Status); + ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn); + DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId)); + SlotId = (UINT8)EvtTrb->SlotId; + ASSERT (SlotId != 0); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n")); - Xhc->UsbDevContext[Index + 1].SlotId = 0; - } - } + ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT)); + Xhc->UsbDevContext[SlotId].Enabled = TRUE; + Xhc->UsbDevContext[SlotId].SlotId = SlotId; + Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword; + Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword; // - // Construct the disable slot command + // 4.3.3 Device Slot Initialization + // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'. // - DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId)); + InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64))); + ASSERT (InputContext != NULL); + ASSERT (((UINTN) InputContext & 0x3F) == 0); + ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64)); + + Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext; - ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot)); - CmdTrbDisSlot.CycleBit = 1; - CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT; - CmdTrbDisSlot.SlotId = SlotId; - Status = XhcCmdTransfer ( - Xhc, - (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot, - XHC_GENERIC_TIMEOUT, - (TRB_TEMPLATE **) (UINTN) &EvtTrb - ); - ASSERT_EFI_ERROR(Status); // - // Free the slot's device context entry + // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1 + // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input + // Context are affected by the command. // - Xhc->DCBAA[SlotId] = 0; + InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1); // - // Free the slot related data structure + // 3) Initialize the Input Slot Context data structure // - for (Index = 0; Index < 31; Index++) { - if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) { - RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0; - if (RingSeg != NULL) { - FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER)); - } - FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]); - } - } + InputContext->Slot.RouteString = RouteChart.Route.RouteString; + InputContext->Slot.Speed = DeviceSpeed + 1; + InputContext->Slot.ContextEntries = 1; + InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum; - for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { - if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) { - FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + if (RouteChart.Route.RouteString) { + // + // The device is behind of hub device. + // + ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart); + ASSERT (ParentSlotId != 0); + // + //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context + // + ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext; + if ((ParentDeviceContext->Slot.TTPortNum == 0) && + (ParentDeviceContext->Slot.TTHubSlotId == 0)) { + if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) { + // + // Full/Low device attached to High speed hub port that isolates the high speed signaling + // environment from Full/Low speed signaling environment for a device + // + InputContext->Slot.TTPortNum = ParentPort; + InputContext->Slot.TTHubSlotId = ParentSlotId; + } + } else { + // + // Inherit the TT parameters from parent device. + // + InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum; + InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId; + // + // If the device is a High speed device then down the speed to be the same as its parent Hub + // + if (DeviceSpeed == EFI_USB_SPEED_HIGH) { + InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed; + } } } - if (Xhc->UsbDevContext[SlotId].InputContext != NULL) { - FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT))); - } - - if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) { - FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT))); - } // - // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established - // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to - // remove urb from XHCI's asynchronous transfer list. + // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint. // - Xhc->UsbDevContext[SlotId].Enabled = FALSE; - + EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING)); + Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing; + CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]); + // + // 5) Initialize the Input default control Endpoint 0 Context (6.2.3). + // + InputContext->EP[0].EPType = ED_CONTROL_BIDIR; + + if (DeviceSpeed == EFI_USB_SPEED_SUPER) { + InputContext->EP[0].MaxPacketSize = 512; + } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) { + InputContext->EP[0].MaxPacketSize = 64; + } else { + InputContext->EP[0].MaxPacketSize = 8; + } + // + // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints + // 1KB, and Bulk and Isoch endpoints 3KB. + // + InputContext->EP[0].AverageTRBLength = 8; + InputContext->EP[0].MaxBurstSize = 0; + InputContext->EP[0].Interval = 0; + InputContext->EP[0].MaxPStreams = 0; + InputContext->EP[0].Mult = 0; + InputContext->EP[0].CErr = 3; + + // + // Init the DCS(dequeue cycle state) as the transfer ring's CCS + // + InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0; + InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0); + + // + // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'. + // + OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64))); + ASSERT (OutputContext != NULL); + ASSERT (((UINTN) OutputContext & 0x3F) == 0); + ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64)); + + Xhc->UsbDevContext[SlotId].OutputContext = OutputContext; + // + // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with + // a pointer to the Output Device Context data structure (6.2.1). + // + Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext; + + // + // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input + // Context data structure described above. + // + ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr)); + CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext); + CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext); + CmdTrbAddr.CycleBit = 1; + CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV; + CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId; + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT (!EFI_ERROR(Status)); + + DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress; + DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress)); + + Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress; + + return Status; +} + + +/** + Disable the specified device slot. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be disabled. + + @retval EFI_SUCCESS Successfully disable the device slot. + +**/ +EFI_STATUS +EFIAPI +XhcDisableSlotCmd ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId + ) +{ + EFI_STATUS Status; + TRB_TEMPLATE *EvtTrb; + CMD_TRB_DISABLE_SLOT CmdTrbDisSlot; + UINT8 Index; + VOID *RingSeg; + + // + // Disable the device slots occupied by these devices on its downstream ports. + // Entry 0 is reserved. + // + for (Index = 0; Index < 255; Index++) { + if (!Xhc->UsbDevContext[Index + 1].Enabled || + (Xhc->UsbDevContext[Index + 1].SlotId == 0) || + (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) { + continue; + } + + Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n")); + Xhc->UsbDevContext[Index + 1].SlotId = 0; + } + } + + // + // Construct the disable slot command + // + DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId)); + + ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot)); + CmdTrbDisSlot.CycleBit = 1; + CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT; + CmdTrbDisSlot.SlotId = SlotId; + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT_EFI_ERROR(Status); + // + // Free the slot's device context entry + // + Xhc->DCBAA[SlotId] = 0; + + // + // Free the slot related data structure + // + for (Index = 0; Index < 31; Index++) { + if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) { + RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0; + if (RingSeg != NULL) { + FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER)); + } + FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]); + } + } + + for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { + if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) { + FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + } + } + + if (Xhc->UsbDevContext[SlotId].InputContext != NULL) { + FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT))); + } + + if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) { + FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT))); + } + // + // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established + // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to + // remove urb from XHCI's asynchronous transfer list. + // + Xhc->UsbDevContext[SlotId].Enabled = FALSE; + Xhc->UsbDevContext[SlotId].SlotId = 0; + + return Status; +} + +/** + Disable the specified device slot. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be disabled. + + @retval EFI_SUCCESS Successfully disable the device slot. + +**/ +EFI_STATUS +EFIAPI +XhcDisableSlotCmd64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId + ) +{ + EFI_STATUS Status; + TRB_TEMPLATE *EvtTrb; + CMD_TRB_DISABLE_SLOT CmdTrbDisSlot; + UINT8 Index; + VOID *RingSeg; + + // + // Disable the device slots occupied by these devices on its downstream ports. + // Entry 0 is reserved. + // + for (Index = 0; Index < 255; Index++) { + if (!Xhc->UsbDevContext[Index + 1].Enabled || + (Xhc->UsbDevContext[Index + 1].SlotId == 0) || + (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) { + continue; + } + + Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n")); + Xhc->UsbDevContext[Index + 1].SlotId = 0; + } + } + + // + // Construct the disable slot command + // + DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId)); + + ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot)); + CmdTrbDisSlot.CycleBit = 1; + CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT; + CmdTrbDisSlot.SlotId = SlotId; + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT_EFI_ERROR(Status); + // + // Free the slot's device context entry + // + Xhc->DCBAA[SlotId] = 0; + + // + // Free the slot related data structure + // + for (Index = 0; Index < 31; Index++) { + if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) { + RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0; + if (RingSeg != NULL) { + FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER)); + } + FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]); + } + } + + for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { + if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) { + FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]); + } + } + + if (Xhc->UsbDevContext[SlotId].InputContext != NULL) { + FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64))); + } + + if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) { + FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64))); + } + // + // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established + // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to + // remove urb from XHCI's asynchronous transfer list. + // + Xhc->UsbDevContext[SlotId].Enabled = FALSE; + Xhc->UsbDevContext[SlotId].SlotId = 0; + + return Status; +} + + +/** + Configure all the device endpoints through XHCI's Configure_Endpoint cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be configured. + @param DeviceSpeed The device's speed. + @param ConfigDesc The pointer to the usb device configuration descriptor. + + @retval EFI_SUCCESS Successfully configure all the device endpoints. + +**/ +EFI_STATUS +EFIAPI +XhcSetConfigCmd ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 DeviceSpeed, + IN USB_CONFIG_DESCRIPTOR *ConfigDesc + ) +{ + EFI_STATUS Status; + + USB_INTERFACE_DESCRIPTOR *IfDesc; + USB_ENDPOINT_DESCRIPTOR *EpDesc; + UINT8 Index; + UINTN NumEp; + UINTN EpIndex; + UINT8 EpAddr; + UINT8 Direction; + UINT8 Dci; + UINT8 MaxDci; + UINT32 PhyAddr; + UINT8 Interval; + + TRANSFER_RING *EndpointTransferRing; + CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP; + INPUT_CONTEXT *InputContext; + DEVICE_CONTEXT *OutputContext; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + // + // 4.6.6 Configure Endpoint + // + InputContext = Xhc->UsbDevContext[SlotId].InputContext; + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; + ZeroMem (InputContext, sizeof (INPUT_CONTEXT)); + CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT)); + + ASSERT (ConfigDesc != NULL); + + MaxDci = 0; + + IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1); + for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) { + while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) { + IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length); + } + + NumEp = IfDesc->NumEndpoints; + + EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1); + for (EpIndex = 0; EpIndex < NumEp; EpIndex++) { + while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) { + EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length); + } + + EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F); + Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut); + + Dci = XhcEndpointToDci (EpAddr, Direction); + ASSERT (Dci < 32); + if (Dci > MaxDci) { + MaxDci = Dci; + } + + InputContext->InputControlContext.Dword2 |= (BIT0 << Dci); + InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize; + + if (DeviceSpeed == EFI_USB_SPEED_SUPER) { + // + // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor. + // + InputContext->EP[Dci-1].MaxBurstSize = 0x0; + } else { + InputContext->EP[Dci-1].MaxBurstSize = 0x0; + } + + switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) { + case USB_ENDPOINT_BULK: + if (Direction == EfiUsbDataIn) { + InputContext->EP[Dci-1].CErr = 3; + InputContext->EP[Dci-1].EPType = ED_BULK_IN; + } else { + InputContext->EP[Dci-1].CErr = 3; + InputContext->EP[Dci-1].EPType = ED_BULK_OUT; + } + + InputContext->EP[Dci-1].AverageTRBLength = 0x1000; + if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) { + EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING)); + Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing; + CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]); + } + + break; + case USB_ENDPOINT_ISO: + if (Direction == EfiUsbDataIn) { + InputContext->EP[Dci-1].CErr = 0; + InputContext->EP[Dci-1].EPType = ED_ISOCH_IN; + } else { + InputContext->EP[Dci-1].CErr = 0; + InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT; + } + break; + case USB_ENDPOINT_INTERRUPT: + if (Direction == EfiUsbDataIn) { + InputContext->EP[Dci-1].CErr = 3; + InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN; + } else { + InputContext->EP[Dci-1].CErr = 3; + InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT; + } + InputContext->EP[Dci-1].AverageTRBLength = 0x1000; + InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize; + // + // Get the bInterval from descriptor and init the the interval field of endpoint context + // + if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) { + Interval = EpDesc->Interval; + // + // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor. + // + InputContext->EP[Dci-1].Interval = 6; + } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) { + Interval = EpDesc->Interval; + ASSERT (Interval >= 1 && Interval <= 16); + // + // Refer to XHCI 1.0 spec section 6.2.3.6, table 61 + // + InputContext->EP[Dci-1].Interval = Interval - 1; + InputContext->EP[Dci-1].AverageTRBLength = 0x1000; + InputContext->EP[Dci-1].MaxESITPayload = 0x0002; + InputContext->EP[Dci-1].MaxBurstSize = 0x0; + InputContext->EP[Dci-1].CErr = 3; + } + + if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) { + EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING)); + Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing; + CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]); + } + break; + + case USB_ENDPOINT_CONTROL: + default: + ASSERT (0); + break; + } + + PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0); + PhyAddr &= ~(0x0F); + PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS; + InputContext->EP[Dci-1].PtrLo = PhyAddr; + InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0); + + EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length); + } + IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length); + } + + InputContext->InputControlContext.Dword2 |= BIT0; + InputContext->Slot.ContextEntries = MaxDci; + // + // configure endpoint + // + ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP)); + CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext); + CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext); + CmdTrbCfgEP.CycleBit = 1; + CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT; + CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId; + DEBUG ((EFI_D_INFO, "Configure Endpoint\n")); + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT_EFI_ERROR(Status); + return Status; } @@ -1945,7 +2450,7 @@ XhcDisableSlotCmd ( **/ EFI_STATUS EFIAPI -XhcSetConfigCmd ( +XhcSetConfigCmd64 ( IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, @@ -1968,16 +2473,16 @@ XhcSetConfigCmd ( TRANSFER_RING *EndpointTransferRing; CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP; - INPUT_CONTEXT *InputContext; - DEVICE_CONTEXT *OutputContext; + INPUT_CONTEXT_64 *InputContext; + DEVICE_CONTEXT_64 *OutputContext; EVT_TRB_COMMAND_COMPLETION *EvtTrb; // // 4.6.6 Configure Endpoint // InputContext = Xhc->UsbDevContext[SlotId].InputContext; OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; - ZeroMem (InputContext, sizeof (INPUT_CONTEXT)); - CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT)); + ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64)); + CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64)); ASSERT (ConfigDesc != NULL); @@ -2124,6 +2629,7 @@ XhcSetConfigCmd ( return Status; } + /** Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd. @@ -2176,6 +2682,59 @@ XhcEvaluateContext ( return Status; } +/** + Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be evaluated. + @param MaxPacketSize The max packet size supported by the device control transfer. + + @retval EFI_SUCCESS Successfully evaluate the device endpoint 0. + +**/ +EFI_STATUS +EFIAPI +XhcEvaluateContext64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT32 MaxPacketSize + ) +{ + EFI_STATUS Status; + CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT_64 *InputContext; + + ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0); + + // + // 4.6.7 Evaluate Context + // + InputContext = Xhc->UsbDevContext[SlotId].InputContext; + ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64)); + + InputContext->InputControlContext.Dword2 |= BIT1; + InputContext->EP[0].MaxPacketSize = MaxPacketSize; + + ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu)); + CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext); + CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext); + CmdTrbEvalu.CycleBit = 1; + CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT; + CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId; + DEBUG ((EFI_D_INFO, "Evaluate context\n")); + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT (!EFI_ERROR(Status)); + + return Status; +} + + /** Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd. @@ -2242,3 +2801,70 @@ XhcConfigHubContext ( return Status; } +/** + Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be configured. + @param PortNum The total number of downstream port supported by the hub. + @param TTT The TT think time of the hub device. + @param MTT The multi-TT of the hub device. + + @retval EFI_SUCCESS Successfully configure the hub device's slot context. + +**/ +EFI_STATUS +XhcConfigHubContext64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 PortNum, + IN UINT8 TTT, + IN UINT8 MTT + ) +{ + EFI_STATUS Status; + + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT_64 *InputContext; + DEVICE_CONTEXT_64 *OutputContext; + CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP; + + ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0); + InputContext = Xhc->UsbDevContext[SlotId].InputContext; + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; + + // + // 4.6.7 Evaluate Context + // + ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64)); + + InputContext->InputControlContext.Dword2 |= BIT0; + + // + // Copy the slot context from OutputContext to Input context + // + CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64)); + InputContext->Slot.Hub = 1; + InputContext->Slot.PortNum = PortNum; + InputContext->Slot.TTT = TTT; + InputContext->Slot.MTT = MTT; + + ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP)); + CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext); + CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext); + CmdTrbCfgEP.CycleBit = 1; + CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT; + CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId; + DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n")); + Status = XhcCmdTransfer ( + Xhc, + (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP, + XHC_GENERIC_TIMEOUT, + (TRB_TEMPLATE **) (UINTN) &EvtTrb + ); + ASSERT (!EFI_ERROR(Status)); + + return Status; +} + + diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h index 2090644e04..f319c56c60 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h @@ -111,6 +111,12 @@ typedef union _USB_DEV_ROUTE { // Endpoint address and its capabilities // typedef struct _USB_ENDPOINT { + // + // Store logical device address assigned by UsbBus + // It's because some XHCI host controllers may assign the same physcial device + // address for those devices inserted at different root port. + // + UINT8 BusAddr; UINT8 DevAddr; UINT8 EpAddr; EFI_USB_DATA_DIRECTION Direction; @@ -144,7 +150,6 @@ typedef struct _TRANSFER_RING { } TRANSFER_RING; typedef struct _EVENT_RING { - UINT32 EventInterrupter; VOID *ERSTBase; VOID *EventRingSeg0; UINTN TrbNumber; @@ -577,6 +582,46 @@ typedef struct _SLOT_CONTEXT { UINT32 RsvdZ7; } SLOT_CONTEXT; +typedef struct _SLOT_CONTEXT_64 { + UINT32 RouteString:20; + UINT32 Speed:4; + UINT32 RsvdZ1:1; + UINT32 MTT:1; + UINT32 Hub:1; + UINT32 ContextEntries:5; + + UINT32 MaxExitLatency:16; + UINT32 RootHubPortNum:8; + UINT32 PortNum:8; + + UINT32 TTHubSlotId:8; + UINT32 TTPortNum:8; + UINT32 TTT:2; + UINT32 RsvdZ2:4; + UINT32 InterTarget:10; + + UINT32 DeviceAddress:8; + UINT32 RsvdZ3:19; + UINT32 SlotState:5; + + UINT32 RsvdZ4; + UINT32 RsvdZ5; + UINT32 RsvdZ6; + UINT32 RsvdZ7; + + UINT32 RsvdZ8; + UINT32 RsvdZ9; + UINT32 RsvdZ10; + UINT32 RsvdZ11; + + UINT32 RsvdZ12; + UINT32 RsvdZ13; + UINT32 RsvdZ14; + UINT32 RsvdZ15; + +} SLOT_CONTEXT_64; + + // // 6.2.3 Endpoint Context // @@ -609,6 +654,47 @@ typedef struct _ENDPOINT_CONTEXT { UINT32 RsvdZ7; } ENDPOINT_CONTEXT; +typedef struct _ENDPOINT_CONTEXT_64 { + UINT32 EPState:3; + UINT32 RsvdZ1:5; + UINT32 Mult:2; + UINT32 MaxPStreams:5; + UINT32 LSA:1; + UINT32 Interval:8; + UINT32 RsvdZ2:8; + + UINT32 RsvdZ3:1; + UINT32 CErr:2; + UINT32 EPType:3; + UINT32 RsvdZ4:1; + UINT32 HID:1; + UINT32 MaxBurstSize:8; + UINT32 MaxPacketSize:16; + + UINT32 PtrLo; + + UINT32 PtrHi; + + UINT32 AverageTRBLength:16; + UINT32 MaxESITPayload:16; + + UINT32 RsvdZ5; + UINT32 RsvdZ6; + UINT32 RsvdZ7; + + UINT32 RsvdZ8; + UINT32 RsvdZ9; + UINT32 RsvdZ10; + UINT32 RsvdZ11; + + UINT32 RsvdZ12; + UINT32 RsvdZ13; + UINT32 RsvdZ14; + UINT32 RsvdZ15; + +} ENDPOINT_CONTEXT_64; + + // // 6.2.5.1 Input Control Context // @@ -623,6 +709,25 @@ typedef struct _INPUT_CONTRL_CONTEXT { UINT32 RsvdZ6; } INPUT_CONTRL_CONTEXT; +typedef struct _INPUT_CONTRL_CONTEXT_64 { + UINT32 Dword1; + UINT32 Dword2; + UINT32 RsvdZ1; + UINT32 RsvdZ2; + UINT32 RsvdZ3; + UINT32 RsvdZ4; + UINT32 RsvdZ5; + UINT32 RsvdZ6; + UINT32 RsvdZ7; + UINT32 RsvdZ8; + UINT32 RsvdZ9; + UINT32 RsvdZ10; + UINT32 RsvdZ11; + UINT32 RsvdZ12; + UINT32 RsvdZ13; + UINT32 RsvdZ14; +} INPUT_CONTRL_CONTEXT_64; + // // 6.2.1 Device Context // @@ -631,6 +736,11 @@ typedef struct _DEVICE_CONTEXT { ENDPOINT_CONTEXT EP[31]; } DEVICE_CONTEXT; +typedef struct _DEVICE_CONTEXT_64 { + SLOT_CONTEXT_64 Slot; + ENDPOINT_CONTEXT_64 EP[31]; +} DEVICE_CONTEXT_64; + // // 6.2.5 Input Context // @@ -640,6 +750,13 @@ typedef struct _INPUT_CONTEXT { ENDPOINT_CONTEXT EP[31]; } INPUT_CONTEXT; +typedef struct _INPUT_CONTEXT_64 { + INPUT_CONTRL_CONTEXT_64 InputControlContext; + SLOT_CONTEXT_64 Slot; + ENDPOINT_CONTEXT_64 EP[31]; +} INPUT_CONTEXT_64; + + /** Initialize the XHCI host controller for schedule. @@ -703,7 +820,7 @@ XhcExecTransfer ( the device and endpoint. @param Xhc The XHCI Instance. - @param DevAddr The address of the target device. + @param BusAddr The logical device address assigned by UsbBus driver. @param EpNum The endpoint of the target. @retval EFI_SUCCESS An asynchronous transfer is removed. @@ -713,7 +830,7 @@ XhcExecTransfer ( EFI_STATUS XhciDelAsyncIntTransfer ( IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 DevAddr, + IN UINT8 BusAddr, IN UINT8 EpNum ); @@ -750,21 +867,6 @@ XhcClearBiosOwnership ( IN USB_XHCI_INSTANCE *Xhc ); -/** - Find out the slot id according to device address assigned by XHCI's Address_Device cmd. - - @param Xhc The XHCI Instance. - @param DevAddr The device address of the target device. - - @return The slot id used by the device. - -**/ -UINT8 -XhcDevAddrToSlotId ( - IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 DevAddr - ); - /** Find out the slot id according to the device's route string. @@ -870,6 +972,29 @@ XhcConfigHubContext ( IN UINT8 MTT ); + +/** + Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be configured. + @param PortNum The total number of downstream port supported by the hub. + @param TTT The TT think time of the hub device. + @param MTT The multi-TT of the hub device. + + @retval EFI_SUCCESS Successfully configure the hub device's slot context. + +**/ +EFI_STATUS +XhcConfigHubContext64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 PortNum, + IN UINT8 TTT, + IN UINT8 MTT + ); + + /** Configure all the device endpoints through XHCI's Configure_Endpoint cmd. @@ -890,6 +1015,28 @@ XhcSetConfigCmd ( IN USB_CONFIG_DESCRIPTOR *ConfigDesc ); + +/** + Configure all the device endpoints through XHCI's Configure_Endpoint cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be configured. + @param DeviceSpeed The device's speed. + @param ConfigDesc The pointer to the usb device configuration descriptor. + + @retval EFI_SUCCESS Successfully configure all the device endpoints. + +**/ +EFI_STATUS +EFIAPI +XhcSetConfigCmd64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 DeviceSpeed, + IN USB_CONFIG_DESCRIPTOR *ConfigDesc + ); + + /** Find out the actual device address according to the requested device address from UsbBus. @@ -928,6 +1075,28 @@ XhcInitializeDeviceSlot ( IN UINT8 DeviceSpeed ); +/** + Assign and initialize the device slot for a new device. + + @param Xhc The XHCI Instance. + @param ParentRouteChart The route string pointed to the parent device. + @param ParentPort The port at which the device is located. + @param RouteChart The route string pointed to the device. + @param DeviceSpeed The device speed. + + @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it. + +**/ +EFI_STATUS +EFIAPI +XhcInitializeDeviceSlot64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN USB_DEV_ROUTE ParentRouteChart, + IN UINT16 ParentPort, + IN USB_DEV_ROUTE RouteChart, + IN UINT8 DeviceSpeed + ); + /** Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd. @@ -946,6 +1115,26 @@ XhcEvaluateContext ( IN UINT32 MaxPacketSize ); + +/** + Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be evaluated. + @param MaxPacketSize The max packet size supported by the device control transfer. + + @retval EFI_SUCCESS Successfully evaluate the device endpoint 0. + +**/ +EFI_STATUS +EFIAPI +XhcEvaluateContext64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT32 MaxPacketSize + ); + + /** Disable the specified device slot. @@ -962,6 +1151,24 @@ XhcDisableSlotCmd ( IN UINT8 SlotId ); + +/** + Disable the specified device slot. + + @param Xhc The XHCI Instance. + @param SlotId The slot id to be disabled. + + @retval EFI_SUCCESS Successfully disable the device slot. + +**/ +EFI_STATUS +EFIAPI +XhcDisableSlotCmd64 ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId + ); + + /** Synchronize the specified transfer ring to update the enqueue and dequeue pointer. @@ -1032,14 +1239,12 @@ CreateTransferRing ( Create XHCI event ring. @param Xhc The XHCI Instance. - @param EventInterrupter The interrupter of event. @param EventRing The created event ring. **/ VOID CreateEventRing ( IN USB_XHCI_INSTANCE *Xhc, - IN UINT8 EventInterrupter, OUT EVENT_RING *EventRing ); diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c index 30bf43cb36..e8f9ed5018 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c @@ -1431,7 +1431,6 @@ UsbBusControllerDriverStop ( // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict // OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - UsbHcSetState (Bus, EfiUsbHcStateHalt); RootHub = Bus->Devices[0]; RootIf = RootHub->Interfaces[0]; -- 2.39.2