summaryrefslogtreecommitdiffstats
path: root/sys/dev/ofw
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-15 14:26:11 +0000
committerian <ian@FreeBSD.org>2014-05-15 14:26:11 +0000
commit27f0a13f0adbfdb658bb63aac86772e0107c1c20 (patch)
tree51fd84ee4d563c9fcc06c0dd196587a24ab23dfc /sys/dev/ofw
parente24fc6cb17a568070581980459e14fc4808f0bb4 (diff)
downloadFreeBSD-src-27f0a13f0adbfdb658bb63aac86772e0107c1c20.zip
FreeBSD-src-27f0a13f0adbfdb658bb63aac86772e0107c1c20.tar.gz
MFC r261351, r261352, r261355, r261396, r261397, r261398, r261403, r261404,
r261405 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. Provide a simpler and more standards-compliant simplebus implementation to get the Routerboard 800 up and running with the vendor device tree. This does not implement some BERI-specific features (which hopefully won't be necessary soon), so move the old code to mips/beri, with a higher attach priority when built, until MIPS interrupt domain support is rearranged. Allow nesting of simplebuses. Add a set of helpers (ofw_bus_get_status() and ofw_bus_status_okay()) to process "status" properties of OF nodes. Fix one remnant endian flaw in nexus.
Diffstat (limited to 'sys/dev/ofw')
-rw-r--r--sys/dev/ofw/ofw_bus.h10
-rw-r--r--sys/dev/ofw/ofw_bus_if.m34
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c27
-rw-r--r--sys/dev/ofw/ofw_bus_subr.h4
-rw-r--r--sys/dev/ofw/ofw_nexus.c5
5 files changed, 43 insertions, 37 deletions
diff --git a/sys/dev/ofw/ofw_bus.h b/sys/dev/ofw/ofw_bus.h
index 1ea4845..f7c7295 100644
--- a/sys/dev/ofw/ofw_bus.h
+++ b/sys/dev/ofw/ofw_bus.h
@@ -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_ */
diff --git a/sys/dev/ofw/ofw_bus_if.m b/sys/dev/ofw/ofw_bus_if.m
index 0034a15..6486e96 100644
--- a/sys/dev/ofw/ofw_bus_if.m
+++ b/sys/dev/ofw/ofw_bus_if.m
@@ -46,6 +46,7 @@ HEADER {
char *obd_model;
char *obd_name;
char *obd_type;
+ char *obd_status;
};
};
@@ -57,7 +58,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 +103,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 +160,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;
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index bf552a8..64ac11f 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -55,6 +55,7 @@ ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat);
OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type);
OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model);
+ OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status);
obd->obd_node = node;
return (0);
}
@@ -73,6 +74,8 @@ ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
free(obd->obd_name, M_OFWPROP);
if (obd->obd_type != NULL)
free(obd->obd_type, M_OFWPROP);
+ if (obd->obd_status != NULL)
+ free(obd->obd_status, M_OFWPROP);
}
int
@@ -147,6 +150,30 @@ ofw_bus_gen_get_type(device_t bus, device_t dev)
return (obd->obd_type);
}
+const char *
+ofw_bus_get_status(device_t dev)
+{
+ const struct ofw_bus_devinfo *obd;
+
+ obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev);
+ if (obd == NULL)
+ return (NULL);
+
+ return (obd->obd_status);
+}
+
+int
+ofw_bus_status_okay(device_t dev)
+{
+ const char *status;
+
+ status = ofw_bus_get_status(dev);
+ if (status == NULL || strcmp(status, "okay") == 0)
+ return (1);
+
+ return (0);
+}
+
int
ofw_bus_is_compatible(device_t dev, const char *onecompat)
{
diff --git a/sys/dev/ofw/ofw_bus_subr.h b/sys/dev/ofw/ofw_bus_subr.h
index e9ef5e4..a4d8b92 100644
--- a/sys/dev/ofw/ofw_bus_subr.h
+++ b/sys/dev/ofw/ofw_bus_subr.h
@@ -72,6 +72,10 @@ 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 *);
+/* Helper to get device status property */
+const char *ofw_bus_get_status(device_t dev);
+int ofw_bus_status_okay(device_t dev);
+
/* Helper to get node's interrupt parent */
void ofw_bus_find_iparent(phandle_t);
diff --git a/sys/dev/ofw/ofw_nexus.c b/sys/dev/ofw/ofw_nexus.c
index f602bfe..b3c5e03 100644
--- a/sys/dev/ofw/ofw_nexus.c
+++ b/sys/dev/ofw/ofw_nexus.c
@@ -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);
}
OpenPOWER on IntegriCloud