From acb97117e373cd585ffae39245eb16f1dfcff33e Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sat, 3 Jan 2009 19:38:47 +0000 Subject: 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 --- sys/dev/ofw/ofw_bus_subr.c | 23 +++++------------------ sys/dev/ofw/openfirm.c | 17 +++++++++++++++++ sys/dev/ofw/openfirm.h | 2 ++ 3 files changed, 24 insertions(+), 18 deletions(-) (limited to 'sys/dev/ofw') diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c index 19de2b979e4c..1cc5207fb1b4 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 c7b220358aad..4c33c9f87b50 100644 --- a/sys/dev/ofw/openfirm.c +++ b/sys/dev/ofw/openfirm.c @@ -219,6 +219,23 @@ OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen) return (OFW_GETPROP(ofw_obj, package, propname, buf, 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 diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h index 08a05449fc7e..614c4b2daf92 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, -- cgit v1.2.3