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