xref: /onnv-gate/usr/src/psm/promif/ieee1275/common/prom_node.c (revision 789:b348f31ed315)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23785Seota  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/promif.h>
300Sstevel@tonic-gate #include <sys/promimpl.h>
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate  * Routines for walking the PROMs devinfo tree
340Sstevel@tonic-gate  */
35*789Sahrens pnode_t
prom_nextnode(pnode_t nodeid)36*789Sahrens prom_nextnode(pnode_t nodeid)
370Sstevel@tonic-gate {
380Sstevel@tonic-gate 	cell_t ci[5];
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("peer");		/* Service name */
410Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
420Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
430Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
440Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate 	promif_preprom();
470Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
480Sstevel@tonic-gate 	promif_postprom();
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: peer phandle */
510Sstevel@tonic-gate }
520Sstevel@tonic-gate 
53*789Sahrens pnode_t
prom_childnode(pnode_t nodeid)54*789Sahrens prom_childnode(pnode_t nodeid)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate 	cell_t ci[5];
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("child");	/* Service name */
590Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
600Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
610Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
620Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	promif_preprom();
650Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
660Sstevel@tonic-gate 	promif_postprom();
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: child phandle */
690Sstevel@tonic-gate }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * prom_walk_devs() implements a generic walker for the OBP tree; this
730Sstevel@tonic-gate  * implementation uses an explicitly managed stack in order to save the
740Sstevel@tonic-gate  * overhead of a recursive implementation.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate void
prom_walk_devs(pnode_t node,int (* cb)(pnode_t,void *,void *),void * arg,void * result)77*789Sahrens prom_walk_devs(pnode_t node, int (*cb)(pnode_t, void *, void *), void *arg,
780Sstevel@tonic-gate     void *result)
790Sstevel@tonic-gate {
80*789Sahrens 	pnode_t stack[OBP_STACKDEPTH];
810Sstevel@tonic-gate 	int stackidx = 0;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	if (node == OBP_NONODE || node == OBP_BADNODE) {
840Sstevel@tonic-gate 		prom_panic("Invalid node specified as root of prom tree walk");
850Sstevel@tonic-gate 	}
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	stack[0] = node;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	for (;;) {
90*789Sahrens 		pnode_t curnode = stack[stackidx];
91*789Sahrens 		pnode_t child;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 		/*
940Sstevel@tonic-gate 		 * We're out of stuff to do at this level, bump back up a level
950Sstevel@tonic-gate 		 * in the tree, and move to the next node;  if the new level
960Sstevel@tonic-gate 		 * will be level -1, we're done.
970Sstevel@tonic-gate 		 */
980Sstevel@tonic-gate 		if (curnode == OBP_NONODE || curnode == OBP_BADNODE) {
990Sstevel@tonic-gate 			stackidx--;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 			if (stackidx < 0)
1020Sstevel@tonic-gate 				return;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 			stack[stackidx] = prom_nextnode(stack[stackidx]);
1050Sstevel@tonic-gate 			continue;
1060Sstevel@tonic-gate 		}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 		switch ((*cb)(curnode, arg, result)) {
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 		case PROM_WALK_TERMINATE:
1110Sstevel@tonic-gate 			return;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 		case PROM_WALK_CONTINUE:
1140Sstevel@tonic-gate 			/*
1150Sstevel@tonic-gate 			 * If curnode has a child, traverse to it,
1160Sstevel@tonic-gate 			 * otherwise move to curnode's sibling.
1170Sstevel@tonic-gate 			 */
1180Sstevel@tonic-gate 			child = prom_childnode(curnode);
1190Sstevel@tonic-gate 			if (child != OBP_NONODE && child != OBP_BADNODE) {
1200Sstevel@tonic-gate 				stackidx++;
1210Sstevel@tonic-gate 				stack[stackidx] = child;
1220Sstevel@tonic-gate 			} else {
1230Sstevel@tonic-gate 				stack[stackidx] =
1240Sstevel@tonic-gate 				    prom_nextnode(stack[stackidx]);
1250Sstevel@tonic-gate 			}
1260Sstevel@tonic-gate 			break;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 		default:
1290Sstevel@tonic-gate 			prom_panic("unrecognized walk directive");
1300Sstevel@tonic-gate 		}
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * prom_findnode_bydevtype() searches the prom device subtree rooted at 'node'
1360Sstevel@tonic-gate  * and returns the first node whose device type property matches the type
1370Sstevel@tonic-gate  * supplied in 'devtype'.
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate static int
bytype_cb(pnode_t node,void * arg,void * result)140*789Sahrens bytype_cb(pnode_t node, void *arg, void *result)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	if (prom_devicetype(node, (char *)arg)) {
143*789Sahrens 		*((pnode_t *)result) = node;
1440Sstevel@tonic-gate 		return (PROM_WALK_TERMINATE);
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 	return (PROM_WALK_CONTINUE);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
149*789Sahrens pnode_t
prom_findnode_bydevtype(pnode_t node,char * devtype)150*789Sahrens prom_findnode_bydevtype(pnode_t node, char *devtype)
1510Sstevel@tonic-gate {
152*789Sahrens 	pnode_t result = OBP_NONODE;
1530Sstevel@tonic-gate 	prom_walk_devs(node, bytype_cb, devtype, &result);
1540Sstevel@tonic-gate 	return (result);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * prom_findnode_byname() searches the prom device subtree rooted at 'node' and
1600Sstevel@tonic-gate  * returns the first node whose name matches the name supplied in 'name'.
1610Sstevel@tonic-gate  */
1620Sstevel@tonic-gate static int
byname_cb(pnode_t node,void * arg,void * result)163*789Sahrens byname_cb(pnode_t node, void *arg, void *result)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	if (prom_getnode_byname(node, (char *)arg)) {
166*789Sahrens 		*((pnode_t *)result) = node;
1670Sstevel@tonic-gate 		return (PROM_WALK_TERMINATE);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 	return (PROM_WALK_CONTINUE);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
172*789Sahrens pnode_t
prom_findnode_byname(pnode_t node,char * name)173*789Sahrens prom_findnode_byname(pnode_t node, char *name)
1740Sstevel@tonic-gate {
175*789Sahrens 	pnode_t result = OBP_NONODE;
1760Sstevel@tonic-gate 	prom_walk_devs(node, byname_cb, name, &result);
1770Sstevel@tonic-gate 	return (result);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * Return the root nodeid.
1820Sstevel@tonic-gate  * Calling prom_nextnode(0) returns the root nodeid.
1830Sstevel@tonic-gate  */
184*789Sahrens pnode_t
prom_rootnode(void)1850Sstevel@tonic-gate prom_rootnode(void)
1860Sstevel@tonic-gate {
187*789Sahrens 	static pnode_t rootnode;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	return (rootnode ? rootnode : (rootnode = prom_nextnode(OBP_NONODE)));
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
192*789Sahrens pnode_t
prom_parentnode(pnode_t nodeid)193*789Sahrens prom_parentnode(pnode_t nodeid)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	cell_t ci[5];
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("parent");	/* Service name */
1980Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
1990Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
2000Sstevel@tonic-gate 	ci[3] = p1275_dnode2cell(nodeid);	/* Arg1: input phandle */
2010Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_NONODE);	/* Res1: Prime result */
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	promif_preprom();
2040Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
2050Sstevel@tonic-gate 	promif_postprom();
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	return (p1275_cell2dnode(ci[4]));	/* Res1: parent phandle */
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
210*789Sahrens pnode_t
prom_finddevice(char * path)2110Sstevel@tonic-gate prom_finddevice(char *path)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate 	cell_t ci[5];
2140Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
2150Sstevel@tonic-gate 	char *opath = NULL;
2160Sstevel@tonic-gate 	size_t len;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if ((uintptr_t)path > (uint32_t)-1) {
2190Sstevel@tonic-gate 		opath = path;
2200Sstevel@tonic-gate 		len = prom_strlen(opath) + 1; /* include terminating NUL */
2210Sstevel@tonic-gate 		path = promplat_alloc(len);
2220Sstevel@tonic-gate 		if (path == NULL) {
2230Sstevel@tonic-gate 			return (OBP_BADNODE);
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 		(void) prom_strcpy(path, opath);
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate #endif
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	promif_preprom();
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("finddevice");	/* Service name */
2320Sstevel@tonic-gate 	ci[1] = (cell_t)1;			/* #argument cells */
2330Sstevel@tonic-gate 	ci[2] = (cell_t)1;			/* #result cells */
2340Sstevel@tonic-gate 	ci[3] = p1275_ptr2cell(path);		/* Arg1: pathname */
2350Sstevel@tonic-gate 	ci[4] = p1275_dnode2cell(OBP_BADNODE);	/* Res1: Prime result */
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	promif_postprom();
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS
2420Sstevel@tonic-gate 	if (opath != NULL)
2430Sstevel@tonic-gate 		promplat_free(path, len);
2440Sstevel@tonic-gate #endif
2450Sstevel@tonic-gate 
246*789Sahrens 	return ((pnode_t)p1275_cell2dnode(ci[4])); /* Res1: phandle */
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
249*789Sahrens pnode_t
prom_chosennode(void)2500Sstevel@tonic-gate prom_chosennode(void)
2510Sstevel@tonic-gate {
252*789Sahrens 	static pnode_t chosen;
253*789Sahrens 	pnode_t	node;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	if (chosen)
2560Sstevel@tonic-gate 		return (chosen);
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	node = prom_finddevice("/chosen");
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (node != OBP_BADNODE)
2610Sstevel@tonic-gate 		return (chosen = node);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	prom_fatal_error("prom_chosennode: Can't find </chosen>\n");
2640Sstevel@tonic-gate 	/*NOTREACHED*/
265785Seota 
266785Seota 	/*
267785Seota 	 * gcc doesn't recognize "NOTREACHED" and puts the warning.
268785Seota 	 * To surpress it, returning an integer value is required.
269785Seota 	 */
270*789Sahrens 	return ((pnode_t)0);
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate  * Returns the nodeid of /aliases.
2750Sstevel@tonic-gate  * /aliases exists in OBP >= 2.4 and in Open Firmware.
2760Sstevel@tonic-gate  * Returns OBP_BADNODE if it doesn't exist.
2770Sstevel@tonic-gate  */
278*789Sahrens pnode_t
prom_alias_node(void)2790Sstevel@tonic-gate prom_alias_node(void)
2800Sstevel@tonic-gate {
281*789Sahrens 	static pnode_t node;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	if (node == 0)
2840Sstevel@tonic-gate 		node = prom_finddevice("/aliases");
2850Sstevel@tonic-gate 	return (node);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate  * Returns the nodeid of /options.
2900Sstevel@tonic-gate  * Returns OBP_BADNODE if it doesn't exist.
2910Sstevel@tonic-gate  */
292*789Sahrens pnode_t
prom_optionsnode(void)2930Sstevel@tonic-gate prom_optionsnode(void)
2940Sstevel@tonic-gate {
295*789Sahrens 	static pnode_t node;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (node == 0)
2980Sstevel@tonic-gate 		node = prom_finddevice("/options");
2990Sstevel@tonic-gate 	return (node);
3000Sstevel@tonic-gate }
301