Set the correct IOAPIC INTIN pin number for pci bus interrupt
sources during MP spec table generation (on emulators). Currently,
the pin number is set to the interrupt line field in the device's
configuration space, which is set to either IRQ 10 or 11 as the
boot rom driver expects. This works since qemu maps all ISA
compatible PIC IRQs onto IOAPIC pins 0-15, including PIRQs. But it
will break if, for some reason, the IRQ is routed to something
other than the INTLINE value using, for eg. ACPI _CRS. This patch
ensures the pin number is set to the correct value (16-23) that the
INTx pin is routed to in APIC mode, in agreement with the ACPI _PRT
provided routing.
Tested on a Linux 5.17.2 guest on qemu with the pci=nomsi and
acpi=noirq boot parameters to force MP table parsing for interrupt
sources.
Signed-off-by: Jay Khandkar <jaykhandkar2002(a)gmail.com>
---
src/fw/mptable.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/src/fw/mptable.c b/src/fw/mptable.c
index 47385cc..3a7b02f 100644
--- a/src/fw/mptable.c
+++ b/src/fw/mptable.c
@@ -18,6 +18,33 @@
#include "util.h" // MaxCountCPUs
#include "x86.h" // cpuid
+/* table to obtain IOAPIC INTIN pin # for a certain pci slot and pin */
+
+/* daisy chaining in line with acpi _PRT */
+#define SLOT_GSIE {0x14, 0x15, 0x16, 0x17}
+#define SLOT_GSIF {0x15, 0x16, 0x17, 0x14}
+#define SLOT_GSIG {0x16, 0x17, 0x14, 0x15}
+#define SLOT_GSIH {0x17, 0x14, 0x15, 0x16}
+#define SLOT_GSIA {0x10, 0x11, 0x12, 0x13}
+
+u8 pirq_intin[32][4] = { SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE, SLOT_GSIF, SLOT_GSIG, SLOT_GSIH,
+ SLOT_GSIE,
+
+ /* INTA -> PIRQA for slot 25 - 31, but 30
+ see the default value of D<N>IR */
+ SLOT_GSIA, SLOT_GSIA, SLOT_GSIA, SLOT_GSIA,
+ SLOT_GSIA,
+
+ /* PCIe->PCI bridge. use PIRQ[E-H] */
+ SLOT_GSIE,
+
+ SLOT_GSIA };
+
void
mptable_setup(void)
{
@@ -114,7 +141,6 @@ mptable_setup(void)
if (pci_bdf_to_bus(bdf) != 0)
break;
int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
- int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
if (pin == 0)
continue;
if (dev != pci_bdf_to_busdev(bdf)) {
@@ -131,7 +157,7 @@ mptable_setup(void)
intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
intsrc->dstapic = ioapic_id;
- intsrc->dstirq = irq;
+ intsrc->dstirq = pirq_intin[pci_bdf_to_dev(bdf)][pin - 1];
intsrc++;
}
--
2.35.2