]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/Xhci: Remove TDs from transfer ring when timeout happens
authorFeng Tian <feng.tian@intel.com>
Wed, 26 Aug 2015 01:19:09 +0000 (01:19 +0000)
committererictian <erictian@Edk2>
Wed, 26 Aug 2015 01:19:09 +0000 (01:19 +0000)
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

MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h

index 390ca0a3762eb1f2956892986c671915538c9499..39c28ab7d83d20cab8d0d6c1f246303ec160ac26 100644 (file)
@@ -905,17 +905,28 @@ XhcControlTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    if (EFI_ERROR (RecoveryStatus)) {\r
-      DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
     }\r
-    Status = EFI_DEVICE_ERROR;\r
     goto FREE_URB;\r
   } else {\r
-    goto FREE_URB;\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto FREE_URB;\r
+    } else {\r
+      goto FREE_URB;\r
+    }\r
   }\r
 \r
   Xhc->PciIo->Flush (Xhc->PciIo);\r
@@ -1241,14 +1252,24 @@ XhcBulkTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    if (EFI_ERROR (RecoveryStatus)) {\r
-      DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+    }\r
+  } else {\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
     }\r
-    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
   Xhc->PciIo->Flush (Xhc->PciIo);\r
@@ -1538,14 +1559,24 @@ XhcSyncInterruptTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
-    if (EFI_ERROR (RecoveryStatus)) {\r
-      DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+    }\r
+  } else {\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
     }\r
-    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
   Xhc->PciIo->Flush (Xhc->PciIo);\r
index 05cd616a034b102e815ee4783cb57d2a2b8e8a57..c25342dc1f7845ffa919642bdf8bcc7ef6b94ada 100644 (file)
@@ -645,12 +645,8 @@ XhcRecoverHaltedEndpoint (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
-  CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;\r
-  CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;\r
   UINT8                       Dci;\r
   UINT8                       SlotId;\r
-  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
 \r
   Status = EFI_SUCCESS;\r
   SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
@@ -665,17 +661,7 @@ XhcRecoverHaltedEndpoint (
   //\r
   // 1) Send Reset endpoint command to transit from halt to stop state\r
   //\r
-  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
-  CmdTrbResetED.CycleBit = 1;\r
-  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
-  CmdTrbResetED.EDID     = Dci;\r
-  CmdTrbResetED.SlotId   = SlotId;\r
-  Status = XhcCmdTransfer (\r
-             Xhc,\r
-             (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
-             XHC_GENERIC_TIMEOUT,\r
-             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
-             );\r
+  Status = XhcResetEndpoint(Xhc, SlotId, Dci);\r
   if (EFI_ERROR(Status)) {\r
     DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
     goto Done;\r
@@ -684,22 +670,70 @@ XhcRecoverHaltedEndpoint (
   //\r
   // 2)Set dequeue pointer\r
   //\r
-  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
-  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
-  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
-  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
-  CmdSetTRDeq.CycleBit = 1;\r
-  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
-  CmdSetTRDeq.Endpoint = Dci;\r
-  CmdSetTRDeq.SlotId   = SlotId;\r
-  Status = XhcCmdTransfer (\r
-             Xhc,\r
-             (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
-             XHC_GENERIC_TIMEOUT,\r
-             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
-             );\r
+  Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 3)Ring the doorbell to transit from stop to active\r
+  //\r
+  XhcRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
+  Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
+  the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
+  state.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  Urb                   The urb which doesn't get completed in a specified timeout range.\r
+\r
+  @retval EFI_SUCCESS           The dequeuing of the TDs is successful.\r
+  @retval Others                Failed to stop the endpoint and dequeue the TDs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDequeueTrbFromEndpoint (\r
+  IN  USB_XHCI_INSTANCE   *Xhc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Dci;\r
+  UINT8                       SlotId;\r
+\r
+  Status = EFI_SUCCESS;\r
+  SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+  if (SlotId == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+  ASSERT (Dci < 32);\r
+  \r
+  DEBUG ((EFI_D_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));\r
+\r
+  //\r
+  // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint\r
+  //\r
+  Status = XhcStopEndpoint(Xhc, SlotId, Dci);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 2)Set dequeue pointer\r
+  //\r
+  Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
   if (EFI_ERROR(Status)) {\r
-    DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
     goto Done;\r
   }\r
 \r
@@ -3061,6 +3095,105 @@ XhcStopEndpoint (
   return Status;\r
 }\r
 \r
+/**\r
+  Reset endpoint through XHCI's Reset_Endpoint cmd.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  SlotId                The slot id to be configured.\r
+  @param  Dci                   The device context index of endpoint.\r
+\r
+  @retval EFI_SUCCESS           Reset endpoint successfully.\r
+  @retval Others                Failed to reset endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcResetEndpoint (\r
+  IN USB_XHCI_INSTANCE      *Xhc,\r
+  IN UINT8                  SlotId,\r
+  IN UINT8                  Dci\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
+  CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
+\r
+  //\r
+  // Send stop endpoint command to transit Endpoint from running to stop state\r
+  //\r
+  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+  CmdTrbResetED.CycleBit = 1;\r
+  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
+  CmdTrbResetED.EDID     = Dci;\r
+  CmdTrbResetED.SlotId   = SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  SlotId                The slot id to be configured.\r
+  @param  Dci                   The device context index of endpoint.\r
+  @param  Urb                   The dequeue pointer of the transfer ring specified\r
+                                by the urb to be updated.\r
+\r
+  @retval EFI_SUCCESS           Set transfer ring dequeue pointer succeeds.\r
+  @retval Others                Failed to set transfer ring dequeue pointer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetTrDequeuePointer (\r
+  IN USB_XHCI_INSTANCE      *Xhc,\r
+  IN UINT8                  SlotId,\r
+  IN UINT8                  Dci,\r
+  IN URB                    *Urb\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
+  CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;\r
+  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
+\r
+  //\r
+  // Send stop endpoint command to transit Endpoint from running to stop state\r
+  //\r
+  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
+  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
+  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdSetTRDeq.CycleBit = 1;\r
+  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
+  CmdSetTRDeq.Endpoint = Dci;\r
+  CmdSetTRDeq.SlotId   = SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Set interface through XHCI's Configure_Endpoint cmd.\r
 \r
index 1b6e34590ec612dae8495951c11844ede8d1e400..931c7efa0c283160f1168788e0b3a569945beb19 100644 (file)
@@ -1317,6 +1317,86 @@ XhcRecoverHaltedEndpoint (
   IN  URB                 *Urb\r
   );\r
 \r
+/**\r
+  System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
+  Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
+  the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
+  state.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  Urb                   The urb which doesn't get completed in a specified timeout range.\r
+\r
+  @retval EFI_SUCCESS           The dequeuing of the TDs is successful.\r
+  @retval Others                Failed to stop the endpoint and dequeue the TDs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDequeueTrbFromEndpoint (\r
+  IN  USB_XHCI_INSTANCE   *Xhc,\r
+  IN  URB                 *Urb\r
+  );\r
+\r
+/**\r
+  Stop endpoint through XHCI's Stop_Endpoint cmd.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  SlotId                The slot id to be configured.\r
+  @param  Dci                   The device context index of endpoint.\r
+\r
+  @retval EFI_SUCCESS           Stop endpoint successfully.\r
+  @retval Others                Failed to stop endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcStopEndpoint (\r
+  IN USB_XHCI_INSTANCE      *Xhc,\r
+  IN UINT8                  SlotId,\r
+  IN UINT8                  Dci\r
+  );\r
+\r
+/**\r
+  Reset endpoint through XHCI's Reset_Endpoint cmd.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  SlotId                The slot id to be configured.\r
+  @param  Dci                   The device context index of endpoint.\r
+\r
+  @retval EFI_SUCCESS           Reset endpoint successfully.\r
+  @retval Others                Failed to reset endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcResetEndpoint (\r
+  IN USB_XHCI_INSTANCE      *Xhc,\r
+  IN UINT8                  SlotId,\r
+  IN UINT8                  Dci\r
+  );\r
+\r
+/**\r
+  Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
+\r
+  @param  Xhc                   The XHCI Instance.\r
+  @param  SlotId                The slot id to be configured.\r
+  @param  Dci                   The device context index of endpoint.\r
+  @param  Urb                   The dequeue pointer of the transfer ring specified\r
+                                by the urb to be updated.\r
+\r
+  @retval EFI_SUCCESS           Set transfer ring dequeue pointer succeeds.\r
+  @retval Others                Failed to set transfer ring dequeue pointer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetTrDequeuePointer (\r
+  IN USB_XHCI_INSTANCE      *Xhc,\r
+  IN UINT8                  SlotId,\r
+  IN UINT8                  Dci,\r
+  IN URB                    *Urb\r
+  );\r
+\r
 /**\r
   Create a new URB for a new transaction.\r
 \r
index 2f16b82d262028f27567f36e03ed1533f3c2c6c2..eaea38d94d299386fcbd62016f2fe755f2ef55ab 100644 (file)
@@ -648,17 +648,28 @@ XhcPeiControlTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
-    if (EFI_ERROR (RecoveryStatus)) {\r
-      DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
     }\r
-    Status = EFI_DEVICE_ERROR;\r
     goto FREE_URB;\r
   } else {\r
-    goto FREE_URB;\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto FREE_URB;\r
+    } else {\r
+      goto FREE_URB;\r
+    }\r
   }\r
 \r
   //\r
@@ -960,14 +971,24 @@ XhcPeiBulkTransfer (
   *TransferResult = Urb->Result;\r
   *DataLength     = Urb->Completed;\r
 \r
-  if (*TransferResult == EFI_USB_NOERROR) {\r
-    Status = EFI_SUCCESS;\r
-  } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
-    RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
-    if (EFI_ERROR (RecoveryStatus)) {\r
-      DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+  if (Status == EFI_TIMEOUT) {\r
+    //\r
+    // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+    //\r
+    RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);\r
+    if (EFI_ERROR(RecoveryStatus)) {\r
+      DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
+    }\r
+  } else {\r
+    if (*TransferResult == EFI_USB_NOERROR) {\r
+      Status = EFI_SUCCESS;\r
+    } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
+      RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
+      if (EFI_ERROR (RecoveryStatus)) {\r
+        DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
+      }\r
+      Status = EFI_DEVICE_ERROR;\r
     }\r
-    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
   XhcPeiFreeUrb (Xhc, Urb);\r
index eedf3779be6116cb81a224b41a123e4427991858..3632e8a7698ab8e03d8bb1eb08ca6b40c2a4cb6d 100644 (file)
@@ -444,12 +444,8 @@ XhcPeiRecoverHaltedEndpoint (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
-  CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;\r
-  CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;\r
   UINT8                       Dci;\r
   UINT8                       SlotId;\r
-  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
 \r
   Status = EFI_SUCCESS;\r
   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
@@ -463,17 +459,7 @@ XhcPeiRecoverHaltedEndpoint (
   //\r
   // 1) Send Reset endpoint command to transit from halt to stop state\r
   //\r
-  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
-  CmdTrbResetED.CycleBit = 1;\r
-  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
-  CmdTrbResetED.EDID     = Dci;\r
-  CmdTrbResetED.SlotId   = SlotId;\r
-  Status = XhcPeiCmdTransfer (\r
-             Xhc,\r
-             (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
-             XHC_GENERIC_TIMEOUT,\r
-             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
-             );\r
+  Status = XhcPeiResetEndpoint (Xhc, SlotId, Dci);\r
   if (EFI_ERROR(Status)) {\r
     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
     goto Done;\r
@@ -482,20 +468,7 @@ XhcPeiRecoverHaltedEndpoint (
   //\r
   // 2) Set dequeue pointer\r
   //\r
-  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
-  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
-  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
-  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
-  CmdSetTRDeq.CycleBit = 1;\r
-  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
-  CmdSetTRDeq.Endpoint = Dci;\r
-  CmdSetTRDeq.SlotId   = SlotId;\r
-  Status = XhcPeiCmdTransfer (\r
-             Xhc,\r
-             (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
-             XHC_GENERIC_TIMEOUT,\r
-             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
-             );\r
+  Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
   if (EFI_ERROR(Status)) {\r
     DEBUG ((EFI_D_ERROR, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
     goto Done;\r
@@ -510,6 +483,65 @@ Done:
   return Status;\r
 }\r
 \r
+/**\r
+  System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
+  Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
+  the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
+  state.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  Urb                   The urb which doesn't get completed in a specified timeout range.\r
+\r
+  @retval EFI_SUCCESS           The dequeuing of the TDs is successful.\r
+  @retval Others                Failed to stop the endpoint and dequeue the TDs.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDequeueTrbFromEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN URB                *Urb\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Dci;\r
+  UINT8                       SlotId;\r
+\r
+  Status = EFI_SUCCESS;\r
+  SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+  if (SlotId == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Dci = XhcPeiEndpointToDci (Urb->Ep.EpAddr, (UINT8) (Urb->Ep.Direction));\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId, Dci));\r
+\r
+  //\r
+  // 1) Send Stop endpoint command to stop endpoint.\r
+  //\r
+  Status = XhcPeiStopEndpoint (Xhc, SlotId, Dci);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 2) Set dequeue pointer\r
+  //\r
+  Status = XhcPeiSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // 3) Ring the doorbell to transit from stop to active\r
+  //\r
+  XhcPeiRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
 /**\r
   Check if the Trb is a transaction of the URB.\r
 \r
@@ -2253,6 +2285,151 @@ XhcPeiConfigHubContext64 (
   return Status;\r
 }\r
 \r
+/**\r
+  Stop endpoint through XHCI's Stop_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Stop endpoint successfully.\r
+  @retval Others        Failed to stop endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiStopEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EVT_TRB_COMMAND_COMPLETION    *EvtTrb;\r
+  CMD_TRB_STOP_ENDPOINT         CmdTrbStopED;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
+\r
+  //\r
+  // Send stop endpoint command to transit Endpoint from running to stop state\r
+  //\r
+  ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
+  CmdTrbStopED.CycleBit = 1;\r
+  CmdTrbStopED.Type     = TRB_TYPE_STOP_ENDPOINT;\r
+  CmdTrbStopED.EDID     = Dci;\r
+  CmdTrbStopED.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Reset endpoint through XHCI's Reset_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Reset endpoint successfully.\r
+  @retval Others        Failed to reset endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiResetEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
+  CMD_TRB_RESET_ENDPOINT      CmdTrbResetED;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
+\r
+  //\r
+  // Send stop endpoint command to transit Endpoint from running to stop state\r
+  //\r
+  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+  CmdTrbResetED.CycleBit = 1;\r
+  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
+  CmdTrbResetED.EDID     = Dci;\r
+  CmdTrbResetED.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+  @param  Urb           The dequeue pointer of the transfer ring specified\r
+                        by the urb to be updated.\r
+\r
+  @retval EFI_SUCCESS   Set transfer ring dequeue pointer succeeds.\r
+  @retval Others        Failed to set transfer ring dequeue pointer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiSetTrDequeuePointer (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci,\r
+  IN URB                *Urb\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EVT_TRB_COMMAND_COMPLETION  *EvtTrb;\r
+  CMD_SET_TR_DEQ_POINTER      CmdSetTRDeq;\r
+  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
+\r
+  //\r
+  // Send stop endpoint command to transit Endpoint from running to stop state\r
+  //\r
+  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+  PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
+  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
+  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (PhyAddr);\r
+  CmdSetTRDeq.CycleBit = 1;\r
+  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
+  CmdSetTRDeq.Endpoint = Dci;\r
+  CmdSetTRDeq.SlotId   = SlotId;\r
+  Status = XhcPeiCmdTransfer (\r
+             Xhc,\r
+             (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Check if there is a new generated event.\r
 \r
index 19672d046a09b311bc164d221ef5a5f026dbc87e..b3d4c4561438ff31ed8d4720b9038834cfd74b2f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Private Header file for Usb Host Controller PEIM\r
 \r
-Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -938,6 +938,66 @@ XhcPeiSetConfigCmd64 (
   IN USB_CONFIG_DESCRIPTOR      *ConfigDesc\r
   );\r
 \r
+/**\r
+  Stop endpoint through XHCI's Stop_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Stop endpoint successfully.\r
+  @retval Others        Failed to stop endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiStopEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  );\r
+\r
+/**\r
+  Reset endpoint through XHCI's Reset_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Reset endpoint successfully.\r
+  @retval Others        Failed to reset endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiResetEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci\r
+  );\r
+\r
+/**\r
+  Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+  @param  Urb           The dequeue pointer of the transfer ring specified\r
+                        by the urb to be updated.\r
+\r
+  @retval EFI_SUCCESS   Set transfer ring dequeue pointer succeeds.\r
+  @retval Others        Failed to set transfer ring dequeue pointer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPeiSetTrDequeuePointer (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN UINT8              SlotId,\r
+  IN UINT8              Dci,\r
+  IN URB                *Urb\r
+  );\r
+\r
 /**\r
   Assign and initialize the device slot for a new device.\r
 \r
@@ -1066,6 +1126,25 @@ XhcPeiRecoverHaltedEndpoint (
   IN URB                *Urb\r
   );\r
 \r
+/**\r
+  System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
+  Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
+  the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
+  state.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  Urb                   The urb which doesn't get completed in a specified timeout range.\r
+\r
+  @retval EFI_SUCCESS           The dequeuing of the TDs is successful.\r
+  @retval Others                Failed to stop the endpoint and dequeue the TDs.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcPeiDequeueTrbFromEndpoint (\r
+  IN PEI_XHC_DEV        *Xhc,\r
+  IN URB                *Urb\r
+  );\r
+\r
 /**\r
   Create a new URB for a new transaction.\r
 \r