xref: /titanic_50/usr/src/uts/sun4v/promif/promif_stree.c (revision de81a4f48d467f6d0263221cbf4a199b6a925948)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
23*de81a4f4Sjm22469  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo #include <sys/promif_impl.h>
301ae08745Sheppo #include <sys/kmem.h>
311ae08745Sheppo #include <sys/machsystm.h>
321ae08745Sheppo 
331ae08745Sheppo /*
341ae08745Sheppo  * A property attached to a node in the kernel's
351ae08745Sheppo  * shadow copy of the PROM device tree.
361ae08745Sheppo  */
371ae08745Sheppo typedef struct prom_prop {
381ae08745Sheppo 	struct prom_prop *pp_next;
391ae08745Sheppo 	char		 *pp_name;
401ae08745Sheppo 	int		 pp_len;
411ae08745Sheppo 	void		 *pp_val;
421ae08745Sheppo } prom_prop_t;
431ae08745Sheppo 
441ae08745Sheppo /*
451ae08745Sheppo  * A node in the kernel's shadow copy of the PROM
461ae08745Sheppo  * device tree.
471ae08745Sheppo  */
481ae08745Sheppo typedef struct prom_node {
491ae08745Sheppo 	pnode_t			pn_nodeid;
501ae08745Sheppo 	struct prom_prop	*pn_propp;
511ae08745Sheppo 	struct prom_node	*pn_parent;
521ae08745Sheppo 	struct prom_node	*pn_child;
531ae08745Sheppo 	struct prom_node	*pn_sibling;
541ae08745Sheppo } prom_node_t;
551ae08745Sheppo 
561ae08745Sheppo static prom_node_t *promif_root;
571ae08745Sheppo 
581ae08745Sheppo static prom_node_t *find_node(pnode_t nodeid);
591ae08745Sheppo static prom_node_t *find_node_work(prom_node_t *np, pnode_t node);
601ae08745Sheppo static int getproplen(prom_node_t *pnp, char *name);
611ae08745Sheppo static void *getprop(prom_node_t *pnp, char *name);
621ae08745Sheppo static char *nextprop(prom_node_t *pnp, char *name);
631ae08745Sheppo 
641ae08745Sheppo #ifndef _KMDB
651ae08745Sheppo static void create_prop(prom_node_t *pnp, char *name, void *val, int len);
661ae08745Sheppo static prom_node_t *create_node(prom_node_t *parent, pnode_t node);
671ae08745Sheppo static void create_peers(prom_node_t *pnp, pnode_t node);
681ae08745Sheppo static void create_children(prom_node_t *pnp, pnode_t parent);
691ae08745Sheppo #endif
701ae08745Sheppo 
711ae08745Sheppo /*
721ae08745Sheppo  * Hooks for kmdb for accessing the PROM shadow tree. The driver portion
731ae08745Sheppo  * of kmdb will retrieve the root of the tree and pass it down to the
741ae08745Sheppo  * debugger portion of kmdb. As the kmdb debugger is standalone, it has
751ae08745Sheppo  * its own promif_root pointer that it will be set to the value passed by
761ae08745Sheppo  * the driver so that kmdb points to the shadow tree maintained by the kernel.
771ae08745Sheppo  * So the "get" function is in the kernel while the "set" function is in kmdb.
781ae08745Sheppo  */
791ae08745Sheppo #ifdef _KMDB
801ae08745Sheppo void
promif_stree_setroot(void * root)811ae08745Sheppo promif_stree_setroot(void *root)
821ae08745Sheppo {
831ae08745Sheppo 	promif_root = (prom_node_t *)root;
841ae08745Sheppo }
851ae08745Sheppo #else
861ae08745Sheppo void *
promif_stree_getroot(void)871ae08745Sheppo promif_stree_getroot(void)
881ae08745Sheppo {
891ae08745Sheppo 	return (promif_root);
901ae08745Sheppo }
911ae08745Sheppo #endif
921ae08745Sheppo 
931ae08745Sheppo /*
941ae08745Sheppo  * Interfaces used internally by promif functions.
951ae08745Sheppo  * These hide all accesses to the shadow tree.
961ae08745Sheppo  */
971ae08745Sheppo 
981ae08745Sheppo pnode_t
promif_stree_parentnode(pnode_t nodeid)991ae08745Sheppo promif_stree_parentnode(pnode_t nodeid)
1001ae08745Sheppo {
1011ae08745Sheppo 	prom_node_t *pnp;
1021ae08745Sheppo 
1031ae08745Sheppo 	pnp = find_node(nodeid);
1041ae08745Sheppo 	if (pnp && pnp->pn_parent) {
1051ae08745Sheppo 		return (pnp->pn_parent->pn_nodeid);
1061ae08745Sheppo 	}
1071ae08745Sheppo 
1081ae08745Sheppo 	return (OBP_NONODE);
1091ae08745Sheppo }
1101ae08745Sheppo 
1111ae08745Sheppo pnode_t
promif_stree_childnode(pnode_t nodeid)1121ae08745Sheppo promif_stree_childnode(pnode_t nodeid)
1131ae08745Sheppo {
1141ae08745Sheppo 	prom_node_t *pnp;
1151ae08745Sheppo 
1161ae08745Sheppo 	pnp = find_node(nodeid);
1171ae08745Sheppo 	if (pnp && pnp->pn_child)
1181ae08745Sheppo 		return (pnp->pn_child->pn_nodeid);
1191ae08745Sheppo 
1201ae08745Sheppo 	return (OBP_NONODE);
1211ae08745Sheppo }
1221ae08745Sheppo 
1231ae08745Sheppo pnode_t
promif_stree_nextnode(pnode_t nodeid)1241ae08745Sheppo promif_stree_nextnode(pnode_t nodeid)
1251ae08745Sheppo {
1261ae08745Sheppo 	prom_node_t *pnp;
1271ae08745Sheppo 
1281ae08745Sheppo 	/*
1291ae08745Sheppo 	 * Note: next(0) returns the root node
1301ae08745Sheppo 	 */
1311ae08745Sheppo 	pnp = find_node(nodeid);
1321ae08745Sheppo 	if (pnp && (nodeid == OBP_NONODE))
1331ae08745Sheppo 		return (pnp->pn_nodeid);
1341ae08745Sheppo 	if (pnp && pnp->pn_sibling)
1351ae08745Sheppo 		return (pnp->pn_sibling->pn_nodeid);
1361ae08745Sheppo 
1371ae08745Sheppo 	return (OBP_NONODE);
1381ae08745Sheppo }
1391ae08745Sheppo 
1401ae08745Sheppo int
promif_stree_getproplen(pnode_t nodeid,char * name)1411ae08745Sheppo promif_stree_getproplen(pnode_t nodeid, char *name)
1421ae08745Sheppo {
1431ae08745Sheppo 	prom_node_t *pnp;
1441ae08745Sheppo 
1451ae08745Sheppo 	pnp = find_node(nodeid);
1461ae08745Sheppo 	if (pnp == NULL)
1471ae08745Sheppo 		return (-1);
1481ae08745Sheppo 
1491ae08745Sheppo 	return (getproplen(pnp, name));
1501ae08745Sheppo }
1511ae08745Sheppo 
1521ae08745Sheppo int
promif_stree_getprop(pnode_t nodeid,char * name,void * value)1531ae08745Sheppo promif_stree_getprop(pnode_t nodeid, char *name, void *value)
1541ae08745Sheppo {
1551ae08745Sheppo 	prom_node_t	*pnp;
1561ae08745Sheppo 	void		*prop;
1571ae08745Sheppo 	int		len;
1581ae08745Sheppo 
1591ae08745Sheppo 	pnp = find_node(nodeid);
1601ae08745Sheppo 	if (pnp == NULL) {
1611ae08745Sheppo 		prom_printf("find_node: no node?\n");
1621ae08745Sheppo 		return (-1);
1631ae08745Sheppo 	}
1641ae08745Sheppo 
1651ae08745Sheppo 	len = getproplen(pnp, name);
1661ae08745Sheppo 	if (len > 0) {
1671ae08745Sheppo 		prop = getprop(pnp, name);
1681ae08745Sheppo 		bcopy(prop, value, len);
1691ae08745Sheppo 	} else {
1701ae08745Sheppo 		prom_printf("find_node: getproplen: %d\n", len);
1711ae08745Sheppo 	}
1721ae08745Sheppo 
1731ae08745Sheppo 	return (len);
1741ae08745Sheppo }
1751ae08745Sheppo 
1761ae08745Sheppo char *
promif_stree_nextprop(pnode_t nodeid,char * name,char * next)1771ae08745Sheppo promif_stree_nextprop(pnode_t nodeid, char *name, char *next)
1781ae08745Sheppo {
1791ae08745Sheppo 	prom_node_t	*pnp;
1801ae08745Sheppo 	char		*propname;
1811ae08745Sheppo 
1821ae08745Sheppo 	next[0] = '\0';
1831ae08745Sheppo 
1841ae08745Sheppo 	pnp = find_node(nodeid);
1851ae08745Sheppo 	if (pnp == NULL)
1861ae08745Sheppo 		return (NULL);
1871ae08745Sheppo 
1881ae08745Sheppo 	propname = nextprop(pnp, name);
1891ae08745Sheppo 	if (propname == NULL)
1901ae08745Sheppo 		return (next);
1911ae08745Sheppo 
1921ae08745Sheppo 	(void) prom_strcpy(next, propname);
1931ae08745Sheppo 
1941ae08745Sheppo 	return (next);
1951ae08745Sheppo }
1961ae08745Sheppo 
1971ae08745Sheppo static prom_node_t *
find_node_work(prom_node_t * np,pnode_t node)1981ae08745Sheppo find_node_work(prom_node_t *np, pnode_t node)
1991ae08745Sheppo {
2001ae08745Sheppo 	prom_node_t *nnp;
201c3bc9566Sae112802 	prom_node_t *snp;
2021ae08745Sheppo 
203c3bc9566Sae112802 	for (snp = np; snp != NULL; snp = snp->pn_sibling) {
204c3bc9566Sae112802 		if (snp->pn_nodeid == node)
205c3bc9566Sae112802 			return (snp);
2061ae08745Sheppo 
207c3bc9566Sae112802 		if (snp->pn_child)
208c3bc9566Sae112802 			if ((nnp = find_node_work(snp->pn_child, node)) != NULL)
2091ae08745Sheppo 				return (nnp);
210c3bc9566Sae112802 	}
2111ae08745Sheppo 
2121ae08745Sheppo 	return (NULL);
2131ae08745Sheppo }
2141ae08745Sheppo 
2151ae08745Sheppo static prom_node_t *
find_node(pnode_t nodeid)2161ae08745Sheppo find_node(pnode_t nodeid)
2171ae08745Sheppo {
2181ae08745Sheppo 
2191ae08745Sheppo 	if (nodeid == OBP_NONODE)
2201ae08745Sheppo 		return (promif_root);
2211ae08745Sheppo 
2221ae08745Sheppo 	if (promif_root == NULL)
2231ae08745Sheppo 		return (NULL);
2241ae08745Sheppo 
2251ae08745Sheppo 	return (find_node_work(promif_root, nodeid));
2261ae08745Sheppo }
2271ae08745Sheppo 
2281ae08745Sheppo static int
getproplen(prom_node_t * pnp,char * name)2291ae08745Sheppo getproplen(prom_node_t *pnp, char *name)
2301ae08745Sheppo {
2311ae08745Sheppo 	struct prom_prop *propp;
2321ae08745Sheppo 
2331ae08745Sheppo 	for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
2341ae08745Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2351ae08745Sheppo 			return (propp->pp_len);
2361ae08745Sheppo 
2371ae08745Sheppo 	return (-1);
2381ae08745Sheppo }
2391ae08745Sheppo 
2401ae08745Sheppo static void *
getprop(prom_node_t * np,char * name)2411ae08745Sheppo getprop(prom_node_t *np, char *name)
2421ae08745Sheppo {
2431ae08745Sheppo 	struct prom_prop *propp;
2441ae08745Sheppo 
2451ae08745Sheppo 	for (propp = np->pn_propp; propp != NULL; propp = propp->pp_next)
2461ae08745Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2471ae08745Sheppo 			return (propp->pp_val);
2481ae08745Sheppo 
2491ae08745Sheppo 	return (NULL);
2501ae08745Sheppo }
2511ae08745Sheppo 
2521ae08745Sheppo static char *
nextprop(prom_node_t * pnp,char * name)2531ae08745Sheppo nextprop(prom_node_t *pnp, char *name)
2541ae08745Sheppo {
2551ae08745Sheppo 	struct prom_prop *propp;
2561ae08745Sheppo 
2571ae08745Sheppo 	/*
2581ae08745Sheppo 	 * getting next of NULL or a null string returns the first prop name
2591ae08745Sheppo 	 */
2601ae08745Sheppo 	if (name == NULL || *name == '\0')
2611ae08745Sheppo 		if (pnp->pn_propp)
2621ae08745Sheppo 			return (pnp->pn_propp->pp_name);
2631ae08745Sheppo 
2641ae08745Sheppo 	for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
2651ae08745Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2661ae08745Sheppo 			if (propp->pp_next)
2671ae08745Sheppo 				return (propp->pp_next->pp_name);
2681ae08745Sheppo 
2691ae08745Sheppo 	return (NULL);
2701ae08745Sheppo }
2711ae08745Sheppo 
2721ae08745Sheppo #ifndef _KMDB
2731ae08745Sheppo 
2741ae08745Sheppo int
promif_stree_setprop(pnode_t nodeid,char * name,void * value,int len)2751ae08745Sheppo promif_stree_setprop(pnode_t nodeid, char *name, void *value, int len)
2761ae08745Sheppo {
2771ae08745Sheppo 	prom_node_t		*pnp;
2781ae08745Sheppo 	struct prom_prop	*prop;
2791ae08745Sheppo 
2801ae08745Sheppo 	pnp = find_node(nodeid);
2811ae08745Sheppo 	if (pnp == NULL) {
2821ae08745Sheppo 		prom_printf("find_node: no node?\n");
2831ae08745Sheppo 		return (-1);
2841ae08745Sheppo 	}
2851ae08745Sheppo 
2861ae08745Sheppo 	/*
2871ae08745Sheppo 	 * If a property with this name exists, replace the existing
2881ae08745Sheppo 	 * value.
2891ae08745Sheppo 	 */
2901ae08745Sheppo 	for (prop = pnp->pn_propp; prop; prop = prop->pp_next)
2911ae08745Sheppo 		if (prom_strcmp(prop->pp_name, name) == 0) {
292a47315d7Sjm22469 			/*
293a47315d7Sjm22469 			 * Make sure we don't get dispatched onto a
294a47315d7Sjm22469 			 * different cpu if we happen to sleep.  See
295a47315d7Sjm22469 			 * kern_postprom().
296a47315d7Sjm22469 			 */
297*de81a4f4Sjm22469 			thread_affinity_set(curthread, CPU->cpu_id);
298*de81a4f4Sjm22469 			kmem_free(prop->pp_val, prop->pp_len);
299a47315d7Sjm22469 
300*de81a4f4Sjm22469 			prop->pp_val = NULL;
301*de81a4f4Sjm22469 			if (len > 0) {
302*de81a4f4Sjm22469 				prop->pp_val = kmem_zalloc(len, KM_SLEEP);
3031ae08745Sheppo 				bcopy(value, prop->pp_val, len);
3041ae08745Sheppo 			}
305*de81a4f4Sjm22469 			thread_affinity_clear(curthread);
3061ae08745Sheppo 			prop->pp_len = len;
3071ae08745Sheppo 			return (len);
3081ae08745Sheppo 		}
3091ae08745Sheppo 
3101ae08745Sheppo 	return (-1);
3111ae08745Sheppo }
3121ae08745Sheppo 
3131ae08745Sheppo /*
3141ae08745Sheppo  * Create a promif private copy of boot's device tree.
3151ae08745Sheppo  */
3161ae08745Sheppo void
promif_stree_init(void)3171ae08745Sheppo promif_stree_init(void)
3181ae08745Sheppo {
3191ae08745Sheppo 	pnode_t		node;
3201ae08745Sheppo 	prom_node_t	*pnp;
3211ae08745Sheppo 
3221ae08745Sheppo 	node = prom_rootnode();
3231ae08745Sheppo 	promif_root = pnp = create_node(OBP_NONODE, node);
3241ae08745Sheppo 
3251ae08745Sheppo 	create_peers(pnp, node);
3261ae08745Sheppo 	create_children(pnp, node);
3271ae08745Sheppo }
3281ae08745Sheppo 
3291ae08745Sheppo static void
create_children(prom_node_t * pnp,pnode_t parent)3301ae08745Sheppo create_children(prom_node_t *pnp, pnode_t parent)
3311ae08745Sheppo {
3321ae08745Sheppo 	prom_node_t	*cnp;
3331ae08745Sheppo 	pnode_t		child;
3341ae08745Sheppo 
3351ae08745Sheppo 	_NOTE(CONSTCOND)
3361ae08745Sheppo 	while (1) {
3371ae08745Sheppo 		child = prom_childnode(parent);
3381ae08745Sheppo 		if (child == 0)
3391ae08745Sheppo 			break;
3401ae08745Sheppo 		if (prom_getproplen(child, "name") <= 0) {
3411ae08745Sheppo 			parent = child;
3421ae08745Sheppo 			continue;
3431ae08745Sheppo 		}
3441ae08745Sheppo 		cnp = create_node(pnp, child);
3451ae08745Sheppo 		pnp->pn_child = cnp;
3461ae08745Sheppo 		create_peers(cnp, child);
3471ae08745Sheppo 		pnp = cnp;
3481ae08745Sheppo 		parent = child;
3491ae08745Sheppo 	}
3501ae08745Sheppo }
3511ae08745Sheppo 
3521ae08745Sheppo static void
create_peers(prom_node_t * np,pnode_t node)3531ae08745Sheppo create_peers(prom_node_t *np, pnode_t node)
3541ae08745Sheppo {
3551ae08745Sheppo 	prom_node_t	*pnp;
3561ae08745Sheppo 	pnode_t		peer;
3571ae08745Sheppo 
3581ae08745Sheppo 	_NOTE(CONSTCOND)
3591ae08745Sheppo 	while (1) {
3601ae08745Sheppo 		peer = prom_nextnode(node);
3611ae08745Sheppo 		if (peer == 0)
3621ae08745Sheppo 			break;
3631ae08745Sheppo 		if (prom_getproplen(peer, "name") <= 0) {
3641ae08745Sheppo 			node = peer;
3651ae08745Sheppo 			continue;
3661ae08745Sheppo 		}
3671ae08745Sheppo 		pnp = create_node(np->pn_parent, peer);
3681ae08745Sheppo 		np->pn_sibling = pnp;
3691ae08745Sheppo 		create_children(pnp, peer);
3701ae08745Sheppo 		np = pnp;
3711ae08745Sheppo 		node = peer;
3721ae08745Sheppo 	}
3731ae08745Sheppo }
3741ae08745Sheppo 
3751ae08745Sheppo static prom_node_t *
create_node(prom_node_t * parent,pnode_t node)3761ae08745Sheppo create_node(prom_node_t *parent, pnode_t node)
3771ae08745Sheppo {
3781ae08745Sheppo 	prom_node_t	*pnp;
3791ae08745Sheppo 	char		prvname[OBP_MAXPROPNAME];
3801ae08745Sheppo 	char		propname[OBP_MAXPROPNAME];
3811ae08745Sheppo 	int		proplen;
3821ae08745Sheppo 	void		*propval;
3831ae08745Sheppo 
384a47315d7Sjm22469 	/*
385a47315d7Sjm22469 	 * Make sure we don't get dispatched onto a different
386a47315d7Sjm22469 	 * cpu if we happen to sleep.  See kern_postprom().
387a47315d7Sjm22469 	 */
388*de81a4f4Sjm22469 	thread_affinity_set(curthread, CPU->cpu_id);
389a47315d7Sjm22469 
3901ae08745Sheppo 	pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP);
3911ae08745Sheppo 	pnp->pn_nodeid = node;
3921ae08745Sheppo 	pnp->pn_parent = parent;
3931ae08745Sheppo 
3941ae08745Sheppo 	prvname[0] = '\0';
3951ae08745Sheppo 
3961ae08745Sheppo 	_NOTE(CONSTCOND)
3971ae08745Sheppo 	while (1) {
3981ae08745Sheppo 		(void) prom_nextprop(node, prvname, propname);
3991ae08745Sheppo 		if (prom_strlen(propname) == 0)
4001ae08745Sheppo 			break;
4011ae08745Sheppo 		if ((proplen = prom_getproplen(node, propname)) == -1)
4021ae08745Sheppo 			continue;
4031ae08745Sheppo 		propval = NULL;
4041ae08745Sheppo 		if (proplen != 0) {
4051ae08745Sheppo 			propval = kmem_zalloc(proplen, KM_SLEEP);
4061ae08745Sheppo 			(void) prom_getprop(node, propname, propval);
4071ae08745Sheppo 		}
4081ae08745Sheppo 		create_prop(pnp, propname, propval, proplen);
4091ae08745Sheppo 
4101ae08745Sheppo 		(void) prom_strcpy(prvname, propname);
4111ae08745Sheppo 	}
4121ae08745Sheppo 
413a47315d7Sjm22469 	thread_affinity_clear(curthread);
414a47315d7Sjm22469 
4151ae08745Sheppo 	return (pnp);
4161ae08745Sheppo }
4171ae08745Sheppo 
4181ae08745Sheppo static void
create_prop(prom_node_t * pnp,char * name,void * val,int len)4191ae08745Sheppo create_prop(prom_node_t *pnp, char *name, void *val, int len)
4201ae08745Sheppo {
4211ae08745Sheppo 	struct prom_prop	*prop;
4221ae08745Sheppo 	struct prom_prop	*newprop;
4231ae08745Sheppo 
424a47315d7Sjm22469 	/*
425a47315d7Sjm22469 	 * Make sure we don't get dispatched onto a different
426a47315d7Sjm22469 	 * cpu if we happen to sleep.  See kern_postprom().
427a47315d7Sjm22469 	 */
428*de81a4f4Sjm22469 	thread_affinity_set(curthread, CPU->cpu_id);
4291ae08745Sheppo 	newprop = kmem_zalloc(sizeof (*newprop), KM_SLEEP);
4301ae08745Sheppo 	newprop->pp_name = kmem_zalloc(prom_strlen(name) + 1, KM_SLEEP);
431a47315d7Sjm22469 	thread_affinity_clear(curthread);
432a47315d7Sjm22469 
4331ae08745Sheppo 	(void) prom_strcpy(newprop->pp_name, name);
4341ae08745Sheppo 	newprop->pp_val = val;
4351ae08745Sheppo 	newprop->pp_len = len;
4361ae08745Sheppo 
4371ae08745Sheppo 	if (pnp->pn_propp == NULL) {
4381ae08745Sheppo 		pnp->pn_propp = newprop;
4391ae08745Sheppo 		return;
4401ae08745Sheppo 	}
4411ae08745Sheppo 
4421ae08745Sheppo 	/* move to the end of the prop list */
4431ae08745Sheppo 	for (prop = pnp->pn_propp; prop->pp_next != NULL; prop = prop->pp_next)
4441ae08745Sheppo 		/* empty */;
4451ae08745Sheppo 
4461ae08745Sheppo 	/* append the new prop */
4471ae08745Sheppo 	prop->pp_next = newprop;
4481ae08745Sheppo }
4491ae08745Sheppo 
4501ae08745Sheppo static void
promif_dump_tree(prom_node_t * pnp)4511ae08745Sheppo promif_dump_tree(prom_node_t *pnp)
4521ae08745Sheppo {
4531ae08745Sheppo 	int		i;
4541ae08745Sheppo 	static int	level = 0;
4551ae08745Sheppo 
4561ae08745Sheppo 	if (pnp == NULL)
4571ae08745Sheppo 		return;
4581ae08745Sheppo 
4591ae08745Sheppo 	for (i = 0; i < level; i++) {
4601ae08745Sheppo 		prom_printf("    ");
4611ae08745Sheppo 	}
4621ae08745Sheppo 
4631ae08745Sheppo 	prom_printf("Node 0x%x (parent=0x%x, sibling=0x%x)\n", pnp->pn_nodeid,
4641ae08745Sheppo 	    (pnp->pn_parent) ? pnp->pn_parent->pn_nodeid : 0,
4651ae08745Sheppo 	    (pnp->pn_sibling) ? pnp->pn_sibling->pn_nodeid : 0);
4661ae08745Sheppo 
4671ae08745Sheppo 	if (pnp->pn_child != NULL) {
4681ae08745Sheppo 		level++;
4691ae08745Sheppo 		promif_dump_tree(pnp->pn_child);
4701ae08745Sheppo 		level--;
4711ae08745Sheppo 	}
4721ae08745Sheppo 
4731ae08745Sheppo 	if (pnp->pn_sibling != NULL)
4741ae08745Sheppo 		promif_dump_tree(pnp->pn_sibling);
4751ae08745Sheppo }
4761ae08745Sheppo 
4771ae08745Sheppo #endif
478