]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - arch/x86/lib/mpspec.c
fdt: Implement weak arch_fixup_fdt()
[people/ms/u-boot.git] / arch / x86 / lib / mpspec.c
index f16fbcbb0d4ca72621675050b1c7fdc537dfd35c..a6e493d69af9aa814fa4398fcd5eaa510a5e5794 100644 (file)
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static bool isa_irq_occupied[16];
+
 struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf)
 {
-       u32 mc;
+       ulong mc;
 
        memcpy(mf->mpf_signature, MPF_SIGNATURE, 4);
-       mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table);
+       mf->mpf_physptr = (ulong)mf + sizeof(struct mp_floating_table);
        mf->mpf_length = 1;
        mf->mpf_spec = MPSPEC_V14;
        mf->mpf_checksum = 0;
@@ -39,7 +41,7 @@ struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf)
        mf->mpf_feature5 = 0;
        mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16);
 
-       mc = (u32)mf + sizeof(struct mp_floating_table);
+       mc = (ulong)mf + sizeof(struct mp_floating_table);
        return (struct mp_config_table *)mc;
 }
 
@@ -217,14 +219,14 @@ void mp_write_compat_address_space(struct mp_config_table *mc, int busid,
 
 u32 mptable_finalize(struct mp_config_table *mc)
 {
-       u32 end;
+       ulong end;
 
        mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc),
                                                  mc->mpe_length);
        mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length);
        end = mp_next_mpe_entry(mc);
 
-       debug("Write the MP table at: %x - %x\n", (u32)mc, end);
+       debug("Write the MP table at: %lx - %lx\n", (ulong)mc, end);
 
        return end;
 }
@@ -243,10 +245,18 @@ static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa,
                        MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
                        bus_isa, 0, apicid, 2);
 
-       for (i = 3; i < 16; i++)
+       for (i = 3; i < 16; i++) {
+               /*
+                * Do not write ISA interrupt entry if it is already occupied
+                * by the platform devices.
+                */
+               if (isa_irq_occupied[i])
+                       continue;
+
                mp_write_intsrc(mc, MP_INT,
                                MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
                                bus_isa, i, apicid, i);
+       }
 }
 
 /*
@@ -269,29 +279,33 @@ 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)
 {
        struct mpc_config_intsrc *intsrc_base;
        int intsrc_entries = 0;
        const void *blob = gd->fdt_blob;
-       int node;
+       struct udevice *dev;
        int len, count;
        const u32 *cell;
-       int i;
-
-       /* Legacy Interrupts */
-       debug("Writing ISA IRQs\n");
-       mptable_add_isa_interrupts(mc, bus_isa, apicid, 0);
+       int i, ret;
 
-       /* Get I/O interrupt information from device tree */
-       node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER);
-       if (node < 0) {
+       ret = uclass_first_device_err(UCLASS_IRQ, &dev);
+       if (ret && ret != -ENODEV) {
                debug("%s: Cannot find irq router node\n", __func__);
-               return -ENOENT;
+               return ret;
        }
 
-       cell = fdt_getprop(blob, node, "intel,pirq-routing", &len);
+       /* Get I/O interrupt information from device tree */
+       cell = fdt_getprop(blob, dev_of_offset(dev), "intel,pirq-routing",
+                          &len);
        if (!cell)
                return -ENOENT;
 
@@ -304,28 +318,41 @@ 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);
+               /*
+                * For PIRQ which is connected to I/O APIC interrupt pin#0-15,
+                * mark it as occupied so that we can skip it later.
+                */
+               if (dstirq < 16)
+                       isa_irq_occupied[dstirq] = true;
+               mp_write_pci_intsrc(mc, MP_INT, bus, dev, pr.pin,
+                                   apicid, dstirq);
                intsrc_entries++;
                cell += sizeof(struct pirq_routing) / sizeof(u32);
        }
 
+       /* Legacy Interrupts */
+       debug("Writing ISA IRQs\n");
+       mptable_add_isa_interrupts(mc, bus_isa, apicid, 0);
+
        return 0;
 }
 
@@ -339,13 +366,13 @@ static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa)
                         bus_isa, 0, MP_APIC_ALL, 1);
 }
 
-u32 write_mp_table(u32 addr)
+ulong write_mp_table(ulong addr)
 {
        struct mp_config_table *mc;
        int ioapic_id, ioapic_ver;
        int bus_isa = 0xff;
        int ret;
-       u32 end;
+       ulong end;
 
        /* 16 byte align the table address */
        addr = ALIGN(addr, 16);