summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc64/sparc64/ofw_machdep.c58
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", &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);
}