]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
MdeModulePkg/Xhci: Fill the 'interval' field for ISO endpoint context
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhciSched.c
index eedf3779be6116cb81a224b41a123e4427991858..3dd2b8909787180ec94bc19af05c382a838d7ca1 100644 (file)
@@ -2,7 +2,7 @@
 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
 which is used to enable recovery function from USB Drivers.\r
 \r
 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
 which is used to enable recovery function from USB Drivers.\r
 \r
-Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2014 - 2017, 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
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -444,12 +444,8 @@ XhcPeiRecoverHaltedEndpoint (
   )\r
 {\r
   EFI_STATUS                  Status;\r
   )\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
   UINT8                       Dci;\r
   UINT8                       SlotId;\r
-  EFI_PHYSICAL_ADDRESS        PhyAddr;\r
 \r
   Status = EFI_SUCCESS;\r
   SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\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
   //\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
   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
   //\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
   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
   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
 /**\r
   Check if the Trb is a transaction of the URB.\r
 \r
@@ -651,7 +683,7 @@ XhcPeiCheckUrbResult (
       case TRB_COMPLETION_SHORT_PACKET:\r
       case TRB_COMPLETION_SUCCESS:\r
         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
       case TRB_COMPLETION_SHORT_PACKET:\r
       case TRB_COMPLETION_SUCCESS:\r
         if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
-          DEBUG ((EFI_D_ERROR, "XhcPeiCheckUrbResult: short packet happens!\n"));\r
+          DEBUG ((EFI_D_VERBOSE, "XhcPeiCheckUrbResult: short packet happens!\n"));\r
         }\r
 \r
         TRBType = (UINT8) (TRBPtr->Type);\r
         }\r
 \r
         TRBType = (UINT8) (TRBPtr->Type);\r
@@ -1163,6 +1195,10 @@ XhcPeiInitializeDeviceSlot (
   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
   //    Context data structure described above.\r
   //\r
   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
   //    Context data structure described above.\r
   //\r
+  // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
+  // to device.\r
+  //\r
+  MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);\r
   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
@@ -1370,6 +1406,10 @@ XhcPeiInitializeDeviceSlot64 (
   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
   //    Context data structure described above.\r
   //\r
   // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
   //    Context data structure described above.\r
   //\r
+  // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
+  // to device.\r
+  //\r
+  MicroSecondDelay (XHC_RESET_RECOVERY_DELAY);\r
   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
   ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
   PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
   CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (PhyAddr);\r
@@ -1709,6 +1749,20 @@ XhcPeiSetConfigCmd (
             InputContext->EP[Dci-1].CErr   = 0;\r
             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
           }\r
             InputContext->EP[Dci-1].CErr   = 0;\r
             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
           }\r
+          //\r
+          // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
+          // Refer to XHCI 1.1 spec section 6.2.3.6.\r
+          //\r
+          if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            InputContext->EP[Dci-1].Interval = Interval + 2;\r
+          } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            InputContext->EP[Dci-1].Interval = Interval - 1;\r
+          }\r
+\r
           //\r
           // Do not support isochronous transfer now.\r
           //\r
           //\r
           // Do not support isochronous transfer now.\r
           //\r
@@ -1912,6 +1966,20 @@ XhcPeiSetConfigCmd64 (
             InputContext->EP[Dci-1].CErr   = 0;\r
             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
           }\r
             InputContext->EP[Dci-1].CErr   = 0;\r
             InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
           }\r
+          //\r
+          // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
+          // Refer to XHCI 1.1 spec section 6.2.3.6.\r
+          //\r
+          if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            InputContext->EP[Dci-1].Interval = Interval + 2;\r
+          } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+            Interval = EpDesc->Interval;\r
+            ASSERT (Interval >= 1 && Interval <= 16);\r
+            InputContext->EP[Dci-1].Interval = Interval - 1;\r
+          }\r
+\r
           //\r
           // Do not support isochronous transfer now.\r
           //\r
           //\r
           // Do not support isochronous transfer now.\r
           //\r
@@ -2253,6 +2321,151 @@ XhcPeiConfigHubContext64 (
   return Status;\r
 }\r
 \r
   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
 /**\r
   Check if there is a new generated event.\r
 \r