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:
parent
f613b2d3b1
commit
bbc6da03ef
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=261351
@ -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);
|
||||
}
|
||||
|
@ -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, ®,
|
||||
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,
|
||||
®, 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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -273,9 +273,7 @@ ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
|
||||
&sc->sc_pci_iinfo, ®, 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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 *
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user