There is a draft spec that defines how interrupts are supposed to be mapped from one bus to another, down to the PIC and CPU interrupt line.
So far we don't implement that spec. But PPC64 Linux requires us to for PCI devices. So let's create a map here.
Draft: http://playground.sun.com/1275/practice/imap/imap0_9d.pdf
Signed-off-by: Alexander Graf agraf@suse.de --- drivers/macio.c | 16 +++++++++++++++- drivers/pci.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/openbios/pci.h | 10 ++++++++++ 3 files changed, 67 insertions(+), 1 deletions(-)
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