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
promif_set_nodes(pnode_t chosen,pnode_t options)46 promif_set_nodes(pnode_t chosen, pnode_t options)
47 {
48 chosennode = chosen;
49 optionsnode = options;
50 }
51
52 int
promif_finddevice(void * p)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
promif_finddevice(void * p)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
promif_nextnode(void * p)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
promif_childnode(void * p)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
promif_parentnode(void * p)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 *
gettoken(char * tp,char * token)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
get_unit_addr(pnode_t np,char * paddr)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
finddevice(char * path)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