x86: mpspec: Allow platform to determine how PIRQ is connected to I/O APIC
authorBin Meng <bmeng.cn@gmail.com>
Wed, 22 Jul 2015 08:21:09 +0000 (01:21 -0700)
committerSimon Glass <sjg@chromium.org>
Tue, 28 Jul 2015 16:36:24 +0000 (10:36 -0600)
Currently during writing MP table I/O interrupt assignment entry, we
assume the PIRQ is directly mapped to I/O APIC INTPIN#16-23, which
however is not always the case on some platforms.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
arch/x86/include/asm/mpspec.h
arch/x86/lib/mpspec.c

index efa9231f922f96041928060b7d90087871ff19e7..ad8eba947b9a42aca24499cfad3693030d5d2223 100644 (file)
@@ -431,6 +431,23 @@ void mp_write_compat_address_space(struct mp_config_table *mc, int busid,
  */
 u32 mptable_finalize(struct mp_config_table *mc);
 
+/**
+ * mp_determine_pci_dstirq() - Determine PCI device's int pin on the I/O APIC
+ *
+ * This determines a PCI device's interrupt pin number on the I/O APIC.
+ *
+ * This can be implemented by platform codes to handle specifal cases, which
+ * do not conform to the normal chipset/board design where PIRQ[A-H] are mapped
+ * directly to I/O APIC INTPIN#16-23.
+ *
+ * @bus:       bus number of the pci device
+ * @dev:       device number of the pci device
+ * @func:      function number of the pci device
+ * @pirq:      PIRQ number the PCI device's interrupt pin is routed to
+ * @return:    interrupt pin number on the I/O APIC
+ */
+int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq);
+
 /**
  * write_mp_table() - Write MP table
  *
index f16fbcbb0d4ca72621675050b1c7fdc537dfd35c..9b2a59b91189379932dda18d6af37b1fe7172a2a 100644 (file)
@@ -269,6 +269,13 @@ static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base,
        return (i == entry_num) ? false : true;
 }
 
+/* TODO: move this to driver model */
+__weak int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq)
+{
+       /* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */
+       return pirq + 16;
+}
+
 static int mptable_add_intsrc(struct mp_config_table *mc,
                              int bus_isa, int apicid)
 {
@@ -304,24 +311,27 @@ static int mptable_add_intsrc(struct mp_config_table *mc,
 
        for (i = 0; i < count; i++) {
                struct pirq_routing pr;
+               int bus, dev, func;
+               int dstirq;
 
                pr.bdf = fdt_addr_to_cpu(cell[0]);
                pr.pin = fdt_addr_to_cpu(cell[1]);
                pr.pirq = fdt_addr_to_cpu(cell[2]);
+               bus = PCI_BUS(pr.bdf);
+               dev = PCI_DEV(pr.bdf);
+               func = PCI_FUNC(pr.bdf);
 
                if (check_dup_entry(intsrc_base, intsrc_entries,
-                                   PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) {
+                                   bus, dev, pr.pin)) {
                        debug("found entry for bus %d device %d INT%c, skipping\n",
-                             PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
-                             'A' + pr.pin - 1);
+                             bus, dev, 'A' + pr.pin - 1);
                        cell += sizeof(struct pirq_routing) / sizeof(u32);
                        continue;
                }
 
-               /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */
-               mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf),
-                                   PCI_DEV(pr.bdf), pr.pin, apicid,
-                                   pr.pirq + 16);
+               dstirq = mp_determine_pci_dstirq(bus, dev, func, pr.pirq);
+               mp_write_pci_intsrc(mc, MP_INT, bus, dev, pr.pin,
+                                   apicid, dstirq);
                intsrc_entries++;
                cell += sizeof(struct pirq_routing) / sizeof(u32);
        }