Move the interrupt mapping from the pre-scan pci_host_set_interrupt_map() to the post-scan ob_pci_host_set_interrupt_map() function.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pci.c | 146 +++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 74 deletions(-)
diff --git a/openbios-devel/drivers/pci.c b/openbios-devel/drivers/pci.c index 09e601c..629a652 100644 --- a/openbios-devel/drivers/pci.c +++ b/openbios-devel/drivers/pci.c @@ -417,70 +417,6 @@ static void pci_set_bus_range(const pci_config_t *config) 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_interrupt_map(phandle_t dev) -{ -/* XXX We currently have a hook in the MPIC init code to fill in its handle. - * If you want to have interrupt maps for your PCI host bus, add your - * architecture to the #if and make your bridge detect code fill in its - * handle too. - * - * It would be great if someone clever could come up with a more universal - * mechanism here. - */ -#if defined(CONFIG_PPC) - u32 props[7 * 8]; - int i; - - /* Oldworld macs do interrupt maps differently */ - if(!is_newworld()) - return; - - 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] = 0; // gets patched in later - props[i+PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7]; - props[i+PCI_INT_MAP_PIC_POL] = 3; - } - set_property(dev, "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(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); -#elif defined(CONFIG_SPARC64) - uint32_t props[12]; - int ncells, device, i; - - /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */ - 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++] = dev; - props[ncells++] = SUN4U_INTERRUPT(device, 1); - } - - set_property(dev, "interrupt-map", (char *)props, ncells * sizeof(props[0])); - - props[0] = 0x0000f800; - props[1] = 0x0; - props[2] = 0x0; - props[3] = 7; - set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); -#endif -} - static void pci_host_set_reg(phandle_t phandle) { phandle_t dev = phandle; @@ -547,7 +483,6 @@ int host_config_cb(const pci_config_t *config) //XXX this overrides "reg" property pci_host_set_reg(get_cur_dev()); pci_host_set_ranges(config); - pci_host_set_interrupt_map(get_cur_dev());
return 0; } @@ -1436,20 +1371,26 @@ static void ob_pci_set_available(phandle_t host, unsigned long mem_base, unsigne 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[128]; + int i; + +#if defined(CONFIG_PPC) phandle_t target_node; - u32 *interrupt_map; - int len, i;
/* Oldworld macs do interrupt maps differently */ if (!is_newworld()) return;
- /* patch in interrupt parent */ - while ((dnode = dt_iterate_type(dnode, "open-pic"))) { + dnode = dt_iterate_type(0, "open-pic"); + if (dnode) { + /* patch in openpic interrupt-parent properties */ target_node = find_dev("/pci/mac-io"); set_int_property(target_node, "interrupt-parent", dnode);
@@ -1477,12 +1418,69 @@ static void ob_pci_host_set_interrupt_map(phandle_t host) target_node = find_dev("/pci"); set_int_property(target_node, "interrupt-parent", dnode);
- interrupt_map = (u32 *)get_property(target_node, "interrupt-map", &len); - for (i = 0; i < 8; i++) { - interrupt_map[(i * 7) + PCI_INT_MAP_PIC_HANDLE] = (u32)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; + + /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */ + 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) { + 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); + } + } + } } - set_property(target_node, "interrupt-map", (char *)interrupt_map, len); + + PUSH(dnode); + fword("peer"); + dnode = POP(); } + set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0])); + + props[0] = 0x0000f800; + props[1] = 0x0; + props[2] = 0x0; + props[3] = 7; + set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); + #endif }