MdeModulePkg/Xhci: Remove TDs from transfer ring when timeout happens

The error handling for timeout case is enhanced to remove TDs from
transfer ring. The original code only removed s/w URB, but the h/w
transfer descriptor TDs didn't get removed. It would cause data lost
for data stream peripheral, such as usb-to-serial device, from the
s/w perspective.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Baraneedharan Anbazhagan <anbazhagan@hp.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18313 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Feng Tian
2015-08-26 01:19:09 +00:00
committed by erictian
parent 3b657538dc
commit 12e6c7381d
6 changed files with 618 additions and 97 deletions

View File

@@ -905,17 +905,28 @@ XhcControlTransfer (
*TransferResult = Urb->Result;
*DataLength = Urb->Completed;
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));
if (Status == EFI_TIMEOUT) {
//
// The transfer timed out. Abort the transfer by dequeueing of the TD.
//
RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
if (EFI_ERROR(RecoveryStatus)) {
DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n"));
}
Status = EFI_DEVICE_ERROR;
goto FREE_URB;
} else {
goto FREE_URB;
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));
}
Status = EFI_DEVICE_ERROR;
goto FREE_URB;
} else {
goto FREE_URB;
}
}
Xhc->PciIo->Flush (Xhc->PciIo);
@@ -1241,14 +1252,24 @@ XhcBulkTransfer (
*TransferResult = Urb->Result;
*DataLength = Urb->Completed;
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));
if (Status == EFI_TIMEOUT) {
//
// The transfer timed out. Abort the transfer by dequeueing of the TD.
//
RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
if (EFI_ERROR(RecoveryStatus)) {
DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n"));
}
} else {
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));
}
Status = EFI_DEVICE_ERROR;
}
Status = EFI_DEVICE_ERROR;
}
Xhc->PciIo->Flush (Xhc->PciIo);
@@ -1538,14 +1559,24 @@ XhcSyncInterruptTransfer (
*TransferResult = Urb->Result;
*DataLength = Urb->Completed;
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));
if (Status == EFI_TIMEOUT) {
//
// The transfer timed out. Abort the transfer by dequeueing of the TD.
//
RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
if (EFI_ERROR(RecoveryStatus)) {
DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n"));
}
} else {
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
} else if (*TransferResult == EFI_USB_ERR_STALL) {
RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));
}
Status = EFI_DEVICE_ERROR;
}
Status = EFI_DEVICE_ERROR;
}
Xhc->PciIo->Flush (Xhc->PciIo);