mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-11 09:50:12 +00:00
Replace multiple nearly-identical copies of code to walk through an FDT
node's interrupts=<...> property creating resource list entries with a single common implementation. This change makes ofw_bus_intr_to_rl() the one true copy of that code and removes the copies of it from other places. This also adds handling of the interrupts-extended property, which allows specifying multiple interrupts for a node where each interrupt can have a separate interrupt-parent. The bindings for this state that the property cells contain an xref phandle to the interrupt parent followed by whatever interrupt info that parent normally expects. This leads to having a variable number of icells per interrupt in the property. For example you could have <&intc1 1 &intc2 26 9 0 &intc3 9 4>. Differential Revision: https://reviews.freebsd.org/D803
This commit is contained in:
parent
89b95481b4
commit
c47d4cde39
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272109
@ -493,46 +493,6 @@ fdt_reg_to_rl(phandle_t node, struct resource_list *rl)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
fdt_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl,
|
||||
struct fdt_sense_level *intr_sl)
|
||||
{
|
||||
phandle_t iparent;
|
||||
uint32_t *intr, icells;
|
||||
int nintr, i, k;
|
||||
|
||||
nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr),
|
||||
(void **)&intr);
|
||||
if (nintr > 0) {
|
||||
if (OF_searchencprop(node, "interrupt-parent", &iparent,
|
||||
sizeof(iparent)) == -1) {
|
||||
device_printf(dev, "No interrupt-parent found, "
|
||||
"assuming direct parent\n");
|
||||
iparent = OF_parent(node);
|
||||
}
|
||||
if (OF_searchencprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
|
||||
device_printf(dev, "Missing #interrupt-cells property, "
|
||||
"assuming <1>\n");
|
||||
icells = 1;
|
||||
}
|
||||
if (icells < 1 || icells > nintr) {
|
||||
device_printf(dev, "Invalid #interrupt-cells property "
|
||||
"value <%d>, assuming <1>\n", icells);
|
||||
icells = 1;
|
||||
}
|
||||
for (i = 0, k = 0; i < nintr; i += icells, k++) {
|
||||
intr[i] = ofw_bus_map_intr(dev, iparent, icells,
|
||||
&intr[i]);
|
||||
resource_list_add(rl, SYS_RES_IRQ, k, intr[i], intr[i],
|
||||
1);
|
||||
}
|
||||
free(intr, M_OFWPROP);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
|
||||
{
|
||||
|
@ -88,7 +88,6 @@ int fdt_get_phyaddr(phandle_t, device_t, int *, void **);
|
||||
int fdt_get_range(phandle_t, int, u_long *, u_long *);
|
||||
int fdt_immr_addr(vm_offset_t);
|
||||
int fdt_regsize(phandle_t, u_long *, u_long *);
|
||||
int fdt_intr_to_rl(device_t, phandle_t, struct resource_list *, struct fdt_sense_level *);
|
||||
int fdt_is_compatible(phandle_t, const char *);
|
||||
int fdt_is_compatible_strict(phandle_t, const char *);
|
||||
int fdt_is_enabled(phandle_t);
|
||||
|
@ -247,11 +247,9 @@ simplebus_setup_dinfo(device_t dev, phandle_t node)
|
||||
{
|
||||
struct simplebus_softc *sc;
|
||||
struct simplebus_devinfo *ndi;
|
||||
uint32_t *reg, *intr, icells;
|
||||
uint32_t *reg;
|
||||
uint64_t phys, size;
|
||||
phandle_t iparent;
|
||||
int i, j, k;
|
||||
int nintr;
|
||||
int nreg;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
@ -289,34 +287,7 @@ simplebus_setup_dinfo(device_t dev, phandle_t node)
|
||||
}
|
||||
free(reg, M_OFWPROP);
|
||||
|
||||
nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr),
|
||||
(void **)&intr);
|
||||
if (nintr > 0) {
|
||||
if (OF_searchencprop(node, "interrupt-parent", &iparent,
|
||||
sizeof(iparent)) == -1) {
|
||||
device_printf(dev, "No interrupt-parent found, "
|
||||
"assuming direct parent\n");
|
||||
iparent = OF_parent(node);
|
||||
}
|
||||
if (OF_searchencprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
|
||||
device_printf(dev, "Missing #interrupt-cells property, "
|
||||
"assuming <1>\n");
|
||||
icells = 1;
|
||||
}
|
||||
if (icells < 1 || icells > nintr) {
|
||||
device_printf(dev, "Invalid #interrupt-cells property "
|
||||
"value <%d>, assuming <1>\n", icells);
|
||||
icells = 1;
|
||||
}
|
||||
for (i = 0, k = 0; i < nintr; i += icells, k++) {
|
||||
intr[i] = ofw_bus_map_intr(dev, iparent, icells,
|
||||
&intr[i]);
|
||||
resource_list_add(&ndi->rl, SYS_RES_IRQ, k, intr[i],
|
||||
intr[i], 1);
|
||||
}
|
||||
free(intr, M_OFWPROP);
|
||||
}
|
||||
ofw_bus_intr_to_rl(dev, node, &ndi->rl);
|
||||
|
||||
return (ndi);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/errno.h>
|
||||
#include <sys/libkern.h>
|
||||
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
@ -367,3 +369,64 @@ ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl)
|
||||
{
|
||||
phandle_t iparent;
|
||||
uint32_t icells, *intr;
|
||||
int err, i, irqnum, nintr, rid;
|
||||
boolean_t extended;
|
||||
|
||||
nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr),
|
||||
(void **)&intr);
|
||||
if (nintr > 0) {
|
||||
if (OF_searchencprop(node, "interrupt-parent", &iparent,
|
||||
sizeof(iparent)) == -1) {
|
||||
device_printf(dev, "No interrupt-parent found, "
|
||||
"assuming direct parent\n");
|
||||
iparent = OF_parent(node);
|
||||
}
|
||||
if (OF_searchencprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
|
||||
device_printf(dev, "Missing #interrupt-cells "
|
||||
"property, assuming <1>\n");
|
||||
icells = 1;
|
||||
}
|
||||
if (icells < 1 || icells > nintr) {
|
||||
device_printf(dev, "Invalid #interrupt-cells property "
|
||||
"value <%d>, assuming <1>\n", icells);
|
||||
icells = 1;
|
||||
}
|
||||
extended = false;
|
||||
} else {
|
||||
nintr = OF_getencprop_alloc(node, "interrupts-extended",
|
||||
sizeof(*intr), (void **)&intr);
|
||||
if (nintr <= 0)
|
||||
return (0);
|
||||
extended = true;
|
||||
}
|
||||
err = 0;
|
||||
rid = 0;
|
||||
for (i = 0; i < nintr; i += icells) {
|
||||
if (extended) {
|
||||
iparent = intr[i++];
|
||||
if (OF_searchencprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
|
||||
device_printf(dev, "Missing #interrupt-cells "
|
||||
"property\n");
|
||||
err = ENOENT;
|
||||
break;
|
||||
}
|
||||
if (icells < 1 || (i + icells) > nintr) {
|
||||
device_printf(dev, "Invalid #interrupt-cells "
|
||||
"property value <%d>\n", icells);
|
||||
err = ERANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
|
||||
resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
|
||||
}
|
||||
free(intr, M_OFWPROP);
|
||||
return (err);
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int,
|
||||
int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *,
|
||||
void *, void *, int, phandle_t *);
|
||||
|
||||
/* Routines for parsing device-tree data into resource lists. */
|
||||
int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *);
|
||||
|
||||
/* Helper to get device status property */
|
||||
const char *ofw_bus_get_status(device_t dev);
|
||||
int ofw_bus_status_okay(device_t dev);
|
||||
|
@ -436,11 +436,9 @@ ofwbus_setup_dinfo(device_t dev, phandle_t node)
|
||||
struct ofwbus_softc *sc;
|
||||
struct ofwbus_devinfo *ndi;
|
||||
const char *nodename;
|
||||
uint32_t *reg, *intr, icells;
|
||||
uint32_t *reg;
|
||||
uint64_t phys, size;
|
||||
phandle_t iparent;
|
||||
int i, j, rid;
|
||||
int nintr;
|
||||
int nreg;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
@ -485,35 +483,7 @@ ofwbus_setup_dinfo(device_t dev, phandle_t node)
|
||||
}
|
||||
free(reg, M_OFWPROP);
|
||||
|
||||
nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr),
|
||||
(void **)&intr);
|
||||
if (nintr > 0) {
|
||||
if (OF_searchencprop(node, "interrupt-parent", &iparent,
|
||||
sizeof(iparent)) == -1) {
|
||||
device_printf(dev, "No interrupt-parent found, "
|
||||
"assuming nexus on <%s>\n", nodename);
|
||||
iparent = 0xffffffff;
|
||||
}
|
||||
if (OF_searchencprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
|
||||
device_printf(dev, "Missing #interrupt-cells property, "
|
||||
"assuming <1> on <%s>\n", nodename);
|
||||
icells = 1;
|
||||
}
|
||||
if (icells < 1 || icells > nintr) {
|
||||
device_printf(dev, "Invalid #interrupt-cells property "
|
||||
"value <%d>, assuming <1> on <%s>\n", icells,
|
||||
nodename);
|
||||
icells = 1;
|
||||
}
|
||||
for (i = 0, rid = 0; i < nintr; i += icells, rid++) {
|
||||
intr[i] = ofw_bus_map_intr(dev, iparent, icells,
|
||||
&intr[i]);
|
||||
resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, rid, intr[i],
|
||||
intr[i], 1);
|
||||
}
|
||||
free(intr, M_OFWPROP);
|
||||
}
|
||||
ofw_bus_intr_to_rl(dev, node, &ndi->ndi_rl);
|
||||
|
||||
return (ndi);
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ simplebus_attach(device_t dev)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fdt_intr_to_rl(dev, dt_child, &di->di_res, di->di_intr_sl)) {
|
||||
if (ofw_bus_intr_to_rl(dev, dt_child, &di->di_res)) {
|
||||
device_printf(dev, "%s: could not process "
|
||||
"'interrupts' property\n", di->di_ofw.obd_name);
|
||||
resource_list_free(&di->di_res);
|
||||
|
@ -200,29 +200,8 @@ ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
|
||||
* interrupts property, so add that value to the device's
|
||||
* resource list.
|
||||
*/
|
||||
if (dinfo->opd_dinfo.cfg.intpin == 0) {
|
||||
ofw_pci_intr_t intr[2];
|
||||
phandle_t iparent;
|
||||
int icells;
|
||||
|
||||
if (OF_getprop(child, "interrupts", &intr,
|
||||
sizeof(intr)) > 0) {
|
||||
iparent = 0;
|
||||
icells = 1;
|
||||
OF_getprop(child, "interrupt-parent", &iparent,
|
||||
sizeof(iparent));
|
||||
if (iparent != 0) {
|
||||
OF_getprop(OF_node_from_xref(iparent),
|
||||
"#interrupt-cells", &icells,
|
||||
sizeof(icells));
|
||||
intr[0] = ofw_bus_map_intr(dev, iparent,
|
||||
icells, intr);
|
||||
}
|
||||
|
||||
resource_list_add(&dinfo->opd_dinfo.resources,
|
||||
SYS_RES_IRQ, 0, intr[0], intr[0], 1);
|
||||
}
|
||||
}
|
||||
if (dinfo->opd_dinfo.cfg.intpin == 0)
|
||||
ofw_bus_intr_to_rl(dev, node, &dinfo->opd_dinfo.resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,8 +128,6 @@ vdevice_attach(device_t dev)
|
||||
{
|
||||
phandle_t root, child;
|
||||
device_t cdev;
|
||||
int icells, i, nintr, *intr;
|
||||
phandle_t iparent;
|
||||
struct vdevice_devinfo *dinfo;
|
||||
|
||||
root = ofw_bus_get_node(dev);
|
||||
@ -144,25 +142,7 @@ vdevice_attach(device_t dev)
|
||||
}
|
||||
resource_list_init(&dinfo->mdi_resources);
|
||||
|
||||
if (OF_searchprop(child, "#interrupt-cells", &icells,
|
||||
sizeof(icells)) <= 0)
|
||||
icells = 2;
|
||||
if (OF_getprop(child, "interrupt-parent", &iparent,
|
||||
sizeof(iparent)) <= 0)
|
||||
iparent = -1;
|
||||
nintr = OF_getprop_alloc(child, "interrupts", sizeof(*intr),
|
||||
(void **)&intr);
|
||||
if (nintr > 0) {
|
||||
for (i = 0; i < nintr; i += icells) {
|
||||
u_int irq = intr[i];
|
||||
if (iparent != -1)
|
||||
irq = ofw_bus_map_intr(dev, iparent,
|
||||
icells, &intr[i]);
|
||||
|
||||
resource_list_add(&dinfo->mdi_resources,
|
||||
SYS_RES_IRQ, i, irq, irq, i);
|
||||
}
|
||||
}
|
||||
ofw_bus_intr_to_rl(dev, child, &dinfo->mdi_resources);
|
||||
|
||||
cdev = device_add_child(dev, NULL, -1);
|
||||
if (cdev == NULL) {
|
||||
|
Loading…
Reference in New Issue
Block a user