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 811ae08745Sheppo promif_stree_setroot(void *root) 821ae08745Sheppo { 831ae08745Sheppo promif_root = (prom_node_t *)root; 841ae08745Sheppo } 851ae08745Sheppo #else 861ae08745Sheppo 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 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 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 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 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 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 * 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 * 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 * 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 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 * 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 * 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 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 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 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 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 * 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 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 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