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