mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
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
|
#ifdef FDT
|
||||||
static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
|
static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent,
|
||||||
int irq);
|
int icells, pcell_t *intr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static device_method_t nexus_methods[] = {
|
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
|
#ifdef FDT
|
||||||
static int
|
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;
|
fdt_pic_decode_t intr_decode;
|
||||||
phandle_t intr_offset;
|
phandle_t intr_offset;
|
||||||
int i, rv, interrupt, trig, pol;
|
int i, rv, interrupt, trig, pol;
|
||||||
|
|
||||||
intr_offset = OF_xref_phandle(iparent);
|
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++) {
|
for (i = 0; fdt_pic_table[i] != NULL; i++) {
|
||||||
intr_decode = fdt_pic_table[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) {
|
if (rv == 0) {
|
||||||
/* This was recognized as our PIC and decoded. */
|
/* 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);
|
return (interrupt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not in table, so guess */
|
/* 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);
|
return (interrupt);
|
||||||
}
|
}
|
||||||
|
@ -1050,7 +1050,8 @@ mv_pcib_route_interrupt(device_t bus, device_t dev, int pin)
|
|||||||
{
|
{
|
||||||
struct mv_pcib_softc *sc;
|
struct mv_pcib_softc *sc;
|
||||||
struct ofw_pci_register reg;
|
struct ofw_pci_register reg;
|
||||||
uint32_t pintr, mintr;
|
uint32_t pintr, mintr[4];
|
||||||
|
int icells;
|
||||||
phandle_t iparent;
|
phandle_t iparent;
|
||||||
|
|
||||||
sc = device_get_softc(bus);
|
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_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
|
||||||
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
|
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
|
||||||
|
|
||||||
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®,
|
icells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
|
||||||
sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
|
®, sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr),
|
||||||
&iparent))
|
&iparent);
|
||||||
return (ofw_bus_map_intr(dev, iparent, mintr));
|
if (icells > 0)
|
||||||
|
return (ofw_bus_map_intr(dev, iparent, icells, mintr));
|
||||||
|
|
||||||
/* Maybe it's a real interrupt, not an intpin */
|
/* Maybe it's a real interrupt, not an intpin */
|
||||||
if (pin > 4)
|
if (pin > 4)
|
||||||
|
@ -501,11 +501,9 @@ fdt_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl,
|
|||||||
icells = 1;
|
icells = 1;
|
||||||
}
|
}
|
||||||
for (i = 0, k = 0; i < nintr; i += icells, k++) {
|
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],
|
resource_list_add(rl, SYS_RES_IRQ, k, intr[i], intr[i],
|
||||||
1);
|
1);
|
||||||
if (icells > 1)
|
|
||||||
ofw_bus_config_intr(dev, intr[i], intr[i+1]);
|
|
||||||
}
|
}
|
||||||
free(intr, M_OFWPROP);
|
free(intr, M_OFWPROP);
|
||||||
}
|
}
|
||||||
|
@ -71,15 +71,9 @@ ofw_bus_get_type(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static __inline int
|
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));
|
return (OFW_BUS_MAP_INTR(dev, dev, iparent, icells, intr));
|
||||||
}
|
|
||||||
|
|
||||||
static __inline int
|
|
||||||
ofw_bus_config_intr(device_t dev, int irq, int sense)
|
|
||||||
{
|
|
||||||
return (OFW_BUS_CONFIG_INTR(dev, dev, irq, sense));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !_DEV_OFW_OFW_BUS_H_ */
|
#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_node_t ofw_bus_default_get_node;
|
||||||
static ofw_bus_get_type_t ofw_bus_default_get_type;
|
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_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 *
|
static const struct ofw_bus_devinfo *
|
||||||
ofw_bus_default_get_devinfo(device_t bus, device_t dev)
|
ofw_bus_default_get_devinfo(device_t bus, device_t dev)
|
||||||
@ -103,27 +102,15 @@ CODE {
|
|||||||
|
|
||||||
int
|
int
|
||||||
ofw_bus_default_map_intr(device_t bus, device_t dev, phandle_t iparent,
|
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. */
|
/* Propagate up the bus hierarchy until someone handles it. */
|
||||||
if (device_get_parent(bus) != NULL)
|
if (device_get_parent(bus) != NULL)
|
||||||
return OFW_BUS_MAP_INTR(device_get_parent(bus), dev,
|
return OFW_BUS_MAP_INTR(device_get_parent(bus), dev,
|
||||||
iparent, irq);
|
iparent, icells, interrupt);
|
||||||
|
|
||||||
/* If that fails, then assume a one-domain system */
|
/* If that fails, then assume a one-domain system */
|
||||||
return (irq);
|
return (interrupt[0]);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -172,20 +159,14 @@ METHOD const char * get_type {
|
|||||||
} DEFAULT ofw_bus_default_get_type;
|
} DEFAULT ofw_bus_default_get_type;
|
||||||
|
|
||||||
# Map an (interrupt parent, IRQ) pair to a unique system-wide interrupt number.
|
# 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 {
|
METHOD int map_intr {
|
||||||
device_t bus;
|
device_t bus;
|
||||||
device_t dev;
|
device_t dev;
|
||||||
phandle_t iparent;
|
phandle_t iparent;
|
||||||
int irq;
|
int icells;
|
||||||
|
pcell_t *interrupt;
|
||||||
} DEFAULT ofw_bus_default_map_intr;
|
} 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",
|
OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells",
|
||||||
&icells, sizeof(icells));
|
&icells, sizeof(icells));
|
||||||
for (i = 0; i < nintr; i+= 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],
|
resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i],
|
||||||
intr[i], 1);
|
intr[i], 1);
|
||||||
if (icells > 1)
|
|
||||||
ofw_bus_config_intr(dev, intr[i], intr[i+1]);
|
|
||||||
}
|
}
|
||||||
free(intr, M_OFWPROP);
|
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),
|
&sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr),
|
||||||
mintr, sizeof(mintr), &iparent);
|
mintr, sizeof(mintr), &iparent);
|
||||||
if (intrcells) {
|
if (intrcells) {
|
||||||
pintr = ofw_bus_map_intr(dev, iparent, mintr[0]);
|
pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
|
||||||
if (intrcells == 2)
|
|
||||||
ofw_bus_config_intr(dev, pintr, mintr[1]);
|
|
||||||
return (pintr);
|
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
|
* it again on higher levels - that causes problems
|
||||||
* in some cases, and never seems to be required.
|
* in some cases, and never seems to be required.
|
||||||
*/
|
*/
|
||||||
mintr[0] = ofw_bus_map_intr(dev, iparent, mintr[0]);
|
mintr[0] = ofw_bus_map_intr(dev, iparent, intrcells,
|
||||||
if (intrcells == 2)
|
mintr);
|
||||||
ofw_bus_config_intr(dev, mintr[0], mintr[1]);
|
|
||||||
|
|
||||||
return (mintr[0]);
|
return (mintr[0]);
|
||||||
}
|
}
|
||||||
} else if (intpin >= 1 && intpin <= 4) {
|
} 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,
|
"#interrupt-cells", &icells,
|
||||||
sizeof(icells));
|
sizeof(icells));
|
||||||
intr[0] = ofw_bus_map_intr(dev, iparent,
|
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,
|
resource_list_add(&dinfo->opd_dinfo.resources,
|
||||||
SYS_RES_IRQ, 0, intr[0], intr[0], 1);
|
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
|
static int
|
||||||
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
|
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;
|
phandle_t node, iparent;
|
||||||
int isz;
|
int isz, icells;
|
||||||
|
|
||||||
node = ofw_bus_get_node(child);
|
node = ofw_bus_get_node(child);
|
||||||
|
|
||||||
if (node == -1) {
|
if (node == -1) {
|
||||||
/* Non-firmware enumerated child, use standard routing */
|
/* 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,
|
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;
|
iparent = -1;
|
||||||
if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
|
if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
|
||||||
iparent = -1;
|
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
|
* Any AAPL,interrupts property gets priority and is
|
||||||
* fully specified (i.e. does not need routing)
|
* fully specified (i.e. does not need routing)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr));
|
isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr));
|
||||||
if (isz == sizeof(intr))
|
if (isz == sizeof(intr[0])*icells)
|
||||||
return ((iparent == -1) ? intr : ofw_bus_map_intr(dev, iparent,
|
return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev,
|
||||||
intr));
|
iparent, icells, intr));
|
||||||
|
|
||||||
isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
|
isz = OF_getprop(node, "interrupts", intr, sizeof(intr));
|
||||||
if (isz == sizeof(intr)) {
|
if (isz == sizeof(intr[0])*icells) {
|
||||||
if (iparent != -1)
|
if (iparent != -1)
|
||||||
intr = ofw_bus_map_intr(dev, iparent, intr);
|
intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr);
|
||||||
} else {
|
} else {
|
||||||
/* No property: our best guess is the intpin. */
|
/* 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
|
* will always use the route_interrupt method, and treat exceptions
|
||||||
* on the level they become apparent.
|
* 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 *
|
static const struct ofw_bus_devinfo *
|
||||||
|
@ -75,7 +75,6 @@ static bus_bind_intr_t nexus_bind_intr;
|
|||||||
#endif
|
#endif
|
||||||
static bus_config_intr_t nexus_config_intr;
|
static bus_config_intr_t nexus_config_intr;
|
||||||
static ofw_bus_map_intr_t nexus_ofw_map_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[] = {
|
static device_method_t nexus_methods[] = {
|
||||||
/* Bus interface */
|
/* Bus interface */
|
||||||
@ -90,7 +89,6 @@ static device_method_t nexus_methods[] = {
|
|||||||
|
|
||||||
/* ofw_bus interface */
|
/* ofw_bus interface */
|
||||||
DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr),
|
DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr),
|
||||||
DEVMETHOD(ofw_bus_config_intr, nexus_ofw_config_intr),
|
|
||||||
|
|
||||||
DEVMETHOD_END
|
DEVMETHOD_END
|
||||||
};
|
};
|
||||||
@ -157,18 +155,15 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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
|
static int
|
||||||
nexus_activate_resource(device_t bus __unused, device_t child __unused,
|
nexus_activate_resource(device_t bus __unused, device_t child __unused,
|
||||||
int type, int rid __unused, struct resource *r)
|
int type, int rid __unused, struct resource *r)
|
||||||
|
@ -157,7 +157,7 @@ vdevice_attach(device_t dev)
|
|||||||
u_int irq = intr[i];
|
u_int irq = intr[i];
|
||||||
if (iparent != -1)
|
if (iparent != -1)
|
||||||
irq = ofw_bus_map_intr(dev, iparent,
|
irq = ofw_bus_map_intr(dev, iparent,
|
||||||
intr[i]);
|
icells, &intr[i]);
|
||||||
|
|
||||||
resource_list_add(&dinfo->mdi_resources,
|
resource_list_add(&dinfo->mdi_resources,
|
||||||
SYS_RES_IRQ, i, irq, irq, i);
|
SYS_RES_IRQ, i, irq, irq, i);
|
||||||
|
Loading…
Reference in New Issue
Block a user