Author: mcayland Date: Fri Jan 8 13:09:48 2016 New Revision: 1377 URL: http://tracker.coreboot.org/trac/openbios/changeset/1377
Log: pci: don't hard-code PCI interrupt maps by default
The current code for openpic interrupts is incorrect for two reasons: firstly it generates an interrupt-map property with 8 IRQ pins (when only 4 are specified and so the last 4 entries are junk), and secondly it hard-codes the entries with a non-standard interrupt-mask to give one entry per pin rather than one entry per PCI device.
Switch everything over to use the existing code used by SPARC64 which dynamically enumerates the child nodes and builds up the correct properties on demand. This ensures that everything will work on PCI platforms particularly if extra cards are dynamically plugged into QEMU.
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 Jan 8 13:09:46 2016 (r1376) +++ trunk/openbios-devel/drivers/pci.c Fri Jan 8 13:09:48 2016 (r1377) @@ -1428,9 +1428,11 @@
static void ob_pci_host_set_interrupt_map(phandle_t host) { - phandle_t dnode = 0; - u32 props[128]; - int i; + phandle_t dnode = 0, pci_childnode = 0; + u32 props[128], intno; + int i, ncells, len; + u32 *val, addr; + char *reg;
#if defined(CONFIG_PPC) phandle_t target_node; @@ -1474,69 +1476,60 @@
target_node = find_dev("/pci"); set_int_property(target_node, "interrupt-parent", dnode); - - /* openpic interrupt mapping */ - for (i = 0; i < (7*8); i += 7) { - props[i + PCI_INT_MAP_PCI0] = 0; - props[i + PCI_INT_MAP_PCI1] = 0; - props[i + PCI_INT_MAP_PCI2] = 0; - props[i + PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1 - props[i + PCI_INT_MAP_PIC_HANDLE] = dnode; - props[i + PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7]; - props[i + PCI_INT_MAP_PIC_POL] = 3; - } - set_property(host, "interrupt-map", (char *)props, 7 * 8 * sizeof(props[0])); - - props[PCI_INT_MAP_PCI0] = 0; - props[PCI_INT_MAP_PCI1] = 0; - props[PCI_INT_MAP_PCI2] = 0; - props[PCI_INT_MAP_PCI_INT] = 0x7; - - set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); } -#elif defined(CONFIG_SPARC64) - int ncells, len; - u32 *val, addr; - char *reg; +#else + /* PCI host bridge is the default interrupt controller */ + dnode = host; +#endif
/* Set interrupt-map for PCI devices with an interrupt pin present */ ncells = 0;
PUSH(host); fword("child"); - dnode = POP(); - while (dnode) { - if (get_int_property(dnode, "interrupts", &len)) { - reg = get_property(dnode, "reg", &len); - if (reg) { + pci_childnode = POP(); + while (pci_childnode) { + intno = get_int_property(pci_childnode, "interrupts", &len); + if (len && intno) { + reg = get_property(pci_childnode, "reg", &len); + if (len && 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)) { + if ((addr & PCI_RANGE_TYPE_MASK) == PCI_RANGE_CONFIG) { +#ifdef CONFIG_SPARC64 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); + props[ncells++] = intno; + props[ncells++] = dnode; + props[ncells++] = SUN4U_INTERRUPT(addr, intno); +#endif + +#ifdef CONFIG_PPC + ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0); + props[ncells++] = intno; + props[ncells++] = dnode; + props[ncells++] = arch->irqs[intno - 1]; + props[ncells++] = 3; +#endif } } } }
- PUSH(dnode); + PUSH(pci_childnode); fword("peer"); - dnode = POP(); + pci_childnode = POP(); } set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
props[0] = 0x0000f800; props[1] = 0x0; props[2] = 0x0; - props[3] = 7; + props[3] = 0x7; set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); -#endif }
int ob_pci_init(void)