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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "mdescplugin.h"
31 static di_prom_handle_t ph
= DI_PROM_HANDLE_NIL
;
33 typedef struct cpu_lookup
{
39 extern int add_cpu_prop(picl_nodehdl_t node
, void *args
);
40 extern md_t
*mdesc_devinit(void);
43 * This function is identical to the one in the picldevtree plugin.
44 * Unfortunately we can't just reuse that code.
47 add_string_list_prop(picl_nodehdl_t nodeh
, char *name
, char *strlist
,
50 ptree_propinfo_t propinfo
;
56 picl_prophdl_t
*proprow
;
59 #define NCOLS_IN_STRING_TABLE 1
61 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
62 PICL_PTYPE_TABLE
, PICL_READ
, sizeof (picl_prophdl_t
), name
,
64 if (err
!= PICL_SUCCESS
)
67 err
= ptree_create_table(&tblh
);
68 if (err
!= PICL_SUCCESS
)
71 err
= ptree_create_and_add_prop(nodeh
, &propinfo
, &tblh
, &proph
);
72 if (err
!= PICL_SUCCESS
)
75 proprow
= alloca(sizeof (picl_prophdl_t
) * nrows
);
76 if (proprow
== NULL
) {
77 (void) ptree_destroy_prop(proph
);
78 return (PICL_FAILURE
);
81 for (j
= 0; j
< nrows
; ++j
) {
82 len
= strlen(strlist
) + 1;
83 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
84 PICL_PTYPE_CHARSTRING
, PICL_READ
, len
, name
,
86 if (err
!= PICL_SUCCESS
)
88 err
= ptree_create_prop(&propinfo
, strlist
, &proprow
[j
]);
89 if (err
!= PICL_SUCCESS
)
92 err
= ptree_add_row_to_table(tblh
, NCOLS_IN_STRING_TABLE
,
94 if (err
!= PICL_SUCCESS
)
98 if (err
!= PICL_SUCCESS
) {
99 for (i
= 0; i
< j
; ++i
)
100 (void) ptree_destroy_prop(proprow
[i
]);
101 (void) ptree_delete_prop(proph
);
102 (void) ptree_destroy_prop(proph
);
106 return (PICL_SUCCESS
);
110 * This function is identical to the one in the picldevtree plugin.
111 * Unfortunately we can't just reuse that code.
114 add_devinfo_props(picl_nodehdl_t nodeh
, di_node_t di_node
)
120 ptree_propinfo_t propinfo
;
122 instance
= di_instance(di_node
);
123 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
124 PICL_PTYPE_INT
, PICL_READ
, sizeof (instance
), PICL_PROP_INSTANCE
,
126 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, &instance
, NULL
);
128 di_val
= di_bus_addr(di_node
);
130 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
131 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(di_val
) + 1,
132 PICL_PROP_BUS_ADDR
, NULL
, NULL
);
133 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, di_val
,
137 di_val
= di_binding_name(di_node
);
139 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
140 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(di_val
) + 1,
141 PICL_PROP_BINDING_NAME
, NULL
, NULL
);
142 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, di_val
,
146 di_val
= di_driver_name(di_node
);
148 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
149 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(di_val
) + 1,
150 PICL_PROP_DRIVER_NAME
, NULL
, NULL
);
151 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, di_val
,
155 di_val
= di_devfs_path(di_node
);
157 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
158 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(di_val
) + 1,
159 PICL_PROP_DEVFS_PATH
, NULL
, NULL
);
160 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, di_val
,
162 di_devfs_path_free(di_val
);
165 for (di_prop
= di_prop_next(di_node
, DI_PROP_NIL
);
166 di_prop
!= DI_PROP_NIL
;
167 di_prop
= di_prop_next(di_node
, di_prop
)) {
169 di_val
= di_prop_name(di_prop
);
170 di_ptype
= di_prop_type(di_prop
);
172 case DI_PROP_TYPE_BOOLEAN
:
173 (void) ptree_init_propinfo(&propinfo
,
174 PTREE_PROPINFO_VERSION
, PICL_PTYPE_VOID
,
175 PICL_READ
, (size_t)0, di_val
, NULL
, NULL
);
176 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
179 case DI_PROP_TYPE_INT
: {
183 len
= di_prop_ints(di_prop
, &idata
);
185 /* Recieved error, so ignore prop */
189 (void) ptree_init_propinfo(&propinfo
,
190 PTREE_PROPINFO_VERSION
, PICL_PTYPE_INT
,
191 PICL_READ
, len
* sizeof (int), di_val
,
194 (void) ptree_init_propinfo(&propinfo
,
195 PTREE_PROPINFO_VERSION
,
196 PICL_PTYPE_BYTEARRAY
, PICL_READ
,
197 len
* sizeof (int), di_val
,
200 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
204 case DI_PROP_TYPE_STRING
: {
208 len
= di_prop_strings(di_prop
, &sdata
);
213 (void) ptree_init_propinfo(&propinfo
,
214 PTREE_PROPINFO_VERSION
,
215 PICL_PTYPE_CHARSTRING
, PICL_READ
,
216 strlen(sdata
) + 1, di_val
,
218 (void) ptree_create_and_add_prop(nodeh
,
219 &propinfo
, sdata
, NULL
);
221 (void) add_string_list_prop(nodeh
, di_val
,
226 case DI_PROP_TYPE_BYTE
: {
228 unsigned char *bdata
;
230 len
= di_prop_bytes(di_prop
, &bdata
);
233 (void) ptree_init_propinfo(&propinfo
,
234 PTREE_PROPINFO_VERSION
, PICL_PTYPE_BYTEARRAY
,
235 PICL_READ
, len
, di_val
, NULL
, NULL
);
236 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
240 case DI_PROP_TYPE_UNKNOWN
:
242 case DI_PROP_TYPE_UNDEF_IT
:
251 * add OBP_REG property to picl cpu node if it's not already there.
254 add_reg_prop(picl_nodehdl_t pn
, di_node_t dn
)
256 int reg_prop
[SUN4V_CPU_REGSIZE
];
260 ptree_propinfo_t propinfo
;
262 status
= ptree_get_propval_by_name(pn
, OBP_REG
, reg_prop
,
264 if (status
== PICL_SUCCESS
) {
267 dlen
= di_prom_prop_lookup_ints(ph
, dn
, OBP_REG
, &pdata
);
271 status
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
272 PICL_PTYPE_BYTEARRAY
, PICL_READ
, dlen
* sizeof (int), OBP_REG
,
274 if (status
!= PICL_SUCCESS
) {
277 (void) ptree_create_and_add_prop(pn
, &propinfo
, pdata
, NULL
);
281 * Create a picl node of type cpu and fill it.
282 * properties are filled from both the device tree and the
283 * Machine description.
286 construct_cpu_node(picl_nodehdl_t plath
, di_node_t dn
)
290 picl_nodehdl_t anodeh
;
292 nodename
= di_node_name(dn
); /* PICL_PROP_NAME */
294 err
= ptree_create_and_add_node(plath
, nodename
, PICL_CLASS_CPU
,
296 if (err
!= PICL_SUCCESS
)
299 add_devinfo_props(anodeh
, dn
);
300 add_reg_prop(anodeh
, dn
);
301 (void) add_cpu_prop(anodeh
, NULL
);
307 * Given a devinfo node find its reg property.
310 get_reg_prop(di_node_t dn
, int **pdata
)
314 dret
= di_prop_lookup_ints(DDI_DEV_T_ANY
, dn
, OBP_REG
, pdata
);
320 dret
= di_prom_prop_lookup_ints(ph
, dn
, OBP_REG
, pdata
);
321 return (dret
< 0? 0 : dret
);
325 * Given a devinfo cpu node find its cpuid property.
328 get_cpuid(di_node_t di_node
)
334 len
= get_reg_prop(di_node
, &idata
);
336 if (len
!= SUN4V_CPU_REGSIZE
)
338 if (len
== SUN4V_CPU_REGSIZE
)
339 dcpuid
= CFGHDL_TO_CPUID(idata
[0]);
345 find_cpu(di_node_t node
, int cpuid
)
351 for (cnode
= di_child_node(node
); cnode
!= DI_NODE_NIL
;
352 cnode
= di_sibling_node(cnode
)) {
353 nodename
= di_node_name(cnode
);
354 if (nodename
== NULL
)
356 if (strcmp(nodename
, OBP_CPU
) == 0) {
357 dcpuid
= get_cpuid(cnode
);
358 if (dcpuid
== cpuid
) {
367 * Callback to the ptree walk function during remove_cpus.
368 * As a part of the args receives a picl nodeh, searches
369 * the device tree for a cpu whose cpuid matches the picl cpu node.
370 * Sets arg struct's result to 1 if it failed to match and terminates
374 remove_cpu_candidate(picl_nodehdl_t nodeh
, void *c_args
)
377 cpu_lookup_t
*cpu_arg
;
380 int reg_prop
[SUN4V_CPU_REGSIZE
];
383 return (PICL_INVALIDARG
);
386 di_node
= cpu_arg
->di_node
;
388 err
= ptree_get_propval_by_name(nodeh
, OBP_REG
, reg_prop
,
391 if (err
!= PICL_SUCCESS
) {
392 return (PICL_WALK_CONTINUE
);
395 pcpuid
= CFGHDL_TO_CPUID(reg_prop
[0]);
397 if (!find_cpu(di_node
, pcpuid
)) {
399 cpu_arg
->nodeh
= nodeh
;
400 return (PICL_WALK_TERMINATE
);
404 return (PICL_WALK_CONTINUE
);
408 * Given the start node of the device tree.
409 * find all cpus in the picl tree that don't have
410 * device tree counterparts and remove them.
413 remove_cpus(di_node_t di_start
)
416 picl_nodehdl_t plath
;
417 cpu_lookup_t cpu_arg
;
419 err
= ptree_get_node_by_path(PLATFORM_PATH
, &plath
);
420 if (err
!= PICL_SUCCESS
)
424 cpu_arg
.di_node
= di_start
;
428 if (ptree_walk_tree_by_class(plath
,
429 PICL_CLASS_CPU
, &cpu_arg
, remove_cpu_candidate
)
433 if (cpu_arg
.result
== 1) {
434 err
= ptree_delete_node(cpu_arg
.nodeh
);
435 if (err
== PICL_SUCCESS
)
436 ptree_destroy_node(cpu_arg
.nodeh
);
438 } while (cpu_arg
.result
);
442 * Callback to the ptree walk function during add_cpus.
443 * As a part of the args receives a cpu di_node, compares
444 * each picl cpu node's cpuid to the device tree node's cpuid.
445 * Sets arg struct's result to 1 on a match.
448 cpu_exists(picl_nodehdl_t nodeh
, void *c_args
)
451 cpu_lookup_t
*cpu_arg
;
457 return (PICL_INVALIDARG
);
460 di_node
= cpu_arg
->di_node
;
461 dcpuid
= get_cpuid(di_node
);
463 err
= ptree_get_propval_by_name(nodeh
, OBP_REG
, reg_prop
,
466 if (err
!= PICL_SUCCESS
)
467 return (PICL_WALK_CONTINUE
);
469 pcpuid
= CFGHDL_TO_CPUID(reg_prop
[0]);
471 if (dcpuid
== pcpuid
) {
473 return (PICL_WALK_TERMINATE
);
477 return (PICL_WALK_CONTINUE
);
481 * Given the root node of the device tree.
482 * compare it to the picl tree and add to it cpus
486 add_cpus(di_node_t di_node
)
490 picl_nodehdl_t plath
;
491 cpu_lookup_t cpu_arg
;
494 err
= ptree_get_node_by_path(PLATFORM_PATH
, &plath
);
495 if (err
!= PICL_SUCCESS
)
498 for (cnode
= di_child_node(di_node
); cnode
!= DI_NODE_NIL
;
499 cnode
= di_sibling_node(cnode
)) {
500 nodename
= di_node_name(cnode
);
501 if (nodename
== NULL
)
503 if (strcmp(nodename
, OBP_CPU
) == 0) {
504 cpu_arg
.di_node
= cnode
;
506 if (ptree_walk_tree_by_class(plath
,
507 PICL_CLASS_CPU
, &cpu_arg
, cpu_exists
)
511 if (cpu_arg
.result
== 0)
513 * Didn't find a matching cpu, add it.
515 (void) construct_cpu_node(plath
,
522 * Handle DR events. Only supports cpu add and remove.
525 update_devices(char *dev
, int op
)
529 if ((di_root
= di_init("/", DINFOCPYALL
)) == DI_NODE_NIL
)
530 return (PICL_FAILURE
);
532 if ((ph
= di_prom_init()) == NULL
)
533 return (PICL_FAILURE
);
536 if (strcmp(dev
, OBP_CPU
) == 0)
540 if (op
== DEV_REMOVE
) {
541 if (strcmp(dev
, OBP_CPU
) == 0)
542 remove_cpus(di_root
);
547 return (PICL_SUCCESS
);