diff options
-rw-r--r-- | sys/arch/sparc64/sparc64/ofw_machdep.c | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/sys/arch/sparc64/sparc64/ofw_machdep.c b/sys/arch/sparc64/sparc64/ofw_machdep.c index deee72bda25..60ac862c37f 100644 --- a/sys/arch/sparc64/sparc64/ofw_machdep.c +++ b/sys/arch/sparc64/sparc64/ofw_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_machdep.c,v 1.9 2004/01/07 20:44:56 pvalchev Exp $ */ +/* $OpenBSD: ofw_machdep.c,v 1.10 2004/05/17 04:34:46 brad Exp $ */ /* $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $ */ /* @@ -45,6 +45,8 @@ #include <machine/openfirm.h> +#include <dev/ofw/ofw_pci.h> + #if defined(FFS) && defined(CD9660) #include <ufs/ffs/fs.h> #endif @@ -557,8 +559,8 @@ prom_get_msgbuf(len, align) * Low-level prom I/O routines. */ -static u_int stdin; -static u_int stdout; +static u_int stdin = 0; +static u_int stdout = 0; int OF_stdin() @@ -652,6 +654,27 @@ compare_cells(int *cell1, int *cell2, int *mask, int ncells) } /* + * Find top pci bus host controller for a node. + */ +static int +find_pci_host_node(int node) +{ + char dev_type[16]; + int pch = 0; + int len; + + for (; node; node = OF_parent(node)) { + len = OF_getprop(node, "device_type", + &dev_type, sizeof(dev_type)); + if (len <= 0) + continue; + if (!strcmp(dev_type, "pci")) + pch = node; + } + return pch; +} + +/* * Follow the OFW algorithm and return an interrupt specifier. * * Pass in the interrupt specifier you want mapped and the node @@ -667,6 +690,13 @@ OF_mapintr(int node, int *interrupt, int validlen, int buflen) int interrupt_map[100]; int interrupt_map_mask[10]; int reg[10]; + char dev_type[32]; + int phc_node; + int rc = -1; + + /* Don't need to map OBP interrupt, it's already */ + if (*interrupt & 0x20) + return validlen; /* * If there is no interrupt map in the bus node, we @@ -687,20 +717,36 @@ OF_mapintr(int node, int *interrupt, int validlen, int buflen) return (-1); } + phc_node = find_pci_host_node(node); + for (; node; node = OF_parent(node)) { #ifdef DEBUG char name[40]; if (ofmapintrdebug) { OF_getprop(node, "name", &name, sizeof(name)); - printf("Node %s\n", name); + printf("Node %s (%x), host %x\n", name, + node, phc_node); } #endif if ((interrupt_map_len = OF_getprop(node, "interrupt-map", &interrupt_map, sizeof(interrupt_map))) <= 0) { + + /* Swizzle interrupt if this is a PCI bridge. */ + if (((len = OF_getprop(node, "device_type", &dev_type, + sizeof(dev_type))) > 0) && + !strcmp(dev_type, "pci") && + (node != phc_node)) { + *interrupt = ((*interrupt + + OFW_PCI_PHYS_HI_DEVICE(reg[0]) - 1) & 3) + 1; + DPRINTF(("OF_mapintr: interrupt %x, reg[0] %x\n", + *interrupt, reg[0])); + } + /* Get reg for next level compare. */ + reg[0] = 0; OF_getprop(node, "reg", ®, sizeof(reg)); continue; } @@ -789,7 +835,7 @@ OF_mapintr(int node, int *interrupt, int validlen, int buflen) #endif for (i=0; i<pintr_cells; i++) interrupt[i] = parent[i]; - validlen = pintr_cells; + rc = validlen = pintr_cells; break; } /* Move on to the next interrupt_map entry. */ @@ -812,5 +858,5 @@ OF_mapintr(int node, int *interrupt, int validlen, int buflen) DPRINTF(("reg len %d\n", len)); } - return (validlen); + return (rc); } |