From owner-svn-src-all@FreeBSD.ORG Mon Sep 1 22:40:32 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3FC7BB0D; Mon, 1 Sep 2014 22:40:32 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 217331C89; Mon, 1 Sep 2014 22:40:32 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s81MeWAK010271; Mon, 1 Sep 2014 22:40:32 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s81MeVrB010269; Mon, 1 Sep 2014 22:40:31 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201409012240.s81MeVrB010269@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Mon, 1 Sep 2014 22:40:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270953 - head/sys/dev/ofw X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Sep 2014 22:40:32 -0000 Author: ian Date: Mon Sep 1 22:40:31 2014 New Revision: 270953 URL: http://svnweb.freebsd.org/changeset/base/270953 Log: Create a mechanism for looking up a device_t associated with an ofw/fdt xref handle, and for registering that association. Also use the same data for faster translations between node and xref handles. Now when fdt properties contain &othernode references, a driver can find the device instance that corresponds to &othernode, and thus can use interfaces provided by that instance. Reviewed by: nwhitehorn Modified: head/sys/dev/ofw/openfirm.c head/sys/dev/ofw/openfirm.h Modified: head/sys/dev/ofw/openfirm.c ============================================================================== --- head/sys/dev/ofw/openfirm.c Mon Sep 1 22:25:42 2014 (r270952) +++ head/sys/dev/ofw/openfirm.c Mon Sep 1 22:40:31 2014 (r270953) @@ -84,6 +84,78 @@ static ofw_t ofw_obj; static struct ofw_kobj ofw_kernel_obj; static struct kobj_ops ofw_kernel_kops; +struct xrefinfo { + phandle_t xref; + phandle_t node; + device_t dev; + SLIST_ENTRY(xrefinfo) next_entry; +}; + +static SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist); +static boolean_t xref_init_done; + +#define FIND_BY_XREF 0 +#define FIND_BY_NODE 1 + +/* + * xref-phandle-device lookup helper routines. + * + * As soon as we are able to use malloc(), walk the node tree and build a list + * of info that cross-references node handles, xref handles, and device_t + * instances. This list exists primarily to allow association of a device_t + * with an xref handle, but it is also used to speed up translation between xref + * and node handles. Before malloc() is available we have to recursively search + * the node tree each time we want to translate between a node and xref handle. + * Afterwards we can do the translations by searching this much shorter list. + */ +static void +xrefinfo_create(phandle_t node) +{ + struct xrefinfo * xi; + phandle_t child, xref; + + /* + * Recursively descend from parent, looking for nodes with a property + * named either "phandle", "ibm,phandle", or "linux,phandle". For each + * such node found create an entry in the xreflist. + */ + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + xrefinfo_create(child); + if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) == + -1 && OF_getencprop(child, "ibm,phandle", &xref, + sizeof(xref)) == -1 && OF_getencprop(child, + "linux,phandle", &xref, sizeof(xref)) == -1) + continue; + xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO); + xi->node = child; + xi->xref = xref; + SLIST_INSERT_HEAD(&xreflist, xi, next_entry); + } +} + +static void +xrefinfo_init(void *unsed) +{ + + xrefinfo_create(OF_peer(0)); + xref_init_done = true; +} +SYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL); + +static struct xrefinfo * +xrefinfo_find(phandle_t phandle, int find_by) +{ + struct xrefinfo * xi; + + SLIST_FOREACH(xi, &xreflist, next_entry) { + if (find_by == FIND_BY_XREF && phandle == xi->xref) + return (xi); + else if (find_by == FIND_BY_NODE && phandle == xi->node) + return (xi); + } + return (NULL); +} + /* * OFW install routines. Highest priority wins, equal priority also * overrides allowing last-set to win. @@ -465,29 +537,67 @@ OF_child_xref_phandle(phandle_t parent, phandle_t OF_node_from_xref(phandle_t xref) { + struct xrefinfo *xi; phandle_t node; - node = OF_child_xref_phandle(OF_peer(0), xref); - if (node == -1) - return (xref); + if (xref_init_done) { + if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) + return (xref); + return (xi->node); + } + if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1) + return (xref); return (node); } phandle_t OF_xref_from_node(phandle_t node) { + struct xrefinfo *xi; phandle_t xref; + if (xref_init_done) { + if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL) + return (node); + return (xi->xref); + } + if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 && OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1) return (node); - return (xref); } +device_t +OF_device_from_xref(phandle_t xref) +{ + struct xrefinfo *xi; + + if (xref_init_done) { + if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) + return (NULL); + return (xi->dev); + } + panic("Attempt to find device before xreflist_init"); +} + +int +OF_device_register_xref(phandle_t xref, device_t dev) +{ + struct xrefinfo *xi; + + if (xref_init_done) { + if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL) + return (ENXIO); + xi->dev = dev; + return (0); + } + panic("Attempt to register device before xreflist_init"); +} + /* Call the method in the scope of a given instance. */ int OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, Modified: head/sys/dev/ofw/openfirm.h ============================================================================== --- head/sys/dev/ofw/openfirm.h Mon Sep 1 22:25:42 2014 (r270952) +++ head/sys/dev/ofw/openfirm.h Mon Sep 1 22:40:31 2014 (r270953) @@ -133,6 +133,16 @@ ssize_t OF_package_to_path(phandle_t no phandle_t OF_node_from_xref(phandle_t xref); phandle_t OF_xref_from_node(phandle_t node); +/* + * When properties contain references to other nodes using xref handles it is + * often necessary to use interfaces provided by the driver for the referenced + * instance. These routines allow a driver that provides such an interface to + * register its association with an xref handle, and for other drivers to obtain + * the device_t associated with an xref handle. + */ +device_t OF_device_from_xref(phandle_t xref); +int OF_device_register_xref(phandle_t xref, device_t dev); + /* Device I/O functions */ ihandle_t OF_open(const char *path); void OF_close(ihandle_t instance);