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 <so...@cmu.edu>
---
 OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c | 154 +++++++++++++++++++--------
 1 file changed, 110 insertions(+), 44 deletions(-)

diff --git a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c 
b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
index 6fc5a89..7117423 100644
--- a/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
+++ b/OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
@@ -25,7 +25,20 @@ EFI_EVENT     mEfiDevPathEvent;
 VOID          *mEmuVariableEventReg;
 EFI_EVENT     mEmuVariableEvent;
 BOOLEAN       mDetectVgaOnly;
+UINT16        mHostBridgeDevId;
 
+//
+// Table of host IRQs matching PCI IRQs A-D
+// (for configuring PCI Interrupt Line register)
+//
+CONST UINT8 PciHostIrqs[] = {
+  0x0a, 0x0a, 0x0b, 0x0b
+};
+
+//
+// Array Size macro
+//
+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
 
 //
 // Type definitions
@@ -716,18 +729,106 @@ Returns:
 }
 
 
+/**
+  Configure PCI Interrupt Line register for applicable devices
+  Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
+
+  @param[in]  Handle - Handle of PCI device instance
+  @param[in]  PciIo - PCI IO protocol instance
+  @param[in]  PciHdr - PCI Header register block
+
+  @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SetPciIntLine (
+  IN EFI_HANDLE           Handle,
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN PCI_TYPE00           *PciHdr
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevPathNode;
+  UINTN                     Slot;
+  UINTN                     Idx;
+  UINT8                     IrqLine;
+  EFI_STATUS                Status;
+
+  Status = EFI_SUCCESS;
+
+  if (PciHdr->Device.InterruptPin != 0) {
+
+    DevPathNode = DevicePathFromHandle (Handle);
+    ASSERT (DevPathNode != NULL);
+
+    //
+    // Compute index into PciHostIrqs[] table by walking
+    // the device path and adding up all device numbers
+    //
+    Status = EFI_NOT_FOUND;
+    Idx = PciHdr->Device.InterruptPin - 1;
+    Slot = 0; // Suppress gcc uninitialized use warning
+    while (!IsDevicePathEnd (DevPathNode)) {
+      if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
+          DevicePathSubType (DevPathNode) == HW_PCI_DP) {
+
+        Status = EFI_SUCCESS;
+        Slot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+        Idx += Slot;
+      }
+
+      DevPathNode = NextDevicePathNode (DevPathNode);
+    }
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Final PciHostIrqs[] index calculation depends on the platform
+    // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
+    //
+    switch (mHostBridgeDevId) {
+      case INTEL_82441_DEVICE_ID:
+        Idx -= 1;
+        break;
+      case INTEL_Q35_MCH_DEVICE_ID:
+        if (Slot > 24) {
+          Idx -= Slot;
+        }
+        break;
+      default:
+        ASSERT (FALSE); // should never get here
+    }
+    Idx %= ARRAY_SIZE (PciHostIrqs);
+    IrqLine = PciHostIrqs[Idx];
+
+    //
+    // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
+    //
+    Status = PciIo->Pci.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               PCI_INT_LINE_OFFSET,
+               1,
+               &IrqLine
+               );
+  }
+
+  return Status;
+}
+
+
 VOID
 PciAcpiInitialization (
   )
 {
-  UINT16 HostBridgeDevId;
   UINTN  Pmba;
 
   //
   // Query Host Bridge DID to determine platform type
   //
-  HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
-  switch (HostBridgeDevId) {
+  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
+  switch (mHostBridgeDevId) {
     case INTEL_82441_DEVICE_ID:
       Pmba = POWER_MGMT_REGISTER_PIIX4 (0x40);
       //
@@ -754,55 +855,20 @@ PciAcpiInitialization (
       break;
     default:
       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
-        __FUNCTION__, HostBridgeDevId));
+        __FUNCTION__, mHostBridgeDevId));
       ASSERT (FALSE);
       return;
   }
 
   //
+  // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
+  //
+  VisitAllPciInstances (SetPciIntLine);
+
+  //
   // Set ACPI SCI_EN bit in PMCNTRL
   //
   IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
-
-  //
-  // Initialize PCI_INTERRUPT_LINE for commonly encountered devices and slots
-  //
-  // FIXME: This should instead be accomplished programmatically by
-  //        ennumerating all PCI devices present in the system and
-  //        computing PCI_INTERRUPT_LINE from PCI_INTERRUPT_PIN, the
-  //        slot/position of the device, and the available host IRQs
-  //        (for an example, see SeaBIOS pci_bios_init_devices() in
-  //        src/fw/pciinit.c)
-  //
-  switch (HostBridgeDevId) {
-    case INTEL_82441_DEVICE_ID:
-      PciWrite8 (PCI_LIB_ADDRESS (0,    1, 2, 0x3c), 0x0b); // usb (northbr.)
-      PciWrite8 (PCI_LIB_ADDRESS (0,    1, 3, 0x3c), 0x0a); // acpi (northbr.)
-      PciWrite8 (PCI_LIB_ADDRESS (0,    3, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    4, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    5, 0, 0x3c), 0x0a);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    6, 0, 0x3c), 0x0a);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    7, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    8, 0, 0x3c), 0x0b);
-      break;
-    case INTEL_Q35_MCH_DEVICE_ID:
-      PciWrite8 (PCI_LIB_ADDRESS (0,    2, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    3, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    4, 0, 0x3c), 0x0a);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    5, 0, 0x3c), 0x0a);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    6, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    7, 0, 0x3c), 0x0b);
-      PciWrite8 (PCI_LIB_ADDRESS (0,    8, 0, 0x3c), 0x0a);
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 0, 0x3c), 0x0a); // uhci1
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 1, 0x3c), 0x0a); // uhci2
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 2, 0x3c), 0x0b); // uhci3
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1d, 7, 0x3c), 0x0b); // ehci1
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 2, 0x3c), 0x0a); // ahci (northbr.)
-      PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 3, 0x3c), 0x0a); // smbus (northbr.)
-      break;
-    default:
-      ASSERT (FALSE); // should never be reached
-  }
 }
 
 
-- 
1.9.3


------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to