]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
MdeModulePkg/PciBusDxe: catch unimplemented extended config space reads
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciReg.c
index 9d50ef824261acc357812e33a911eec017bea09b..42b773ab31bea8d5264b6afa708f848014b538fd 100644 (file)
@@ -2,14 +2,8 @@
 \r
   The XHCI register operation routines.\r
 \r
-Copyright (c) 2011, 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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -112,7 +106,7 @@ XhcReadOpReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->CapLength + Offset),\r
+                             Xhc->CapLength + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -148,7 +142,7 @@ XhcWriteOpReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->CapLength + Offset),\r
+                             Xhc->CapLength + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -158,75 +152,9 @@ XhcWriteOpReg (
   }\r
 }\r
 \r
-/**\r
-  Write the data to the 2-bytes width XHCI operational register.\r
-\r
-  @param  Xhc          The XHCI Instance.\r
-  @param  Offset       The offset of the 2-bytes width operational register.\r
-  @param  Data         The data to write.\r
-\r
-**/\r
-VOID\r
-XhcWriteOpReg16 (\r
-  IN USB_XHCI_INSTANCE    *Xhc,\r
-  IN UINT32               Offset,\r
-  IN UINT16               Data\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-\r
-  ASSERT (Xhc->CapLength != 0);\r
-\r
-  Status = Xhc->PciIo->Mem.Write (\r
-                             Xhc->PciIo,\r
-                             EfiPciIoWidthUint16,\r
-                             XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->CapLength + Offset),\r
-                             1,\r
-                             &Data\r
-                             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "XhcWriteOpReg16: Pci Io Write error: %r at %d\n", Status, Offset));\r
-  }\r
-}\r
-\r
-/**\r
-  Read XHCI door bell register.\r
-\r
-  @param  Xhc          The XHCI Instance.\r
-  @param  Offset       The offset of the door bell register.\r
-\r
-  @return The register content read\r
-\r
-**/\r
-UINT32\r
-XhcReadDoorBellReg (\r
-  IN  USB_XHCI_INSTANCE   *Xhc,\r
-  IN  UINT32              Offset\r
-  )\r
-{\r
-  UINT32                  Data;\r
-  EFI_STATUS              Status;\r
-\r
-  ASSERT (Xhc->DBOff != 0);\r
 \r
-  Status = Xhc->PciIo->Mem.Read (\r
-                             Xhc->PciIo,\r
-                             EfiPciIoWidthUint32,\r
-                             XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->DBOff + Offset),\r
-                             1,\r
-                             &Data\r
-                             );\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "XhcReadDoorBellReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
-    Data = 0xFFFFFFFF;\r
-  }\r
 \r
-  return Data;\r
-}\r
 \r
 /**\r
   Write the data to the XHCI door bell register.\r
@@ -251,7 +179,7 @@ XhcWriteDoorBellReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->DBOff + Offset),\r
+                             Xhc->DBOff + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -285,7 +213,7 @@ XhcReadRuntimeReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             Xhc->RTSOff + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -321,7 +249,7 @@ XhcWriteRuntimeReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             Xhc->RTSOff + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -355,7 +283,7 @@ XhcReadExtCapReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->ExtCapRegBase + Offset),\r
+                             Xhc->ExtCapRegBase + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -391,7 +319,7 @@ XhcWriteExtCapReg (
                              Xhc->PciIo,\r
                              EfiPciIoWidthUint32,\r
                              XHC_BAR_INDEX,\r
-                             (UINT64) (Xhc->ExtCapRegBase + Offset),\r
+                             Xhc->ExtCapRegBase + Offset,\r
                              1,\r
                              &Data\r
                              );\r
@@ -515,16 +443,16 @@ XhcWaitOpRegBit (
   )\r
 {\r
   UINT32                  Index;\r
-  UINT                  Loop;\r
+  UINT64                  Loop;\r
 \r
-  Loop   = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;\r
+  Loop   = Timeout * XHC_1_MILLISECOND;\r
 \r
   for (Index = 0; Index < Loop; Index++) {\r
     if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
       return EFI_SUCCESS;\r
     }\r
 \r
-    gBS->Stall (XHC_POLL_DELAY);\r
+    gBS->Stall (XHC_1_MICROSECOND);\r
   }\r
 \r
   return EFI_TIMEOUT;\r
@@ -543,6 +471,10 @@ XhcSetBiosOwnership (
 {\r
   UINT32                    Buffer;\r
 \r
+  if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {\r
+    return;\r
+  }\r
+\r
   DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));\r
 \r
   Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);\r
@@ -563,6 +495,10 @@ XhcClearBiosOwnership (
 {\r
   UINT32                    Buffer;\r
 \r
+  if (Xhc->UsbLegSupOffset == 0xFFFFFFFF) {\r
+    return;\r
+  }\r
+\r
   DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));\r
 \r
   Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);\r
@@ -571,16 +507,18 @@ XhcClearBiosOwnership (
 }\r
 \r
 /**\r
-  Calculate the XHCI legacy support capability register offset.\r
+  Calculate the offset of the XHCI capability.\r
 \r
   @param  Xhc     The XHCI Instance.\r
+  @param  CapId   The XHCI Capability ID.\r
 \r
   @return The offset of XHCI legacy support capability register.\r
 \r
 **/\r
 UINT32\r
-XhcGetLegSupCapAddr (\r
-  IN USB_XHCI_INSTANCE    *Xhc\r
+XhcGetCapabilityAddr (\r
+  IN USB_XHCI_INSTANCE    *Xhc,\r
+  IN UINT8                CapId\r
   )\r
 {\r
   UINT32 ExtCapOffset;\r
@@ -594,7 +532,7 @@ XhcGetLegSupCapAddr (
     // Check if the extended capability register's capability id is USB Legacy Support.\r
     //\r
     Data = XhcReadExtCapReg (Xhc, ExtCapOffset);\r
-    if ((Data & 0xFF) == 0x1) {\r
+    if ((Data & 0xFF) == CapId) {\r
       return ExtCapOffset;\r
     }\r
     //\r
@@ -604,7 +542,7 @@ XhcGetLegSupCapAddr (
     ExtCapOffset += (NextExtCapReg << 2);\r
   } while (NextExtCapReg != 0);\r
 \r
-  return 0;\r
+  return 0xFFFFFFFF;\r
 }\r
 \r
 /**\r
@@ -642,6 +580,39 @@ XhcIsSysError (
   return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
 }\r
 \r
+/**\r
+  Set USBCMD Host System Error Enable(HSEE) Bit if PCICMD SERR# Enable Bit is set.\r
+\r
+  The USBCMD HSEE Bit will be reset to default 0 by USBCMD Host Controller Reset(HCRST).\r
+  This function is to set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.\r
+\r
+  @param Xhc            The XHCI Instance.\r
+\r
+**/\r
+VOID\r
+XhcSetHsee (\r
+  IN USB_XHCI_INSTANCE  *Xhc\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  UINT16                XhciCmd;\r
+\r
+  PciIo = Xhc->PciIo;\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint16,\r
+                        PCI_COMMAND_OFFSET,\r
+                        sizeof (XhciCmd) / sizeof (UINT16),\r
+                        &XhciCmd\r
+                        );\r
+  if (!EFI_ERROR (Status)) {\r
+    if ((XhciCmd & EFI_PCI_COMMAND_SERR) != 0) {\r
+      XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_HSEE);\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Reset the XHCI host controller.\r
 \r
@@ -660,6 +631,8 @@ XhcResetHC (
 {\r
   EFI_STATUS              Status;\r
 \r
+  Status = EFI_SUCCESS;\r
+\r
   DEBUG ((EFI_D_INFO, "XhcResetHC!\n"));\r
   //\r
   // Host can only be reset when it is halt. If not so, halt it\r
@@ -672,8 +645,26 @@ XhcResetHC (
     }\r
   }\r
 \r
-  XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
-  Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
+  if ((Xhc->DebugCapSupOffset == 0xFFFFFFFF) || ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) != XHC_CAP_USB_DEBUG) ||\r
+      ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) == 0)) {\r
+    XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
+    //\r
+    // Some XHCI host controllers require to have extra 1ms delay before accessing any MMIO register during reset.\r
+    // Otherwise there may have the timeout case happened.\r
+    // The below is a workaround to solve such problem.\r
+    //\r
+    gBS->Stall (XHC_1_MILLISECOND);\r
+    Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // The USBCMD HSEE Bit will be reset to default 0 by USBCMD HCRST.\r
+      // Set USBCMD HSEE Bit if PCICMD SERR# Enable Bit is set.\r
+      //\r
+      XhcSetHsee (Xhc);\r
+    }\r
+  }\r
+\r
   return Status;\r
 }\r
 \r