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:
parent
a79bdfef68
commit
acb97117e3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -64,7 +64,6 @@ struct uninorth_softc {
|
||||
struct ofw_bus_iinfo sc_pci_iinfo;
|
||||
|
||||
int sc_u3;
|
||||
int sc_icells;
|
||||
};
|
||||
|
||||
struct unin_chip_softc {
|
||||
|
Loading…
x
Reference in New Issue
Block a user