summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-09-25 15:02:33 +0000
committerian <ian@FreeBSD.org>2014-09-25 15:02:33 +0000
commite2b20df1df60383594cba82c87a9e274a203c0e4 (patch)
tree8c05a95849482bf2011d96d0f963467525a2b01e
parent627f648fad5a4583afb310616c761bc7bd041878 (diff)
downloadFreeBSD-src-e2b20df1df60383594cba82c87a9e274a203c0e4.zip
FreeBSD-src-e2b20df1df60383594cba82c87a9e274a203c0e4.tar.gz
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
-rw-r--r--sys/dev/fdt/fdt_common.c40
-rw-r--r--sys/dev/fdt/fdt_common.h1
-rw-r--r--sys/dev/fdt/simplebus.c33
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c63
-rw-r--r--sys/dev/ofw/ofw_bus_subr.h3
-rw-r--r--sys/dev/ofw/ofwbus.c34
-rw-r--r--sys/mips/beri/beri_simplebus.c2
-rw-r--r--sys/powerpc/ofw/ofw_pcibus.c25
-rw-r--r--sys/powerpc/pseries/vdevice.c22
9 files changed, 74 insertions, 149 deletions
diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c
index 77cf8ba..9d0c0f0 100644
--- a/sys/dev/fdt/fdt_common.c
+++ b/sys/dev/fdt/fdt_common.c
@@ -494,46 +494,6 @@ out:
}
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)
{
phandle_t phy_node;
diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h
index d306f65..0a79ce0 100644
--- a/sys/dev/fdt/fdt_common.h
+++ b/sys/dev/fdt/fdt_common.h
@@ -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);
diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index e21b913..4159783 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -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);
}
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index 7ddb5e6..cd11693 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -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);
+}
diff --git a/sys/dev/ofw/ofw_bus_subr.h b/sys/dev/ofw/ofw_bus_subr.h
index a4d8b92..59f83fc 100644
--- a/sys/dev/ofw/ofw_bus_subr.h
+++ b/sys/dev/ofw/ofw_bus_subr.h
@@ -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);
diff --git a/sys/dev/ofw/ofwbus.c b/sys/dev/ofw/ofwbus.c
index 11a6a64..2b975ac 100644
--- a/sys/dev/ofw/ofwbus.c
+++ b/sys/dev/ofw/ofwbus.c
@@ -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);
}
diff --git a/sys/mips/beri/beri_simplebus.c b/sys/mips/beri/beri_simplebus.c
index 3862a04..87ad3be 100644
--- a/sys/mips/beri/beri_simplebus.c
+++ b/sys/mips/beri/beri_simplebus.c
@@ -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);
diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c
index aa943ac..75ef51a 100644
--- a/sys/powerpc/ofw/ofw_pcibus.c
+++ b/sys/powerpc/ofw/ofw_pcibus.c
@@ -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);
}
}
diff --git a/sys/powerpc/pseries/vdevice.c b/sys/powerpc/pseries/vdevice.c
index d2c399b..8dadd63 100644
--- a/sys/powerpc/pseries/vdevice.c
+++ b/sys/powerpc/pseries/vdevice.c
@@ -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) {
OpenPOWER on IntegriCloud