]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
OvmfPkg: extract QemuBootOrderLib
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / BdsPlatform.c
index 4b76c6e89030b05c1df36dbcba9ce122a2e2ab85..341f5c15963d2605c5fd2681032657a6636b11f7 100644 (file)
@@ -13,7 +13,7 @@
 **/\r
 \r
 #include "BdsPlatform.h"\r
-#include "QemuBootOrder.h"\r
+#include <Library/QemuBootOrderLib.h>\r
 \r
 \r
 //\r
@@ -25,7 +25,20 @@ EFI_EVENT     mEfiDevPathEvent;
 VOID          *mEmuVariableEventReg;\r
 EFI_EVENT     mEmuVariableEvent;\r
 BOOLEAN       mDetectVgaOnly;\r
+UINT16        mHostBridgeDevId;\r
 \r
+//\r
+// Table of host IRQs matching PCI IRQs A-D\r
+// (for configuring PCI Interrupt Line register)\r
+//\r
+CONST UINT8 PciHostIrqs[] = {\r
+  0x0a, 0x0a, 0x0b, 0x0b\r
+};\r
+\r
+//\r
+// Array Size macro\r
+//\r
+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))\r
 \r
 //\r
 // Type definitions\r
@@ -716,64 +729,176 @@ Returns:
 }\r
 \r
 \r
-VOID\r
-PciInitialization (\r
+/**\r
+  Configure PCI Interrupt Line register for applicable devices\r
+  Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
+\r
+  @param[in]  Handle - Handle of PCI device instance\r
+  @param[in]  PciIo - PCI IO protocol instance\r
+  @param[in]  PciHdr - PCI Header register block\r
+\r
+  @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetPciIntLine (\r
+  IN EFI_HANDLE           Handle,\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN PCI_TYPE00           *PciHdr\r
   )\r
 {\r
-  //\r
-  // Bus 0, Device 0, Function 0 - Host to PCI Bridge\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 0, 0, 0x3c), 0x00);\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;\r
+  UINTN                     RootSlot;\r
+  UINTN                     Idx;\r
+  UINT8                     IrqLine;\r
+  EFI_STATUS                Status;\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 0 - PCI to ISA Bridge\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x3c), 0x00);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // LNKA routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // LNKB routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // LNKC routing target\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // LNKD routing target\r
+  Status = EFI_SUCCESS;\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 1 - IDE Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x3c), 0x00);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 1, 0x0d), 0x40);\r
+  if (PciHdr->Device.InterruptPin != 0) {\r
 \r
-  //\r
-  // Bus 0, Device 1, Function 3 - Power Managment Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3c), 0x09);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 1, 3, 0x3d), 0x01); // INTA\r
+    DevPathNode = DevicePathFromHandle (Handle);\r
+    ASSERT (DevPathNode != NULL);\r
 \r
-  //\r
-  // Bus 0, Device 2, Function 0 - Video Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 2, 0, 0x3c), 0x00);\r
+    //\r
+    // Compute index into PciHostIrqs[] table by walking\r
+    // the device path and adding up all device numbers\r
+    //\r
+    Status = EFI_NOT_FOUND;\r
+    RootSlot = 0;\r
+    Idx = PciHdr->Device.InterruptPin - 1;\r
+    while (!IsDevicePathEnd (DevPathNode)) {\r
+      if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
+          DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
 \r
-  //\r
-  // Bus 0, Device 3, Function 0 - Network Controller\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3c), 0x0a);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 3, 0, 0x3d), 0x01); // INTA (-> LNKC)\r
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
 \r
-  //\r
-  // Bus 0, Device 5, Function 0 - RAM Memory\r
-  //\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3c), 0x0b);\r
-  PciWrite8 (PCI_LIB_ADDRESS (0, 5, 0, 0x3d), 0x01); // INTA (-> LNKA)\r
+        //\r
+        // Unlike SeaBIOS, which starts climbing from the leaf device\r
+        // up toward the root, we traverse the device path starting at\r
+        // the root moving toward the leaf node.\r
+        // The slot number of the top-level parent bridge is needed for\r
+        // Q35 cases with more than 24 slots on the root bus.\r
+        //\r
+        if (Status != EFI_SUCCESS) {\r
+          Status = EFI_SUCCESS;\r
+          RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+        }\r
+      }\r
+\r
+      DevPathNode = NextDevicePathNode (DevPathNode);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (RootSlot == 0) {\r
+      DEBUG((\r
+        EFI_D_ERROR,\r
+        "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
+        __FUNCTION__\r
+        ));\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Final PciHostIrqs[] index calculation depends on the platform\r
+    // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
+    //\r
+    switch (mHostBridgeDevId) {\r
+      case INTEL_82441_DEVICE_ID:\r
+        Idx -= 1;\r
+        break;\r
+      case INTEL_Q35_MCH_DEVICE_ID:\r
+        //\r
+        // SeaBIOS contains the following comment:\r
+        // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
+        //  with a different starting index - see q35-acpi-dsdt.dsl.\r
+        //\r
+        //  Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
+        //\r
+        if (RootSlot > 24) {\r
+          //\r
+          // in this case, subtract back out RootSlot from Idx\r
+          // (SeaBIOS never adds it to begin with, but that would make our\r
+          //  device path traversal loop above too awkward)\r
+          //\r
+          Idx -= RootSlot;\r
+        }\r
+        break;\r
+      default:\r
+        ASSERT (FALSE); // should never get here\r
+    }\r
+    Idx %= ARRAY_SIZE (PciHostIrqs);\r
+    IrqLine = PciHostIrqs[Idx];\r
+\r
+    //\r
+    // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
+    //\r
+    Status = PciIo->Pci.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               PCI_INT_LINE_OFFSET,\r
+               1,\r
+               &IrqLine\r
+               );\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
 VOID\r
-AcpiInitialization (\r
-  VOID\r
+PciAcpiInitialization (\r
   )\r
 {\r
+  UINTN  Pmba;\r
+\r
+  //\r
+  // Query Host Bridge DID to determine platform type\r
+  //\r
+  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+  switch (mHostBridgeDevId) {\r
+    case INTEL_82441_DEVICE_ID:\r
+      Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);\r
+      //\r
+      // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
+      //\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
+      break;\r
+    case INTEL_Q35_MCH_DEVICE_ID:\r
+      Pmba = POWER_MGMT_REGISTER_Q35 (0x40);\r
+      //\r
+      // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
+      //\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
+      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
+      break;\r
+    default:\r
+      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
+        __FUNCTION__, mHostBridgeDevId));\r
+      ASSERT (FALSE);\r
+      return;\r
+  }\r
+\r
+  //\r
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
+  //\r
+  VisitAllPciInstances (SetPciIntLine);\r
+\r
   //\r
   // Set ACPI SCI_EN bit in PMCNTRL\r
   //\r
-  IoOr16 ((PciRead32 (PCI_LIB_ADDRESS (0, 1, 3, 0x40)) & ~BIT0) + 4, BIT0);\r
+  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
 }\r
 \r
 \r
@@ -938,8 +1063,7 @@ Returns:
   //\r
   BdsLibConnectAll ();\r
 \r
-  PciInitialization ();\r
-  AcpiInitialization ();\r
+  PciAcpiInitialization ();\r
 \r
   //\r
   // Clear the logo after all devices are connected.\r