summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2013-09-15 14:19:17 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2013-09-15 14:19:17 +0000
commit3b7e4aa267bc7eedadb66a6fa1fac2a227969a41 (patch)
treefe3ff164532f1f65b1e3f0ea2a314284c1f99fe8
parent22333bfe67484518658495ee5fe5290229a67687 (diff)
downloadFreeBSD-src-3b7e4aa267bc7eedadb66a6fa1fac2a227969a41.zip
FreeBSD-src-3b7e4aa267bc7eedadb66a6fa1fac2a227969a41.tar.gz
Add a kernel interface (OF_xref_phandle()) for systems where phandles
used as cross-references in the device tree and phandles as used by the Open Firmware client interface are in different namespaces. This include IBM pSeries hardware as well as FDT systems. FDT certainly abuses ihandles for this purpose and should be modified to use this API eventually. This changes no behavior on systems where FreeBSD already worked. Reviewed by: marius Approved by: re (kib) MFC after: 2 weeks
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c2
-rw-r--r--sys/dev/ofw/openfirm.c42
-rw-r--r--sys/dev/ofw/openfirm.h8
-rw-r--r--sys/powerpc/ofw/ofw_pcibus.c9
4 files changed, 56 insertions, 5 deletions
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index a1bd8b3..9b9dee4 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -300,7 +300,7 @@ ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
i = imapsz;
while (i > 0) {
bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
- if (OF_searchprop(parent, "#interrupt-cells",
+ if (OF_searchprop(OF_xref_phandle(parent), "#interrupt-cells",
&pintrsz, sizeof(pintrsz)) == -1)
pintrsz = 1; /* default */
pintrsz *= sizeof(pcell_t);
diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c
index d63edce..0760854 100644
--- a/sys/dev/ofw/openfirm.c
+++ b/sys/dev/ofw/openfirm.c
@@ -386,6 +386,48 @@ OF_package_to_path(phandle_t package, char *buf, size_t len)
return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len));
}
+/* Look up effective phandle (see FDT/PAPR spec) */
+static phandle_t
+OF_child_xref_phandle(phandle_t parent, phandle_t xref)
+{
+ phandle_t child, rxref;
+
+ /*
+ * Recursively descend from parent, looking for a node with a property
+ * named either "phandle", "ibm,phandle", or "linux,phandle" that
+ * matches the xref we are looking for.
+ */
+
+ for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
+ rxref = OF_child_xref_phandle(child, xref);
+ if (rxref != -1)
+ return (rxref);
+
+ if (OF_getprop(child, "phandle", &rxref, sizeof(rxref)) == -1 &&
+ OF_getprop(child, "ibm,phandle", &rxref,
+ sizeof(rxref)) == -1 && OF_getprop(child,
+ "linux,phandle", &rxref, sizeof(rxref)) == -1)
+ continue;
+
+ if (rxref == xref)
+ return (child);
+ }
+
+ return (-1);
+}
+
+phandle_t
+OF_xref_phandle(phandle_t xref)
+{
+ phandle_t node;
+
+ node = OF_child_xref_phandle(OF_peer(0), xref);
+ if (node == -1)
+ return (xref);
+
+ return (node);
+}
+
/* Call the method in the scope of a given instance. */
int
OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns,
diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h
index 17a0b87..e6ede1d 100644
--- a/sys/dev/ofw/openfirm.h
+++ b/sys/dev/ofw/openfirm.h
@@ -118,6 +118,14 @@ ssize_t OF_canon(const char *path, char *buf, size_t len);
phandle_t OF_finddevice(const char *path);
ssize_t OF_package_to_path(phandle_t node, char *buf, size_t len);
+/*
+ * Some OF implementations (IBM, FDT) have a concept of effective phandles
+ * used for device-tree cross-references. Given one of these, returns the
+ * real phandle. If one can't be found (or running on OF implementations
+ * without this property), returns its input.
+ */
+phandle_t OF_xref_phandle(phandle_t xref);
+
/* Device I/O functions */
ihandle_t OF_open(const char *path);
void OF_close(ihandle_t instance);
diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c
index c3dfed0..a714b6e 100644
--- a/sys/powerpc/ofw/ofw_pcibus.c
+++ b/sys/powerpc/ofw/ofw_pcibus.c
@@ -210,11 +210,12 @@ ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
icells = 1;
OF_getprop(child, "interrupt-parent", &iparent,
sizeof(iparent));
- OF_getprop(iparent, "#interrupt-cells", &icells,
- sizeof(icells));
-
- if (iparent != 0)
+ if (iparent != 0) {
+ OF_getprop(OF_xref_phandle(iparent),
+ "#interrupt-cells", &icells,
+ sizeof(icells));
intr[0] = MAP_IRQ(iparent, intr[0]);
+ }
if (iparent != 0 && icells > 1) {
powerpc_config_intr(intr[0],
OpenPOWER on IntegriCloud