]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
MdeModulePkg UsbBusPei: Fix wrong buffer length used to read hub desc
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / HubPeim.c
index 5b7ebfad909688353a9fe4184e082db1bf99e4d4..ac930ee8ea0046615108aad77762141748306404 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Usb Hub Request Support In PEI Phase\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2018, 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
@@ -276,9 +276,10 @@ PeiHubClearHubFeature (
 }\r
 \r
 /**\r
-  Get a given hub descriptor.\r
+  Get a given (SuperSpeed) hub descriptor.\r
 \r
   @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice   Indicates the hub controller device.\r
   @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.\r
   @param  DescriptorSize The length of Hub Descriptor buffer.\r
   @param  HubDescriptor  Caller allocated buffer to store the hub descriptor if\r
@@ -292,21 +293,28 @@ PeiHubClearHubFeature (
 EFI_STATUS\r
 PeiGetHubDescriptor (\r
   IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_USB_DEVICE            *PeiUsbDevice,\r
   IN  PEI_USB_IO_PPI            *UsbIoPpi,\r
   IN  UINTN                     DescriptorSize,\r
   OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor\r
   )\r
 {\r
   EFI_USB_DEVICE_REQUEST      DevReq;\r
+  UINT8                       DescType;\r
+\r
   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
 \r
+  DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?\r
+             USB_DT_SUPERSPEED_HUB :\r
+             USB_DT_HUB;\r
+\r
   //\r
   // Fill Device request packet\r
   //\r
   DevReq.RequestType = USB_RT_HUB | 0x80;\r
   DevReq.Request     = USB_HUB_GET_DESCRIPTOR;\r
-  DevReq.Value       = USB_DT_HUB << 8;\r
-  DevReq.Length      = (UINT16)DescriptorSize;\r
+  DevReq.Value       = (UINT16) (DescType << 8);\r
+  DevReq.Length      = (UINT16) DescriptorSize;\r
 \r
   return  UsbIoPpi->UsbControlTransfer (\r
                       PeiServices,\r
@@ -319,6 +327,87 @@ PeiGetHubDescriptor (
                       );\r
 }\r
 \r
+/**\r
+  Read the whole usb hub descriptor. It is necessary\r
+  to do it in two steps because hub descriptor is of\r
+  variable length.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice      Indicates the hub controller device.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if\r
+                            successfully returned.\r
+\r
+  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubReadDesc (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN PEI_USB_DEVICE             *PeiUsbDevice,\r
+  IN PEI_USB_IO_PPI             *UsbIoPpi,\r
+  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  // First get the hub descriptor length\r
+  //\r
+  Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the whole hub descriptor\r
+  //\r
+  return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);\r
+}\r
+\r
+/**\r
+  USB hub control transfer to set the hub depth.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice      Indicates the hub controller device.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       Depth of the hub is set.\r
+  @retval Others            Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbHubCtrlSetHubDepth (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN PEI_USB_DEVICE             *PeiUsbDevice,\r
+  IN PEI_USB_IO_PPI             *UsbIoPpi\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST        DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DevReq.RequestType = USB_RT_HUB;\r
+  DevReq.Request     = USB_HUB_REQ_SET_DEPTH;\r
+  DevReq.Value       = PeiUsbDevice->Tier;\r
+  DevReq.Length      = 0;\r
+\r
+  return  UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DevReq,\r
+                      EfiUsbNoData,\r
+                      PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                      NULL,\r
+                      0\r
+                      );\r
+}\r
+\r
 /**\r
   Configure a given hub.\r
 \r
@@ -335,112 +424,96 @@ PeiDoHubConfig (
   IN PEI_USB_DEVICE      *PeiUsbDevice\r
   )\r
 {\r
-  EFI_USB_HUB_DESCRIPTOR  HubDescriptor;\r
+  UINT8                   HubDescBuffer[256];\r
+  EFI_USB_HUB_DESCRIPTOR  *HubDescriptor;\r
   EFI_STATUS              Status;\r
   EFI_USB_HUB_STATUS      HubStatus;\r
   UINTN                   Index;\r
-  UINT32                  PortStatus;\r
   PEI_USB_IO_PPI          *UsbIoPpi;\r
 \r
-  ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
   UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
 \r
   //\r
-  // First get the hub descriptor length\r
+  // The length field of descriptor is UINT8 type, so the buffer\r
+  // with 256 bytes is enough to hold the descriptor data.\r
   //\r
-  Status = PeiGetHubDescriptor (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            2,\r
-            &HubDescriptor\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+  HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;\r
+\r
   //\r
-  // First get the whole descriptor, then\r
-  // get the number of hub ports\r
+  // Get the hub descriptor \r
   //\r
-  Status = PeiGetHubDescriptor (\r
+  Status = PeiUsbHubReadDesc (\r
             PeiServices,\r
+            PeiUsbDevice,\r
             UsbIoPpi,\r
-            HubDescriptor.Length,\r
-            &HubDescriptor\r
+            HubDescriptor\r
             );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
+  PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;\r
 \r
-  Status = PeiHubGetHubStatus (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (UINT32 *) &HubStatus\r
-            );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-  //\r
-  //  Get all hub ports status\r
-  //\r
-  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-\r
-    Status = PeiHubGetPortStatus (\r
-              PeiServices,\r
-              UsbIoPpi,\r
-              (UINT8) (Index + 1),\r
-              &PortStatus\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-  }\r
-  //\r
-  //  Power all the hub ports\r
-  //\r
-  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-    Status = PeiHubSetPortFeature (\r
-              PeiServices,\r
-              UsbIoPpi,\r
-              (UINT8) (Index + 1),\r
-              EfiUsbPortPower\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-  }\r
-  //\r
-  // Clear Hub Status Change\r
-  //\r
-  Status = PeiHubGetHubStatus (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (UINT32 *) &HubStatus\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+  if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));\r
+    PeiUsbHubCtrlSetHubDepth (\r
+      PeiServices,\r
+      PeiUsbDevice,\r
+      UsbIoPpi\r
+      );\r
   } else {\r
     //\r
-    // Hub power supply change happens\r
+    //  Power all the hub ports\r
     //\r
-    if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
-      PeiHubClearHubFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        C_HUB_LOCAL_POWER\r
-        );\r
+    for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+      Status = PeiHubSetPortFeature (\r
+                PeiServices,\r
+                UsbIoPpi,\r
+                (UINT8) (Index + 1),\r
+                EfiUsbPortPower\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));\r
+        continue;\r
+      }\r
+    }\r
+\r
+    DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));\r
+    if (HubDescriptor->PwrOn2PwrGood > 0) {\r
+      MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
     }\r
+\r
     //\r
-    // Hub change overcurrent happens\r
+    // Clear Hub Status Change\r
     //\r
-    if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
-      PeiHubClearHubFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        C_HUB_OVER_CURRENT\r
-        );\r
+    Status = PeiHubGetHubStatus (\r
+              PeiServices,\r
+              UsbIoPpi,\r
+              (UINT32 *) &HubStatus\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    } else {\r
+      //\r
+      // Hub power supply change happens\r
+      //\r
+      if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+        PeiHubClearHubFeature (\r
+          PeiServices,\r
+          UsbIoPpi,\r
+          C_HUB_LOCAL_POWER\r
+          );\r
+      }\r
+      //\r
+      // Hub change overcurrent happens\r
+      //\r
+      if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+        PeiHubClearHubFeature (\r
+          PeiServices,\r
+          UsbIoPpi,\r
+          C_HUB_OVER_CURRENT\r
+          );\r
+      }\r
     }\r
   }\r
 \r
@@ -462,10 +535,10 @@ PeiResetHubPort (
   IN UINT8               PortNum\r
   )\r
 {\r
-  UINT8               Try;\r
+  EFI_STATUS          Status;\r
+  UINTN               Index;\r
   EFI_USB_PORT_STATUS HubPortStatus;\r
 \r
-\r
   MicroSecondDelay (100 * 1000);\r
 \r
   //\r
@@ -478,27 +551,49 @@ PeiResetHubPort (
     EfiUsbPortReset\r
     );\r
 \r
-  Try = 10;\r
-  do {\r
-    PeiHubGetPortStatus (\r
-      PeiServices,\r
-      UsbIoPpi,\r
-      PortNum,\r
-      (UINT32 *) &HubPortStatus\r
-      );\r
+  //\r
+  // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
+  // section 7.1.7.5 for timing requirements.\r
+  //\r
+  MicroSecondDelay (USB_SET_PORT_RESET_STALL);\r
 \r
-    MicroSecondDelay (2 * 1000);\r
-    Try -= 1;\r
-  } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+  //\r
+  // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
+  //\r
+  ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+  for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+    Status = PeiHubGetPortStatus (\r
+               PeiServices,\r
+               UsbIoPpi,\r
+               PortNum,\r
+               (UINT32 *) &HubPortStatus\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return;\r
+    }\r
+\r
+    if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+      break;\r
+    }\r
+\r
+    MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+  }\r
+\r
+  if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+    DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));\r
+    return;\r
+  }\r
 \r
   //\r
-  // clear reset root port\r
+  // clear reset change root port\r
   //\r
   PeiHubClearPortFeature (\r
     PeiServices,\r
     UsbIoPpi,\r
     PortNum,\r
-    EfiUsbPortReset\r
+    EfiUsbPortResetChange\r
     );\r
 \r
   MicroSecondDelay (1 * 1000);\r