xref: /onnv-gate/usr/src/uts/sun4v/promif/promif_stree.c (revision 5768:a5a9220c3610)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
23*5768Sjm22469  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo #include <sys/promif_impl.h>
301991Sheppo #include <sys/kmem.h>
311991Sheppo #include <sys/machsystm.h>
321991Sheppo 
331991Sheppo /*
341991Sheppo  * A property attached to a node in the kernel's
351991Sheppo  * shadow copy of the PROM device tree.
361991Sheppo  */
371991Sheppo typedef struct prom_prop {
381991Sheppo 	struct prom_prop *pp_next;
391991Sheppo 	char		 *pp_name;
401991Sheppo 	int		 pp_len;
411991Sheppo 	void		 *pp_val;
421991Sheppo } prom_prop_t;
431991Sheppo 
441991Sheppo /*
451991Sheppo  * A node in the kernel's shadow copy of the PROM
461991Sheppo  * device tree.
471991Sheppo  */
481991Sheppo typedef struct prom_node {
491991Sheppo 	pnode_t			pn_nodeid;
501991Sheppo 	struct prom_prop	*pn_propp;
511991Sheppo 	struct prom_node	*pn_parent;
521991Sheppo 	struct prom_node	*pn_child;
531991Sheppo 	struct prom_node	*pn_sibling;
541991Sheppo } prom_node_t;
551991Sheppo 
561991Sheppo static prom_node_t *promif_root;
571991Sheppo 
581991Sheppo static prom_node_t *find_node(pnode_t nodeid);
591991Sheppo static prom_node_t *find_node_work(prom_node_t *np, pnode_t node);
601991Sheppo static int getproplen(prom_node_t *pnp, char *name);
611991Sheppo static void *getprop(prom_node_t *pnp, char *name);
621991Sheppo static char *nextprop(prom_node_t *pnp, char *name);
631991Sheppo 
641991Sheppo #ifndef _KMDB
651991Sheppo static void create_prop(prom_node_t *pnp, char *name, void *val, int len);
661991Sheppo static prom_node_t *create_node(prom_node_t *parent, pnode_t node);
671991Sheppo static void create_peers(prom_node_t *pnp, pnode_t node);
681991Sheppo static void create_children(prom_node_t *pnp, pnode_t parent);
691991Sheppo #endif
701991Sheppo 
711991Sheppo /*
721991Sheppo  * Hooks for kmdb for accessing the PROM shadow tree. The driver portion
731991Sheppo  * of kmdb will retrieve the root of the tree and pass it down to the
741991Sheppo  * debugger portion of kmdb. As the kmdb debugger is standalone, it has
751991Sheppo  * its own promif_root pointer that it will be set to the value passed by
761991Sheppo  * the driver so that kmdb points to the shadow tree maintained by the kernel.
771991Sheppo  * So the "get" function is in the kernel while the "set" function is in kmdb.
781991Sheppo  */
791991Sheppo #ifdef _KMDB
801991Sheppo void
promif_stree_setroot(void * root)811991Sheppo promif_stree_setroot(void *root)
821991Sheppo {
831991Sheppo 	promif_root = (prom_node_t *)root;
841991Sheppo }
851991Sheppo #else
861991Sheppo void *
promif_stree_getroot(void)871991Sheppo promif_stree_getroot(void)
881991Sheppo {
891991Sheppo 	return (promif_root);
901991Sheppo }
911991Sheppo #endif
921991Sheppo 
931991Sheppo /*
941991Sheppo  * Interfaces used internally by promif functions.
951991Sheppo  * These hide all accesses to the shadow tree.
961991Sheppo  */
971991Sheppo 
981991Sheppo pnode_t
promif_stree_parentnode(pnode_t nodeid)991991Sheppo promif_stree_parentnode(pnode_t nodeid)
1001991Sheppo {
1011991Sheppo 	prom_node_t *pnp;
1021991Sheppo 
1031991Sheppo 	pnp = find_node(nodeid);
1041991Sheppo 	if (pnp && pnp->pn_parent) {
1051991Sheppo 		return (pnp->pn_parent->pn_nodeid);
1061991Sheppo 	}
1071991Sheppo 
1081991Sheppo 	return (OBP_NONODE);
1091991Sheppo }
1101991Sheppo 
1111991Sheppo pnode_t
promif_stree_childnode(pnode_t nodeid)1121991Sheppo promif_stree_childnode(pnode_t nodeid)
1131991Sheppo {
1141991Sheppo 	prom_node_t *pnp;
1151991Sheppo 
1161991Sheppo 	pnp = find_node(nodeid);
1171991Sheppo 	if (pnp && pnp->pn_child)
1181991Sheppo 		return (pnp->pn_child->pn_nodeid);
1191991Sheppo 
1201991Sheppo 	return (OBP_NONODE);
1211991Sheppo }
1221991Sheppo 
1231991Sheppo pnode_t
promif_stree_nextnode(pnode_t nodeid)1241991Sheppo promif_stree_nextnode(pnode_t nodeid)
1251991Sheppo {
1261991Sheppo 	prom_node_t *pnp;
1271991Sheppo 
1281991Sheppo 	/*
1291991Sheppo 	 * Note: next(0) returns the root node
1301991Sheppo 	 */
1311991Sheppo 	pnp = find_node(nodeid);
1321991Sheppo 	if (pnp && (nodeid == OBP_NONODE))
1331991Sheppo 		return (pnp->pn_nodeid);
1341991Sheppo 	if (pnp && pnp->pn_sibling)
1351991Sheppo 		return (pnp->pn_sibling->pn_nodeid);
1361991Sheppo 
1371991Sheppo 	return (OBP_NONODE);
1381991Sheppo }
1391991Sheppo 
1401991Sheppo int
promif_stree_getproplen(pnode_t nodeid,char * name)1411991Sheppo promif_stree_getproplen(pnode_t nodeid, char *name)
1421991Sheppo {
1431991Sheppo 	prom_node_t *pnp;
1441991Sheppo 
1451991Sheppo 	pnp = find_node(nodeid);
1461991Sheppo 	if (pnp == NULL)
1471991Sheppo 		return (-1);
1481991Sheppo 
1491991Sheppo 	return (getproplen(pnp, name));
1501991Sheppo }
1511991Sheppo 
1521991Sheppo int
promif_stree_getprop(pnode_t nodeid,char * name,void * value)1531991Sheppo promif_stree_getprop(pnode_t nodeid, char *name, void *value)
1541991Sheppo {
1551991Sheppo 	prom_node_t	*pnp;
1561991Sheppo 	void		*prop;
1571991Sheppo 	int		len;
1581991Sheppo 
1591991Sheppo 	pnp = find_node(nodeid);
1601991Sheppo 	if (pnp == NULL) {
1611991Sheppo 		prom_printf("find_node: no node?\n");
1621991Sheppo 		return (-1);
1631991Sheppo 	}
1641991Sheppo 
1651991Sheppo 	len = getproplen(pnp, name);
1661991Sheppo 	if (len > 0) {
1671991Sheppo 		prop = getprop(pnp, name);
1681991Sheppo 		bcopy(prop, value, len);
1691991Sheppo 	} else {
1701991Sheppo 		prom_printf("find_node: getproplen: %d\n", len);
1711991Sheppo 	}
1721991Sheppo 
1731991Sheppo 	return (len);
1741991Sheppo }
1751991Sheppo 
1761991Sheppo char *
promif_stree_nextprop(pnode_t nodeid,char * name,char * next)1771991Sheppo promif_stree_nextprop(pnode_t nodeid, char *name, char *next)
1781991Sheppo {
1791991Sheppo 	prom_node_t	*pnp;
1801991Sheppo 	char		*propname;
1811991Sheppo 
1821991Sheppo 	next[0] = '\0';
1831991Sheppo 
1841991Sheppo 	pnp = find_node(nodeid);
1851991Sheppo 	if (pnp == NULL)
1861991Sheppo 		return (NULL);
1871991Sheppo 
1881991Sheppo 	propname = nextprop(pnp, name);
1891991Sheppo 	if (propname == NULL)
1901991Sheppo 		return (next);
1911991Sheppo 
1921991Sheppo 	(void) prom_strcpy(next, propname);
1931991Sheppo 
1941991Sheppo 	return (next);
1951991Sheppo }
1961991Sheppo 
1971991Sheppo static prom_node_t *
find_node_work(prom_node_t * np,pnode_t node)1981991Sheppo find_node_work(prom_node_t *np, pnode_t node)
1991991Sheppo {
2001991Sheppo 	prom_node_t *nnp;
2014366Sae112802 	prom_node_t *snp;
2021991Sheppo 
2034366Sae112802 	for (snp = np; snp != NULL; snp = snp->pn_sibling) {
2044366Sae112802 		if (snp->pn_nodeid == node)
2054366Sae112802 			return (snp);
2061991Sheppo 
2074366Sae112802 		if (snp->pn_child)
2084366Sae112802 			if ((nnp = find_node_work(snp->pn_child, node)) != NULL)
2094366Sae112802 				return (nnp);
2104366Sae112802 	}
2111991Sheppo 
2121991Sheppo 	return (NULL);
2131991Sheppo }
2141991Sheppo 
2151991Sheppo static prom_node_t *
find_node(pnode_t nodeid)2161991Sheppo find_node(pnode_t nodeid)
2171991Sheppo {
2181991Sheppo 
2191991Sheppo 	if (nodeid == OBP_NONODE)
2201991Sheppo 		return (promif_root);
2211991Sheppo 
2221991Sheppo 	if (promif_root == NULL)
2231991Sheppo 		return (NULL);
2241991Sheppo 
2251991Sheppo 	return (find_node_work(promif_root, nodeid));
2261991Sheppo }
2271991Sheppo 
2281991Sheppo static int
getproplen(prom_node_t * pnp,char * name)2291991Sheppo getproplen(prom_node_t *pnp, char *name)
2301991Sheppo {
2311991Sheppo 	struct prom_prop *propp;
2321991Sheppo 
2331991Sheppo 	for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
2341991Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2351991Sheppo 			return (propp->pp_len);
2361991Sheppo 
2371991Sheppo 	return (-1);
2381991Sheppo }
2391991Sheppo 
2401991Sheppo static void *
getprop(prom_node_t * np,char * name)2411991Sheppo getprop(prom_node_t *np, char *name)
2421991Sheppo {
2431991Sheppo 	struct prom_prop *propp;
2441991Sheppo 
2451991Sheppo 	for (propp = np->pn_propp; propp != NULL; propp = propp->pp_next)
2461991Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2471991Sheppo 			return (propp->pp_val);
2481991Sheppo 
2491991Sheppo 	return (NULL);
2501991Sheppo }
2511991Sheppo 
2521991Sheppo static char *
nextprop(prom_node_t * pnp,char * name)2531991Sheppo nextprop(prom_node_t *pnp, char *name)
2541991Sheppo {
2551991Sheppo 	struct prom_prop *propp;
2561991Sheppo 
2571991Sheppo 	/*
2581991Sheppo 	 * getting next of NULL or a null string returns the first prop name
2591991Sheppo 	 */
2601991Sheppo 	if (name == NULL || *name == '\0')
2611991Sheppo 		if (pnp->pn_propp)
2621991Sheppo 			return (pnp->pn_propp->pp_name);
2631991Sheppo 
2641991Sheppo 	for (propp = pnp->pn_propp; propp != NULL; propp = propp->pp_next)
2651991Sheppo 		if (prom_strcmp(propp->pp_name, name) == 0)
2661991Sheppo 			if (propp->pp_next)
2671991Sheppo 				return (propp->pp_next->pp_name);
2681991Sheppo 
2691991Sheppo 	return (NULL);
2701991Sheppo }
2711991Sheppo 
2721991Sheppo #ifndef _KMDB
2731991Sheppo 
2741991Sheppo int
promif_stree_setprop(pnode_t nodeid,char * name,void * value,int len)2751991Sheppo promif_stree_setprop(pnode_t nodeid, char *name, void *value, int len)
2761991Sheppo {
2771991Sheppo 	prom_node_t		*pnp;
2781991Sheppo 	struct prom_prop	*prop;
2791991Sheppo 
2801991Sheppo 	pnp = find_node(nodeid);
2811991Sheppo 	if (pnp == NULL) {
2821991Sheppo 		prom_printf("find_node: no node?\n");
2831991Sheppo 		return (-1);
2841991Sheppo 	}
2851991Sheppo 
2861991Sheppo 	/*
2871991Sheppo 	 * If a property with this name exists, replace the existing
2881991Sheppo 	 * value.
2891991Sheppo 	 */
2901991Sheppo 	for (prop = pnp->pn_propp; prop; prop = prop->pp_next)
2911991Sheppo 		if (prom_strcmp(prop->pp_name, name) == 0) {
292*5768Sjm22469 			/*
293*5768Sjm22469 			 * Make sure we don't get dispatched onto a
294*5768Sjm22469 			 * different cpu if we happen to sleep.  See
295*5768Sjm22469 			 * kern_postprom().
296*5768Sjm22469 			 */
297*5768Sjm22469 			thread_affinity_set(curthread, CPU->cpu_id);
2981991Sheppo 			kmem_free(prop->pp_val, prop->pp_len);
299*5768Sjm22469 
3001991Sheppo 			prop->pp_val = NULL;
3011991Sheppo 			if (len > 0) {
3021991Sheppo 				prop->pp_val = kmem_zalloc(len, KM_SLEEP);
3031991Sheppo 				bcopy(value, prop->pp_val, len);
3041991Sheppo 			}
305*5768Sjm22469 			thread_affinity_clear(curthread);
3061991Sheppo 			prop->pp_len = len;
3071991Sheppo 			return (len);
3081991Sheppo 		}
3091991Sheppo 
3101991Sheppo 	return (-1);
3111991Sheppo }
3121991Sheppo 
3131991Sheppo /*
3141991Sheppo  * Create a promif private copy of boot's device tree.
3151991Sheppo  */
3161991Sheppo void
promif_stree_init(void)3171991Sheppo promif_stree_init(void)
3181991Sheppo {
3191991Sheppo 	pnode_t		node;
3201991Sheppo 	prom_node_t	*pnp;
3211991Sheppo 
3221991Sheppo 	node = prom_rootnode();
3231991Sheppo 	promif_root = pnp = create_node(OBP_NONODE, node);
3241991Sheppo 
3251991Sheppo 	create_peers(pnp, node);
3261991Sheppo 	create_children(pnp, node);
3271991Sheppo }
3281991Sheppo 
3291991Sheppo static void
create_children(prom_node_t * pnp,pnode_t parent)3301991Sheppo create_children(prom_node_t *pnp, pnode_t parent)
3311991Sheppo {
3321991Sheppo 	prom_node_t	*cnp;
3331991Sheppo 	pnode_t		child;
3341991Sheppo 
3351991Sheppo 	_NOTE(CONSTCOND)
3361991Sheppo 	while (1) {
3371991Sheppo 		child = prom_childnode(parent);
3381991Sheppo 		if (child == 0)
3391991Sheppo 			break;
3401991Sheppo 		if (prom_getproplen(child, "name") <= 0) {
3411991Sheppo 			parent = child;
3421991Sheppo 			continue;
3431991Sheppo 		}
3441991Sheppo 		cnp = create_node(pnp, child);
3451991Sheppo 		pnp->pn_child = cnp;
3461991Sheppo 		create_peers(cnp, child);
3471991Sheppo 		pnp = cnp;
3481991Sheppo 		parent = child;
3491991Sheppo 	}
3501991Sheppo }
3511991Sheppo 
3521991Sheppo static void
create_peers(prom_node_t * np,pnode_t node)3531991Sheppo create_peers(prom_node_t *np, pnode_t node)
3541991Sheppo {
3551991Sheppo 	prom_node_t	*pnp;
3561991Sheppo 	pnode_t		peer;
3571991Sheppo 
3581991Sheppo 	_NOTE(CONSTCOND)
3591991Sheppo 	while (1) {
3601991Sheppo 		peer = prom_nextnode(node);
3611991Sheppo 		if (peer == 0)
3621991Sheppo 			break;
3631991Sheppo 		if (prom_getproplen(peer, "name") <= 0) {
3641991Sheppo 			node = peer;
3651991Sheppo 			continue;
3661991Sheppo 		}
3671991Sheppo 		pnp = create_node(np->pn_parent, peer);
3681991Sheppo 		np->pn_sibling = pnp;
3691991Sheppo 		create_children(pnp, peer);
3701991Sheppo 		np = pnp;
3711991Sheppo 		node = peer;
3721991Sheppo 	}
3731991Sheppo }
3741991Sheppo 
3751991Sheppo static prom_node_t *
create_node(prom_node_t * parent,pnode_t node)3761991Sheppo create_node(prom_node_t *parent, pnode_t node)
3771991Sheppo {
3781991Sheppo 	prom_node_t	*pnp;
3791991Sheppo 	char		prvname[OBP_MAXPROPNAME];
3801991Sheppo 	char		propname[OBP_MAXPROPNAME];
3811991Sheppo 	int		proplen;
3821991Sheppo 	void		*propval;
3831991Sheppo 
3845502Sjm22469 	/*
3855502Sjm22469 	 * Make sure we don't get dispatched onto a different
3865502Sjm22469 	 * cpu if we happen to sleep.  See kern_postprom().
3875502Sjm22469 	 */
388*5768Sjm22469 	thread_affinity_set(curthread, CPU->cpu_id);
3895502Sjm22469 
3901991Sheppo 	pnp = kmem_zalloc(sizeof (prom_node_t), KM_SLEEP);
3911991Sheppo 	pnp->pn_nodeid = node;
3921991Sheppo 	pnp->pn_parent = parent;
3931991Sheppo 
3941991Sheppo 	prvname[0] = '\0';
3951991Sheppo 
3961991Sheppo 	_NOTE(CONSTCOND)
3971991Sheppo 	while (1) {
3981991Sheppo 		(void) prom_nextprop(node, prvname, propname);
3991991Sheppo 		if (prom_strlen(propname) == 0)
4001991Sheppo 			break;
4011991Sheppo 		if ((proplen = prom_getproplen(node, propname)) == -1)
4021991Sheppo 			continue;
4031991Sheppo 		propval = NULL;
4041991Sheppo 		if (proplen != 0) {
4051991Sheppo 			propval = kmem_zalloc(proplen, KM_SLEEP);
4061991Sheppo 			(void) prom_getprop(node, propname, propval);
4071991Sheppo 		}
4081991Sheppo 		create_prop(pnp, propname, propval, proplen);
4091991Sheppo 
4101991Sheppo 		(void) prom_strcpy(prvname, propname);
4111991Sheppo 	}
4121991Sheppo 
4135502Sjm22469 	thread_affinity_clear(curthread);
4145502Sjm22469 
4151991Sheppo 	return (pnp);
4161991Sheppo }
4171991Sheppo 
4181991Sheppo static void
create_prop(prom_node_t * pnp,char * name,void * val,int len)4191991Sheppo create_prop(prom_node_t *pnp, char *name, void *val, int len)
4201991Sheppo {
4211991Sheppo 	struct prom_prop	*prop;
4221991Sheppo 	struct prom_prop	*newprop;
4231991Sheppo 
4245502Sjm22469 	/*
4255502Sjm22469 	 * Make sure we don't get dispatched onto a different
4265502Sjm22469 	 * cpu if we happen to sleep.  See kern_postprom().
4275502Sjm22469 	 */
428*5768Sjm22469 	thread_affinity_set(curthread, CPU->cpu_id);
4291991Sheppo 	newprop = kmem_zalloc(sizeof (*newprop), KM_SLEEP);
4301991Sheppo 	newprop->pp_name = kmem_zalloc(prom_strlen(name) + 1, KM_SLEEP);
4315502Sjm22469 	thread_affinity_clear(curthread);
4325502Sjm22469 
4331991Sheppo 	(void) prom_strcpy(newprop->pp_name, name);
4341991Sheppo 	newprop->pp_val = val;
4351991Sheppo 	newprop->pp_len = len;
4361991Sheppo 
4371991Sheppo 	if (pnp->pn_propp == NULL) {
4381991Sheppo 		pnp->pn_propp = newprop;
4391991Sheppo 		return;
4401991Sheppo 	}
4411991Sheppo 
4421991Sheppo 	/* move to the end of the prop list */
4431991Sheppo 	for (prop = pnp->pn_propp; prop->pp_next != NULL; prop = prop->pp_next)
4441991Sheppo 		/* empty */;
4451991Sheppo 
4461991Sheppo 	/* append the new prop */
4471991Sheppo 	prop->pp_next = newprop;
4481991Sheppo }
4491991Sheppo 
4501991Sheppo static void
promif_dump_tree(prom_node_t * pnp)4511991Sheppo promif_dump_tree(prom_node_t *pnp)
4521991Sheppo {
4531991Sheppo 	int		i;
4541991Sheppo 	static int	level = 0;
4551991Sheppo 
4561991Sheppo 	if (pnp == NULL)
4571991Sheppo 		return;
4581991Sheppo 
4591991Sheppo 	for (i = 0; i < level; i++) {
4601991Sheppo 		prom_printf("    ");
4611991Sheppo 	}
4621991Sheppo 
4631991Sheppo 	prom_printf("Node 0x%x (parent=0x%x, sibling=0x%x)\n", pnp->pn_nodeid,
4641991Sheppo 	    (pnp->pn_parent) ? pnp->pn_parent->pn_nodeid : 0,
4651991Sheppo 	    (pnp->pn_sibling) ? pnp->pn_sibling->pn_nodeid : 0);
4661991Sheppo 
4671991Sheppo 	if (pnp->pn_child != NULL) {
4681991Sheppo 		level++;
4691991Sheppo 		promif_dump_tree(pnp->pn_child);
4701991Sheppo 		level--;
4711991Sheppo 	}
4721991Sheppo 
4731991Sheppo 	if (pnp->pn_sibling != NULL)
4741991Sheppo 		promif_dump_tree(pnp->pn_sibling);
4751991Sheppo }
4761991Sheppo 
4771991Sheppo #endif
478