167204Sobrien/*	$NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $	*/
267204Sobrien
3139749Simp/*-
467204Sobrien * Copyright (C) 1995, 1996 Wolfgang Solfrank.
567204Sobrien * Copyright (C) 1995, 1996 TooLs GmbH.
667204Sobrien * All rights reserved.
767204Sobrien *
867204Sobrien * Redistribution and use in source and binary forms, with or without
967204Sobrien * modification, are permitted provided that the following conditions
1067204Sobrien * are met:
1167204Sobrien * 1. Redistributions of source code must retain the above copyright
1267204Sobrien *    notice, this list of conditions and the following disclaimer.
1367204Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1467204Sobrien *    notice, this list of conditions and the following disclaimer in the
1567204Sobrien *    documentation and/or other materials provided with the distribution.
1667204Sobrien * 3. All advertising materials mentioning features or use of this software
1767204Sobrien *    must display the following acknowledgement:
1867204Sobrien *	This product includes software developed by TooLs GmbH.
1967204Sobrien * 4. The name of TooLs GmbH may not be used to endorse or promote products
2067204Sobrien *    derived from this software without specific prior written permission.
2167204Sobrien *
2267204Sobrien * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2367204Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2467204Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2567204Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2667204Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2767204Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2867204Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2967204Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3067204Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3167204Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3267204Sobrien */
33139749Simp/*-
3467204Sobrien * Copyright (C) 2000 Benno Rice.
3567204Sobrien * All rights reserved.
3667204Sobrien *
3767204Sobrien * Redistribution and use in source and binary forms, with or without
3867204Sobrien * modification, are permitted provided that the following conditions
3967204Sobrien * are met:
4067204Sobrien * 1. Redistributions of source code must retain the above copyright
4167204Sobrien *    notice, this list of conditions and the following disclaimer.
4267204Sobrien * 2. Redistributions in binary form must reproduce the above copyright
4367204Sobrien *    notice, this list of conditions and the following disclaimer in the
4467204Sobrien *    documentation and/or other materials provided with the distribution.
4567204Sobrien *
4667204Sobrien * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
4767204Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4867204Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4967204Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5067204Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
5167204Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
5267204Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5367204Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
5467204Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
5567204Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5667204Sobrien */
5767204Sobrien
58170838Smarius#include <sys/cdefs.h>
59170838Smarius__FBSDID("$FreeBSD$");
60170838Smarius
61208614Sraj#include "opt_platform.h"
62208614Sraj
6380697Sjake#include <sys/param.h>
6486557Stmm#include <sys/kernel.h>
65273655Sian#include <sys/lock.h>
6686557Stmm#include <sys/malloc.h>
67273655Sian#include <sys/mutex.h>
68273655Sian#include <sys/queue.h>
6978346Sbenno#include <sys/systm.h>
70259255Sandreast#include <sys/endian.h>
7178346Sbenno
7267204Sobrien#include <machine/stdarg.h>
7367204Sobrien
74194138Smarius#include <dev/ofw/ofwvar.h>
7578346Sbenno#include <dev/ofw/openfirm.h>
7668548Sbenno
77186347Snwhitehorn#include "ofw_if.h"
78186347Snwhitehorn
79230631Smariusstatic void OF_putchar(int c, void *arg);
80230631Smarius
81133862SmariusMALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties");
8286557Stmm
8367204Sobrienstatic ihandle_t stdout;
8467204Sobrien
85215049Snwhitehornstatic ofw_def_t	*ofw_def_impl = NULL;
86186347Snwhitehornstatic ofw_t		ofw_obj;
87186347Snwhitehornstatic struct ofw_kobj	ofw_kernel_obj;
88186347Snwhitehornstatic struct kobj_ops	ofw_kernel_kops;
89186347Snwhitehorn
90273655Sianstruct xrefinfo {
91273655Sian	phandle_t	xref;
92273655Sian	phandle_t 	node;
93273655Sian	device_t  	dev;
94273655Sian	SLIST_ENTRY(xrefinfo) next_entry;
95273655Sian};
96273655Sian
97273655Sianstatic SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist);
98273655Sianstatic struct mtx xreflist_lock;
99273655Sianstatic boolean_t xref_init_done;
100273655Sian
101273655Sian#define	FIND_BY_XREF	0
102273655Sian#define	FIND_BY_NODE	1
103273655Sian#define	FIND_BY_DEV	2
104273655Sian
105186347Snwhitehorn/*
106273655Sian * xref-phandle-device lookup helper routines.
107273655Sian *
108273655Sian * As soon as we are able to use malloc(), walk the node tree and build a list
109273655Sian * of info that cross-references node handles, xref handles, and device_t
110273655Sian * instances.  This list exists primarily to allow association of a device_t
111273655Sian * with an xref handle, but it is also used to speed up translation between xref
112273655Sian * and node handles.  Before malloc() is available we have to recursively search
113273655Sian * the node tree each time we want to translate between a node and xref handle.
114273655Sian * Afterwards we can do the translations by searching this much shorter list.
115273655Sian */
116273655Sianstatic void
117273655Sianxrefinfo_create(phandle_t node)
118273655Sian{
119273655Sian	struct xrefinfo * xi;
120273655Sian	phandle_t child, xref;
121273655Sian
122273655Sian	/*
123273655Sian	 * Recursively descend from parent, looking for nodes with a property
124273655Sian	 * named either "phandle", "ibm,phandle", or "linux,phandle".  For each
125273655Sian	 * such node found create an entry in the xreflist.
126273655Sian	 */
127273655Sian	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
128273655Sian		xrefinfo_create(child);
129273655Sian		if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) ==
130273655Sian		    -1 && OF_getencprop(child, "ibm,phandle", &xref,
131273655Sian		    sizeof(xref)) == -1 && OF_getencprop(child,
132273655Sian		    "linux,phandle", &xref, sizeof(xref)) == -1)
133273655Sian			continue;
134273655Sian		xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO);
135273655Sian		xi->node = child;
136273655Sian		xi->xref = xref;
137273655Sian		SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
138273655Sian	}
139273655Sian}
140273655Sian
141273655Sianstatic void
142273655Sianxrefinfo_init(void *unsed)
143273655Sian{
144273655Sian
145273655Sian	/*
146273655Sian	 * There is no locking during this init because it runs much earlier
147273655Sian	 * than any of the clients/consumers of the xref list data, but we do
148273655Sian	 * initialize the mutex that will be used for access later.
149273655Sian	 */
150273655Sian	mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF);
151273655Sian	xrefinfo_create(OF_peer(0));
152273655Sian	xref_init_done = true;
153273655Sian}
154273655SianSYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL);
155273655Sian
156273655Sianstatic struct xrefinfo *
157283477Sianxrefinfo_find(uintptr_t key, int find_by)
158273655Sian{
159273655Sian	struct xrefinfo *rv, *xi;
160273655Sian
161273655Sian	rv = NULL;
162273655Sian	mtx_lock(&xreflist_lock);
163273655Sian	SLIST_FOREACH(xi, &xreflist, next_entry) {
164283477Sian		if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) ||
165283477Sian		    (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) ||
166283477Sian		    (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) {
167273655Sian			rv = xi;
168273655Sian			break;
169273655Sian		}
170273655Sian	}
171273655Sian	mtx_unlock(&xreflist_lock);
172273655Sian	return (rv);
173273655Sian}
174273655Sian
175273655Sianstatic struct xrefinfo *
176273655Sianxrefinfo_add(phandle_t node, phandle_t xref, device_t dev)
177273655Sian{
178273655Sian	struct xrefinfo *xi;
179273655Sian
180273655Sian	xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK);
181273655Sian	xi->node = node;
182273655Sian	xi->xref = xref;
183273655Sian	xi->dev  = dev;
184273655Sian	mtx_lock(&xreflist_lock);
185273655Sian	SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
186273655Sian	mtx_unlock(&xreflist_lock);
187273655Sian	return (xi);
188273655Sian}
189273655Sian
190273655Sian/*
191230631Smarius * OFW install routines.  Highest priority wins, equal priority also
192186347Snwhitehorn * overrides allowing last-set to win.
193186347Snwhitehorn */
194186347SnwhitehornSET_DECLARE(ofw_set, ofw_def_t);
195186347Snwhitehorn
196186347Snwhitehornboolean_t
197186347SnwhitehornOF_install(char *name, int prio)
198186347Snwhitehorn{
199194138Smarius	ofw_def_t *ofwp, **ofwpp;
200186347Snwhitehorn	static int curr_prio = 0;
201186347Snwhitehorn
202186347Snwhitehorn	/*
203194138Smarius	 * Try and locate the OFW kobj corresponding to the name.
204194138Smarius	 */
205186347Snwhitehorn	SET_FOREACH(ofwpp, ofw_set) {
206186347Snwhitehorn		ofwp = *ofwpp;
207186347Snwhitehorn
208186347Snwhitehorn		if (ofwp->name &&
209186347Snwhitehorn		    !strcmp(ofwp->name, name) &&
210186347Snwhitehorn		    prio >= curr_prio) {
211186347Snwhitehorn			curr_prio = prio;
212186347Snwhitehorn			ofw_def_impl = ofwp;
213186347Snwhitehorn			return (TRUE);
214186347Snwhitehorn		}
215186347Snwhitehorn	}
216186347Snwhitehorn
217186347Snwhitehorn	return (FALSE);
218186347Snwhitehorn}
219186347Snwhitehorn
220194138Smarius/* Initializer */
221208614Srajint
222186347SnwhitehornOF_init(void *cookie)
22367204Sobrien{
224170838Smarius	phandle_t chosen;
225208614Sraj	int rv;
22678346Sbenno
227215049Snwhitehorn	if (ofw_def_impl == NULL)
228215049Snwhitehorn		return (-1);
229215049Snwhitehorn
230186347Snwhitehorn	ofw_obj = &ofw_kernel_obj;
231186347Snwhitehorn	/*
232186347Snwhitehorn	 * Take care of compiling the selected class, and
233194138Smarius	 * then statically initialize the OFW object.
234186347Snwhitehorn	 */
235186347Snwhitehorn	kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops);
236227537Smarius	kobj_init_static((kobj_t)ofw_obj, ofw_def_impl);
237186347Snwhitehorn
238208614Sraj	rv = OFW_INIT(ofw_obj, cookie);
239186347Snwhitehorn
240228201Sjchandra	if ((chosen = OF_finddevice("/chosen")) != -1)
241265967Sian		if (OF_getencprop(chosen, "stdout", &stdout,
242265967Sian		    sizeof(stdout)) == -1)
243208614Sraj			stdout = -1;
244208614Sraj
245208614Sraj	return (rv);
24667204Sobrien}
24767204Sobrien
248230631Smariusstatic void
249230631SmariusOF_putchar(int c, void *arg __unused)
250230631Smarius{
251230631Smarius	char cbuf;
252230631Smarius
253230631Smarius	if (c == '\n') {
254230631Smarius		cbuf = '\r';
255230631Smarius		OF_write(stdout, &cbuf, 1);
256230631Smarius	}
257230631Smarius
258230631Smarius	cbuf = c;
259230631Smarius	OF_write(stdout, &cbuf, 1);
260230631Smarius}
261230631Smarius
26278346Sbennovoid
26378346SbennoOF_printf(const char *fmt, ...)
26478346Sbenno{
26578346Sbenno	va_list	va;
26678346Sbenno
26778346Sbenno	va_start(va, fmt);
268230631Smarius	(void)kvprintf(fmt, OF_putchar, NULL, 10, va);
26978346Sbenno	va_end(va);
27078346Sbenno}
27178346Sbenno
27267204Sobrien/*
27367204Sobrien * Generic functions
27467204Sobrien */
27567204Sobrien
27667204Sobrien/* Test to see if a service exists. */
27767204Sobrienint
278186347SnwhitehornOF_test(const char *name)
27967204Sobrien{
280194138Smarius
281215049Snwhitehorn	if (ofw_def_impl == NULL)
282215049Snwhitehorn		return (-1);
283215049Snwhitehorn
284186347Snwhitehorn	return (OFW_TEST(ofw_obj, name));
28567204Sobrien}
28667204Sobrien
287115973Sjakeint
288186347SnwhitehornOF_interpret(const char *cmd, int nreturns, ...)
289115973Sjake{
290115973Sjake	va_list ap;
291212477Smarius	cell_t slots[16];
292115973Sjake	int i = 0;
293186347Snwhitehorn	int status;
294115973Sjake
295215049Snwhitehorn	if (ofw_def_impl == NULL)
296215049Snwhitehorn		return (-1);
297215049Snwhitehorn
298186347Snwhitehorn	status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots);
299190522Smarius	if (status == -1)
300190522Smarius		return (status);
301186347Snwhitehorn
302171265Speter	va_start(ap, nreturns);
303190522Smarius	while (i < nreturns)
304186347Snwhitehorn		*va_arg(ap, cell_t *) = slots[i++];
305115973Sjake	va_end(ap);
306186347Snwhitehorn
307115973Sjake	return (status);
308115973Sjake}
309115973Sjake
31067204Sobrien/*
31167204Sobrien * Device tree functions
31267204Sobrien */
31367204Sobrien
31467204Sobrien/* Return the next sibling of this node or 0. */
31567204Sobrienphandle_t
31667204SobrienOF_peer(phandle_t node)
31767204Sobrien{
318194138Smarius
319215049Snwhitehorn	if (ofw_def_impl == NULL)
320215049Snwhitehorn		return (0);
321215049Snwhitehorn
322186347Snwhitehorn	return (OFW_PEER(ofw_obj, node));
32367204Sobrien}
32467204Sobrien
32567204Sobrien/* Return the first child of this node or 0. */
32667204Sobrienphandle_t
32767204SobrienOF_child(phandle_t node)
32867204Sobrien{
329194138Smarius
330215049Snwhitehorn	if (ofw_def_impl == NULL)
331215049Snwhitehorn		return (0);
332215049Snwhitehorn
333186347Snwhitehorn	return (OFW_CHILD(ofw_obj, node));
33467204Sobrien}
33567204Sobrien
33667204Sobrien/* Return the parent of this node or 0. */
33767204Sobrienphandle_t
33867204SobrienOF_parent(phandle_t node)
33967204Sobrien{
340194138Smarius
341215049Snwhitehorn	if (ofw_def_impl == NULL)
342215049Snwhitehorn		return (0);
343215049Snwhitehorn
344186347Snwhitehorn	return (OFW_PARENT(ofw_obj, node));
34567204Sobrien}
34667204Sobrien
34767204Sobrien/* Return the package handle that corresponds to an instance handle. */
34867204Sobrienphandle_t
34967204SobrienOF_instance_to_package(ihandle_t instance)
35067204Sobrien{
351194138Smarius
352215049Snwhitehorn	if (ofw_def_impl == NULL)
353215049Snwhitehorn		return (-1);
354215049Snwhitehorn
355186347Snwhitehorn	return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance));
35667204Sobrien}
35767204Sobrien
35867204Sobrien/* Get the length of a property of a package. */
359186347Snwhitehornssize_t
360186347SnwhitehornOF_getproplen(phandle_t package, const char *propname)
36167204Sobrien{
362194138Smarius
363215049Snwhitehorn	if (ofw_def_impl == NULL)
364215049Snwhitehorn		return (-1);
365215049Snwhitehorn
366186347Snwhitehorn	return (OFW_GETPROPLEN(ofw_obj, package, propname));
36767204Sobrien}
36867204Sobrien
369239366Shrs/* Check existence of a property of a package. */
370239366Shrsint
371239366ShrsOF_hasprop(phandle_t package, const char *propname)
372239366Shrs{
373239366Shrs
374239366Shrs	return (OF_getproplen(package, propname) >= 0 ? 1 : 0);
375239366Shrs}
376239366Shrs
37767204Sobrien/* Get the value of a property of a package. */
378186347Snwhitehornssize_t
379186347SnwhitehornOF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
38067204Sobrien{
381194138Smarius
382215049Snwhitehorn	if (ofw_def_impl == NULL)
383215049Snwhitehorn		return (-1);
384215049Snwhitehorn
385186347Snwhitehorn	return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen));
38667204Sobrien}
38767204Sobrien
388259255Sandreastssize_t
389259255SandreastOF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
390259255Sandreast{
391259255Sandreast	ssize_t retval;
392259255Sandreast	int i;
393259255Sandreast
394259255Sandreast	KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes"));
395259255Sandreast
396259255Sandreast	retval = OF_getprop(node, propname, buf, len);
397259255Sandreast	for (i = 0; i < len/4; i++)
398259255Sandreast		buf[i] = be32toh(buf[i]);
399259255Sandreast
400259255Sandreast	return (retval);
401259255Sandreast}
402259255Sandreast
40386557Stmm/*
404208614Sraj * Recursively search the node and its parent for the given property, working
405186728Snwhitehorn * downward from the node to the device tree root.  Returns the value of the
406186728Snwhitehorn * first match.
407186728Snwhitehorn */
408186728Snwhitehornssize_t
409194138SmariusOF_searchprop(phandle_t node, const char *propname, void *buf, size_t len)
410186728Snwhitehorn{
411186728Snwhitehorn	ssize_t rv;
412186728Snwhitehorn
413194138Smarius	for (; node != 0; node = OF_parent(node))
414186728Snwhitehorn		if ((rv = OF_getprop(node, propname, buf, len)) != -1)
415186728Snwhitehorn			return (rv);
416186728Snwhitehorn	return (-1);
417186728Snwhitehorn}
418186728Snwhitehorn
419259255Sandreastssize_t
420259255SandreastOF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len)
421259255Sandreast{
422259255Sandreast	ssize_t rv;
423259255Sandreast
424259255Sandreast	for (; node != 0; node = OF_parent(node))
425259255Sandreast		if ((rv = OF_getencprop(node, propname, buf, len)) != -1)
426259255Sandreast			return (rv);
427259255Sandreast	return (-1);
428259255Sandreast}
429259255Sandreast
430186728Snwhitehorn/*
431129588Smarius * Store the value of a property of a package into newly allocated memory
432194138Smarius * (using the M_OFWPROP malloc pool and M_WAITOK).  elsz is the size of a
433129588Smarius * single element, the number of elements is return in number.
43486557Stmm */
435186347Snwhitehornssize_t
436186347SnwhitehornOF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf)
43786557Stmm{
43886557Stmm	int len;
43986557Stmm
44086557Stmm	*buf = NULL;
44186557Stmm	if ((len = OF_getproplen(package, propname)) == -1 ||
44286557Stmm	    len % elsz != 0)
44386557Stmm		return (-1);
44486557Stmm
445111119Simp	*buf = malloc(len, M_OFWPROP, M_WAITOK);
44686557Stmm	if (OF_getprop(package, propname, *buf, len) == -1) {
44786557Stmm		free(*buf, M_OFWPROP);
44886557Stmm		*buf = NULL;
44986557Stmm		return (-1);
45086557Stmm	}
45186557Stmm	return (len / elsz);
45286557Stmm}
45386557Stmm
454259255Sandreastssize_t
455259255SandreastOF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf)
456259255Sandreast{
457259255Sandreast	ssize_t retval;
458259255Sandreast	pcell_t *cell;
459259255Sandreast	int i;
460259255Sandreast
461259255Sandreast	retval = OF_getprop_alloc(package, name, elsz, buf);
462265967Sian	if (retval == -1 || retval*elsz % 4 != 0)
463265967Sian		return (-1);
464259255Sandreast
465259255Sandreast	cell = *buf;
466259255Sandreast	for (i = 0; i < retval*elsz/4; i++)
467259255Sandreast		cell[i] = be32toh(cell[i]);
468259255Sandreast
469259255Sandreast	return (retval);
470259255Sandreast}
471259255Sandreast
47267204Sobrien/* Get the next property of a package. */
47367204Sobrienint
474186347SnwhitehornOF_nextprop(phandle_t package, const char *previous, char *buf, size_t size)
47567204Sobrien{
476194138Smarius
477215049Snwhitehorn	if (ofw_def_impl == NULL)
478215049Snwhitehorn		return (-1);
479215049Snwhitehorn
480186347Snwhitehorn	return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size));
48167204Sobrien}
48267204Sobrien
48367204Sobrien/* Set the value of a property of a package. */
48467204Sobrienint
485186347SnwhitehornOF_setprop(phandle_t package, const char *propname, const void *buf, size_t len)
48667204Sobrien{
487194138Smarius
488215049Snwhitehorn	if (ofw_def_impl == NULL)
489215049Snwhitehorn		return (-1);
490215049Snwhitehorn
491186347Snwhitehorn	return (OFW_SETPROP(ofw_obj, package, propname, buf,len));
49267204Sobrien}
49367204Sobrien
49467204Sobrien/* Convert a device specifier to a fully qualified pathname. */
495186347Snwhitehornssize_t
496186347SnwhitehornOF_canon(const char *device, char *buf, size_t len)
49767204Sobrien{
498194138Smarius
499215049Snwhitehorn	if (ofw_def_impl == NULL)
500215049Snwhitehorn		return (-1);
501215049Snwhitehorn
502186347Snwhitehorn	return (OFW_CANON(ofw_obj, device, buf, len));
50367204Sobrien}
50467204Sobrien
50567204Sobrien/* Return a package handle for the specified device. */
50667204Sobrienphandle_t
50768548SbennoOF_finddevice(const char *device)
50867204Sobrien{
509194138Smarius
510215049Snwhitehorn	if (ofw_def_impl == NULL)
511215049Snwhitehorn		return (-1);
512215049Snwhitehorn
513186347Snwhitehorn	return (OFW_FINDDEVICE(ofw_obj, device));
51467204Sobrien}
51567204Sobrien
51667204Sobrien/* Return the fully qualified pathname corresponding to an instance. */
517186347Snwhitehornssize_t
518186347SnwhitehornOF_instance_to_path(ihandle_t instance, char *buf, size_t len)
51967204Sobrien{
520194138Smarius
521215049Snwhitehorn	if (ofw_def_impl == NULL)
522215049Snwhitehorn		return (-1);
523215049Snwhitehorn
524186347Snwhitehorn	return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len));
52567204Sobrien}
52667204Sobrien
52767204Sobrien/* Return the fully qualified pathname corresponding to a package. */
528186347Snwhitehornssize_t
529186347SnwhitehornOF_package_to_path(phandle_t package, char *buf, size_t len)
53067204Sobrien{
531194138Smarius
532215049Snwhitehorn	if (ofw_def_impl == NULL)
533215049Snwhitehorn		return (-1);
534215049Snwhitehorn
535186347Snwhitehorn	return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len));
53667204Sobrien}
53767204Sobrien
538255596Snwhitehorn/* Look up effective phandle (see FDT/PAPR spec) */
539255596Snwhitehornstatic phandle_t
540255596SnwhitehornOF_child_xref_phandle(phandle_t parent, phandle_t xref)
541255596Snwhitehorn{
542255596Snwhitehorn	phandle_t child, rxref;
543255596Snwhitehorn
544255596Snwhitehorn	/*
545255596Snwhitehorn	 * Recursively descend from parent, looking for a node with a property
546255596Snwhitehorn	 * named either "phandle", "ibm,phandle", or "linux,phandle" that
547255596Snwhitehorn	 * matches the xref we are looking for.
548255596Snwhitehorn	 */
549255596Snwhitehorn
550255596Snwhitehorn	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
551255596Snwhitehorn		rxref = OF_child_xref_phandle(child, xref);
552255596Snwhitehorn		if (rxref != -1)
553255596Snwhitehorn			return (rxref);
554255596Snwhitehorn
555265967Sian		if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) ==
556265967Sian		    -1 && OF_getencprop(child, "ibm,phandle", &rxref,
557265967Sian		    sizeof(rxref)) == -1 && OF_getencprop(child,
558255596Snwhitehorn		    "linux,phandle", &rxref, sizeof(rxref)) == -1)
559255596Snwhitehorn			continue;
560255596Snwhitehorn
561255596Snwhitehorn		if (rxref == xref)
562255596Snwhitehorn			return (child);
563255596Snwhitehorn	}
564255596Snwhitehorn
565255596Snwhitehorn	return (-1);
566255596Snwhitehorn}
567255596Snwhitehorn
568255596Snwhitehornphandle_t
569273652SianOF_node_from_xref(phandle_t xref)
570255596Snwhitehorn{
571273655Sian	struct xrefinfo *xi;
572255596Snwhitehorn	phandle_t node;
573255596Snwhitehorn
574273655Sian	if (xref_init_done) {
575273655Sian		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
576273655Sian			return (xref);
577273655Sian		return (xi->node);
578273655Sian	}
579273655Sian
580273655Sian	if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1)
581255596Snwhitehorn		return (xref);
582255596Snwhitehorn	return (node);
583255596Snwhitehorn}
584255596Snwhitehorn
585273652Sianphandle_t
586273652SianOF_xref_from_node(phandle_t node)
587273652Sian{
588273655Sian	struct xrefinfo *xi;
589273652Sian	phandle_t xref;
590273652Sian
591273655Sian	if (xref_init_done) {
592273655Sian		if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL)
593273655Sian			return (node);
594273655Sian		return (xi->xref);
595273655Sian	}
596273655Sian
597273652Sian	if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) ==
598273652Sian	    -1 && OF_getencprop(node, "ibm,phandle", &xref,
599273652Sian	    sizeof(xref)) == -1 && OF_getencprop(node,
600273652Sian	    "linux,phandle", &xref, sizeof(xref)) == -1)
601273652Sian		return (node);
602273652Sian	return (xref);
603273652Sian}
604273652Sian
605273655Siandevice_t
606273655SianOF_device_from_xref(phandle_t xref)
607273655Sian{
608273655Sian	struct xrefinfo *xi;
609273655Sian
610273655Sian	if (xref_init_done) {
611273655Sian		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
612273655Sian			return (NULL);
613273655Sian		return (xi->dev);
614273655Sian	}
615273655Sian	panic("Attempt to find device before xreflist_init");
616273655Sian}
617273655Sian
618273655Sianphandle_t
619273655SianOF_xref_from_device(device_t dev)
620273655Sian{
621273655Sian	struct xrefinfo *xi;
622273655Sian
623273655Sian	if (xref_init_done) {
624273655Sian		if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL)
625273655Sian			return (0);
626273655Sian		return (xi->xref);
627273655Sian	}
628273655Sian	panic("Attempt to find xref before xreflist_init");
629273655Sian}
630273655Sian
631273655Sianint
632273655SianOF_device_register_xref(phandle_t xref, device_t dev)
633273655Sian{
634273655Sian	struct xrefinfo *xi;
635273655Sian
636273655Sian	/*
637273655Sian	 * If the given xref handle doesn't already exist in the list then we
638273655Sian	 * add a list entry.  In theory this can only happen on a system where
639273655Sian	 * nodes don't contain phandle properties and xref and node handles are
640273655Sian	 * synonymous, so the xref handle is added as the node handle as well.
641273655Sian	 */
642273655Sian	if (xref_init_done) {
643273655Sian		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
644273655Sian			xrefinfo_add(xref, xref, dev);
645273655Sian		else
646273655Sian			xi->dev = dev;
647273655Sian		return (0);
648273655Sian	}
649273655Sian	panic("Attempt to register device before xreflist_init");
650273655Sian}
651273655Sian
65267204Sobrien/*  Call the method in the scope of a given instance. */
65367204Sobrienint
654186347SnwhitehornOF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns,
655186347Snwhitehorn    ...)
65667204Sobrien{
65767204Sobrien	va_list ap;
658209801Snwhitehorn	cell_t args_n_results[12];
659186347Snwhitehorn	int n, status;
66067204Sobrien
661215049Snwhitehorn	if (nargs > 6 || ofw_def_impl == NULL)
662170838Smarius		return (-1);
66367204Sobrien	va_start(ap, nreturns);
664186347Snwhitehorn	for (n = 0; n < nargs; n++)
665209801Snwhitehorn		args_n_results[n] = va_arg(ap, cell_t);
666186347Snwhitehorn
667186347Snwhitehorn	status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns,
668186347Snwhitehorn	    args_n_results);
669186347Snwhitehorn	if (status != 0)
670186347Snwhitehorn		return (status);
671186347Snwhitehorn
672186347Snwhitehorn	for (; n < nargs + nreturns; n++)
673209801Snwhitehorn		*va_arg(ap, cell_t *) = args_n_results[n];
67467204Sobrien	va_end(ap);
675170838Smarius	return (0);
67667204Sobrien}
67767204Sobrien
67867204Sobrien/*
679170838Smarius * Device I/O functions
68067204Sobrien */
68167204Sobrien
68267204Sobrien/* Open an instance for a device. */
68367204Sobrienihandle_t
684186347SnwhitehornOF_open(const char *device)
68567204Sobrien{
686194138Smarius
687215049Snwhitehorn	if (ofw_def_impl == NULL)
688215049Snwhitehorn		return (0);
689215049Snwhitehorn
690186347Snwhitehorn	return (OFW_OPEN(ofw_obj, device));
69167204Sobrien}
69267204Sobrien
69367204Sobrien/* Close an instance. */
69467204Sobrienvoid
69567204SobrienOF_close(ihandle_t instance)
69667204Sobrien{
697194138Smarius
698215049Snwhitehorn	if (ofw_def_impl == NULL)
699215049Snwhitehorn		return;
700215049Snwhitehorn
701186347Snwhitehorn	OFW_CLOSE(ofw_obj, instance);
70267204Sobrien}
70367204Sobrien
70467204Sobrien/* Read from an instance. */
705186347Snwhitehornssize_t
706186347SnwhitehornOF_read(ihandle_t instance, void *addr, size_t len)
70767204Sobrien{
708194138Smarius
709215049Snwhitehorn	if (ofw_def_impl == NULL)
710215049Snwhitehorn		return (-1);
711215049Snwhitehorn
712186347Snwhitehorn	return (OFW_READ(ofw_obj, instance, addr, len));
71367204Sobrien}
71467204Sobrien
71567204Sobrien/* Write to an instance. */
716186347Snwhitehornssize_t
717186347SnwhitehornOF_write(ihandle_t instance, const void *addr, size_t len)
71867204Sobrien{
719194138Smarius
720215049Snwhitehorn	if (ofw_def_impl == NULL)
721215049Snwhitehorn		return (-1);
722215049Snwhitehorn
723186347Snwhitehorn	return (OFW_WRITE(ofw_obj, instance, addr, len));
72467204Sobrien}
72567204Sobrien
72667204Sobrien/* Seek to a position. */
72767204Sobrienint
728186347SnwhitehornOF_seek(ihandle_t instance, uint64_t pos)
72967204Sobrien{
730194138Smarius
731215049Snwhitehorn	if (ofw_def_impl == NULL)
732215049Snwhitehorn		return (-1);
733215049Snwhitehorn
734186347Snwhitehorn	return (OFW_SEEK(ofw_obj, instance, pos));
73567204Sobrien}
73667204Sobrien
73767204Sobrien/*
738170838Smarius * Memory functions
73967204Sobrien */
74067204Sobrien
74167204Sobrien/* Claim an area of memory. */
74267204Sobrienvoid *
743186347SnwhitehornOF_claim(void *virt, size_t size, u_int align)
74467204Sobrien{
745194138Smarius
746215049Snwhitehorn	if (ofw_def_impl == NULL)
747215049Snwhitehorn		return ((void *)-1);
748215049Snwhitehorn
749186347Snwhitehorn	return (OFW_CLAIM(ofw_obj, virt, size, align));
75067204Sobrien}
75167204Sobrien
75267204Sobrien/* Release an area of memory. */
75367204Sobrienvoid
754186347SnwhitehornOF_release(void *virt, size_t size)
75567204Sobrien{
756194138Smarius
757215049Snwhitehorn	if (ofw_def_impl == NULL)
758215049Snwhitehorn		return;
759215049Snwhitehorn
760186347Snwhitehorn	OFW_RELEASE(ofw_obj, virt, size);
76167204Sobrien}
76267204Sobrien
76367204Sobrien/*
764170838Smarius * Control transfer functions
76567204Sobrien */
76667204Sobrien
767133862Smarius/* Suspend and drop back to the Open Firmware interface. */
76867204Sobrienvoid
76967204SobrienOF_enter()
77067204Sobrien{
771194138Smarius
772215049Snwhitehorn	if (ofw_def_impl == NULL)
773215049Snwhitehorn		return;
774215049Snwhitehorn
775186347Snwhitehorn	OFW_ENTER(ofw_obj);
77667204Sobrien}
77767204Sobrien
778133862Smarius/* Shut down and drop back to the Open Firmware interface. */
77968548Sbennovoid
78067204SobrienOF_exit()
78167204Sobrien{
782194138Smarius
783215049Snwhitehorn	if (ofw_def_impl == NULL)
784215049Snwhitehorn		panic("OF_exit: Open Firmware not available");
785215049Snwhitehorn
786186347Snwhitehorn	/* Should not return */
787186347Snwhitehorn	OFW_EXIT(ofw_obj);
78867204Sobrien
789170838Smarius	for (;;)			/* just in case */
790170838Smarius		;
79167204Sobrien}
792