xref: /onnv-gate/usr/src/psm/promif/ieee1275/common/prom_node.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 1994,1998-2000,2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/promif.h>
30*0Sstevel@tonic-gate #include <sys/promimpl.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * Routines for walking the PROMs devinfo tree
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate dnode_t
36*0Sstevel@tonic-gate prom_nextnode(dnode_t nodeid)
37*0Sstevel@tonic-gate {
38*0Sstevel@tonic-gate 	cell_t ci[5];
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("peer");		/* Service name */
41*0Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
42*0Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
43*0Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
44*0Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate 	promif_preprom();
47*0Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
48*0Sstevel@tonic-gate 	promif_postprom();
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: peer phandle */
51*0Sstevel@tonic-gate }
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate dnode_t
54*0Sstevel@tonic-gate prom_childnode(dnode_t nodeid)
55*0Sstevel@tonic-gate {
56*0Sstevel@tonic-gate 	cell_t ci[5];
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("child");	/* Service name */
59*0Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
60*0Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
61*0Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
62*0Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	promif_preprom();
65*0Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
66*0Sstevel@tonic-gate 	promif_postprom();
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: child phandle */
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /*
72*0Sstevel@tonic-gate  * prom_walk_devs() implements a generic walker for the OBP tree; this
73*0Sstevel@tonic-gate  * implementation uses an explicitly managed stack in order to save the
74*0Sstevel@tonic-gate  * overhead of a recursive implementation.
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate void
77*0Sstevel@tonic-gate prom_walk_devs(dnode_t node, int (*cb)(dnode_t, void *, void *), void *arg,
78*0Sstevel@tonic-gate     void *result)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	dnode_t stack[OBP_STACKDEPTH];
81*0Sstevel@tonic-gate 	int stackidx = 0;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	if (node == OBP_NONODE || node == OBP_BADNODE) {
84*0Sstevel@tonic-gate 		prom_panic("Invalid node specified as root of prom tree walk");
85*0Sstevel@tonic-gate 	}
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	stack[0] = node;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	for (;;) {
90*0Sstevel@tonic-gate 		dnode_t curnode = stack[stackidx];
91*0Sstevel@tonic-gate 		dnode_t child;
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 		/*
94*0Sstevel@tonic-gate 		 * We're out of stuff to do at this level, bump back up a level
95*0Sstevel@tonic-gate 		 * in the tree, and move to the next node;  if the new level
96*0Sstevel@tonic-gate 		 * will be level -1, we're done.
97*0Sstevel@tonic-gate 		 */
98*0Sstevel@tonic-gate 		if (curnode == OBP_NONODE || curnode == OBP_BADNODE) {
99*0Sstevel@tonic-gate 			stackidx--;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 			if (stackidx < 0)
102*0Sstevel@tonic-gate 				return;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 			stack[stackidx] = prom_nextnode(stack[stackidx]);
105*0Sstevel@tonic-gate 			continue;
106*0Sstevel@tonic-gate 		}
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 		switch ((*cb)(curnode, arg, result)) {
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 		case PROM_WALK_TERMINATE:
111*0Sstevel@tonic-gate 			return;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 		case PROM_WALK_CONTINUE:
114*0Sstevel@tonic-gate 			/*
115*0Sstevel@tonic-gate 			 * If curnode has a child, traverse to it,
116*0Sstevel@tonic-gate 			 * otherwise move to curnode's sibling.
117*0Sstevel@tonic-gate 			 */
118*0Sstevel@tonic-gate 			child = prom_childnode(curnode);
119*0Sstevel@tonic-gate 			if (child != OBP_NONODE && child != OBP_BADNODE) {
120*0Sstevel@tonic-gate 				stackidx++;
121*0Sstevel@tonic-gate 				stack[stackidx] = child;
122*0Sstevel@tonic-gate 			} else {
123*0Sstevel@tonic-gate 				stack[stackidx] =
124*0Sstevel@tonic-gate 				    prom_nextnode(stack[stackidx]);
125*0Sstevel@tonic-gate 			}
126*0Sstevel@tonic-gate 			break;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 		default:
129*0Sstevel@tonic-gate 			prom_panic("unrecognized walk directive");
130*0Sstevel@tonic-gate 		}
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate /*
135*0Sstevel@tonic-gate  * prom_findnode_bydevtype() searches the prom device subtree rooted at 'node'
136*0Sstevel@tonic-gate  * and returns the first node whose device type property matches the type
137*0Sstevel@tonic-gate  * supplied in 'devtype'.
138*0Sstevel@tonic-gate  */
139*0Sstevel@tonic-gate static int
140*0Sstevel@tonic-gate bytype_cb(dnode_t node, void *arg, void *result)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	if (prom_devicetype(node, (char *)arg)) {
143*0Sstevel@tonic-gate 		*((dnode_t *)result) = node;
144*0Sstevel@tonic-gate 		return (PROM_WALK_TERMINATE);
145*0Sstevel@tonic-gate 	}
146*0Sstevel@tonic-gate 	return (PROM_WALK_CONTINUE);
147*0Sstevel@tonic-gate }
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate dnode_t
150*0Sstevel@tonic-gate prom_findnode_bydevtype(dnode_t node, char *devtype)
151*0Sstevel@tonic-gate {
152*0Sstevel@tonic-gate 	dnode_t result = OBP_NONODE;
153*0Sstevel@tonic-gate 	prom_walk_devs(node, bytype_cb, devtype, &result);
154*0Sstevel@tonic-gate 	return (result);
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate /*
159*0Sstevel@tonic-gate  * prom_findnode_byname() searches the prom device subtree rooted at 'node' and
160*0Sstevel@tonic-gate  * returns the first node whose name matches the name supplied in 'name'.
161*0Sstevel@tonic-gate  */
162*0Sstevel@tonic-gate static int
163*0Sstevel@tonic-gate byname_cb(dnode_t node, void *arg, void *result)
164*0Sstevel@tonic-gate {
165*0Sstevel@tonic-gate 	if (prom_getnode_byname(node, (char *)arg)) {
166*0Sstevel@tonic-gate 		*((dnode_t *)result) = node;
167*0Sstevel@tonic-gate 		return (PROM_WALK_TERMINATE);
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 	return (PROM_WALK_CONTINUE);
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate dnode_t
173*0Sstevel@tonic-gate prom_findnode_byname(dnode_t node, char *name)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	dnode_t result = OBP_NONODE;
176*0Sstevel@tonic-gate 	prom_walk_devs(node, byname_cb, name, &result);
177*0Sstevel@tonic-gate 	return (result);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * Return the root nodeid.
182*0Sstevel@tonic-gate  * Calling prom_nextnode(0) returns the root nodeid.
183*0Sstevel@tonic-gate  */
184*0Sstevel@tonic-gate dnode_t
185*0Sstevel@tonic-gate prom_rootnode(void)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	static dnode_t rootnode;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	return (rootnode ? rootnode : (rootnode = prom_nextnode(OBP_NONODE)));
190*0Sstevel@tonic-gate }
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate dnode_t
193*0Sstevel@tonic-gate prom_parentnode(dnode_t nodeid)
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate 	cell_t ci[5];
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("parent");	/* Service name */
198*0Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
199*0Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
200*0Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
201*0Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	promif_preprom();
204*0Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
205*0Sstevel@tonic-gate 	promif_postprom();
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: parent phandle */
208*0Sstevel@tonic-gate }
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate dnode_t
211*0Sstevel@tonic-gate prom_finddevice(char *path)
212*0Sstevel@tonic-gate {
213*0Sstevel@tonic-gate 	cell_t ci[5];
214*0Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
215*0Sstevel@tonic-gate 	char *opath = NULL;
216*0Sstevel@tonic-gate 	size_t len;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if ((uintptr_t)path > (uint32_t)-1) {
219*0Sstevel@tonic-gate 		opath = path;
220*0Sstevel@tonic-gate 		len = prom_strlen(opath) + 1; /* include terminating NUL */
221*0Sstevel@tonic-gate 		path = promplat_alloc(len);
222*0Sstevel@tonic-gate 		if (path == NULL) {
223*0Sstevel@tonic-gate 			return (OBP_BADNODE);
224*0Sstevel@tonic-gate 		}
225*0Sstevel@tonic-gate 		(void) prom_strcpy(path, opath);
226*0Sstevel@tonic-gate 	}
227*0Sstevel@tonic-gate #endif
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	promif_preprom();
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("finddevice");	/* Service name */
232*0Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
233*0Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
234*0Sstevel@tonic-gate 	ci[3] = p1275_ptr2cell(path);		/* Arg1: pathname */
235*0Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_BADNODE);	/* Res1: Prime result */
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	promif_postprom();
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
242*0Sstevel@tonic-gate 	if (opath != NULL)
243*0Sstevel@tonic-gate 		promplat_free(path, len);
244*0Sstevel@tonic-gate #endif
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	return ((dnode_t)p1275_cell2dnode(ci[4])); /* Res1: phandle */
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate dnode_t
250*0Sstevel@tonic-gate prom_chosennode(void)
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	static dnode_t chosen;
253*0Sstevel@tonic-gate 	dnode_t	node;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (chosen)
256*0Sstevel@tonic-gate 		return (chosen);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	node = prom_finddevice("/chosen");
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (node != OBP_BADNODE)
261*0Sstevel@tonic-gate 		return (chosen = node);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	prom_fatal_error("prom_chosennode: Can't find </chosen>\n");
264*0Sstevel@tonic-gate 	/*NOTREACHED*/
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate /*
268*0Sstevel@tonic-gate  * Returns the nodeid of /aliases.
269*0Sstevel@tonic-gate  * /aliases exists in OBP >= 2.4 and in Open Firmware.
270*0Sstevel@tonic-gate  * Returns OBP_BADNODE if it doesn't exist.
271*0Sstevel@tonic-gate  */
272*0Sstevel@tonic-gate dnode_t
273*0Sstevel@tonic-gate prom_alias_node(void)
274*0Sstevel@tonic-gate {
275*0Sstevel@tonic-gate 	static dnode_t node;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	if (node == 0)
278*0Sstevel@tonic-gate 		node = prom_finddevice("/aliases");
279*0Sstevel@tonic-gate 	return (node);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate /*
283*0Sstevel@tonic-gate  * Returns the nodeid of /options.
284*0Sstevel@tonic-gate  * Returns OBP_BADNODE if it doesn't exist.
285*0Sstevel@tonic-gate  */
286*0Sstevel@tonic-gate dnode_t
287*0Sstevel@tonic-gate prom_optionsnode(void)
288*0Sstevel@tonic-gate {
289*0Sstevel@tonic-gate 	static dnode_t node;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (node == 0)
292*0Sstevel@tonic-gate 		node = prom_finddevice("/options");
293*0Sstevel@tonic-gate 	return (node);
294*0Sstevel@tonic-gate }
295