Open Firmware interrupt specifiers can consist of arbitrary-length byte

strings and include arbitrary information (IRQ line/domain/sense). When the
ofw_bus_map_intr() API was introduced, it assumed that, as on most systems,
these were either 1 cell, containing an interrupt line, or 2, containing
a line number plus a sense code. It turns out a non-negligible number of
ARM systems use 3 (or even 4!) cells for interrupts, so make this more
general.
This commit is contained in:
Nathan Whitehorn 2014-02-01 17:17:35 +00:00
parent f613b2d3b1
commit bbc6da03ef
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=261351
11 changed files with 54 additions and 88 deletions

View File

@ -98,7 +98,7 @@ static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
#ifdef FDT
static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
int irq);
int icells, pcell_t *intr);
#endif
static device_method_t nexus_methods[] = {
@ -339,15 +339,16 @@ nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
#ifdef FDT
static int
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int irq)
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
pcell_t *intr)
{
pcell_t intr[2];
fdt_pic_decode_t intr_decode;
phandle_t intr_offset;
int i, rv, interrupt, trig, pol;
intr_offset = OF_xref_phandle(iparent);
intr[0] = cpu_to_fdt32(irq);
for (i = 0; i < icells; i++)
intr[i] = cpu_to_fdt32(intr[i]);
for (i = 0; fdt_pic_table[i] != NULL; i++) {
intr_decode = fdt_pic_table[i];
@ -355,13 +356,13 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int irq)
if (rv == 0) {
/* This was recognized as our PIC and decoded. */
interrupt = FDT_MAP_IRQ(intr_parent, interrupt);
interrupt = FDT_MAP_IRQ(intr_parent, intr[0]);
return (interrupt);
}
}
/* Not in table, so guess */
interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(*intr));
interrupt = FDT_MAP_IRQ(intr_parent, intr[0]);
return (interrupt);
}

View File

@ -1050,7 +1050,8 @@ mv_pcib_route_interrupt(device_t bus, device_t dev, int pin)
{
struct mv_pcib_softc *sc;
struct ofw_pci_register reg;
uint32_t pintr, mintr;
uint32_t pintr, mintr[4];
int icells;
phandle_t iparent;
sc = device_get_softc(bus);
@ -1062,10 +1063,11 @@ mv_pcib_route_interrupt(device_t bus, device_t dev, int pin)
(pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
&iparent))
return (ofw_bus_map_intr(dev, iparent, mintr));
icells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
&reg, sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr),
&iparent);
if (icells > 0)
return (ofw_bus_map_intr(dev, iparent, icells, mintr));
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)

View File

@ -501,11 +501,9 @@ fdt_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl,
icells = 1;
}
for (i = 0, k = 0; i < nintr; i += icells, k++) {
intr[i] = ofw_bus_map_intr(dev, iparent, intr[i]);
intr[i] = ofw_bus_map_intr(dev, iparent, icells, intr);
resource_list_add(rl, SYS_RES_IRQ, k, intr[i], intr[i],
1);
if (icells > 1)
ofw_bus_config_intr(dev, intr[i], intr[i+1]);
}
free(intr, M_OFWPROP);
}

View File

@ -71,15 +71,9 @@ ofw_bus_get_type(device_t dev)
}
static __inline int
ofw_bus_map_intr(device_t dev, phandle_t iparent, int irq)
ofw_bus_map_intr(device_t dev, phandle_t iparent, int icells, pcell_t *intr)
{
return (OFW_BUS_MAP_INTR(dev, dev, iparent, irq));
}
static __inline int
ofw_bus_config_intr(device_t dev, int irq, int sense)
{
return (OFW_BUS_CONFIG_INTR(dev, dev, irq, sense));
return (OFW_BUS_MAP_INTR(dev, dev, iparent, icells, intr));
}
#endif /* !_DEV_OFW_OFW_BUS_H_ */

View File

@ -57,7 +57,6 @@ CODE {
static ofw_bus_get_node_t ofw_bus_default_get_node;
static ofw_bus_get_type_t ofw_bus_default_get_type;
static ofw_bus_map_intr_t ofw_bus_default_map_intr;
static ofw_bus_config_intr_t ofw_bus_default_config_intr;
static const struct ofw_bus_devinfo *
ofw_bus_default_get_devinfo(device_t bus, device_t dev)
@ -103,27 +102,15 @@ CODE {
int
ofw_bus_default_map_intr(device_t bus, device_t dev, phandle_t iparent,
int irq)
int icells, pcell_t *interrupt)
{
/* Propagate up the bus hierarchy until someone handles it. */
if (device_get_parent(bus) != NULL)
return OFW_BUS_MAP_INTR(device_get_parent(bus), dev,
iparent, irq);
iparent, icells, interrupt);
/* If that fails, then assume a one-domain system */
return (irq);
}
int
ofw_bus_default_config_intr(device_t bus, device_t dev, int irq,
int sense)
{
/* Propagate up the bus hierarchy until someone handles it. */
if (device_get_parent(bus) != NULL)
return OFW_BUS_CONFIG_INTR(device_get_parent(bus), dev,
irq, sense);
return (ENXIO);
return (interrupt[0]);
}
};
@ -172,20 +159,14 @@ METHOD const char * get_type {
} DEFAULT ofw_bus_default_get_type;
# Map an (interrupt parent, IRQ) pair to a unique system-wide interrupt number.
# If the interrupt encoding includes a sense field, the interrupt sense will
# also be configured.
METHOD int map_intr {
device_t bus;
device_t dev;
phandle_t iparent;
int irq;
int icells;
pcell_t *interrupt;
} DEFAULT ofw_bus_default_map_intr;
# Configure an interrupt using the device-tree encoded sense key (the second
# value in the interrupts property if interrupt-cells is 2). IRQ should be
# encoded as from ofw_bus_map_intr().
METHOD int config_intr {
device_t bus;
device_t dev;
int irq;
int sense;
} DEFAULT ofw_bus_default_config_intr;

View File

@ -467,11 +467,10 @@ nexus_setup_dinfo(device_t dev, phandle_t node)
OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells",
&icells, sizeof(icells));
for (i = 0; i < nintr; i+= icells) {
intr[i] = ofw_bus_map_intr(dev, iparent, intr[i]);
intr[i] = ofw_bus_map_intr(dev, iparent, icells,
&intr[i]);
resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i],
intr[i], 1);
if (icells > 1)
ofw_bus_config_intr(dev, intr[i], intr[i+1]);
}
free(intr, M_OFWPROP);
}

View File

@ -273,9 +273,7 @@ ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
&sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
mintr, sizeof(mintr), &iparent);
if (intrcells) {
pintr = ofw_bus_map_intr(dev, iparent, mintr[0]);
if (intrcells == 2)
ofw_bus_config_intr(dev, pintr, mintr[1]);
pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
return (pintr);
}

View File

@ -158,10 +158,8 @@ ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
* it again on higher levels - that causes problems
* in some cases, and never seems to be required.
*/
mintr[0] = ofw_bus_map_intr(dev, iparent, mintr[0]);
if (intrcells == 2)
ofw_bus_config_intr(dev, mintr[0], mintr[1]);
mintr[0] = ofw_bus_map_intr(dev, iparent, intrcells,
mintr);
return (mintr[0]);
}
} else if (intpin >= 1 && intpin <= 4) {

View File

@ -216,13 +216,9 @@ ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
"#interrupt-cells", &icells,
sizeof(icells));
intr[0] = ofw_bus_map_intr(dev, iparent,
intr[0]);
icells, intr);
}
if (iparent != 0 && icells > 1)
ofw_bus_config_intr(dev, intr[0],
intr[1]);
resource_list_add(&dinfo->opd_dinfo.resources,
SYS_RES_IRQ, 0, intr[0], intr[0], 1);
}
@ -309,18 +305,18 @@ ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf,
static int
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
{
ofw_pci_intr_t intr;
ofw_pci_intr_t intr[2];
phandle_t node, iparent;
int isz;
int isz, icells;
node = ofw_bus_get_node(child);
if (node == -1) {
/* Non-firmware enumerated child, use standard routing */
intr = pci_get_intpin(child);
intr[0] = pci_get_intpin(child);
return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child,
intr));
intr[0]));
}
/*
@ -331,24 +327,28 @@ ofw_pcibus_assign_interrupt(device_t dev, device_t child)
iparent = -1;
if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
iparent = -1;
icells = 1;
if (iparent != -1)
OF_getprop(OF_xref_phandle(iparent), "#interrupt-cells",
&icells, sizeof(icells));
/*
* Any AAPL,interrupts property gets priority and is
* fully specified (i.e. does not need routing)
*/
isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr));
if (isz == sizeof(intr))
return ((iparent == -1) ? intr : ofw_bus_map_intr(dev, iparent,
intr));
isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr));
if (isz == sizeof(intr[0])*icells)
return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev,
iparent, icells, intr));
isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
if (isz == sizeof(intr)) {
isz = OF_getprop(node, "interrupts", intr, sizeof(intr));
if (isz == sizeof(intr[0])*icells) {
if (iparent != -1)
intr = ofw_bus_map_intr(dev, iparent, intr);
intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr);
} else {
/* No property: our best guess is the intpin. */
intr = pci_get_intpin(child);
intr[0] = pci_get_intpin(child);
}
/*
@ -361,7 +361,7 @@ ofw_pcibus_assign_interrupt(device_t dev, device_t child)
* will always use the route_interrupt method, and treat exceptions
* on the level they become apparent.
*/
return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr));
return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0]));
}
static const struct ofw_bus_devinfo *

View File

@ -75,7 +75,6 @@ static bus_bind_intr_t nexus_bind_intr;
#endif
static bus_config_intr_t nexus_config_intr;
static ofw_bus_map_intr_t nexus_ofw_map_intr;
static ofw_bus_config_intr_t nexus_ofw_config_intr;
static device_method_t nexus_methods[] = {
/* Bus interface */
@ -90,7 +89,6 @@ static device_method_t nexus_methods[] = {
/* ofw_bus interface */
DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr),
DEVMETHOD(ofw_bus_config_intr, nexus_ofw_config_intr),
DEVMETHOD_END
};
@ -157,18 +155,15 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
}
static int
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int irq)
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
pcell_t *irq)
{
return (MAP_IRQ(iparent, irq));
u_int intr = MAP_IRQ(iparent, irq[0]);
if (icells > 1)
powerpc_fw_config_intr(irq[0], irq[1]);
return (intr);
}
static int
nexus_ofw_config_intr(device_t dev, device_t child, int irq, int sense)
{
return (powerpc_fw_config_intr(irq, sense));
}
static int
nexus_activate_resource(device_t bus __unused, device_t child __unused,
int type, int rid __unused, struct resource *r)

View File

@ -157,7 +157,7 @@ vdevice_attach(device_t dev)
u_int irq = intr[i];
if (iparent != -1)
irq = ofw_bus_map_intr(dev, iparent,
intr[i]);
icells, &intr[i]);
resource_list_add(&dinfo->mdi_resources,
SYS_RES_IRQ, i, irq, irq, i);