X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FXhciDxe%2FXhciSched.c;h=6d4044a09b198eb04fd01c61bffdde14fc414c17;hb=e0e7f80cc31b625fe45be1ec48d48fd60b613c77;hp=f160a1d2ec7d864f2b6bed252dd1b458d87d61bc;hpb=92870c983c6d99d31f449d8dcd729090255dda49;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c index f160a1d2ec..6d4044a09b 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c @@ -15,167 +15,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "Xhci.h" -/** - Allocates a buffer of a certain pool type at a specified alignment. - - Allocates the number bytes specified by AllocationSize of a certain pool type with an alignment - specified by Alignment. The allocated buffer is returned. If AllocationSize is 0, then a valid - buffer of 0 size is returned. If there is not enough memory at the specified alignment remaining - to satisfy the request, then NULL is returned. - If Alignment is not a power of two and Alignment is not zero, then ASSERT(). - - @param PoolType The type of pool to allocate. - @param AllocationSize The number of bytes to allocate. - @param Alignment The requested alignment of the allocation. Must be a power of two. - If Alignment is zero, then byte alignment is used. - - @return A pointer to the allocated buffer or NULL if allocation fails. - -**/ -VOID * -InternalAllocateAlignedPool ( - IN EFI_MEMORY_TYPE PoolType, - IN UINTN AllocationSize, - IN UINTN Alignment - ) -{ - VOID *RawAddress; - UINTN AlignedAddress; - UINTN AlignmentMask; - UINTN OverAllocationSize; - UINTN RealAllocationSize; - VOID **FreePointer; - - // - // Alignment must be a power of two or zero. - // - ASSERT ((Alignment & (Alignment - 1)) == 0); - - if (Alignment == 0) { - AlignmentMask = Alignment; - } else { - AlignmentMask = Alignment - 1; - } - // - // Calculate the extra memory size, over-allocate memory pool and get the aligned memory address. - // - OverAllocationSize = sizeof (RawAddress) + AlignmentMask; - RealAllocationSize = AllocationSize + OverAllocationSize; - // - // Make sure that AllocationSize plus OverAllocationSize does not overflow. - // - ASSERT (RealAllocationSize > AllocationSize); - - RawAddress = NULL; - gBS->AllocatePool (PoolType, RealAllocationSize, &RawAddress); - if (RawAddress == NULL) { - return NULL; - } - AlignedAddress = ((UINTN) RawAddress + OverAllocationSize) & ~AlignmentMask; - // - // Save the original memory address just before the aligned address. - // - FreePointer = (VOID **)(AlignedAddress - sizeof (RawAddress)); - *FreePointer = RawAddress; - - return (VOID *) AlignedAddress; -} - -/** - Allocates and zeros a buffer of a certain pool type at a specified alignment. - - Allocates the number bytes specified by AllocationSize of a certain pool type with an alignment - specified by Alignment, clears the buffer with zeros, and returns a pointer to the allocated - buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there is not - enough memory at the specified alignment remaining to satisfy the request, then NULL is returned. - If Alignment is not a power of two and Alignment is not zero, then ASSERT(). - - @param PoolType The type of pool to allocate. - @param AllocationSize The number of bytes to allocate. - @param Alignment The requested alignment of the allocation. Must be a power of two. - If Alignment is zero, then byte alignment is used. - - @return A pointer to the allocated buffer or NULL if allocation fails. - -**/ -VOID * -InternalAllocateAlignedZeroPool ( - IN EFI_MEMORY_TYPE PoolType, - IN UINTN AllocationSize, - IN UINTN Alignment - ) -{ - VOID *Memory; - Memory = InternalAllocateAlignedPool (PoolType, AllocationSize, Alignment); - if (Memory != NULL) { - ZeroMem (Memory, AllocationSize); - } - return Memory; -} - -/** - Allocates and zeros a buffer of type EfiBootServicesData at a specified alignment. - - Allocates the number bytes specified by AllocationSize of type EfiBootServicesData with an - alignment specified by Alignment, clears the buffer with zeros, and returns a pointer to the - allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there - is not enough memory at the specified alignment remaining to satisfy the request, then NULL is - returned. - If Alignment is not a power of two and Alignment is not zero, then ASSERT(). - - @param AllocationSize The number of bytes to allocate. - @param Alignment The requested alignment of the allocation. Must be a power of two. - If Alignment is zero, then byte alignment is used. - - @return A pointer to the allocated buffer or NULL if allocation fails. - -**/ -VOID * -EFIAPI -AllocateAlignedZeroPool ( - IN UINTN AllocationSize, - IN UINTN Alignment - ) -{ - return InternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment); -} - -/** - Frees a buffer that was previously allocated with one of the aligned pool allocation functions - in the Memory Allocation Library. - - Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the - aligned pool allocation services of the Memory Allocation Library. - If Buffer was not allocated with an aligned pool allocation function in the Memory Allocation - Library, then ASSERT(). - - @param Buffer Pointer to the buffer to free. - -**/ -VOID -EFIAPI -FreeAlignedPool ( - IN VOID *Buffer - ) -{ - VOID *RawAddress; - VOID **FreePointer; - EFI_STATUS Status; - - // - // Get the pre-saved original address in the over-allocate pool. - // - FreePointer = (VOID **)((UINTN) Buffer - sizeof (RawAddress)); - RawAddress = *FreePointer; - - Status = gBS->FreePool (RawAddress); - ASSERT_EFI_ERROR (Status); -} - /** Create a command transfer TRB to support XHCI command interfaces. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param CmdTrb The cmd TRB to be executed. @return Created URB or NULL. @@ -183,8 +26,8 @@ FreeAlignedPool ( **/ URB* XhcCreateCmdTrb ( - IN USB_XHCI_DEV *Xhc, - IN TRB *CmdTrb + IN USB_XHCI_INSTANCE *Xhc, + IN TRB_TEMPLATE *CmdTrb ) { URB *Urb; @@ -200,11 +43,11 @@ XhcCreateCmdTrb ( XhcSyncTrsRing (Xhc, Urb->Ring); Urb->TrbNum = 1; Urb->TrbStart = Urb->Ring->RingEnqueue; - CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB)); + CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE)); 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; @@ -214,9 +57,9 @@ XhcCreateCmdTrb ( /** Execute a XHCI cmd TRB pointed by CmdTrb. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param CmdTrb The cmd TRB to be executed. - @param TimeOut Indicates the maximum time, in millisecond, which the + @param Timeout Indicates the maximum time, in millisecond, which the transfer is allowed to complete. @param EvtTrb The event TRB corresponding to the cmd TRB. @@ -229,10 +72,10 @@ XhcCreateCmdTrb ( EFI_STATUS EFIAPI XhcCmdTransfer ( - IN USB_XHCI_DEV *Xhc, - IN TRB *CmdTrb, - IN UINTN TimeOut, - OUT TRB **EvtTrb + IN USB_XHCI_INSTANCE *Xhc, + IN TRB_TEMPLATE *CmdTrb, + IN UINTN Timeout, + OUT TRB_TEMPLATE **EvtTrb ) { EFI_STATUS Status; @@ -263,9 +106,9 @@ XhcCmdTransfer ( goto ON_EXIT; } - ASSERT (Urb->EvtRing == &Xhc->CmdEventRing); + ASSERT (Urb->EvtRing == &Xhc->EventRing); - Status = XhcExecTransfer (Xhc, TRUE, Urb, TimeOut); + Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout); *EvtTrb = Urb->EvtTrbStart; if (Urb->Result == EFI_USB_NOERROR) { @@ -281,8 +124,8 @@ ON_EXIT: /** Create a new URB for a new transaction. - @param Xhc The XHCI device - @param DevAddr The device address + @param Xhc The XHCI Instance + @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 @@ -298,8 +141,8 @@ ON_EXIT: **/ URB* XhcCreateUrb ( - IN USB_XHCI_DEV *Xhc, - IN UINT8 DevAddr, + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 BusAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINTN MaxPacket, @@ -324,8 +167,8 @@ XhcCreateUrb ( InitializeListHead (&Urb->UrbList); Ep = &Urb->Ep; - Ep->DevAddr = DevAddr; - Ep->EpAddr = EpAddr & 0x0F; + Ep->BusAddr = BusAddr; + Ep->EpAddr = (UINT8)(EpAddr & 0x0F); Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut; Ep->DevSpeed = DevSpeed; Ep->MaxPacket = MaxPacket; @@ -338,6 +181,7 @@ XhcCreateUrb ( Urb->Context = Context; Status = XhcCreateTransferTrb (Xhc, Urb); + ASSERT_EFI_ERROR (Status); return Urb; } @@ -345,20 +189,19 @@ XhcCreateUrb ( /** Create a transfer TRB. - @param Xhc The XHCI device + @param Xhc The XHCI Instance @param Urb The urb used to construct the transfer TRB. @return Created TRB or NULL **/ EFI_STATUS -EFIAPI XhcCreateTransferTrb ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb ) { - DEVICE_CONTEXT *OutputDevContxt; + VOID *OutputContext; TRANSFER_RING *EPRing; UINT8 EPType; UINT8 SlotId; @@ -368,12 +211,21 @@ XhcCreateTransferTrb ( UINTN Len; UINTN TrbNum; - SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr); - Dci = XhcEndpointToDci (Urb->Ep.EpAddr, Urb->Ep.Direction); - EPRing = (TRANSFER_RING *)(UINTN) UsbDevContext[SlotId].EndpointTransferRing[Dci-1]; + 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; - OutputDevContxt = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId]; - EPType = (UINT8) OutputDevContxt->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 @@ -382,34 +234,34 @@ 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; // // For control transfer, create SETUP_STAGE_TRB first. // - TrbStart = EPRing->RingEnqueue; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->bmRequestType = Urb->Request->RequestType; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->bRequest = Urb->Request->Request; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wValue = Urb->Request->Value; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wIndex = Urb->Request->Index; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wLength = Urb->Request->Length; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->Lenth = 8; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IOC = 1; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IDT = 1; - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->Type = TRB_TYPE_SETUP_STAGE; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; + TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType; + TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request; + TrbStart->TrbCtrSetup.wValue = Urb->Request->Value; + TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index; + TrbStart->TrbCtrSetup.wLength = Urb->Request->Length; + TrbStart->TrbCtrSetup.Lenth = 8; + TrbStart->TrbCtrSetup.IntTarget = 0; + TrbStart->TrbCtrSetup.IOC = 1; + TrbStart->TrbCtrSetup.IDT = 1; + TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE; if (Urb->Ep.Direction == EfiUsbDataIn) { - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 3; + TrbStart->TrbCtrSetup.TRT = 3; } else if (Urb->Ep.Direction == EfiUsbDataOut) { - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 2; + TrbStart->TrbCtrSetup.TRT = 2; } else { - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 0; + TrbStart->TrbCtrSetup.TRT = 0; } // // Update the cycle bit // - ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0; + TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0; Urb->TrbNum++; // @@ -417,28 +269,28 @@ XhcCreateTransferTrb ( // if (Urb->DataLen > 0) { XhcSyncTrsRing (Xhc, EPRing); - TrbStart = EPRing->RingEnqueue; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TRBPtrLo = XHC_LOW_32BIT(Urb->Data); - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TRBPtrHi = XHC_HIGH_32BIT(Urb->Data); - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->Lenth = (UINT32) Urb->DataLen; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TDSize = 0; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->ISP = 1; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IOC = 1; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IDT = 0; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->CH = 0; - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->Type = TRB_TYPE_DATA_STAGE; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; + TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->Data); + TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data); + TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen; + TrbStart->TrbCtrData.TDSize = 0; + TrbStart->TrbCtrData.IntTarget = 0; + TrbStart->TrbCtrData.ISP = 1; + TrbStart->TrbCtrData.IOC = 1; + TrbStart->TrbCtrData.IDT = 0; + TrbStart->TrbCtrData.CH = 0; + TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE; if (Urb->Ep.Direction == EfiUsbDataIn) { - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 1; + TrbStart->TrbCtrData.DIR = 1; } else if (Urb->Ep.Direction == EfiUsbDataOut) { - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 0; + TrbStart->TrbCtrData.DIR = 0; } else { - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 0; + TrbStart->TrbCtrData.DIR = 0; } // // Update the cycle bit // - ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0; + TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0; Urb->TrbNum++; } // @@ -446,60 +298,60 @@ XhcCreateTransferTrb ( // Get the pointer to next TRB for status stage use // XhcSyncTrsRing (Xhc, EPRing); - TrbStart = EPRing->RingEnqueue; - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter; - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->IOC = 1; - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->CH = 0; - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->Type = TRB_TYPE_STATUS_STAGE; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; + TrbStart->TrbCtrStatus.IntTarget = 0; + TrbStart->TrbCtrStatus.IOC = 1; + TrbStart->TrbCtrStatus.CH = 0; + TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE; if (Urb->Ep.Direction == EfiUsbDataIn) { - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 0; + TrbStart->TrbCtrStatus.DIR = 0; } else if (Urb->Ep.Direction == EfiUsbDataOut) { - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 1; + TrbStart->TrbCtrStatus.DIR = 1; } else { - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 0; + TrbStart->TrbCtrStatus.DIR = 0; } // // Update the cycle bit // - ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0; + TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0; // // Update the enqueue pointer // XhcSyncTrsRing (Xhc, EPRing); Urb->TrbNum++; - Urb->TrbEnd = TrbStart; + Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart; break; 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; TotalLen = 0; Len = 0; TrbNum = 0; - TrbStart = EPRing->RingEnqueue; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; while (TotalLen < Urb->DataLen) { if ((TotalLen + 0x10000) >= Urb->DataLen) { Len = Urb->DataLen - TotalLen; } else { Len = 0x10000; } - TrbStart = EPRing->RingEnqueue; - ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen); - ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); - ((TRANSFER_TRB_NORMAL *) TrbStart)->Lenth = (UINT32) Len; - ((TRANSFER_TRB_NORMAL *) TrbStart)->TDSize = 0; - ((TRANSFER_TRB_NORMAL *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter; - ((TRANSFER_TRB_NORMAL *) TrbStart)->ISP = 1; - ((TRANSFER_TRB_NORMAL *) TrbStart)->IOC = 1; - ((TRANSFER_TRB_NORMAL *) TrbStart)->Type = TRB_TYPE_NORMAL; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; + TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen); + TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); + TrbStart->TrbNormal.Lenth = (UINT32) Len; + TrbStart->TrbNormal.TDSize = 0; + TrbStart->TrbNormal.IntTarget = 0; + TrbStart->TrbNormal.ISP = 1; + TrbStart->TrbNormal.IOC = 1; + TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL; // // Update the cycle bit // - ((TRANSFER_TRB_NORMAL *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0; + TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0; XhcSyncTrsRing (Xhc, EPRing); TrbNum++; @@ -507,45 +359,38 @@ XhcCreateTransferTrb ( } Urb->TrbNum = TrbNum; - Urb->TrbEnd = TrbStart; + Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart; break; 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; TotalLen = 0; Len = 0; TrbNum = 0; - TrbStart = EPRing->RingEnqueue; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; while (TotalLen < Urb->DataLen) { if ((TotalLen + 0x10000) >= Urb->DataLen) { Len = Urb->DataLen - TotalLen; } else { Len = 0x10000; } - TrbStart = EPRing->RingEnqueue; - ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen); - ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); - ((TRANSFER_TRB_NORMAL *) TrbStart)->Lenth = (UINT32) Len; - ((TRANSFER_TRB_NORMAL *) TrbStart)->TDSize = 0; - ((TRANSFER_TRB_NORMAL *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter; - ((TRANSFER_TRB_NORMAL *) TrbStart)->ISP = 1; - ((TRANSFER_TRB_NORMAL *) TrbStart)->IOC = 1; - ((TRANSFER_TRB_NORMAL *) TrbStart)->Type = TRB_TYPE_NORMAL; + TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue; + TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen); + TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen); + TrbStart->TrbNormal.Lenth = (UINT32) Len; + TrbStart->TrbNormal.TDSize = 0; + TrbStart->TrbNormal.IntTarget = 0; + TrbStart->TrbNormal.ISP = 1; + TrbStart->TrbNormal.IOC = 1; + TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL; // // Update the cycle bit // - ((TRANSFER_TRB_NORMAL *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0; + TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0; XhcSyncTrsRing (Xhc, EPRing); TrbNum++; @@ -553,7 +398,7 @@ XhcCreateTransferTrb ( } Urb->TrbNum = TrbNum; - Urb->TrbEnd = TrbStart; + Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart; break; default: @@ -569,12 +414,12 @@ XhcCreateTransferTrb ( /** Initialize the XHCI host controller for schedule. - @param Xhc The XHCI device to be initialized. + @param Xhc The XHCI Instance to be initialized. **/ VOID XhcInitSched ( - IN USB_XHCI_DEV *Xhc + IN USB_XHCI_INSTANCE *Xhc ) { VOID *Dcbaa; @@ -600,8 +445,9 @@ XhcInitSched ( // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'. // Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64); - Dcbaa = AllocateAlignedZeroPool(Entries, 64); + Dcbaa = AllocatePages (EFI_SIZE_TO_PAGES (Entries)); ASSERT (Dcbaa != NULL); + ZeroMem (Dcbaa, Entries); // // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary. @@ -610,14 +456,17 @@ XhcInitSched ( // MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo); Xhc->MaxScratchpadBufs = MaxScratchpadBufs; - ASSERT (MaxScratchpadBufs >= 0 && MaxScratchpadBufs <= 1023); + ASSERT (MaxScratchpadBufs <= 1023); if (MaxScratchpadBufs != 0) { - ScratchBuf = AllocateAlignedZeroPool(MaxScratchpadBufs * sizeof (UINT64), Xhc->PageSize); + ScratchBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)), Xhc->PageSize); ASSERT (ScratchBuf != NULL); + ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64)); Xhc->ScratchBuf = ScratchBuf; for (Index = 0; Index < MaxScratchpadBufs; Index++) { - ScratchEntryBuf = AllocateAlignedZeroPool(Xhc->PageSize, Xhc->PageSize); + ScratchEntryBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc->PageSize), Xhc->PageSize); + ASSERT (ScratchEntryBuf != NULL); + ZeroMem (ScratchEntryBuf, Xhc->PageSize); *ScratchBuf++ = (UINT64)(UINTN)ScratchEntryBuf; } @@ -632,9 +481,14 @@ XhcInitSched ( // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with // 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)Xhc->DCBAA); - DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)Xhc->DCBAA)); + Xhc->DCBAA = (UINT64 *)(UINTN)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)); // // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register @@ -651,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)); @@ -668,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)); } /** @@ -682,7 +538,7 @@ XhcInitSched ( reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running state. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param Urb The urb which makes the endpoint halted. @retval EFI_SUCCESS The recovery is successful. @@ -692,21 +548,25 @@ XhcInitSched ( EFI_STATUS EFIAPI XhcRecoverHaltedEndpoint ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb ) { - EFI_STATUS Status; - EVT_TRB_COMMAND *EvtTrb; - CMD_TRB_RESET_ED CmdTrbResetED; - CMD_SET_TR_DEQ CmdSetTRDeq; - UINT8 Dci; - UINT8 SlotId; - - Status = EFI_SUCCESS; - SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, Urb->Ep.Direction); + EFI_STATUS Status; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + CMD_TRB_RESET_ENDPOINT CmdTrbResetED; + CMD_SET_TR_DEQ_POINTER CmdSetTRDeq; + UINT8 Dci; + UINT8 SlotId; + 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)); // @@ -719,9 +579,9 @@ XhcRecoverHaltedEndpoint ( CmdTrbResetED.SlotId = SlotId; Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrbResetED, + (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT (!EFI_ERROR(Status)); @@ -737,9 +597,9 @@ XhcRecoverHaltedEndpoint ( CmdSetTRDeq.SlotId = SlotId; Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdSetTRDeq, + (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT (!EFI_ERROR(Status)); @@ -754,16 +614,13 @@ XhcRecoverHaltedEndpoint ( /** Create XHCI event ring. - @param Xhc The XHCI device. - @param EventInterrupter The interrupter of event. + @param Xhc The XHCI Instance. @param EventRing The created event ring. **/ VOID -EFIAPI CreateEventRing ( - IN USB_XHCI_DEV *Xhc, - IN UINT8 EventInterrupter, + IN USB_XHCI_INSTANCE *Xhc, OUT EVENT_RING *EventRing ) { @@ -772,24 +629,25 @@ CreateEventRing ( ASSERT (EventRing != NULL); - Buf = AllocateAlignedZeroPool(sizeof (TRB) * EVENT_RING_TRB_NUMBER, 64); + Buf = AllocatePages (EFI_SIZE_TO_PAGES (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 = Buf; - EventRing->EventInterrupter = EventInterrupter; EventRing->TrbNumber = EVENT_RING_TRB_NUMBER; - EventRing->EventRingDequeue = (TRB *) EventRing->EventRingSeg0; - EventRing->EventRingEnqueue = (TRB *) EventRing->EventRingSeg0; + EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0; + EventRing->EventRingEnqueue = (TRB_TEMPLATE *) 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; - Buf = AllocateAlignedZeroPool(sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER, 64); + Buf = AllocatePages (EFI_SIZE_TO_PAGES (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 = ERSTBase; @@ -802,65 +660,81 @@ 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)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) 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); } /** Create XHCI transfer ring. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param TrbNum The number of TRB in the ring. @param TransferRing The created transfer ring. **/ VOID -EFIAPI CreateTransferRing ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN UINTN TrbNum, OUT TRANSFER_RING *TransferRing ) { VOID *Buf; - LNK_TRB *EndTrb; + LINK_TRB *EndTrb; - Buf = AllocateAlignedZeroPool(sizeof (TRB) * TrbNum, 64); + Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TrbNum)); ASSERT (Buf != NULL); ASSERT (((UINTN) Buf & 0x3F) == 0); + ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum); TransferRing->RingSeg0 = Buf; TransferRing->TrbNumber = TrbNum; - TransferRing->RingEnqueue = (TRB *) TransferRing->RingSeg0; - TransferRing->RingDequeue = (TRB *) TransferRing->RingSeg0; + TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0; + TransferRing->RingDequeue = (TRB_TEMPLATE *) 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 = (LNK_TRB*) ((UINTN)Buf + sizeof (TRB) * (TrbNum - 1)); + 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); @@ -877,14 +751,14 @@ CreateTransferRing ( /** Free XHCI event ring. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param EventRing The event ring to be freed. **/ EFI_STATUS EFIAPI XhcFreeEventRing ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN EVENT_RING *EventRing ) { @@ -892,13 +766,11 @@ XhcFreeEventRing ( EVENT_RING_SEG_TABLE_ENTRY *TablePtr; VOID *RingBuf; EVENT_RING_SEG_TABLE_ENTRY *EventRingPtr; - UINTN InterrupterTarget; if(EventRing->EventRingSeg0 == NULL) { return EFI_SUCCESS; } - InterrupterTarget = EventRing->EventInterrupter; // // Get the Event Ring Segment Table base address // @@ -909,51 +781,51 @@ XhcFreeEventRing ( // for (Index = 0; Index < ERST_NUMBER; Index++) { EventRingPtr = TablePtr + Index; - RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | ((UINT64)EventRingPtr->PtrHi << 32)); + RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | LShiftU64 ((UINT64)EventRingPtr->PtrHi, 32)); if(RingBuf != NULL) { - FreeAlignedPool (RingBuf); + FreePages (RingBuf, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER)); ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY)); } } - FreeAlignedPool (TablePtr); + FreePages (TablePtr, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER)); return EFI_SUCCESS; } /** Free the resouce allocated at initializing schedule. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. **/ VOID XhcFreeSched ( - IN USB_XHCI_DEV *Xhc + IN USB_XHCI_INSTANCE *Xhc ) { UINT32 Index; + UINT64 *ScratchBuf; if (Xhc->ScratchBuf != NULL) { + ScratchBuf = Xhc->ScratchBuf; for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) { - FreeAlignedPool ((VOID*)(UINTN)*Xhc->ScratchBuf++); + FreeAlignedPages ((VOID*)(UINTN)*ScratchBuf++, EFI_SIZE_TO_PAGES (Xhc->PageSize)); } + FreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64))); } if (Xhc->DCBAA != NULL) { - FreeAlignedPool (Xhc->DCBAA); + FreePages (Xhc->DCBAA, EFI_SIZE_TO_PAGES((Xhc->MaxSlotsEn + 1) * sizeof(UINT64))); Xhc->DCBAA = NULL; } if (Xhc->CmdRing.RingSeg0 != NULL){ - FreeAlignedPool (Xhc->CmdRing.RingSeg0); + FreePages (Xhc->CmdRing.RingSeg0, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER)); 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); } /** @@ -969,11 +841,11 @@ XhcFreeSched ( BOOLEAN IsTransferRingTrb ( IN TRANSFER_RING *Ring, - IN TRB *Trb + IN TRB_TEMPLATE *Trb ) { BOOLEAN Flag; - TRB *Trb1; + TRB_TEMPLATE *Trb1; UINTN Index; Trb1 = Ring->RingSeg0; @@ -996,7 +868,7 @@ IsTransferRingTrb ( Check the URB's execution result and update the URB's result accordingly. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param Urb The URB to check result. @return Whether the result of URB transfer is finialized. @@ -1004,14 +876,14 @@ IsTransferRingTrb ( **/ EFI_STATUS XhcCheckUrbResult ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb ) { BOOLEAN StartDone; BOOLEAN EndDone; EVT_TRB_TRANSFER *EvtTrb; - TRB *TRBPtr; + TRB_TEMPLATE *TRBPtr; UINTN Index; UINT8 TRBType; EFI_STATUS Status; @@ -1037,80 +909,88 @@ XhcCheckUrbResult ( Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart; for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) { XhcSyncEventRing (Xhc, Urb->EvtRing); - Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, &(TRB *)EvtTrb); + Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, ((TRB_TEMPLATE **)&EvtTrb)); if (Status == EFI_NOT_READY) { Urb->Result |= EFI_USB_ERR_TIMEOUT; goto EXIT; } - TRBPtr = (TRB *)(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->Completcode) { - case TRB_COMPLETION_STALL_ERROR: - Urb->Result |= EFI_USB_ERR_STALL; - Status = EFI_DEVICE_ERROR; - DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completcode = %x\n",EvtTrb->Completcode)); - goto EXIT; - break; + TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((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! Completcode = %x\n",EvtTrb->Completcode)); - 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! Completcode = %x\n",EvtTrb->Completcode)); - 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! Completcode = %x\n",EvtTrb->Completcode)); - 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)) { - if (EvtTrb->Completcode == TRB_COMPLETION_SHORT_PACKET) { + 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! Completcode = 0x%x!\n",EvtTrb->Completcode)); - 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; + } } } @@ -1122,10 +1002,10 @@ EXIT: /** Execute the transfer by polling the URB. This is a synchronous operation. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param CmdTransfer The executed URB is for cmd transfer or not. @param Urb The URB to execute. - @param TimeOut The time to wait before abort, in millisecond. + @param Timeout The time to wait before abort, in millisecond. @return EFI_DEVICE_ERROR The transfer failed due to transfer error. @return EFI_TIMEOUT The transfer failed due to time out. @@ -1134,10 +1014,10 @@ EXIT: **/ EFI_STATUS XhcExecTransfer ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN BOOLEAN CmdTransfer, IN URB *Urb, - IN UINTN TimeOut + IN UINTN Timeout ) { EFI_STATUS Status; @@ -1150,13 +1030,17 @@ XhcExecTransfer ( SlotId = 0; Dci = 0; } else { - SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, 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; - Loop = (TimeOut * XHC_1_MILLISECOND / XHC_SYNC_POLL_INTERVAL) + 1; - if (TimeOut == 0) { + Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1; + if (Timeout == 0) { Loop = 0xFFFFFFFF; } @@ -1167,7 +1051,7 @@ XhcExecTransfer ( if ((Status != EFI_NOT_READY)) { break; } - gBS->Stall (XHC_SYNC_POLL_INTERVAL); + gBS->Stall (XHC_POLL_DELAY); } return Status; @@ -1177,8 +1061,8 @@ XhcExecTransfer ( Delete a single asynchronous interrupt transfer for the device and endpoint. - @param Xhc The XHCI device. - @param DevAddr The address of the target device. + @param Xhc The XHCI Instance. + @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. @@ -1187,8 +1071,8 @@ XhcExecTransfer ( **/ EFI_STATUS XhciDelAsyncIntTransfer ( - IN USB_XHCI_DEV *Xhc, - IN UINT8 DevAddr, + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 BusAddr, IN UINT8 EpNum ) { @@ -1196,17 +1080,15 @@ XhciDelAsyncIntTransfer ( LIST_ENTRY *Next; URB *Urb; EFI_USB_DATA_DIRECTION Direction; - BOOLEAN Found; Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut; EpNum &= 0x0F; - Found = FALSE; - 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); @@ -1222,12 +1104,12 @@ XhciDelAsyncIntTransfer ( /** Remove all the asynchronous interrutp transfers. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. **/ VOID XhciDelAllAsyncIntTransfers ( - IN USB_XHCI_DEV *Xhc + IN USB_XHCI_INSTANCE *Xhc ) { LIST_ENTRY *Entry; @@ -1245,13 +1127,13 @@ XhciDelAllAsyncIntTransfers ( /** Update the queue head for next round of asynchronous transfer - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param Urb The URB to update **/ VOID XhcUpdateAsyncRequest ( - IN USB_XHCI_DEV* Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb ) { @@ -1259,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; + } } } @@ -1270,7 +1156,7 @@ XhcUpdateAsyncRequest ( Interrupt transfer periodic check handler. @param Event Interrupt event. - @param Context Pointer to USB_XHCI_DEV. + @param Context Pointer to USB_XHCI_INSTANCE. **/ VOID @@ -1280,7 +1166,7 @@ XhcMonitorAsyncRequests ( IN VOID *Context ) { - USB_XHCI_DEV *Xhc; + USB_XHCI_INSTANCE *Xhc; LIST_ENTRY *Entry; LIST_ENTRY *Next; UINT8 *ProcBuf; @@ -1291,7 +1177,7 @@ XhcMonitorAsyncRequests ( OldTpl = gBS->RaiseTPL (XHC_TPL); - Xhc = (USB_XHCI_DEV*) Context; + Xhc = (USB_XHCI_INSTANCE*) Context; EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) { Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList); @@ -1299,7 +1185,7 @@ XhcMonitorAsyncRequests ( // // Make sure that the device is available before every check. // - SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr); + SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr); if (SlotId == 0) { continue; } @@ -1323,7 +1209,7 @@ XhcMonitorAsyncRequests ( if (Urb->Result == EFI_USB_NOERROR) { ASSERT (Urb->Completed <= Urb->DataLen); - ProcBuf = AllocatePool (Urb->Completed); + ProcBuf = AllocateZeroPool (Urb->Completed); if (ProcBuf == NULL) { XhcUpdateAsyncRequest (Xhc, Urb); @@ -1365,7 +1251,7 @@ XhcMonitorAsyncRequests ( /** Monitor the port status change. Enable/Disable device slot if there is a device attached/detached. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param ParentRouteChart The route string pointed to the parent device if it exists. @param Port The port to be polled. @param PortState The port state. @@ -1377,7 +1263,7 @@ XhcMonitorAsyncRequests ( EFI_STATUS EFIAPI XhcPollPortStatusChange ( - IN USB_XHCI_DEV* Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT8 Port, IN EFI_USB_PORT_STATUS *PortState @@ -1391,17 +1277,17 @@ XhcPollPortStatusChange ( Status = EFI_SUCCESS; if (ParentRouteChart.Dword == 0) { - RouteChart.Field.RouteString = 0; - RouteChart.Field.RootPortNum = Port + 1; - RouteChart.Field.TierNum = 1; + RouteChart.Route.RouteString = 0; + RouteChart.Route.RootPortNum = Port + 1; + RouteChart.Route.TierNum = 1; } else { if(Port < 14) { - RouteChart.Field.RouteString = ParentRouteChart.Field.RouteString | (Port << (4 * (ParentRouteChart.Field.TierNum - 1))); + RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1))); } else { - RouteChart.Field.RouteString = ParentRouteChart.Field.RouteString | (15 << (4 * (ParentRouteChart.Field.TierNum - 1))); + RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1))); } - RouteChart.Field.RootPortNum = ParentRouteChart.Field.RootPortNum; - RouteChart.Field.TierNum = ParentRouteChart.Field.TierNum + 1; + RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum; + RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1; } if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) && @@ -1420,18 +1306,26 @@ XhcPollPortStatusChange ( // // Execute Enable_Slot cmd for attached device, initialize device context and assign device address. // - SlotId = XhcRouteStringToSlotId (RouteChart); + 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) { // // Device is detached. Disable the allocated device slot and release resource. // - SlotId = XhcRouteStringToSlotId (RouteChart); + 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); } } @@ -1459,7 +1353,7 @@ XhcEndpointToDci ( if (EpAddr == 0) { return 1; } else { - Index = 2 * EpAddr; + Index = (UINT8) (2 * EpAddr); if (Direction == EfiUsbDataIn) { Index += 1; } @@ -1467,41 +1361,11 @@ XhcEndpointToDci ( } } -/** - Find out the slot id according to device address assigned by XHCI's Address_Device cmd. - - @param DevAddr The device address of the target device. - - @return The slot id used by the device. - -**/ -UINT8 -EFIAPI -XhcDevAddrToSlotId ( - IN UINT8 DevAddr - ) -{ - UINT8 Index; - - for (Index = 0; Index < 255; Index++) { - if (UsbDevContext[Index + 1].Enabled && - (UsbDevContext[Index + 1].SlotId != 0) && - (UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) { - break; - } - } - - if (Index == 255) { - return 0; - } - - return UsbDevContext[Index + 1].SlotId; -} - /** Find out the actual device address according to the requested device address from UsbBus. - @param BusDevAddr The requested device address by UsbBus upper driver. + @param Xhc The XHCI Instance. + @param BusDevAddr The requested device address by UsbBus upper driver. @return The actual device address assigned to the device. @@ -1509,15 +1373,16 @@ XhcDevAddrToSlotId ( UINT8 EFIAPI XhcBusDevAddrToSlotId ( - IN UINT8 BusDevAddr + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 BusDevAddr ) { UINT8 Index; for (Index = 0; Index < 255; Index++) { - if (UsbDevContext[Index + 1].Enabled && - (UsbDevContext[Index + 1].SlotId != 0) && - (UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) { + if (Xhc->UsbDevContext[Index + 1].Enabled && + (Xhc->UsbDevContext[Index + 1].SlotId != 0) && + (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) { break; } } @@ -1526,13 +1391,14 @@ XhcBusDevAddrToSlotId ( return 0; } - return UsbDevContext[Index + 1].SlotId; + return Xhc->UsbDevContext[Index + 1].SlotId; } /** Find out the slot id according to the device's route string. - @param RouteString The route string described the device location. + @param Xhc The XHCI Instance. + @param RouteString The route string described the device location. @return The slot id used by the device. @@ -1540,15 +1406,16 @@ XhcBusDevAddrToSlotId ( UINT8 EFIAPI XhcRouteStringToSlotId ( - IN USB_DEV_ROUTE RouteString + IN USB_XHCI_INSTANCE *Xhc, + IN USB_DEV_ROUTE RouteString ) { UINT8 Index; for (Index = 0; Index < 255; Index++) { - if (UsbDevContext[Index + 1].Enabled && - (UsbDevContext[Index + 1].SlotId != 0) && - (UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) { + if (Xhc->UsbDevContext[Index + 1].Enabled && + (Xhc->UsbDevContext[Index + 1].SlotId != 0) && + (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) { break; } } @@ -1557,13 +1424,13 @@ XhcRouteStringToSlotId ( return 0; } - return UsbDevContext[Index + 1].SlotId; + return Xhc->UsbDevContext[Index + 1].SlotId; } /** Synchronize the specified event ring to update the enqueue and dequeue pointer. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param EvtRing The event ring to sync. @retval EFI_SUCCESS The event ring is synchronized successfully. @@ -1572,14 +1439,16 @@ XhcRouteStringToSlotId ( EFI_STATUS EFIAPI XhcSyncEventRing ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN EVENT_RING *EvtRing ) { UINTN Index; - TRB *EvtTrb1; - TRB *EvtTrb2; - TRB *XhcDequeue; + TRB_TEMPLATE *EvtTrb1; + TRB_TEMPLATE *EvtTrb2; + UINT64 XhcDequeue; + UINT32 High; + UINT32 Low; ASSERT (EvtRing != NULL); @@ -1608,17 +1477,20 @@ XhcSyncEventRing ( // // Apply the EventRingDequeue to Xhc // - XhcDequeue = (TRB *)(UINTN) XhcReadRuntimeReg64 ( - Xhc, - XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter) - ); - - if (((UINT64) XhcDequeue & (~0x0F)) != ((UINT64) EvtRing->EventRingDequeue & (~0x0F))) { - XhcWriteRuntimeReg64 ( - Xhc, - XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter), - (UINT64)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; @@ -1627,7 +1499,7 @@ XhcSyncEventRing ( /** Synchronize the specified transfer ring to update the enqueue and dequeue pointer. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param TrsRing The transfer ring to sync. @retval EFI_SUCCESS The transfer ring is synchronized successfully. @@ -1636,12 +1508,12 @@ XhcSyncEventRing ( EFI_STATUS EFIAPI XhcSyncTrsRing ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN TRANSFER_RING *TrsRing ) { UINTN Index; - TRB *TrsTrb; + TRB_TEMPLATE *TrsTrb; ASSERT (TrsRing != NULL); // @@ -1656,16 +1528,16 @@ XhcSyncTrsRing ( } TrsTrb++; if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) { - ASSERT (((LNK_TRB*)TrsTrb)->TC != 0); + ASSERT (((LINK_TRB*)TrsTrb)->TC != 0); // // set cycle bit in Link TRB as normal // - ((LNK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0; + ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0; // // Toggle PCS maintained by software // TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1; - TrsTrb = (TRB*)(UINTN)((TrsTrb->Dword1 | ((UINT64)TrsTrb->Dword2 << 32)) & ~0x0F); + TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F); } } @@ -1678,12 +1550,12 @@ XhcSyncTrsRing ( // // Clear the Trb context for enqueue, but reserve the PCS bit // - TrsTrb->Dword1 = 0; - TrsTrb->Dword2 = 0; - TrsTrb->Dword3 = 0; - TrsTrb->RsvdZ1 = 0; - TrsTrb->Type = 0; - TrsTrb->RsvdZ2 = 0; + TrsTrb->Parameter1 = 0; + TrsTrb->Parameter2 = 0; + TrsTrb->Status = 0; + TrsTrb->RsvdZ1 = 0; + TrsTrb->Type = 0; + TrsTrb->Control = 0; return EFI_SUCCESS; } @@ -1691,7 +1563,7 @@ XhcSyncTrsRing ( /** Check if there is a new generated event. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param EvtRing The event ring to check. @param NewEvtTrb The new event TRB found. @@ -1702,13 +1574,13 @@ XhcSyncTrsRing ( EFI_STATUS EFIAPI XhcCheckNewEvent ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN EVENT_RING *EvtRing, - OUT TRB **NewEvtTrb + OUT TRB_TEMPLATE **NewEvtTrb ) { EFI_STATUS Status; - TRB *EvtTrb; + TRB_TEMPLATE*EvtTrb; ASSERT (EvtRing != NULL); @@ -1721,7 +1593,7 @@ XhcCheckNewEvent ( Status = EFI_SUCCESS; - if (((EvtTrb->Dword3 >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) { + if (((EvtTrb->Status >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) { Status = EFI_DEVICE_ERROR; } @@ -1729,7 +1601,7 @@ XhcCheckNewEvent ( // // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring. // - if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB) * EvtRing->TrbNumber)) { + if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) { EvtRing->EventRingDequeue = EvtRing->EventRingSeg0; } @@ -1739,7 +1611,7 @@ XhcCheckNewEvent ( /** Ring the door bell to notify XHCI there is a transaction to be executed. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param SlotId The slot id of the target device. @param Dci The device context index of the target slot or endpoint. @@ -1749,7 +1621,7 @@ XhcCheckNewEvent ( EFI_STATUS EFIAPI XhcRingDoorBell ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 Dci ) @@ -1766,7 +1638,7 @@ XhcRingDoorBell ( /** Ring the door bell to notify XHCI there is a transaction to be executed through URB. - @param Xhc The XHCI device. + @param Xhc The XHCI Instance. @param Urb The URB to be rung. @retval EFI_SUCCESS Successfully ring the door bell. @@ -1774,15 +1646,15 @@ XhcRingDoorBell ( **/ EFI_STATUS RingIntTransferDoorBell ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb ) { UINT8 SlotId; UINT8 Dci; - SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr); - Dci = XhcEndpointToDci(Urb->Ep.EpAddr, 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; } @@ -1790,7 +1662,7 @@ RingIntTransferDoorBell ( /** Assign and initialize the device slot for a new device. - @param Xhc The XHCI 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. @@ -1802,34 +1674,34 @@ RingIntTransferDoorBell ( EFI_STATUS EFIAPI XhcInitializeDeviceSlot ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT16 ParentPort, IN USB_DEV_ROUTE RouteChart, IN UINT8 DeviceSpeed ) { - EFI_STATUS Status; - EVT_TRB_COMMAND *EvtTrb; - INPUT_CONTEXT *InputContext; - DEVICE_CONTEXT *OutputDevContxt; - TRANSFER_RING *EndpointTransferRing; - CMD_TRB_ADDR_DEV CmdTrbAddr; - UINT8 DeviceAddress; - CMD_TRB_EN_SLOT CmdTrb; - UINT8 SlotId; - UINT8 ParentSlotId; - DEVICE_CONTEXT *ParentDeviceContext; - - ZeroMem (&CmdTrb, sizeof (CMD_TRB_EN_SLOT)); + EFI_STATUS Status; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT *InputContext; + DEVICE_CONTEXT *OutputContext; + TRANSFER_RING *EndpointTransferRing; + CMD_TRB_ADDRESS_DEVICE CmdTrbAddr; + UINT8 DeviceAddress; + CMD_TRB_ENABLE_SLOT CmdTrb; + UINT8 SlotId; + UINT8 ParentSlotId; + DEVICE_CONTEXT *ParentDeviceContext; + + ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT)); CmdTrb.CycleBit = 1; CmdTrb.Type = TRB_TYPE_EN_SLOT; Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrb, + (TRB_TEMPLATE *) (UINTN) &CmdTrb, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT_EFI_ERROR (Status); ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn); @@ -1837,21 +1709,22 @@ XhcInitializeDeviceSlot ( SlotId = (UINT8)EvtTrb->SlotId; ASSERT (SlotId != 0); - ZeroMem (&UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT)); - UsbDevContext[SlotId].Enabled = TRUE; - UsbDevContext[SlotId].SlotId = SlotId; - UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword; - UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword; + 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; // // 4.3.3 Device Slot Initialization // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'. // - InputContext = AllocateAlignedZeroPool(sizeof (INPUT_CONTEXT), 64); + InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT))); ASSERT (InputContext != NULL); ASSERT (((UINTN) InputContext & 0x3F) == 0); + ZeroMem (InputContext, sizeof (INPUT_CONTEXT)); - UsbDevContext[SlotId].InputContext = (VOID *) InputContext; + Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext; // // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1 @@ -1863,21 +1736,21 @@ XhcInitializeDeviceSlot ( // // 3) Initialize the Input Slot Context data structure // - InputContext->Slot.RouteStr = RouteChart.Field.RouteString; + InputContext->Slot.RouteString = RouteChart.Route.RouteString; InputContext->Slot.Speed = DeviceSpeed + 1; InputContext->Slot.ContextEntries = 1; - InputContext->Slot.RootHubPortNum = RouteChart.Field.RootPortNum; + InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum; - if (RouteChart.Field.RouteString) { + if (RouteChart.Route.RouteString) { // // The device is behind of hub device. // - ParentSlotId = XhcRouteStringToSlotId(ParentRouteChart); + 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 *)UsbDevContext[ParentSlotId].OutputDevContxt; + ParentDeviceContext = (DEVICE_CONTEXT *)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)) { @@ -1906,9 +1779,9 @@ XhcInitializeDeviceSlot ( // // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint. // - EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64); - UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing; - CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[0]); + 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). // @@ -1935,152 +1808,448 @@ XhcInitializeDeviceSlot ( // // Init the DCS(dequeue cycle state) as the transfer ring's CCS // - InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0; - InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0); + 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'. // - OutputDevContxt = AllocateAlignedZeroPool(sizeof (DEVICE_CONTEXT), 64); - ASSERT (OutputDevContxt != NULL); - ASSERT (((UINTN) OutputDevContxt & 0x3F) == 0); + OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT))); + ASSERT (OutputContext != NULL); + ASSERT (((UINTN) OutputContext & 0x3F) == 0); + ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT)); - UsbDevContext[SlotId].OutputDevContxt = OutputDevContxt; + 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) OutputDevContxt; + 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 (UsbDevContext[SlotId].InputContext); - CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (UsbDevContext[SlotId].InputContext); + 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 = UsbDevContext[SlotId].SlotId; + CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId; Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrbAddr, + (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT (!EFI_ERROR(Status)); - DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputDevContxt)->Slot.DeviceAddress; + DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress; DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress)); - UsbDevContext[SlotId].XhciDevAddr = DeviceAddress; + Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress; return Status; } /** - Disable the specified device slot. + Assign and initialize the device slot for a new device. - @param Xhc The XHCI device. - @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_DEV *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 *EvtTrb; - CMD_TRB_DIS_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 (!UsbDevContext[Index + 1].Enabled || - (UsbDevContext[Index + 1].SlotId == 0) || - (UsbDevContext[Index + 1].ParentRouteString.Dword != UsbDevContext[SlotId].RouteString.Dword)) { - continue; - } + 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; + + ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT)); + CmdTrb.CycleBit = 1; + CmdTrb.Type = TRB_TYPE_EN_SLOT; - Status = XhcDisableSlotCmd (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")); - 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)); - ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot)); - CmdTrbDisSlot.CycleBit = 1; - CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT; - CmdTrbDisSlot.SlotId = SlotId; - Status = XhcCmdTransfer ( - Xhc, - (TRB *) (UINTN) &CmdTrbDisSlot, - XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb - ); - ASSERT_EFI_ERROR(Status); - // - // Free the slot's device context entry - // - Xhc->DCBAA[SlotId] = 0; + Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext; // - // Free the slot related data structure + // 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. // - for (Index = 0; Index < 31; Index++) { - if (UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) { - RingSeg = ((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0; - if (RingSeg != NULL) { - FreeAlignedPool(RingSeg); - } - FreeAlignedPool(UsbDevContext[SlotId].EndpointTransferRing[Index]); - } - } - - for (Index = 0; Index < UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) { - if (UsbDevContext[SlotId].ConfDesc[Index] != NULL) { - FreePool (UsbDevContext[SlotId].ConfDesc[Index]); - } - } - - if (UsbDevContext[SlotId].InputContext != NULL) { - FreeAlignedPool (UsbDevContext[SlotId].InputContext); - } + InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1); - if (UsbDevContext[SlotId].OutputDevContxt != NULL) { - FreeAlignedPool (UsbDevContext[SlotId].OutputDevContxt); - } // - // 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. + // 3) Initialize the Input Slot Context data structure // - UsbDevContext[SlotId].Enabled = FALSE; - - return Status; -} - -/** - Configure all the device endpoints through XHCI's Configure_Endpoint cmd. + InputContext->Slot.RouteString = RouteChart.Route.RouteString; + InputContext->Slot.Speed = DeviceSpeed + 1; + InputContext->Slot.ContextEntries = 1; + InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum; - @param Xhc The XHCI device. - @param SlotId The slot id to be configured. + 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; + } + } + } + + // + // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint. + // + 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. @@ -2090,38 +2259,230 @@ XhcDisableSlotCmd ( EFI_STATUS EFIAPI XhcSetConfigCmd ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, - IN UINT8 DeviceSpeed, + 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_CFG_ED CmdTrbCfgEP; - INPUT_CONTEXT *InputContext; - DEVICE_CONTEXT *OutputDevContxt; - EVT_TRB_COMMAND *EvtTrb; + 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 = UsbDevContext[SlotId].InputContext; - OutputDevContxt = UsbDevContext[SlotId].OutputDevContxt; + InputContext = Xhc->UsbDevContext[SlotId].InputContext; + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; ZeroMem (InputContext, sizeof (INPUT_CONTEXT)); - CopyMem (&InputContext->Slot, &OutputDevContxt->Slot, sizeof (SLOT_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; +} + +/** + 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 + ) +{ + 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_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_64)); + CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64)); ASSERT (ConfigDesc != NULL); @@ -2141,10 +2502,11 @@ XhcSetConfigCmd ( EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length); } - EpAddr = EpDesc->EndpointAddress & 0x0F; + EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F); Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut); Dci = XhcEndpointToDci (EpAddr, Direction); + ASSERT (Dci < 32); if (Dci > MaxDci) { MaxDci = Dci; } @@ -2172,10 +2534,10 @@ XhcSetConfigCmd ( } InputContext->EP[Dci-1].AverageTRBLength = 0x1000; - if (UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) { - EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64); - UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing; - CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[Dci-1]); + 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; @@ -2204,22 +2566,26 @@ XhcSetConfigCmd ( if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) { Interval = EpDesc->Interval; // - // BUGBUG: Hard code the interval to MAX + // 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_SUPER) { + } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) { Interval = EpDesc->Interval; - InputContext->EP[Dci-1].Interval = 0x0F; + 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 (UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) { - EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64); - UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing; - CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[Dci-1]); + 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; @@ -2229,11 +2595,11 @@ XhcSetConfigCmd ( break; } - PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0); + PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0); PhyAddr &= ~(0x0F); - PhyAddr |= ((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS; + 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)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0); + 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); } @@ -2250,23 +2616,24 @@ XhcSetConfigCmd ( CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext); CmdTrbCfgEP.CycleBit = 1; CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT; - CmdTrbCfgEP.SlotId = UsbDevContext[SlotId].SlotId; + CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId; DEBUG ((EFI_D_INFO, "Configure Endpoint\n")); Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrbCfgEP, + (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT_EFI_ERROR(Status); return Status; } + /** Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd. - @param Xhc The XHCI device. + @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. @@ -2276,22 +2643,22 @@ XhcSetConfigCmd ( EFI_STATUS EFIAPI XhcEvaluateContext ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT32 MaxPacketSize ) { - EFI_STATUS Status; - CMD_TRB_EVALU_CONTX CmdTrbEvalu; - EVT_TRB_COMMAND *EvtTrb; - INPUT_CONTEXT *InputContext; + EFI_STATUS Status; + CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT *InputContext; - ASSERT (UsbDevContext[SlotId].SlotId != 0); + ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0); // // 4.6.7 Evaluate Context // - InputContext = UsbDevContext[SlotId].InputContext; + InputContext = Xhc->UsbDevContext[SlotId].InputContext; ZeroMem (InputContext, sizeof (INPUT_CONTEXT)); InputContext->InputControlContext.Dword2 |= BIT1; @@ -2302,23 +2669,76 @@ XhcEvaluateContext ( CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext); CmdTrbEvalu.CycleBit = 1; CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT; - CmdTrbEvalu.SlotId = UsbDevContext[SlotId].SlotId; + CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId; DEBUG ((EFI_D_INFO, "Evaluate context\n")); Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrbEvalu, + (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT (!EFI_ERROR(Status)); 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. - @param Xhc The XHCI device. + @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. @@ -2329,23 +2749,23 @@ XhcEvaluateContext ( **/ EFI_STATUS XhcConfigHubContext ( - IN USB_XHCI_DEV *Xhc, + IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 PortNum, IN UINT8 TTT, IN UINT8 MTT ) { - EFI_STATUS Status; + EFI_STATUS Status; - EVT_TRB_COMMAND *EvtTrb; - INPUT_CONTEXT *InputContext; - DEVICE_CONTEXT *OutputDevContxt; - CMD_CFG_ED CmdTrbCfgEP; + EVT_TRB_COMMAND_COMPLETION *EvtTrb; + INPUT_CONTEXT *InputContext; + DEVICE_CONTEXT *OutputContext; + CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP; - ASSERT (UsbDevContext[SlotId].SlotId != 0); - InputContext = UsbDevContext[SlotId].InputContext; - OutputDevContxt = UsbDevContext[SlotId].OutputDevContxt; + ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0); + InputContext = Xhc->UsbDevContext[SlotId].InputContext; + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; // // 4.6.7 Evaluate Context @@ -2357,7 +2777,73 @@ XhcConfigHubContext ( // // Copy the slot context from OutputContext to Input context // - CopyMem(&(InputContext->Slot), &(OutputDevContxt->Slot), sizeof (SLOT_CONTEXT)); + CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT)); + 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; +} + +/** + 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; @@ -2368,16 +2854,17 @@ XhcConfigHubContext ( CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext); CmdTrbCfgEP.CycleBit = 1; CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT; - CmdTrbCfgEP.SlotId = UsbDevContext[SlotId].SlotId; + CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId; DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n")); Status = XhcCmdTransfer ( Xhc, - (TRB *) (UINTN) &CmdTrbCfgEP, + (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP, XHC_GENERIC_TIMEOUT, - (TRB **) (UINTN) &EvtTrb + (TRB_TEMPLATE **) (UINTN) &EvtTrb ); ASSERT (!EFI_ERROR(Status)); return Status; } +