diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c index c337f15118..dfcf252a18 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c @@ -819,6 +819,7 @@ XhcTransfer ( DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed)); } else if (EFI_ERROR (RecoveryStatus)) { DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type)); + Status = RecoveryStatus; } } diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c index e8cb7ede54..dcd6ddf17c 100644 --- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c +++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c @@ -1311,6 +1311,58 @@ EXIT: return Urb->Finished; } +/** + Check whether an endpoint is in the Running state. + + @param Xhc The XHCI instance. + @param SlotId The slot id. + @param Dci The device context index. + + @retval TRUE The endpoint is in the Running state. + @retval FALSE The endpoint is not in the Running state. + +**/ +STATIC +BOOLEAN +EFIAPI +XhcEndpointRunning ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 Dci + ) +{ + DEVICE_CONTEXT *OutputContext; + + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; + return OutputContext && OutputContext->EP[Dci - 1].EPState == 1; +} + +/** + Check whether an endpoint is in the Halted state. + + @param Xhc The XHCI instance. + @param SlotId The slot id. + @param Dci The device context index. + + @retval TRUE The endpoint is in the Halted state. + @retval FALSE The endpoint is not in the Halted state. + +**/ +STATIC +BOOLEAN +EFIAPI +XhcEndpointHalted ( + IN USB_XHCI_INSTANCE *Xhc, + IN UINT8 SlotId, + IN UINT8 Dci + ) +{ + DEVICE_CONTEXT *OutputContext; + + OutputContext = Xhc->UsbDevContext[SlotId].OutputContext; + return OutputContext && OutputContext->EP[Dci - 1].EPState == 2; +} + /** Execute the transfer by polling the URB. This is a synchronous operation. @@ -1359,6 +1411,10 @@ XhcExecTransfer ( ASSERT (Dci < 32); } + if (!CmdTransfer && XhcEndpointHalted (Xhc, SlotId, Dci)) { + goto DONE; + } + if (Timeout == 0) { IndefiniteTimeout = TRUE; } @@ -1389,9 +1445,15 @@ XhcExecTransfer ( ElapsedTicks += TicksDelta; } while (IndefiniteTimeout || ElapsedTicks < TimeoutTicks); +DONE: if (!Finished) { - Urb->Result = EFI_USB_ERR_TIMEOUT; - Status = EFI_TIMEOUT; + if (XhcEndpointHalted (Xhc, SlotId, Dci)) { + Urb->Result = EFI_USB_ERR_STALL; + Status = EFI_DEVICE_ERROR; + } else { + Urb->Result = EFI_USB_ERR_TIMEOUT; + Status = EFI_TIMEOUT; + } } else if (Urb->Result != EFI_USB_NOERROR) { Status = EFI_DEVICE_ERROR; } @@ -3518,6 +3580,22 @@ XhcStopEndpoint ( EvtTrb = NULL; + if (XhcEndpointHalted (Xhc, SlotId, Dci)) { + if (PendingUrb != NULL) { + PendingUrb->Result = EFI_USB_ERR_STALL; + } + + return EFI_DEVICE_ERROR; + } + + if (!XhcEndpointRunning (Xhc, SlotId, Dci)) { + if (PendingUrb != NULL) { + PendingUrb->Result = EFI_USB_ERR_SYSTEM; + } + + return EFI_DEVICE_ERROR; + } + // // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks // the PendingUrb completion status, because it's possible that the PendingUrb is diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c index 8c09831f56..482c5a53c6 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c @@ -281,7 +281,7 @@ UsbBootExecCmdWithRetry ( DataLen, Timeout ); - if ((Status == EFI_SUCCESS) || (Status == EFI_NO_MEDIA)) { + if ((Status == EFI_SUCCESS) || (Status == EFI_NO_MEDIA) || (Status == EFI_DEVICE_ERROR)) { break; }