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 ++ sys/powerpc/powermac/grackle.c | 17 ++++------------- sys/powerpc/powermac/gracklevar.h | 1 - sys/powerpc/powermac/macio.c | 8 +++----- sys/powerpc/powermac/uninorth.c | 15 ++++----------- sys/powerpc/powermac/uninorthvar.h | 1 - 8 files changed, 35 insertions(+), 49 deletions(-) (limited to 'sys') 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, diff --git a/sys/powerpc/powermac/grackle.c b/sys/powerpc/powermac/grackle.c index 9dd796d33a4e..fc323bf5ba9a 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, ®, - 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 78461d88ae7f..8d58c0acbd28 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 71be1136ccc7..5c17925d5f0f 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 b0b55a4d161d..d9de1afcf97d 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, ®, - 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 6bb4024fbb6b..4480eb840e0d 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 { -- cgit v1.2.3