diff --git a/drivers/macio.c b/drivers/macio.c index 3b7a3af..f43aaa8 100644 --- a/drivers/macio.c +++ b/drivers/macio.c @@ -18,6 +18,7 @@ #include "macio.h" #include "cuda.h" #include "escc.h" +#include "openbios/pci.h" #define OW_IO_NVRAM_SIZE 0x00020000 #define OW_IO_NVRAM_OFFSET 0x00060000 @@ -172,9 +173,13 @@ openpic_init(const char *path, uint32_t addr) fword("finish-device"); if (is_newworld()) { + u32 *interrupt_map; + int len, i; + /* patch in interrupt parent */ dnode = find_dev(buf); - target_node = find_dev("/pci"); + + target_node = find_dev("/pci/mac-io"); set_int_property(target_node, "interrupt-parent", dnode); target_node = find_dev("/pci/mac-io/escc/ch-a"); @@ -182,6 +187,15 @@ openpic_init(const char *path, uint32_t addr) target_node = find_dev("/pci/mac-io/escc/ch-b"); set_int_property(target_node, "interrupt-parent", dnode); + + 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 < 4; i++) { + interrupt_map[(i * 7) + PCI_INT_MAP_PIC_HANDLE] = (u32)dnode; + } + set_property(target_node, "interrupt-map", (char *)interrupt_map, len); } } diff --git a/drivers/pci.c b/drivers/pci.c index 7d681f1..60918b0 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -278,6 +278,47 @@ static void pci_set_bus_range(const pci_config_t *config) set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0])); } +static void pci_host_set_interrupt_map(const pci_config_t *config) +{ +/* 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) + phandle_t dev = get_cur_dev(); + u32 props[7 * 4]; + int i; + +#if defined(CONFIG_PPC) + /* Oldworld macs do interrupt maps differently */ + if(!is_newworld()) + return; +#endif + + for (i = 0; i < (7*4); 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 * 4 * 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])); +#endif +} + static void pci_host_set_reg(const pci_config_t *config) { phandle_t dev = get_cur_dev(); @@ -344,6 +385,7 @@ int host_config_cb(const pci_config_t *config) pci_host_set_reg(config); pci_host_set_ranges(config); pci_set_bus_range(config); + pci_host_set_interrupt_map(config); return 0; } diff --git a/include/openbios/pci.h b/include/openbios/pci.h index f500595..4f87ded 100644 --- a/include/openbios/pci.h +++ b/include/openbios/pci.h @@ -24,6 +24,16 @@ struct pci_arch_t { extern const pci_arch_t *arch; +/* Device tree offsets */ + +#define PCI_INT_MAP_PCI0 0 +#define PCI_INT_MAP_PCI1 1 +#define PCI_INT_MAP_PCI2 2 +#define PCI_INT_MAP_PCI_INT 3 +#define PCI_INT_MAP_PIC_HANDLE 4 +#define PCI_INT_MAP_PIC_INT 5 +#define PCI_INT_MAP_PIC_POL 6 + /* Device classes and subclasses */ #define PCI_BASE_CLASS_STORAGE 0x01