Home | History | Annotate | Download | only in promif
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/esunddi.h>
     29 #include <sys/promif_impl.h>
     30 
     31 #ifdef _KMDB
     32 static pnode_t chosennode;
     33 static pnode_t optionsnode;
     34 #else
     35 static char *gettoken(char *tp, char *token);
     36 static pnode_t finddevice(char *path);
     37 #endif
     38 
     39 /*
     40  * Routines for walking the PROMs devinfo tree
     41  */
     42 
     43 #ifdef _KMDB
     44 
     45 void
     46 promif_set_nodes(pnode_t chosen, pnode_t options)
     47 {
     48 	chosennode = chosen;
     49 	optionsnode = options;
     50 }
     51 
     52 int
     53 promif_finddevice(void *p)
     54 {
     55 	cell_t	*ci = (cell_t *)p;
     56 	char *path;
     57 
     58 	ASSERT(ci[1] == 1);
     59 
     60 	path = p1275_cell2ptr(ci[3]);
     61 
     62 	if (strcmp("/chosen", path) == 0) {
     63 		ci[4] = p1275_dnode2cell(chosennode);
     64 	} else if (strcmp("/options", path) == 0) {
     65 		ci[4] = p1275_dnode2cell(optionsnode);
     66 	} else {
     67 		/* only supports known nodes */
     68 		ASSERT(0);
     69 	}
     70 
     71 	return (0);
     72 }
     73 
     74 #else
     75 
     76 int
     77 promif_finddevice(void *p)
     78 {
     79 	cell_t	*ci = (cell_t *)p;
     80 	pnode_t	node;
     81 
     82 	ASSERT(ci[1] == 1);
     83 
     84 	/*
     85 	 * We are passing the cpu pointer (CPU->cpu_id) explicitly to
     86 	 * thread_affinity_set() so that we don't attempt to grab the
     87 	 * cpu_lock internally in thread_affinity_set() and may sleep
     88 	 * as a result.
     89 	 * It is safe to pass CPU->cpu_id and it will always be valid.
     90 	 */
     91 	thread_affinity_set(curthread, CPU->cpu_id);
     92 	node = finddevice(p1275_cell2ptr(ci[3]));
     93 
     94 	ci[4] = p1275_dnode2cell(node);
     95 	thread_affinity_clear(curthread);
     96 
     97 	return (0);
     98 }
     99 
    100 #endif
    101 
    102 int
    103 promif_nextnode(void *p)
    104 {
    105 	cell_t	*ci = (cell_t *)p;
    106 	pnode_t	next;
    107 
    108 	ASSERT(ci[1] == 1);
    109 
    110 	next = promif_stree_nextnode(p1275_cell2dnode(ci[3]));
    111 
    112 	ci[4] = p1275_dnode2cell(next);
    113 
    114 	return (0);
    115 }
    116 
    117 int
    118 promif_childnode(void *p)
    119 {
    120 	cell_t	*ci = (cell_t *)p;
    121 	pnode_t	child;
    122 
    123 	ASSERT(ci[1] == 1);
    124 
    125 	child = promif_stree_childnode(p1275_cell2dnode(ci[3]));
    126 
    127 	ci[4] = p1275_dnode2cell(child);
    128 
    129 	return (0);
    130 }
    131 
    132 int
    133 promif_parentnode(void *p)
    134 {
    135 	cell_t	*ci = (cell_t *)p;
    136 	pnode_t	parent;
    137 
    138 	ASSERT(ci[1] == 1);
    139 
    140 	parent = promif_stree_parentnode(p1275_cell2dnode(ci[3]));
    141 
    142 	ci[4] = p1275_dnode2cell(parent);
    143 
    144 	return (0);
    145 }
    146 
    147 #ifndef _KMDB
    148 
    149 /*
    150  * Get a token from a prom pathname, collecting everything
    151  * until a non-comma, non-colon separator is found. Any
    152  * options, including the ':' option separator, on the end
    153  * of the token are removed.
    154  */
    155 static char *
    156 gettoken(char *tp, char *token)
    157 {
    158 	char *result = token;
    159 
    160 	for (;;) {
    161 		tp = prom_path_gettoken(tp, token);
    162 		token += prom_strlen(token);
    163 		if ((*tp == ',') || (*tp == ':')) {
    164 			*token++ = *tp++;
    165 			*token = '\0';
    166 			continue;
    167 		}
    168 		break;
    169 	}
    170 
    171 	/* strip off any options from the token */
    172 	prom_strip_options(result, result);
    173 
    174 	return (tp);
    175 }
    176 
    177 /*
    178  * Retrieve the unit address for a node by looking it up
    179  * in the corresponding dip. -1 is returned if no unit
    180  * address can be determined.
    181  */
    182 static int
    183 get_unit_addr(pnode_t np, char *paddr)
    184 {
    185 	dev_info_t	*dip;
    186 	char		*addr;
    187 
    188 	if ((dip = e_ddi_nodeid_to_dip(np)) == NULL) {
    189 		return (-1);
    190 	}
    191 
    192 	if ((addr = ddi_get_name_addr(dip)) == NULL) {
    193 		ddi_release_devi(dip);
    194 		return (-1);
    195 	}
    196 
    197 	(void) prom_strcpy(paddr, addr);
    198 
    199 	ddi_release_devi(dip);
    200 
    201 	return (0);
    202 }
    203 
    204 /*
    205  * Get node id of node in prom tree that path identifies
    206  */
    207 static pnode_t
    208 finddevice(char *path)
    209 {
    210 	char	name[OBP_MAXPROPNAME];
    211 	char	addr[OBP_MAXPROPNAME];
    212 	char	pname[OBP_MAXPROPNAME];
    213 	char	paddr[OBP_MAXPROPNAME];
    214 	char	*tp;
    215 	pnode_t	np;
    216 	pnode_t	device;
    217 
    218 	CIF_DBG_NODE("finddevice: %s\n", path);
    219 
    220 	tp = path;
    221 	np = prom_rootnode();
    222 	device = OBP_BADNODE;
    223 
    224 	/* must be a fully specified path */
    225 	if (*tp++ != '/')
    226 		goto done;
    227 
    228 	for (;;) {
    229 		/* get the name from the path */
    230 		tp = gettoken(tp, name);
    231 		if (*name == '\0')
    232 			break;
    233 
    234 		/* get the address from the path */
    235 		if (*tp == '@') {
    236 			tp++;
    237 			tp = gettoken(tp, addr);
    238 		} else {
    239 			addr[0] = '\0';
    240 		}
    241 
    242 		CIF_DBG_NODE("looking for: %s%s%s\n", name,
    243 		    (*addr != '\0') ? "@" : "", addr);
    244 
    245 		if ((np = prom_childnode(np)) == OBP_NONODE)
    246 			break;
    247 
    248 		while (np != OBP_NONODE) {
    249 
    250 			/* get the name from the current node */
    251 			if (prom_getprop(np, OBP_NAME, pname) < 0)
    252 				goto done;
    253 
    254 			/* get the address from the current node */
    255 			if (get_unit_addr(np, paddr) < 0)
    256 				paddr[0] = '\0';
    257 
    258 			/* compare the names and addresses */
    259 			if ((prom_strcmp(name, pname) == 0) &&
    260 			    (prom_strcmp(addr, paddr) == 0)) {
    261 				CIF_DBG_NODE("found dev: %s%s%s (0x%x)\n",
    262 				    pname, (*paddr != '\0') ? "@" : "",
    263 				    paddr, np);
    264 				break;
    265 			} else {
    266 				CIF_DBG_NODE("  no match: %s%s%s vs %s%s%s\n",
    267 				    name, (*addr != '\0') ? "@" : "", addr,
    268 				    pname, (*paddr != '\0') ? "@" : "", paddr);
    269 			}
    270 			np = prom_nextnode(np);
    271 		}
    272 
    273 		/* path does not map to a node */
    274 		if (np == OBP_NONODE)
    275 			break;
    276 
    277 		if (*tp == '\0') {
    278 			/* found a matching node */
    279 			device = np;
    280 			break;
    281 		}
    282 
    283 		/*
    284 		 * Continue the loop with the
    285 		 * next component of the path.
    286 		 */
    287 		tp++;
    288 	}
    289 done:
    290 
    291 	if (device == OBP_BADNODE) {
    292 		CIF_DBG_NODE("device not found\n\n");
    293 	} else {
    294 		CIF_DBG_NODE("returning 0x%x\n\n", device);
    295 	}
    296 
    297 	return (device);
    298 }
    299 
    300 #endif
    301