MdeModulePkg/XhciDxe: Event Ring traverse algorithm enhancement to avoid that those completed async transfer events don't get handled in time and are flushed by newer coming events.

Signed-off-by: erictian
Reviewed-by: li-elvin


git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13145 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
erictian 2012-03-27 12:07:38 +00:00
parent ecc722ad41
commit a50f7c4c09
7 changed files with 2346 additions and 2287 deletions

View File

@ -32,6 +32,20 @@ USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
{XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET} {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
}; };
USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
{XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
{XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
{XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
{XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
};
USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
{XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
{XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
{XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
{XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
};
EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = { EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {
XhcDriverBindingSupported, XhcDriverBindingSupported,
XhcDriverBindingStart, XhcDriverBindingStart,
@ -861,7 +875,7 @@ XhcControlTransfer (
Status = EFI_OUT_OF_RESOURCES; Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT; goto ON_EXIT;
} }
ASSERT (Urb->EvtRing == &Xhc->EventRing);
Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
// //
@ -998,21 +1012,23 @@ XhcControlTransfer (
// //
// Convert the XHCI port/port change state to UEFI status // Convert the XHCI port/port change state to UEFI status
// //
MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP); MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
for (Index = 0; Index < MapSize; Index++) { for (Index = 0; Index < MapSize; Index++) {
if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) { if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbPortStateMap[Index].UefiState); PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
} }
} }
MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
for (Index = 0; Index < MapSize; Index++) { for (Index = 0; Index < MapSize; Index++) {
if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) { if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbPortChangeMap[Index].UefiState); PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
} }
} }
XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus); XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
*(UINT32 *)Data = *(UINT32*)&PortStatus;
} }
FREE_URB: FREE_URB:
@ -1147,8 +1163,6 @@ XhcBulkTransfer (
goto ON_EXIT; goto ON_EXIT;
} }
ASSERT (Urb->EvtRing == &Xhc->EventRing);
Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout); Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
*TransferResult = Urb->Result; *TransferResult = Urb->Result;
@ -1272,7 +1286,7 @@ XhcAsyncInterruptTransfer (
} }
Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress); Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status)); DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
goto ON_EXIT; goto ON_EXIT;
} }
@ -1321,8 +1335,6 @@ XhcAsyncInterruptTransfer (
goto ON_EXIT; goto ON_EXIT;
} }
ASSERT (Urb->EvtRing == &Xhc->EventRing);
InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList); InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);
// //
// Ring the doorbell // Ring the doorbell

View File

@ -2,7 +2,7 @@
Provides some data structure definitions used by the XHCI host controller driver. Provides some data structure definitions used by the XHCI host controller driver.
Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -71,10 +71,10 @@ typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;
// //
#define XHC_TPL TPL_NOTIFY #define XHC_TPL TPL_NOTIFY
#define CMD_RING_TRB_NUMBER 0x40 #define CMD_RING_TRB_NUMBER 0x100
#define TR_RING_TRB_NUMBER 0x40 #define TR_RING_TRB_NUMBER 0x100
#define ERST_NUMBER 0x01 #define ERST_NUMBER 0x01
#define EVENT_RING_TRB_NUMBER 0x80 #define EVENT_RING_TRB_NUMBER 0x200
#define CMD_INTER 0 #define CMD_INTER 0
#define CTRL_INTER 1 #define CTRL_INTER 1

View File

@ -2,7 +2,7 @@
This file contains the register definition of XHCI host controller. This file contains the register definition of XHCI host controller.
Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -172,6 +172,15 @@ typedef union {
#define XHC_PORTSC_CEC BIT23 // Port Config Error Change #define XHC_PORTSC_CEC BIT23 // Port Config Error Change
#define XHC_PORTSC_CAS BIT24 // Cold Attach Status #define XHC_PORTSC_CAS BIT24 // Cold Attach Status
#define XHC_HUB_PORTSC_CCS BIT0 // Hub's Current Connect Status
#define XHC_HUB_PORTSC_PED BIT1 // Hub's Port Enabled/Disabled
#define XHC_HUB_PORTSC_OCA BIT3 // Hub's Over-current Active
#define XHC_HUB_PORTSC_RESET BIT4 // Hub's Port Reset
#define XHC_HUB_PORTSC_PP BIT9 // Hub's Port Power
#define XHC_HUB_PORTSC_CSC BIT16 // Hub's Connect Status Change
#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change
#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change
#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change
#define XHC_IMAN_IP BIT0 // Interrupt Pending #define XHC_IMAN_IP BIT0 // Interrupt Pending
#define XHC_IMAN_IE BIT1 // Interrupt Enable #define XHC_IMAN_IE BIT1 // Interrupt Enable

View File

@ -47,10 +47,6 @@ XhcCreateCmdTrb (
Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0; Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
Urb->TrbEnd = Urb->TrbStart; Urb->TrbEnd = Urb->TrbStart;
Urb->EvtRing = &Xhc->EventRing;
XhcSyncEventRing (Xhc, Urb->EvtRing);
Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
return Urb; return Urb;
} }
@ -106,10 +102,8 @@ XhcCmdTransfer (
goto ON_EXIT; goto ON_EXIT;
} }
ASSERT (Urb->EvtRing == &Xhc->EventRing);
Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout); Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);
*EvtTrb = Urb->EvtTrbStart; *EvtTrb = Urb->EvtTrb;
if (Urb->Result == EFI_USB_NOERROR) { if (Urb->Result == EFI_USB_NOERROR) {
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
@ -216,6 +210,12 @@ XhcCreateTransferTrb (
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }
Urb->Finished = FALSE;
Urb->StartDone = FALSE;
Urb->EndDone = FALSE;
Urb->Completed = 0;
Urb->Result = EFI_USB_NOERROR;
Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction)); Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
ASSERT (Dci < 32); ASSERT (Dci < 32);
EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]; EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
@ -234,9 +234,6 @@ XhcCreateTransferTrb (
Urb->TrbStart = EPRing->RingEnqueue; Urb->TrbStart = EPRing->RingEnqueue;
switch (EPType) { switch (EPType) {
case ED_CONTROL_BIDIR: case ED_CONTROL_BIDIR:
Urb->EvtRing = &Xhc->EventRing;
XhcSyncEventRing (Xhc, Urb->EvtRing);
Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
// //
// For control transfer, create SETUP_STAGE_TRB first. // For control transfer, create SETUP_STAGE_TRB first.
// //
@ -325,10 +322,6 @@ XhcCreateTransferTrb (
case ED_BULK_OUT: case ED_BULK_OUT:
case ED_BULK_IN: case ED_BULK_IN:
Urb->EvtRing = &Xhc->EventRing;
XhcSyncEventRing (Xhc, Urb->EvtRing);
Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
TotalLen = 0; TotalLen = 0;
Len = 0; Len = 0;
TrbNum = 0; TrbNum = 0;
@ -364,10 +357,6 @@ XhcCreateTransferTrb (
case ED_INTERRUPT_OUT: case ED_INTERRUPT_OUT:
case ED_INTERRUPT_IN: case ED_INTERRUPT_IN:
Urb->EvtRing = &Xhc->EventRing;
XhcSyncEventRing (Xhc, Urb->EvtRing);
Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;
TotalLen = 0; TotalLen = 0;
Len = 0; Len = 0;
TrbNum = 0; TrbNum = 0;
@ -829,39 +818,78 @@ XhcFreeSched (
} }
/** /**
Check if it is ring TRB. Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
@param Ring The transfer ring @param Xhc The XHCI Instance.
@param Trb The TRB to check if it's in the transfer ring @param Trb The TRB to be checked.
@param Urb The pointer to the matched Urb.
@retval TRUE It is in the ring @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
@retval FALSE It is not in the ring @retval FALSE The Trb is not matched with any URBs in the async list.
**/
BOOLEAN
IsAsyncIntTrb (
IN USB_XHCI_INSTANCE *Xhc,
IN TRB_TEMPLATE *Trb,
OUT URB **Urb
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
TRB_TEMPLATE *CheckedTrb;
URB *CheckedUrb;
UINTN Index;
EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
CheckedTrb = CheckedUrb->TrbStart;
for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {
if (Trb == CheckedTrb) {
*Urb = CheckedUrb;
return TRUE;
}
CheckedTrb++;
if ((UINTN)CheckedTrb >= ((UINTN) CheckedUrb->Ring->RingSeg0 + sizeof (TRB_TEMPLATE) * CheckedUrb->Ring->TrbNumber)) {
CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;
}
}
}
return FALSE;
}
/**
Check if the Trb is a transaction of the URB.
@param Trb The TRB to be checked
@param Urb The transfer ring to be checked.
@retval TRUE It is a transaction of the URB.
@retval FALSE It is not any transaction of the URB.
**/ **/
BOOLEAN BOOLEAN
IsTransferRingTrb ( IsTransferRingTrb (
IN TRANSFER_RING *Ring, IN TRB_TEMPLATE *Trb,
IN TRB_TEMPLATE *Trb IN URB *Urb
) )
{ {
BOOLEAN Flag; TRB_TEMPLATE *CheckedTrb;
TRB_TEMPLATE *Trb1;
UINTN Index; UINTN Index;
Trb1 = Ring->RingSeg0; CheckedTrb = Urb->Ring->RingSeg0;
Flag = FALSE;
ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER); ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
for (Index = 0; Index < Ring->TrbNumber; Index++) { for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
if (Trb == Trb1) { if (Trb == CheckedTrb) {
Flag = TRUE; return TRUE;
break;
} }
Trb1++; CheckedTrb++;
} }
return Flag; return FALSE;
} }
/** /**
@ -880,19 +908,25 @@ XhcCheckUrbResult (
IN URB *Urb IN URB *Urb
) )
{ {
BOOLEAN StartDone;
BOOLEAN EndDone;
EVT_TRB_TRANSFER *EvtTrb; EVT_TRB_TRANSFER *EvtTrb;
TRB_TEMPLATE *TRBPtr; TRB_TEMPLATE *TRBPtr;
UINTN Index; UINTN Index;
UINT8 TRBType; UINT8 TRBType;
EFI_STATUS Status; EFI_STATUS Status;
URB *AsyncUrb;
URB *CheckedUrb;
UINT64 XhcDequeue;
UINT32 High;
UINT32 Low;
ASSERT ((Xhc != NULL) && (Urb != NULL)); ASSERT ((Xhc != NULL) && (Urb != NULL));
Urb->Completed = 0;
Urb->Result = EFI_USB_NOERROR;
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
if (Urb->Finished) {
goto EXIT;
}
EvtTrb = NULL; EvtTrb = NULL;
if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) { if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
@ -902,16 +936,15 @@ XhcCheckUrbResult (
} }
// //
// Restore the EventRingDequeue and poll the transfer event ring from beginning // Traverse the event ring to find out all new events from the previous check.
// //
StartDone = FALSE; XhcSyncEventRing (Xhc, &Xhc->EventRing);
EndDone = FALSE; for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart; Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) {
XhcSyncEventRing (Xhc, Urb->EvtRing);
Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, ((TRB_TEMPLATE **)&EvtTrb));
if (Status == EFI_NOT_READY) { if (Status == EFI_NOT_READY) {
Urb->Result |= EFI_USB_ERR_TIMEOUT; //
// All new events are handled, return directly.
//
goto EXIT; goto EXIT;
} }
@ -923,34 +956,44 @@ XhcCheckUrbResult (
} }
TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32)); TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
if (IsTransferRingTrb (Urb->Ring, TRBPtr)) {
//
// Update the status of Urb according to the finished event regardless of whether
// the urb is current checked one or in the XHCI's async transfer list.
// This way is used to avoid that those completed async transfer events don't get
// handled in time and are flushed by newer coming events.
//
if (IsTransferRingTrb (TRBPtr, Urb)) {
CheckedUrb = Urb;
} else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
CheckedUrb = AsyncUrb;
} else {
continue;
}
switch (EvtTrb->Completecode) { switch (EvtTrb->Completecode) {
case TRB_COMPLETION_STALL_ERROR: case TRB_COMPLETION_STALL_ERROR:
Urb->Result |= EFI_USB_ERR_STALL; CheckedUrb->Result |= EFI_USB_ERR_STALL;
Status = EFI_DEVICE_ERROR; CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode)); DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
goto EXIT;
break; break;
case TRB_COMPLETION_BABBLE_ERROR: case TRB_COMPLETION_BABBLE_ERROR:
Urb->Result |= EFI_USB_ERR_BABBLE; CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
Status = EFI_DEVICE_ERROR; CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode)); DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
goto EXIT;
break; break;
case TRB_COMPLETION_DATA_BUFFER_ERROR: case TRB_COMPLETION_DATA_BUFFER_ERROR:
Urb->Result |= EFI_USB_ERR_BUFFER; CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
Status = EFI_DEVICE_ERROR; CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode)); DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
goto EXIT;
break; break;
case TRB_COMPLETION_USB_TRANSACTION_ERROR: case TRB_COMPLETION_USB_TRANSACTION_ERROR:
Urb->Result |= EFI_USB_ERR_TIMEOUT; CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
Status = EFI_DEVICE_ERROR; CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode)); DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
goto EXIT;
break; break;
case TRB_COMPLETION_SHORT_PACKET: case TRB_COMPLETION_SHORT_PACKET:
@ -963,38 +1006,56 @@ XhcCheckUrbResult (
if ((TRBType == TRB_TYPE_DATA_STAGE) || if ((TRBType == TRB_TYPE_DATA_STAGE) ||
(TRBType == TRB_TYPE_NORMAL) || (TRBType == TRB_TYPE_NORMAL) ||
(TRBType == TRB_TYPE_ISOCH)) { (TRBType == TRB_TYPE_ISOCH)) {
Urb->Completed += (Urb->DataLen - EvtTrb->Lenth); CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);
} }
Status = EFI_SUCCESS;
break; break;
default: default:
DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode)); DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
Urb->Result |= EFI_USB_ERR_TIMEOUT; CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
Status = EFI_DEVICE_ERROR; CheckedUrb->Finished = TRUE;
goto EXIT;
break; break;
} }
// //
// Only check first and end Trb event address // Only check first and end Trb event address
// //
if (TRBPtr == Urb->TrbStart) { if (TRBPtr == CheckedUrb->TrbStart) {
StartDone = TRUE; CheckedUrb->StartDone = TRUE;
} }
if (TRBPtr == Urb->TrbEnd) { if (TRBPtr == CheckedUrb->TrbEnd) {
EndDone = TRUE; CheckedUrb->EndDone = TRUE;
} }
if (StartDone && EndDone) { if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
break; CheckedUrb->Finished = TRUE;
} CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
} }
} }
EXIT: EXIT:
//
// Advance event ring to last available entry
//
// Some 3rd party XHCI external cards don't support single 64-bytes width register access,
// So divide it to two 32-bytes width register access.
//
Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Xhc->EventRing.EventRingDequeue & (~0x0F))) {
//
// Some 3rd party XHCI external cards don't support single 64-bytes width register access,
// So divide it to two 32-bytes width register access.
//
XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (Xhc->EventRing.EventRingDequeue) | BIT3);
XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (Xhc->EventRing.EventRingDequeue));
}
return Status; return Status;
} }
@ -1048,12 +1109,16 @@ XhcExecTransfer (
for (Index = 0; Index < Loop; Index++) { for (Index = 0; Index < Loop; Index++) {
Status = XhcCheckUrbResult (Xhc, Urb); Status = XhcCheckUrbResult (Xhc, Urb);
if ((Status != EFI_NOT_READY)) { if (Urb->Finished) {
break; break;
} }
gBS->Stall (XHC_POLL_DELAY); gBS->Stall (XHC_POLL_DELAY);
} }
if (Index == Loop) {
Urb->Result = EFI_USB_ERR_TIMEOUT;
}
return Status; return Status;
} }
@ -1196,7 +1261,7 @@ XhcMonitorAsyncRequests (
// //
Status = XhcCheckUrbResult (Xhc, Urb); Status = XhcCheckUrbResult (Xhc, Urb);
if (Status == EFI_NOT_READY) { if (!Urb->Finished) {
continue; continue;
} }
@ -1219,8 +1284,6 @@ XhcMonitorAsyncRequests (
CopyMem (ProcBuf, Urb->Data, Urb->Completed); CopyMem (ProcBuf, Urb->Data, Urb->Completed);
} }
XhcUpdateAsyncRequest (Xhc, Urb);
// //
// Leave error recovery to its related device driver. A // Leave error recovery to its related device driver. A
// common case of the error recovery is to re-submit the // common case of the error recovery is to re-submit the
@ -1244,6 +1307,8 @@ XhcMonitorAsyncRequests (
if (ProcBuf != NULL) { if (ProcBuf != NULL) {
gBS->FreePool (ProcBuf); gBS->FreePool (ProcBuf);
} }
XhcUpdateAsyncRequest (Xhc, Urb);
} }
gBS->RestoreTPL (OldTpl); gBS->RestoreTPL (OldTpl);
} }
@ -1445,10 +1510,6 @@ XhcSyncEventRing (
{ {
UINTN Index; UINTN Index;
TRB_TEMPLATE *EvtTrb1; TRB_TEMPLATE *EvtTrb1;
TRB_TEMPLATE *EvtTrb2;
UINT64 XhcDequeue;
UINT32 High;
UINT32 Low;
ASSERT (EvtRing != NULL); ASSERT (EvtRing != NULL);
@ -1456,41 +1517,25 @@ XhcSyncEventRing (
// Calculate the EventRingEnqueue and EventRingCCS. // Calculate the EventRingEnqueue and EventRingCCS.
// Note: only support single Segment // Note: only support single Segment
// //
EvtTrb1 = EvtRing->EventRingSeg0; EvtTrb1 = EvtRing->EventRingDequeue;
EvtTrb2 = EvtRing->EventRingSeg0;
for (Index = 0; Index < EvtRing->TrbNumber; Index++) { for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
if (EvtTrb1->CycleBit != EvtTrb2->CycleBit) { if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
break; break;
} }
EvtTrb1++; EvtTrb1++;
if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
EvtTrb1 = EvtRing->EventRingSeg0;
EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
}
} }
if (Index < EvtRing->TrbNumber) { if (Index < EvtRing->TrbNumber) {
EvtRing->EventRingEnqueue = EvtTrb1; EvtRing->EventRingEnqueue = EvtTrb1;
EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 1 : 0;
} else { } else {
EvtRing->EventRingEnqueue = EvtTrb2; ASSERT (FALSE);
EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 0 : 1;
}
//
// Apply the EventRingDequeue to Xhc
//
// 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, XHC_LOW_32BIT (EvtRing->EventRingDequeue) | BIT3);
XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (EvtRing->EventRingDequeue));
} }
return EFI_SUCCESS; return EFI_SUCCESS;
@ -1593,10 +1638,6 @@ XhcCheckNewEvent (
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
if (((EvtTrb->Status >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) {
Status = EFI_DEVICE_ERROR;
}
EvtRing->EventRingDequeue++; EvtRing->EventRingDequeue++;
// //
// If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring. // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
@ -1845,7 +1886,7 @@ XhcInitializeDeviceSlot (
ASSERT (!EFI_ERROR(Status)); ASSERT (!EFI_ERROR(Status));
DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress; DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress)); DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress; Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
@ -2038,7 +2079,7 @@ XhcInitializeDeviceSlot64 (
ASSERT (!EFI_ERROR(Status)); ASSERT (!EFI_ERROR(Status));
DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress; DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress)); DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress; Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;

View File

@ -2,7 +2,7 @@
This file contains the definition for XHCI host controller schedule routines. This file contains the definition for XHCI host controller schedule routines.
Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -189,8 +189,11 @@ typedef struct _URB {
TRB_TEMPLATE *TrbStart; TRB_TEMPLATE *TrbStart;
TRB_TEMPLATE *TrbEnd; TRB_TEMPLATE *TrbEnd;
UINTN TrbNum; UINTN TrbNum;
EVENT_RING *EvtRing; BOOLEAN StartDone;
TRB_TEMPLATE *EvtTrbStart; BOOLEAN EndDone;
BOOLEAN Finished;
TRB_TEMPLATE *EvtTrb;
} URB; } URB;
// //

View File

@ -862,7 +862,7 @@ UsbEnumeratePort (
} }
DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n", DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
Port, PortState.PortChangeStatus, PortState.PortStatus, HubIf)); Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));
// //
// This driver only process two kinds of events now: over current and // This driver only process two kinds of events now: over current and

View File

@ -2,7 +2,7 @@
Unified interface for RootHub and Hub. Unified interface for RootHub and Hub.
Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR> Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -844,12 +844,6 @@ UsbHubGetPortStatus (
Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState); Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
//
// Mark the USB_PORT_STAT_SUPER_SPEED bit if SuperSpeed
//
if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
PortState->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
}
return Status; return Status;
} }