]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/UsbBus&XhciDxe: Solve a bug that 2 or more tiers SS hubs with SS devices...
authorFeng Tian <feng.tian@intel.com>
Fri, 22 Nov 2013 07:46:00 +0000 (07:46 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 22 Nov 2013 07:46:00 +0000 (07:46 +0000)
1.Port reset process may not be proper for some vendor's SS hubs. If the corresponding port shows the reset has been done by C_RESET bit we have to skip the whole reset process for attached devices.
2.Clean C_BH_RESET bit immediately to avoid usb timer entering too many times when 5 tiers hubs are connected.
3.Stop checking URB if there is an error happened.
4.Better error handling for fast hot-plug.

Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Elvin Li <elvin.li@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14889 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c

index 443df729d2edfc56bd8144eb1823f63e74a750af..5ca58fbb9e7d719d458f932a5bbe2ad025e00084 100644 (file)
@@ -32,6 +32,13 @@ USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
   {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
 };
 
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
+  {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
+  {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
+  {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+  {XHC_PORTSC_PRC, EfiUsbPortResetChange}
+};
+
 USB_PORT_STATE_MAP  mUsbHubPortStateMap[] = {
   {XHC_HUB_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},
   {XHC_HUB_PORTSC_PED,   USB_PORT_STAT_ENABLE},
@@ -46,6 +53,14 @@ USB_PORT_STATE_MAP  mUsbHubPortChangeMap[] = {
   {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
 };
 
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
+  {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
+  {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
+  {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+  {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
+  {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
+};
+
 EFI_DRIVER_BINDING_PROTOCOL  gXhciDriverBinding = {
   XhcDriverBindingSupported,
   XhcDriverBindingStart,
@@ -432,6 +447,14 @@ XhcGetRootHubPortStatus (
     }
   }
 
+  MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+  for (Index = 0; Index < MapSize; Index++) {
+    if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
+      XhcClearRootHubPortFeature (This, PortNumber, mUsbClearPortChangeMap[Index].Selector);
+    }
+  }
+
   //
   // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
   // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
@@ -469,8 +492,6 @@ XhcSetRootHubPortFeature (
   UINT32                  Offset;
   UINT32                  State;
   UINT32                  TotalPort;
-  UINT8                   SlotId;
-  USB_DEV_ROUTE           RouteChart;
   EFI_STATUS              Status;
   EFI_TPL                 OldTpl;
 
@@ -526,24 +547,13 @@ XhcSetRootHubPortFeature (
       }
     }
 
-    RouteChart.Route.RouteString = 0;
-    RouteChart.Route.RootPortNum = PortNumber + 1;
-    RouteChart.Route.TierNum     = 1;
     //
-    // If the port reset operation happens after the usb super speed device is enabled,
-    // The subsequent configuration, such as getting device descriptor, will fail.
-    // So here a workaround is introduced to skip the reset operation if the device is enabled.
+    // 4.3.1 Resetting a Root Hub Port
+    // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
     //
-    SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
-    if (SlotId == 0) {
-      //
-      // 4.3.1 Resetting a Root Hub Port
-      // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
-      //
-      State |= XHC_PORTSC_RESET;
-      XhcWriteOpReg (Xhc, Offset, State);
-      XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
-    }
+    State |= XHC_PORTSC_RESET;
+    XhcWriteOpReg (Xhc, Offset, State);
+    XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
     break;
 
   case EfiUsbPortPower:
@@ -763,6 +773,8 @@ XhcControlTransfer (
   UINTN                   MapSize;
   EFI_USB_PORT_STATUS     PortStatus;
   UINT32                  State;
+  EFI_USB_DEVICE_REQUEST  ClearPortRequest;
+  UINTN                   Len;
 
   //
   // Validate parameters
@@ -808,6 +820,7 @@ XhcControlTransfer (
 
   Status          = EFI_DEVICE_ERROR;
   *TransferResult = EFI_USB_ERR_SYSTEM;
+  Len             = 0;
 
   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
     DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
@@ -839,6 +852,11 @@ XhcControlTransfer (
         Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
       }
     }
+
+    if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
+      Status = EFI_DEVICE_ERROR;
+      goto ON_EXIT;
+    }
     //
     // The actual device address has been assigned by XHCI during initializing the device slot.
     // So we just need establish the mapping relationship between the device address requested from UsbBus
@@ -849,20 +867,6 @@ XhcControlTransfer (
     Status = EFI_SUCCESS;
     goto ON_EXIT;
   }
-  
-  //
-  // If the port reset operation happens after the usb super speed device is enabled,
-  // The subsequent configuration, such as getting device descriptor, will fail.
-  // So here a workaround is introduced to skip the reset operation if the device is enabled.
-  //
-  if ((Request->Request     == USB_REQ_SET_FEATURE) &&
-      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)) &&
-      (Request->Value       == EfiUsbPortReset)) {
-    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
-      Status = EFI_SUCCESS;
-      goto ON_EXIT;
-    }
-  }
 
   //
   // Create a new URB, insert it into the asynchronous
@@ -1050,6 +1054,33 @@ XhcControlTransfer (
       }
     }
 
+    MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+    for (Index = 0; Index < MapSize; Index++) {
+      if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
+        ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+        ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
+        ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;
+        ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;
+        ClearPortRequest.Index        = Request->Index;
+        ClearPortRequest.Length       = 0;
+
+        XhcControlTransfer (
+          This, 
+          DeviceAddress,
+          DeviceSpeed,
+          MaximumPacketLength,
+          &ClearPortRequest,
+          EfiUsbNoData,
+          NULL,
+          &Len,
+          Timeout,
+          Translator,
+          TransferResult
+          );
+      }
+    }
+
     XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
 
     *(UINT32 *)Data = *(UINT32*)&PortStatus;
index 20a5510bfec9f714a3579ea221e50c9318b47682..dc82811984e4073edbe21efebfab6dc0df24fb2c 100644 (file)
@@ -2,7 +2,7 @@
 \r
   This file contains the register definition of XHCI host controller.\r
 \r
-Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -169,7 +169,7 @@ typedef union {
 #define XHC_PORTSC_RESET                   BIT4  // Port Reset\r
 #define XHC_PORTSC_PLS                     (BIT5|BIT6|BIT7|BIT8)     // Port Link State\r
 #define XHC_PORTSC_PP                      BIT9  // Port Power\r
-#define XHC_PORTSC_PS                      (BIT10|BIT11|BIT12|BIT13) // Port Speed\r
+#define XHC_PORTSC_PS                      (BIT10|BIT11|BIT12)       // Port Speed\r
 #define XHC_PORTSC_LWS                     BIT16 // Port Link State Write Strobe\r
 #define XHC_PORTSC_CSC                     BIT17 // Connect Status Change\r
 #define XHC_PORTSC_PEC                     BIT18 // Port Enabled/Disabled Change\r
@@ -189,12 +189,18 @@ typedef union {
 #define XHC_HUB_PORTSC_PEC                 BIT17 // Hub's Port Enabled/Disabled Change\r
 #define XHC_HUB_PORTSC_OCC                 BIT19 // Hub's Over-Current Change\r
 #define XHC_HUB_PORTSC_PRC                 BIT20 // Hub's Port Reset Change\r
+#define XHC_HUB_PORTSC_BHRC                BIT21 // Hub's Port Warm Reset Change\r
 #define XHC_IMAN_IP                        BIT0  // Interrupt Pending\r
 #define XHC_IMAN_IE                        BIT1  // Interrupt Enable\r
 \r
 #define XHC_IMODI_MASK                     0x0000FFFF  // Interrupt Moderation Interval\r
 #define XHC_IMODC_MASK                     0xFFFF0000  // Interrupt Moderation Counter\r
 \r
+//\r
+//  Hub Class Feature Selector for Clear Port Feature Request\r
+//\r
+#define Usb3PortBHPortResetChange          29\r
+\r
 //\r
 // Structure to map the hardware port states to the\r
 // UEFI's port states.\r
@@ -204,6 +210,14 @@ typedef struct {
   UINT16                  UefiState;\r
 } USB_PORT_STATE_MAP;\r
 \r
+//\r
+// Structure to map the hardware port states to feature selector for clear port feature request.\r
+//\r
+typedef struct {\r
+  UINT32                  HwState;\r
+  UINT16                  Selector;\r
+} USB_CLEAR_PORT_MAP;\r
+\r
 /**\r
   Read 1-byte width XHCI capability register.\r
 \r
index bcb419403dd326f0744b08c8bba3a27594b13d5e..ec13e49a7cb0e5479fba3f4453742f830208d799 100644 (file)
@@ -1105,25 +1105,25 @@ XhcCheckUrbResult (
         CheckedUrb->Result  |= EFI_USB_ERR_STALL;\r
         CheckedUrb->Finished = TRUE;\r
         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
-        break;\r
+        goto EXIT;\r
 \r
       case TRB_COMPLETION_BABBLE_ERROR:\r
         CheckedUrb->Result  |= EFI_USB_ERR_BABBLE;\r
         CheckedUrb->Finished = TRUE;\r
         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
-        break;\r
+        goto EXIT;\r
 \r
       case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
         CheckedUrb->Result  |= EFI_USB_ERR_BUFFER;\r
         CheckedUrb->Finished = TRUE;\r
         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
-        break;\r
+        goto EXIT;\r
 \r
       case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;\r
         CheckedUrb->Finished = TRUE;\r
         DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
-        break;\r
+        goto EXIT;\r
 \r
       case TRB_COMPLETION_SHORT_PACKET:\r
       case TRB_COMPLETION_SUCCESS:\r
@@ -1144,7 +1144,7 @@ XhcCheckUrbResult (
         DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
         CheckedUrb->Result  |= EFI_USB_ERR_TIMEOUT;\r
         CheckedUrb->Finished = TRUE;\r
-        break;\r
+        goto EXIT;\r
     }\r
 \r
     //\r
@@ -1535,6 +1535,10 @@ XhcPollPortStatusChange (
 \r
   Status = EFI_SUCCESS;\r
 \r
+  if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   if (ParentRouteChart.Dword == 0) {\r
     RouteChart.Route.RouteString = 0;\r
     RouteChart.Route.RootPortNum = Port + 1;\r
@@ -1549,6 +1553,15 @@ XhcPollPortStatusChange (
     RouteChart.Route.TierNum       = ParentRouteChart.Route.TierNum + 1;\r
   }\r
 \r
+  SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
+  if (SlotId != 0) {\r
+    if (Xhc->HcCParams.Data.Csz == 0) {\r
+      Status = XhcDisableSlotCmd (Xhc, SlotId);\r
+    } else {\r
+      Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
+    }\r
+  }\r
+\r
   if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
       ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
     //\r
@@ -1566,26 +1579,15 @@ XhcPollPortStatusChange (
     // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
     //\r
     SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
-    if (SlotId == 0) {\r
+    if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
       if (Xhc->HcCParams.Data.Csz == 0) {\r
         Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
       } else {\r
         Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
       }\r
     }\r
-  } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {\r
-    //\r
-    // Device is detached. Disable the allocated device slot and release resource.\r
-    //\r
-    SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
-    if (SlotId != 0) {\r
-      if (Xhc->HcCParams.Data.Csz == 0) {\r
-        Status = XhcDisableSlotCmd (Xhc, SlotId);\r
-      } else {\r
-        Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
-      }\r
-    }\r
-  }\r
+  } \r
+\r
   return Status;\r
 }\r
 \r
index 2fcacad46e468d2f0fc5f90bf3d06d696ac33509..e3752d1f83ef7fa1835bce82fa1845c911f5989d 100644 (file)
@@ -968,6 +968,15 @@ UsbHubResetPort (
   UINTN                   Index;\r
   EFI_STATUS              Status;\r
 \r
+  Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+    DEBUG (( EFI_D_INFO, "UsbHubResetPort: skip reset on hub %p port %d\n", HubIf, Port));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   Status  = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);\r
 \r
   if (EFI_ERROR (Status)) {\r
@@ -1272,6 +1281,16 @@ UsbRootHubResetPort (
   // should be handled in the EHCI driver.\r
   //\r
   Bus     = RootIf->Device->Bus;\r
+\r
+  Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+    DEBUG (( EFI_D_INFO, "UsbRootHubResetPort: skip reset on root port %d\n", Port));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
 \r
   if (EFI_ERROR (Status)) {\r