summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2009-01-03 19:38:47 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2009-01-03 19:38:47 +0000
commit4ca12119c31e0cd42b3cb4b28dd898b8218290dc (patch)
tree098db494b106fc2ba6859a08899f153876ecd41f /sys
parent6299d1e736cea0af7a3dba4c67151b374fa64885 (diff)
downloadFreeBSD-src-4ca12119c31e0cd42b3cb4b28dd898b8218290dc.zip
FreeBSD-src-4ca12119c31e0cd42b3cb4b28dd898b8218290dc.tar.gz
Fix the OFW interrupt map parser to use its own idea of the number of interrupt
cells in the map, instead of using a value passed to it and then panicing if it disagrees. This fixes interrupt map parsing for PCI bridges on some Apple Uninorth PCI controllers. Reported by: marcel Tested on: G4 iBook, Sun Ultra 5
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c23
-rw-r--r--sys/dev/ofw/openfirm.c17
-rw-r--r--sys/dev/ofw/openfirm.h2
-rw-r--r--sys/powerpc/powermac/grackle.c17
-rw-r--r--sys/powerpc/powermac/gracklevar.h1
-rw-r--r--sys/powerpc/powermac/macio.c8
-rw-r--r--sys/powerpc/powermac/uninorth.c15
-rw-r--r--sys/powerpc/powermac/uninorthvar.h1
8 files changed, 35 insertions, 49 deletions
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index 19de2b97..1cc5207 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -146,18 +146,6 @@ ofw_bus_gen_get_type(device_t bus, device_t dev)
return (obd->obd_type);
}
-static int
-ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen)
-{
- int rv;
-
- for (; node != 0; node = OF_parent(node)) {
- if ((rv = OF_getprop(node, propname, buf, buflen)) != -1)
- return (rv);
- }
- return (-1);
-}
-
void
ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
{
@@ -249,17 +237,16 @@ ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
mptr = imap;
i = imapsz;
- tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz;
while (i > 0) {
- KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
- if (ofw_bus_searchprop(parent, "#interrupt-cells",
+ if (OF_searchprop(parent, "#interrupt-cells",
&pintrsz, sizeof(pintrsz)) == -1)
pintrsz = 1; /* default */
pintrsz *= sizeof(pcell_t);
- if (pintrsz != rintrsz)
- panic("ofw_bus_search_intrmap: expected interrupt cell "
- "size incorrect: %d > %d", rintrsz, pintrsz);
+
+ /* Compute the map stride size */
+ tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz;
+ KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
/*
* XXX: Apple hardware uses a second cell to set information
diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c
index c7b2203..4c33c9f 100644
--- a/sys/dev/ofw/openfirm.c
+++ b/sys/dev/ofw/openfirm.c
@@ -220,6 +220,23 @@ OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
}
/*
+ * Resursively search the node and its parent for the given property, working
+ * downward from the node to the device tree root. Returns the value of the
+ * first match.
+ */
+ssize_t
+OF_searchprop(phandle_t node, char *propname, void *buf, size_t len)
+{
+ ssize_t rv;
+
+ for (; node != 0; node = OF_parent(node)) {
+ if ((rv = OF_getprop(node, propname, buf, len)) != -1)
+ return (rv);
+ }
+ return (-1);
+}
+
+/*
* Store the value of a property of a package into newly allocated memory
* (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a
* single element, the number of elements is return in number.
diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h
index 08a0544..614c4b2 100644
--- a/sys/dev/ofw/openfirm.h
+++ b/sys/dev/ofw/openfirm.h
@@ -104,6 +104,8 @@ phandle_t OF_parent(phandle_t node);
ssize_t OF_getproplen(phandle_t node, const char *propname);
ssize_t OF_getprop(phandle_t node, const char *propname, void *buf,
size_t len);
+ssize_t OF_searchprop(phandle_t node, char *propname, void *buf,
+ size_t len);
ssize_t OF_getprop_alloc(phandle_t node, const char *propname,
int elsz, void **buf);
int OF_nextprop(phandle_t node, const char *propname, char *buf,
diff --git a/sys/powerpc/powermac/grackle.c b/sys/powerpc/powermac/grackle.c
index 9dd796d..fc323bf 100644
--- a/sys/powerpc/powermac/grackle.c
+++ b/sys/powerpc/powermac/grackle.c
@@ -165,7 +165,7 @@ static int
grackle_attach(device_t dev)
{
struct grackle_softc *sc;
- phandle_t node, iparent;
+ phandle_t node;
u_int32_t busrange[2];
struct grackle_range *rp, *io, *mem[2];
int nmem, i, error;
@@ -254,14 +254,6 @@ grackle_attach(device_t dev)
ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
- /* We need the number of interrupt cells to read the imap */
- if (OF_getprop(node, "interrupt-parent", &iparent,sizeof(iparent)) <= 0)
- iparent = node;
-
- if (OF_getprop(iparent,"#interrupt-cells",&sc->sc_icells,
- sizeof(sc->sc_icells)) <= 0)
- sc->sc_icells = 1;
-
device_add_child(dev, "pci", device_get_unit(dev));
return (bus_generic_attach(dev));
}
@@ -348,15 +340,14 @@ grackle_route_interrupt(device_t bus, device_t dev, int pin)
{
struct grackle_softc *sc;
struct ofw_pci_register reg;
- uint32_t pintr, mintr[2];
+ uint32_t pintr, mintr;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
- sizeof(reg), &pintr, sizeof(pintr), &mintr,
- sizeof(mintr[0])*sc->sc_icells, maskbuf))
- return (mintr[0]);
+ sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf))
+ return (mintr);
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
diff --git a/sys/powerpc/powermac/gracklevar.h b/sys/powerpc/powermac/gracklevar.h
index 78461d8..8d58c0a 100644
--- a/sys/powerpc/powermac/gracklevar.h
+++ b/sys/powerpc/powermac/gracklevar.h
@@ -52,7 +52,6 @@ struct grackle_softc {
struct rman sc_mem_rman;
bus_space_tag_t sc_memt;
bus_dma_tag_t sc_dmat;
- int sc_icells;
struct ofw_bus_iinfo sc_pci_iinfo;
};
diff --git a/sys/powerpc/powermac/macio.c b/sys/powerpc/powermac/macio.c
index 71be113..5c17925 100644
--- a/sys/powerpc/powermac/macio.c
+++ b/sys/powerpc/powermac/macio.c
@@ -185,7 +185,6 @@ macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
{
int *intr;
int i, nintr;
- phandle_t iparent;
int icells;
if (dinfo->mdi_ninterrupts >= 6) {
@@ -193,10 +192,9 @@ macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
return;
}
- icells = 1;
-
- if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent)) == sizeof(iparent))
- OF_getprop(iparent, "#interrupt-cells", &icells, sizeof(icells));
+ if (OF_searchprop(devnode, "#interrupt-cells", &icells, sizeof(icells))
+ <= 0)
+ icells = 1;
nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr),
(void **)&intr);
diff --git a/sys/powerpc/powermac/uninorth.c b/sys/powerpc/powermac/uninorth.c
index b0b55a4..d9de1af 100644
--- a/sys/powerpc/powermac/uninorth.c
+++ b/sys/powerpc/powermac/uninorth.c
@@ -164,7 +164,7 @@ uninorth_attach(device_t dev)
{
struct uninorth_softc *sc;
const char *compatible;
- phandle_t node, child, iparent;
+ phandle_t node, child;
u_int32_t reg[2], busrange[2];
struct uninorth_range *rp, *io, *mem[2];
int nmem, i, error;
@@ -296,12 +296,6 @@ uninorth_attach(device_t dev)
ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
- /* We need the number of interrupt cells to read the imap */
- sc->sc_icells = 2;
- if (OF_getprop(node, "interrupt-parent", &iparent,sizeof(iparent)) > 0)
- OF_getprop(iparent,"#interrupt-cells",&sc->sc_icells,
- sizeof(sc->sc_icells));
-
device_add_child(dev, "pci", device_get_unit(dev));
return (bus_generic_attach(dev));
}
@@ -370,15 +364,14 @@ uninorth_route_interrupt(device_t bus, device_t dev, int pin)
{
struct uninorth_softc *sc;
struct ofw_pci_register reg;
- uint32_t pintr, mintr[2];
+ uint32_t pintr, mintr;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
- sizeof(reg), &pintr, sizeof(pintr), mintr,
- sizeof(mintr[0])*sc->sc_icells, maskbuf))
- return (mintr[0]);
+ sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf))
+ return (mintr);
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
diff --git a/sys/powerpc/powermac/uninorthvar.h b/sys/powerpc/powermac/uninorthvar.h
index 6bb4024..4480eb8 100644
--- a/sys/powerpc/powermac/uninorthvar.h
+++ b/sys/powerpc/powermac/uninorthvar.h
@@ -64,7 +64,6 @@ struct uninorth_softc {
struct ofw_bus_iinfo sc_pci_iinfo;
int sc_u3;
- int sc_icells;
};
struct unin_chip_softc {
OpenPOWER on IntegriCloud