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
This commit is contained in:
Nathan Whitehorn 2009-01-03 19:38:47 +00:00
parent a79bdfef68
commit acb97117e3
8 changed files with 35 additions and 49 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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;
};

View File

@ -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);

View File

@ -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)

View File

@ -64,7 +64,6 @@ struct uninorth_softc {
struct ofw_bus_iinfo sc_pci_iinfo;
int sc_u3;
int sc_icells;
};
struct unin_chip_softc {