Author: mcayland Date: Fri Nov 14 20:17:48 2014 New Revision: 1327 URL: http://tracker.coreboot.org/trac/openbios/changeset/1327
Log: SPARC64: fix interrupt mapping for PCI slots
Instead of using hard-coded interrupt mappings for the NE2000 (slot 4) and CMD646 (slot 5) devices, we can now interrogate the device tree after the PCI scan to locate any devices with interrupt pins and map them accordingly.
This fixes the regression with PCI devices added with QEMU's -device syntax not having their interrupt pins mapped (particularly virtio devices).
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Modified: trunk/openbios-devel/drivers/pci.c
Modified: trunk/openbios-devel/drivers/pci.c ============================================================================== --- trunk/openbios-devel/drivers/pci.c Fri Nov 14 20:17:45 2014 (r1326) +++ trunk/openbios-devel/drivers/pci.c Fri Nov 14 20:17:48 2014 (r1327) @@ -417,10 +417,6 @@ set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0])); }
-/* Convert device/irq pin to interrupt property */ -#define SUN4U_INTERRUPT(dev, irq_pin) \ - ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f) - static void pci_host_set_reg(phandle_t phandle) { phandle_t dev = phandle; @@ -1375,14 +1371,19 @@ set_property(host, "available", (char *)props, ncells * sizeof(props[0])); }
+/* Convert device/irq pin to interrupt property */ +#define SUN4U_INTERRUPT(dev, irq_pin) \ + ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f) + static void ob_pci_host_set_interrupt_map(phandle_t host) { -#if defined(CONFIG_PPC) phandle_t dnode = 0; - u32 props[56]; - phandle_t target_node; + u32 props[128]; int i;
+#if defined(CONFIG_PPC) + phandle_t target_node; + /* Oldworld macs do interrupt maps differently */ if (!is_newworld()) return; @@ -1437,20 +1438,40 @@ set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); } #elif defined(CONFIG_SPARC64) - uint32_t props[12]; - int ncells, device, i; + int ncells, len; + u32 *val, addr; + char *reg;
- /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */ + /* Set interrupt-map for PCI devices with an interrupt pin present */ ncells = 0; - for (i = 4; i <= 5; i++) { - device = i << 11;
- ncells += pci_encode_phys_addr(props + ncells, 0, 0, device, 0, 0); - props[ncells++] = 1; - props[ncells++] = host; - props[ncells++] = SUN4U_INTERRUPT(device, 1); - } + PUSH(host); + fword("child"); + dnode = POP(); + while (dnode) { + if (get_int_property(dnode, "interrupts", &len)) { + reg = get_property(dnode, "reg", &len); + if (reg) { + val = (u32 *)reg; + + for (i = 0; i < (len / sizeof(u32)); i += 5) { + addr = val[i]; + + /* Device address is in 1st 32-bit word of encoded PCI address for config space */ + if (!(addr & 0x03000000)) { + ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0); + props[ncells++] = 1; /* always interrupt pin 1 for QEMU */ + props[ncells++] = host; + props[ncells++] = SUN4U_INTERRUPT(addr, 1); + } + } + } + }
+ PUSH(dnode); + fword("peer"); + dnode = POP(); + } set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
props[0] = 0x0000f800;