1d84d862obrien/*	$NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $	*/
2d84d862obrien
34b31995imp/*-
41537078pfg * SPDX-License-Identifier: BSD-4-Clause
51537078pfg *
6d84d862obrien * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7d84d862obrien * Copyright (C) 1995, 1996 TooLs GmbH.
8d84d862obrien * All rights reserved.
9d84d862obrien *
10d84d862obrien * Redistribution and use in source and binary forms, with or without
11d84d862obrien * modification, are permitted provided that the following conditions
12d84d862obrien * are met:
13d84d862obrien * 1. Redistributions of source code must retain the above copyright
14d84d862obrien *    notice, this list of conditions and the following disclaimer.
15d84d862obrien * 2. Redistributions in binary form must reproduce the above copyright
16d84d862obrien *    notice, this list of conditions and the following disclaimer in the
17d84d862obrien *    documentation and/or other materials provided with the distribution.
18d84d862obrien * 3. All advertising materials mentioning features or use of this software
19d84d862obrien *    must display the following acknowledgement:
20d84d862obrien *	This product includes software developed by TooLs GmbH.
21d84d862obrien * 4. The name of TooLs GmbH may not be used to endorse or promote products
22d84d862obrien *    derived from this software without specific prior written permission.
23d84d862obrien *
24d84d862obrien * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25d84d862obrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26d84d862obrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27d84d862obrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28d84d862obrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29d84d862obrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30d84d862obrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31d84d862obrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32d84d862obrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33d84d862obrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34d84d862obrien */
354b31995imp/*-
36d84d862obrien * Copyright (C) 2000 Benno Rice.
37d84d862obrien * All rights reserved.
38d84d862obrien *
39d84d862obrien * Redistribution and use in source and binary forms, with or without
40d84d862obrien * modification, are permitted provided that the following conditions
41d84d862obrien * are met:
42d84d862obrien * 1. Redistributions of source code must retain the above copyright
43d84d862obrien *    notice, this list of conditions and the following disclaimer.
44d84d862obrien * 2. Redistributions in binary form must reproduce the above copyright
45d84d862obrien *    notice, this list of conditions and the following disclaimer in the
46d84d862obrien *    documentation and/or other materials provided with the distribution.
47d84d862obrien *
48d84d862obrien * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
49d84d862obrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50d84d862obrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51d84d862obrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52d84d862obrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53d84d862obrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54d84d862obrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55d84d862obrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56d84d862obrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57d84d862obrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58d84d862obrien */
59d84d862obrien
60128f33dmarius#include <sys/cdefs.h>
61128f33dmarius__FBSDID("$FreeBSD$");
62128f33dmarius
63ef99eb1raj#include "opt_platform.h"
64ef99eb1raj
65104745fjake#include <sys/param.h>
66f90b466tmm#include <sys/kernel.h>
67d965bceian#include <sys/lock.h>
68f90b466tmm#include <sys/malloc.h>
69d965bceian#include <sys/mutex.h>
70d965bceian#include <sys/queue.h>
7110abd05benno#include <sys/systm.h>
72f79afefnwhitehorn#include <sys/endian.h>
73d84d862obrien
7410abd05benno#include <machine/stdarg.h>
757d73a33benno
763fcef6dnwhitehorn#include <dev/ofw/ofwvar.h>
773961775marius#include <dev/ofw/openfirm.h>
783fcef6dnwhitehorn
793fcef6dnwhitehorn#include "ofw_if.h"
80d84d862obrien
8144e78d9mariusstatic void OF_putchar(int c, void *arg);
8244e78d9marius
8324ad8a9mariusMALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties");
84f90b466tmm
85d84d862obrienstatic ihandle_t stdout;
86d84d862obrien
87afe737dnwhitehornstatic ofw_def_t	*ofw_def_impl = NULL;
883fcef6dnwhitehornstatic ofw_t		ofw_obj;
893fcef6dnwhitehornstatic struct ofw_kobj	ofw_kernel_obj;
903fcef6dnwhitehornstatic struct kobj_ops	ofw_kernel_kops;
913fcef6dnwhitehorn
92c1f3eb1ianstruct xrefinfo {
93c1f3eb1ian	phandle_t	xref;
94c1f3eb1ian	phandle_t 	node;
95c1f3eb1ian	device_t  	dev;
96c1f3eb1ian	SLIST_ENTRY(xrefinfo) next_entry;
97c1f3eb1ian};
98c1f3eb1ian
99c1f3eb1ianstatic SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist);
100d965bceianstatic struct mtx xreflist_lock;
101c1f3eb1ianstatic boolean_t xref_init_done;
102c1f3eb1ian
103c1f3eb1ian#define	FIND_BY_XREF	0
104c1f3eb1ian#define	FIND_BY_NODE	1
1051853fe0ian#define	FIND_BY_DEV	2
106c1f3eb1ian
107c1f3eb1ian/*
108c1f3eb1ian * xref-phandle-device lookup helper routines.
109c1f3eb1ian *
110c1f3eb1ian * As soon as we are able to use malloc(), walk the node tree and build a list
111c1f3eb1ian * of info that cross-references node handles, xref handles, and device_t
112c1f3eb1ian * instances.  This list exists primarily to allow association of a device_t
113c1f3eb1ian * with an xref handle, but it is also used to speed up translation between xref
114c1f3eb1ian * and node handles.  Before malloc() is available we have to recursively search
115c1f3eb1ian * the node tree each time we want to translate between a node and xref handle.
116c1f3eb1ian * Afterwards we can do the translations by searching this much shorter list.
117c1f3eb1ian */
118c1f3eb1ianstatic void
119c1f3eb1ianxrefinfo_create(phandle_t node)
120c1f3eb1ian{
121c1f3eb1ian	struct xrefinfo * xi;
122c1f3eb1ian	phandle_t child, xref;
123c1f3eb1ian
124c1f3eb1ian	/*
125c1f3eb1ian	 * Recursively descend from parent, looking for nodes with a property
126c1f3eb1ian	 * named either "phandle", "ibm,phandle", or "linux,phandle".  For each
127c1f3eb1ian	 * such node found create an entry in the xreflist.
128c1f3eb1ian	 */
129c1f3eb1ian	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
130c1f3eb1ian		xrefinfo_create(child);
131c1f3eb1ian		if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) ==
132c1f3eb1ian		    -1 && OF_getencprop(child, "ibm,phandle", &xref,
133c1f3eb1ian		    sizeof(xref)) == -1 && OF_getencprop(child,
134c1f3eb1ian		    "linux,phandle", &xref, sizeof(xref)) == -1)
135c1f3eb1ian			continue;
136c1f3eb1ian		xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO);
137c1f3eb1ian		xi->node = child;
138c1f3eb1ian		xi->xref = xref;
139c1f3eb1ian		SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
140c1f3eb1ian	}
141c1f3eb1ian}
142c1f3eb1ian
143c1f3eb1ianstatic void
144c1f3eb1ianxrefinfo_init(void *unsed)
145c1f3eb1ian{
146c1f3eb1ian
147d965bceian	/*
148d965bceian	 * There is no locking during this init because it runs much earlier
149d965bceian	 * than any of the clients/consumers of the xref list data, but we do
150d965bceian	 * initialize the mutex that will be used for access later.
151d965bceian	 */
152d965bceian	mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF);
153c1f3eb1ian	xrefinfo_create(OF_peer(0));
154c1f3eb1ian	xref_init_done = true;
155c1f3eb1ian}
156c1f3eb1ianSYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL);
157c1f3eb1ian
158c1f3eb1ianstatic struct xrefinfo *
159861c5f1zbbxrefinfo_find(uintptr_t key, int find_by)
160c1f3eb1ian{
161d965bceian	struct xrefinfo *rv, *xi;
162c1f3eb1ian
163d965bceian	rv = NULL;
164d965bceian	mtx_lock(&xreflist_lock);
165c1f3eb1ian	SLIST_FOREACH(xi, &xreflist, next_entry) {
166861c5f1zbb		if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) ||
167861c5f1zbb		    (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) ||
168861c5f1zbb		    (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) {
169d965bceian			rv = xi;
170d965bceian			break;
171d965bceian		}
172c1f3eb1ian	}
173d965bceian	mtx_unlock(&xreflist_lock);
174d965bceian	return (rv);
175d965bceian}
176d965bceian
177d965bceianstatic struct xrefinfo *
178d965bceianxrefinfo_add(phandle_t node, phandle_t xref, device_t dev)
179d965bceian{
180d965bceian	struct xrefinfo *xi;
181d965bceian
182d965bceian	xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK);
183d965bceian	xi->node = node;
184d965bceian	xi->xref = xref;
185d965bceian	xi->dev  = dev;
186d965bceian	mtx_lock(&xreflist_lock);
187d965bceian	SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
188d965bceian	mtx_unlock(&xreflist_lock);
189d965bceian	return (xi);
190c1f3eb1ian}
191c1f3eb1ian
1923fcef6dnwhitehorn/*
19344e78d9marius * OFW install routines.  Highest priority wins, equal priority also
1943fcef6dnwhitehorn * overrides allowing last-set to win.
1953fcef6dnwhitehorn */
1963fcef6dnwhitehornSET_DECLARE(ofw_set, ofw_def_t);
1973fcef6dnwhitehorn
1983fcef6dnwhitehornboolean_t
1993fcef6dnwhitehornOF_install(char *name, int prio)
2003fcef6dnwhitehorn{
2013961775marius	ofw_def_t *ofwp, **ofwpp;
2023fcef6dnwhitehorn	static int curr_prio = 0;
2033fcef6dnwhitehorn
20452d9398nwhitehorn	/* Allow OF layer to be uninstalled */
20552d9398nwhitehorn	if (name == NULL) {
20652d9398nwhitehorn		ofw_def_impl = NULL;
20752d9398nwhitehorn		return (FALSE);
20852d9398nwhitehorn	}
20952d9398nwhitehorn
2103fcef6dnwhitehorn	/*
2113961775marius	 * Try and locate the OFW kobj corresponding to the name.
2123961775marius	 */
2133fcef6dnwhitehorn	SET_FOREACH(ofwpp, ofw_set) {
2143fcef6dnwhitehorn		ofwp = *ofwpp;
2153fcef6dnwhitehorn
2163fcef6dnwhitehorn		if (ofwp->name &&
2173fcef6dnwhitehorn		    !strcmp(ofwp->name, name) &&
2183fcef6dnwhitehorn		    prio >= curr_prio) {
2193fcef6dnwhitehorn			curr_prio = prio;
2203fcef6dnwhitehorn			ofw_def_impl = ofwp;
2213fcef6dnwhitehorn			return (TRUE);
2223fcef6dnwhitehorn		}
2233fcef6dnwhitehorn	}
2243fcef6dnwhitehorn
2253fcef6dnwhitehorn	return (FALSE);
2263fcef6dnwhitehorn}
2273fcef6dnwhitehorn
2283961775marius/* Initializer */
229ef99eb1rajint
2303fcef6dnwhitehornOF_init(void *cookie)
231d84d862obrien{
232128f33dmarius	phandle_t chosen;
233ef99eb1raj	int rv;
23410abd05benno
235afe737dnwhitehorn	if (ofw_def_impl == NULL)
236afe737dnwhitehorn		return (-1);
237afe737dnwhitehorn
2383fcef6dnwhitehorn	ofw_obj = &ofw_kernel_obj;
2393fcef6dnwhitehorn	/*
2403fcef6dnwhitehorn	 * Take care of compiling the selected class, and
2413961775marius	 * then statically initialize the OFW object.
2423fcef6dnwhitehorn	 */
2433fcef6dnwhitehorn	kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops);
2444b64581marius	kobj_init_static((kobj_t)ofw_obj, ofw_def_impl);
2453fcef6dnwhitehorn
246ef99eb1raj	rv = OFW_INIT(ofw_obj, cookie);
247ef99eb1raj
248e5b89f2jchandra	if ((chosen = OF_finddevice("/chosen")) != -1)
2499a7fe80nwhitehorn		if (OF_getencprop(chosen, "stdout", &stdout,
2509a7fe80nwhitehorn		    sizeof(stdout)) == -1)
251ef99eb1raj			stdout = -1;
2523fcef6dnwhitehorn
253ef99eb1raj	return (rv);
25410abd05benno}
25510abd05benno
25644e78d9mariusstatic void
25744e78d9mariusOF_putchar(int c, void *arg __unused)
25844e78d9marius{
25944e78d9marius	char cbuf;
26044e78d9marius
26144e78d9marius	if (c == '\n') {
26244e78d9marius		cbuf = '\r';
26344e78d9marius		OF_write(stdout, &cbuf, 1);
26444e78d9marius	}
26544e78d9marius
26644e78d9marius	cbuf = c;
26744e78d9marius	OF_write(stdout, &cbuf, 1);
26844e78d9marius}
26944e78d9marius
27010abd05bennovoid
27110abd05bennoOF_printf(const char *fmt, ...)
27210abd05benno{
27310abd05benno	va_list	va;
27410abd05benno
27510abd05benno	va_start(va, fmt);
27644e78d9marius	(void)kvprintf(fmt, OF_putchar, NULL, 10, va);
27710abd05benno	va_end(va);
278d84d862obrien}
279d84d862obrien
280d84d862obrien/*
281d84d862obrien * Generic functions
282d84d862obrien */
283d84d862obrien
284d84d862obrien/* Test to see if a service exists. */
285d84d862obrienint
2863fcef6dnwhitehornOF_test(const char *name)
287d84d862obrien{
2883961775marius
289afe737dnwhitehorn	if (ofw_def_impl == NULL)
290afe737dnwhitehorn		return (-1);
291afe737dnwhitehorn
2923fcef6dnwhitehorn	return (OFW_TEST(ofw_obj, name));
293d84d862obrien}
294d84d862obrien
295b5d362bjakeint
2963fcef6dnwhitehornOF_interpret(const char *cmd, int nreturns, ...)
297b5d362bjake{
298b5d362bjake	va_list ap;
2990b2ac86marius	cell_t slots[16];
300b5d362bjake	int i = 0;
3013fcef6dnwhitehorn	int status;
3023fcef6dnwhitehorn
303afe737dnwhitehorn	if (ofw_def_impl == NULL)
304afe737dnwhitehorn		return (-1);
305afe737dnwhitehorn
3063fcef6dnwhitehorn	status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots);
307aa09259marius	if (status == -1)
308aa09259marius		return (status);
309b5d362bjake
310ba90a8epeter	va_start(ap, nreturns);
311aa09259marius	while (i < nreturns)
3123fcef6dnwhitehorn		*va_arg(ap, cell_t *) = slots[i++];
313b5d362bjake	va_end(ap);
314b5d362bjake
3153fcef6dnwhitehorn	return (status);
316d84d862obrien}
317d84d862obrien
318d84d862obrien/*
319d84d862obrien * Device tree functions
320d84d862obrien */
321d84d862obrien
322d84d862obrien/* Return the next sibling of this node or 0. */
323d84d862obrienphandle_t
324d84d862obrienOF_peer(phandle_t node)
325d84d862obrien{
3263961775marius
327afe737dnwhitehorn	if (ofw_def_impl == NULL)
328afe737dnwhitehorn		return (0);
329afe737dnwhitehorn
3303fcef6dnwhitehorn	return (OFW_PEER(ofw_obj, node));
331d84d862obrien}
332d84d862obrien
333d84d862obrien/* Return the first child of this node or 0. */
334d84d862obrienphandle_t
335d84d862obrienOF_child(phandle_t node)
336d84d862obrien{
3373961775marius
338afe737dnwhitehorn	if (ofw_def_impl == NULL)
339afe737dnwhitehorn		return (0);
340afe737dnwhitehorn
3413fcef6dnwhitehorn	return (OFW_CHILD(ofw_obj, node));
342d84d862obrien}
343d84d862obrien
344d84d862obrien/* Return the parent of this node or 0. */
345d84d862obrienphandle_t
346d84d862obrienOF_parent(phandle_t node)
347d84d862obrien{
3483961775marius
349afe737dnwhitehorn	if (ofw_def_impl == NULL)
350afe737dnwhitehorn		return (0);
351afe737dnwhitehorn
3523fcef6dnwhitehorn	return (OFW_PARENT(ofw_obj, node));
353d84d862obrien}
354d84d862obrien
355d84d862obrien/* Return the package handle that corresponds to an instance handle. */
356d84d862obrienphandle_t
357d84d862obrienOF_instance_to_package(ihandle_t instance)
358d84d862obrien{
3593961775marius
360afe737dnwhitehorn	if (ofw_def_impl == NULL)
361afe737dnwhitehorn		return (-1);
362afe737dnwhitehorn
3633fcef6dnwhitehorn	return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance));
364d84d862obrien}
365d84d862obrien
366d84d862obrien/* Get the length of a property of a package. */
3673fcef6dnwhitehornssize_t
3683fcef6dnwhitehornOF_getproplen(phandle_t package, const char *propname)
369d84d862obrien{
3703961775marius
371afe737dnwhitehorn	if (ofw_def_impl == NULL)
372afe737dnwhitehorn		return (-1);
373afe737dnwhitehorn
3743fcef6dnwhitehorn	return (OFW_GETPROPLEN(ofw_obj, package, propname));
375d84d862obrien}
376d84d862obrien
3775320d21hrs/* Check existence of a property of a package. */
3785320d21hrsint
3795320d21hrsOF_hasprop(phandle_t package, const char *propname)
3805320d21hrs{
3815320d21hrs
3825320d21hrs	return (OF_getproplen(package, propname) >= 0 ? 1 : 0);
3835320d21hrs}
3845320d21hrs
385d84d862obrien/* Get the value of a property of a package. */
3863fcef6dnwhitehornssize_t
3873fcef6dnwhitehornOF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
388d84d862obrien{
3893961775marius
390afe737dnwhitehorn	if (ofw_def_impl == NULL)
391afe737dnwhitehorn		return (-1);
392afe737dnwhitehorn
3933fcef6dnwhitehorn	return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen));
394d84d862obrien}
395d84d862obrien
396f79afefnwhitehornssize_t
397f79afefnwhitehornOF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
398f79afefnwhitehorn{
399f79afefnwhitehorn	ssize_t retval;
400f79afefnwhitehorn	int i;
401f79afefnwhitehorn
40266c25f9andreast	KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes"));
403f79afefnwhitehorn
404f79afefnwhitehorn	retval = OF_getprop(node, propname, buf, len);
405dfc2b35zbb	if (retval <= 0)
406dfc2b35zbb		return (retval);
407dfc2b35zbb
408f79afefnwhitehorn	for (i = 0; i < len/4; i++)
409f79afefnwhitehorn		buf[i] = be32toh(buf[i]);
410f79afefnwhitehorn
411f79afefnwhitehorn	return (retval);
412f79afefnwhitehorn}
413f79afefnwhitehorn
414f90b466tmm/*
415ef99eb1raj * Recursively search the node and its parent for the given property, working
4164ca1211nwhitehorn * downward from the node to the device tree root.  Returns the value of the
4174ca1211nwhitehorn * first match.
4184ca1211nwhitehorn */
4194ca1211nwhitehornssize_t
4203961775mariusOF_searchprop(phandle_t node, const char *propname, void *buf, size_t len)
4214ca1211nwhitehorn{
4224ca1211nwhitehorn	ssize_t rv;
4234ca1211nwhitehorn
4243961775marius	for (; node != 0; node = OF_parent(node))
4254ca1211nwhitehorn		if ((rv = OF_getprop(node, propname, buf, len)) != -1)
4264ca1211nwhitehorn			return (rv);
4274ca1211nwhitehorn	return (-1);
4284ca1211nwhitehorn}
4294ca1211nwhitehorn
43015e1002nwhitehornssize_t
431eb86958gonzoOF_searchencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
43215e1002nwhitehorn{
43315e1002nwhitehorn	ssize_t rv;
43415e1002nwhitehorn
43515e1002nwhitehorn	for (; node != 0; node = OF_parent(node))
43615e1002nwhitehorn		if ((rv = OF_getencprop(node, propname, buf, len)) != -1)
43715e1002nwhitehorn			return (rv);
43815e1002nwhitehorn	return (-1);
43915e1002nwhitehorn}
44015e1002nwhitehorn
4414ca1211nwhitehorn/*
44224c9adbmarius * Store the value of a property of a package into newly allocated memory
4431252c93gonzo * (using the M_OFWPROP malloc pool and M_WAITOK).
4441252c93gonzo */
4451252c93gonzossize_t
4461252c93gonzoOF_getprop_alloc(phandle_t package, const char *propname, void **buf)
4471252c93gonzo{
4481252c93gonzo	int len;
4491252c93gonzo
4501252c93gonzo	*buf = NULL;
4511252c93gonzo	if ((len = OF_getproplen(package, propname)) == -1)
4521252c93gonzo		return (-1);
4531252c93gonzo
4541252c93gonzo	if (len > 0) {
4551252c93gonzo		*buf = malloc(len, M_OFWPROP, M_WAITOK);
4561252c93gonzo		if (OF_getprop(package, propname, *buf, len) == -1) {
4571252c93gonzo			free(*buf, M_OFWPROP);
4581252c93gonzo			*buf = NULL;
4591252c93gonzo			return (-1);
4601252c93gonzo		}
4611252c93gonzo	}
4621252c93gonzo	return (len);
4631252c93gonzo}
4641252c93gonzo
4651252c93gonzo/*
4661252c93gonzo * Store the value of a property of a package into newly allocated memory
4673961775marius * (using the M_OFWPROP malloc pool and M_WAITOK).  elsz is the size of a
46824c9adbmarius * single element, the number of elements is return in number.
469f90b466tmm */
4703fcef6dnwhitehornssize_t
4711252c93gonzoOF_getprop_alloc_multi(phandle_t package, const char *propname, int elsz, void **buf)
472f90b466tmm{
473f90b466tmm	int len;
474f90b466tmm
475f90b466tmm	*buf = NULL;
476f90b466tmm	if ((len = OF_getproplen(package, propname)) == -1 ||
477f90b466tmm	    len % elsz != 0)
478f90b466tmm		return (-1);
479f90b466tmm
4801252c93gonzo	if (len > 0) {
4811252c93gonzo		*buf = malloc(len, M_OFWPROP, M_WAITOK);
4821252c93gonzo		if (OF_getprop(package, propname, *buf, len) == -1) {
4831252c93gonzo			free(*buf, M_OFWPROP);
4841252c93gonzo			*buf = NULL;
4851252c93gonzo			return (-1);
4861252c93gonzo		}
487f90b466tmm	}
488f90b466tmm	return (len / elsz);
489f90b466tmm}
490f90b466tmm
4913308d36gonzossize_t
4923308d36gonzoOF_getencprop_alloc(phandle_t package, const char *name, void **buf)
4933308d36gonzo{
4943308d36gonzo	ssize_t ret;
4953308d36gonzo
4963308d36gonzo	ret = OF_getencprop_alloc_multi(package, name, sizeof(pcell_t),
4973308d36gonzo	    buf);
4983308d36gonzo	if (ret < 0)
4993308d36gonzo		return (ret);
5003308d36gonzo	else
5013308d36gonzo		return (ret * sizeof(pcell_t));
5023308d36gonzo}
5031252c93gonzo
50415e1002nwhitehornssize_t
5053308d36gonzoOF_getencprop_alloc_multi(phandle_t package, const char *name, int elsz,
5063308d36gonzo    void **buf)
50715e1002nwhitehorn{
50815e1002nwhitehorn	ssize_t retval;
50915e1002nwhitehorn	pcell_t *cell;
51015e1002nwhitehorn	int i;
51115e1002nwhitehorn
5121252c93gonzo	retval = OF_getprop_alloc_multi(package, name, elsz, buf);
513aef5f9floos	if (retval == -1)
5149a7fe80nwhitehorn		return (-1);
51515e1002nwhitehorn
51615e1002nwhitehorn	cell = *buf;
517aef5f9floos	for (i = 0; i < retval * elsz / 4; i++)
51815e1002nwhitehorn		cell[i] = be32toh(cell[i]);
51915e1002nwhitehorn
52015e1002nwhitehorn	return (retval);
52115e1002nwhitehorn}
52215e1002nwhitehorn
52323a2d5fgonzo/* Free buffer allocated by OF_getencprop_alloc or OF_getprop_alloc */
52423a2d5fgonzovoid OF_prop_free(void *buf)
52523a2d5fgonzo{
52623a2d5fgonzo
52723a2d5fgonzo	free(buf, M_OFWPROP);
52823a2d5fgonzo}
52923a2d5fgonzo
530d84d862obrien/* Get the next property of a package. */
531d84d862obrienint
5323fcef6dnwhitehornOF_nextprop(phandle_t package, const char *previous, char *buf, size_t size)
533d84d862obrien{
5343961775marius
535afe737dnwhitehorn	if (ofw_def_impl == NULL)
536afe737dnwhitehorn		return (-1);
537afe737dnwhitehorn
5383fcef6dnwhitehorn	return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size));
539d84d862obrien}
540d84d862obrien
541d84d862obrien/* Set the value of a property of a package. */
542d84d862obrienint
5433fcef6dnwhitehornOF_setprop(phandle_t package, const char *propname, const void *buf, size_t len)
544d84d862obrien{
5453961775marius
546afe737dnwhitehorn	if (ofw_def_impl == NULL)
547afe737dnwhitehorn		return (-1);
548afe737dnwhitehorn
5493fcef6dnwhitehorn	return (OFW_SETPROP(ofw_obj, package, propname, buf,len));
550d84d862obrien}
551d84d862obrien
552d84d862obrien/* Convert a device specifier to a fully qualified pathname. */
5533fcef6dnwhitehornssize_t
5543fcef6dnwhitehornOF_canon(const char *device, char *buf, size_t len)
555d84d862obrien{
5563961775marius
557afe737dnwhitehorn	if (ofw_def_impl == NULL)
558afe737dnwhitehorn		return (-1);
559afe737dnwhitehorn
5603fcef6dnwhitehorn	return (OFW_CANON(ofw_obj, device, buf, len));
561d84d862obrien}
562d84d862obrien
563d84d862obrien/* Return a package handle for the specified device. */
564d84d862obrienphandle_t
5657d73a33bennoOF_finddevice(const char *device)
566d84d862obrien{
5673961775marius
568afe737dnwhitehorn	if (ofw_def_impl == NULL)
569afe737dnwhitehorn		return (-1);
570afe737dnwhitehorn
5713fcef6dnwhitehorn	return (OFW_FINDDEVICE(ofw_obj, device));
572d84d862obrien}
573d84d862obrien
574d84d862obrien/* Return the fully qualified pathname corresponding to an instance. */
5753fcef6dnwhitehornssize_t
5763fcef6dnwhitehornOF_instance_to_path(ihandle_t instance, char *buf, size_t len)
577d84d862obrien{
5783961775marius
579afe737dnwhitehorn	if (ofw_def_impl == NULL)
580afe737dnwhitehorn		return (-1);
581afe737dnwhitehorn
5823fcef6dnwhitehorn	return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len));
583d84d862obrien}
584d84d862obrien
585d84d862obrien/* Return the fully qualified pathname corresponding to a package. */
5863fcef6dnwhitehornssize_t
5873fcef6dnwhitehornOF_package_to_path(phandle_t package, char *buf, size_t len)
588d84d862obrien{
5893961775marius
590afe737dnwhitehorn	if (ofw_def_impl == NULL)
591afe737dnwhitehorn		return (-1);
592afe737dnwhitehorn
5933fcef6dnwhitehorn	return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len));
594d84d862obrien}
595d84d862obrien
5963b7e4aanwhitehorn/* Look up effective phandle (see FDT/PAPR spec) */
5973b7e4aanwhitehornstatic phandle_t
5983b7e4aanwhitehornOF_child_xref_phandle(phandle_t parent, phandle_t xref)
5993b7e4aanwhitehorn{
6003b7e4aanwhitehorn	phandle_t child, rxref;
6013b7e4aanwhitehorn
6023b7e4aanwhitehorn	/*
6033b7e4aanwhitehorn	 * Recursively descend from parent, looking for a node with a property
6043b7e4aanwhitehorn	 * named either "phandle", "ibm,phandle", or "linux,phandle" that
6053b7e4aanwhitehorn	 * matches the xref we are looking for.
6063b7e4aanwhitehorn	 */
6073b7e4aanwhitehorn
6083b7e4aanwhitehorn	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
6093b7e4aanwhitehorn		rxref = OF_child_xref_phandle(child, xref);
6103b7e4aanwhitehorn		if (rxref != -1)
6113b7e4aanwhitehorn			return (rxref);
6123b7e4aanwhitehorn
6139a7fe80nwhitehorn		if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) ==
6149a7fe80nwhitehorn		    -1 && OF_getencprop(child, "ibm,phandle", &rxref,
6159a7fe80nwhitehorn		    sizeof(rxref)) == -1 && OF_getencprop(child,
6163b7e4aanwhitehorn		    "linux,phandle", &rxref, sizeof(rxref)) == -1)
6173b7e4aanwhitehorn			continue;
6183b7e4aanwhitehorn
6193b7e4aanwhitehorn		if (rxref == xref)
6203b7e4aanwhitehorn			return (child);
6213b7e4aanwhitehorn	}
6223b7e4aanwhitehorn
6233b7e4aanwhitehorn	return (-1);
6243b7e4aanwhitehorn}
6253b7e4aanwhitehorn
6263b7e4aanwhitehornphandle_t
627b149a9eianOF_node_from_xref(phandle_t xref)
6283b7e4aanwhitehorn{
629c1f3eb1ian	struct xrefinfo *xi;
6303b7e4aanwhitehorn	phandle_t node;
6313b7e4aanwhitehorn
632c1f3eb1ian	if (xref_init_done) {
633c1f3eb1ian		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
634c1f3eb1ian			return (xref);
635c1f3eb1ian		return (xi->node);
636c1f3eb1ian	}
6373b7e4aanwhitehorn
638c1f3eb1ian	if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1)
639c1f3eb1ian		return (xref);
6403b7e4aanwhitehorn	return (node);
6413b7e4aanwhitehorn}
6423b7e4aanwhitehorn
643c8e7d83ianphandle_t
644c8e7d83ianOF_xref_from_node(phandle_t node)
645b149a9eian{
646c1f3eb1ian	struct xrefinfo *xi;
647b149a9eian	phandle_t xref;
648b149a9eian
649c1f3eb1ian	if (xref_init_done) {
650c1f3eb1ian		if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL)
651c8e7d83ian			return (node);
652c1f3eb1ian		return (xi->xref);
653c1f3eb1ian	}
654c1f3eb1ian
655988b55candrew	if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 &&
656988b55candrew	    OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 &&
657988b55candrew	    OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1)
658c8e7d83ian		return (node);
659b149a9eian	return (xref);
660b149a9eian}
661b149a9eian
662c1f3eb1iandevice_t
663c1f3eb1ianOF_device_from_xref(phandle_t xref)
664c1f3eb1ian{
665c1f3eb1ian	struct xrefinfo *xi;
666c1f3eb1ian
667c1f3eb1ian	if (xref_init_done) {
668c1f3eb1ian		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
669c1f3eb1ian			return (NULL);
670c1f3eb1ian		return (xi->dev);
671c1f3eb1ian	}
672c1f3eb1ian	panic("Attempt to find device before xreflist_init");
673c1f3eb1ian}
674c1f3eb1ian
67529ba19bianphandle_t
67629ba19bianOF_xref_from_device(device_t dev)
67729ba19bian{
67829ba19bian	struct xrefinfo *xi;
67929ba19bian
68029ba19bian	if (xref_init_done) {
68129ba19bian		if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL)
68229ba19bian			return (0);
68329ba19bian		return (xi->xref);
68429ba19bian	}
68529ba19bian	panic("Attempt to find xref before xreflist_init");
68629ba19bian}
68729ba19bian
688c1f3eb1ianint
689c1f3eb1ianOF_device_register_xref(phandle_t xref, device_t dev)
690c1f3eb1ian{
691c1f3eb1ian	struct xrefinfo *xi;
692c1f3eb1ian
693d965bceian	/*
694d965bceian	 * If the given xref handle doesn't already exist in the list then we
695d965bceian	 * add a list entry.  In theory this can only happen on a system where
696d965bceian	 * nodes don't contain phandle properties and xref and node handles are
697d965bceian	 * synonymous, so the xref handle is added as the node handle as well.
698d965bceian	 */
699