]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: PlatformBdsLib: Dynamic PCI Interrupt Line register setup
authorGabriel Somlo <somlo@cmu.edu>
Mon, 17 Nov 2014 19:09:12 +0000 (19:09 +0000)
committerlersek <lersek@Edk2>
Mon, 17 Nov 2014 19:09:12 +0000 (19:09 +0000)
Remove hard-coded list of PCI devices for which the Interrupt Line
register is initialized. Instead, provide a "visitor" function to
initialize the register only for present and applicable PCI devices.

At this time, we match the behavior of SeaBIOS (file src/fw/pciinit.c,
functions *_pci_slot_get_irq() and "map the interrupt" block from
pci_bios_init_device()).

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16398 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c

index 6fc5a8978021821b281cc9ec74978f7388f56fc6..df07281448b342578dcbef84aa72b5aa3399bfb2 100644 (file)
@@ -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,18 +729,136 @@ Returns:
 }\r
 \r
 \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
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;\r
+  UINTN                     RootSlot;\r
+  UINTN                     Idx;\r
+  UINT8                     IrqLine;\r
+  EFI_STATUS                Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (PciHdr->Device.InterruptPin != 0) {\r
+\r
+    DevPathNode = DevicePathFromHandle (Handle);\r
+    ASSERT (DevPathNode != NULL);\r
+\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
+        Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+\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
 PciAcpiInitialization (\r
   )\r
 {\r
-  UINT16 HostBridgeDevId;\r
   UINTN  Pmba;\r
 \r
   //\r
   // Query Host Bridge DID to determine platform type\r
   //\r
-  HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
-  switch (HostBridgeDevId) {\r
+  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+  switch (mHostBridgeDevId) {\r
     case INTEL_82441_DEVICE_ID:\r
       Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);\r
       //\r
@@ -754,55 +885,20 @@ PciAcpiInitialization (
       break;\r
     default:\r
       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
-        __FUNCTION__, HostBridgeDevId));\r
+        __FUNCTION__, mHostBridgeDevId));\r
       ASSERT (FALSE);\r
       return;\r
   }\r
 \r
   //\r
-  // Set ACPI SCI_EN bit in PMCNTRL\r
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
   //\r
-  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
+  VisitAllPciInstances (SetPciIntLine);\r
 \r
   //\r
-  // Initialize PCI_INTERRUPT_LINE for commonly encountered devices and slots\r
-  //\r
-  // FIXME: This should instead be accomplished programmatically by\r
-  //        ennumerating all PCI devices present in the system and\r
-  //        computing PCI_INTERRUPT_LINE from PCI_INTERRUPT_PIN, the\r
-  //        slot/position of the device, and the available host IRQs\r
-  //        (for an example, see SeaBIOS pci_bios_init_devices() in\r
-  //        src/fw/pciinit.c)\r
+  // Set ACPI SCI_EN bit in PMCNTRL\r
   //\r
-  switch (HostBridgeDevId) {\r
-    case INTEL_82441_DEVICE_ID:\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    1, 2, 0x3c), 0x0b); // usb (northbr.)\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    1, 3, 0x3c), 0x0a); // acpi (northbr.)\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    3, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    4, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    5, 0, 0x3c), 0x0a);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    6, 0, 0x3c), 0x0a);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    7, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    8, 0, 0x3c), 0x0b);\r
-      break;\r
-    case INTEL_Q35_MCH_DEVICE_ID:\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    2, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    3, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    4, 0, 0x3c), 0x0a);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    5, 0, 0x3c), 0x0a);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    6, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    7, 0, 0x3c), 0x0b);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0,    8, 0, 0x3c), 0x0a);\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 0, 0x3c), 0x0a); // uhci1\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 1, 0x3c), 0x0a); // uhci2\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 2, 0x3c), 0x0b); // uhci3\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 7, 0x3c), 0x0b); // ehci1\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 2, 0x3c), 0x0a); // ahci (northbr.)\r
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 3, 0x3c), 0x0a); // smbus (northbr.)\r
-      break;\r
-    default:\r
-      ASSERT (FALSE); // should never be reached\r
-  }\r
+  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
 }\r
 \r
 \r