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*535c87f8Smb  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #include "mdescplugin.h"
281ae08745Sheppo 
291ae08745Sheppo static	di_prom_handle_t	ph = DI_PROM_HANDLE_NIL;
301ae08745Sheppo 
311ae08745Sheppo typedef struct cpu_lookup {
321ae08745Sheppo 	di_node_t di_node;
331ae08745Sheppo 	picl_nodehdl_t nodeh;
341ae08745Sheppo 	int result;
351ae08745Sheppo } cpu_lookup_t;
361ae08745Sheppo 
371ae08745Sheppo extern int add_cpu_prop(picl_nodehdl_t node, void *args);
381ae08745Sheppo extern md_t *mdesc_devinit(void);
391ae08745Sheppo 
401ae08745Sheppo /*
411ae08745Sheppo  * This function is identical to the one in the picldevtree plugin.
421ae08745Sheppo  * Unfortunately we can't just reuse that code.
431ae08745Sheppo  */
44*535c87f8Smb int
add_string_list_prop(picl_nodehdl_t nodeh,char * name,char * strlist,unsigned int nrows)451ae08745Sheppo add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist,
461ae08745Sheppo     unsigned int nrows)
471ae08745Sheppo {
481ae08745Sheppo 	ptree_propinfo_t	propinfo;
491ae08745Sheppo 	picl_prophdl_t		proph;
501ae08745Sheppo 	picl_prophdl_t		tblh;
511ae08745Sheppo 	int			err;
521ae08745Sheppo 	unsigned int		i;
531ae08745Sheppo 	unsigned int		j;
541ae08745Sheppo 	picl_prophdl_t		*proprow;
551ae08745Sheppo 	int			len;
561ae08745Sheppo 
571ae08745Sheppo #define	NCOLS_IN_STRING_TABLE	1
581ae08745Sheppo 
591ae08745Sheppo 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
601ae08745Sheppo 	    PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name,
611ae08745Sheppo 	    NULL, NULL);
621ae08745Sheppo 	if (err != PICL_SUCCESS)
631ae08745Sheppo 		return (err);
641ae08745Sheppo 
651ae08745Sheppo 	err = ptree_create_table(&tblh);
661ae08745Sheppo 	if (err != PICL_SUCCESS)
671ae08745Sheppo 		return (err);
681ae08745Sheppo 
691ae08745Sheppo 	err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph);
701ae08745Sheppo 	if (err != PICL_SUCCESS)
711ae08745Sheppo 		return (err);
721ae08745Sheppo 
731ae08745Sheppo 	proprow = alloca(sizeof (picl_prophdl_t) * nrows);
741ae08745Sheppo 	if (proprow == NULL) {
751ae08745Sheppo 		(void) ptree_destroy_prop(proph);
761ae08745Sheppo 		return (PICL_FAILURE);
771ae08745Sheppo 	}
781ae08745Sheppo 
791ae08745Sheppo 	for (j = 0; j < nrows; ++j) {
801ae08745Sheppo 		len = strlen(strlist) + 1;
811ae08745Sheppo 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
821ae08745Sheppo 		    PICL_PTYPE_CHARSTRING, PICL_READ, len, name,
831ae08745Sheppo 		    NULL, NULL);
841ae08745Sheppo 		if (err != PICL_SUCCESS)
851ae08745Sheppo 			break;
861ae08745Sheppo 		err = ptree_create_prop(&propinfo, strlist, &proprow[j]);
871ae08745Sheppo 		if (err != PICL_SUCCESS)
881ae08745Sheppo 			break;
891ae08745Sheppo 		strlist += len;
901ae08745Sheppo 		err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE,
911ae08745Sheppo 		    &proprow[j]);
921ae08745Sheppo 		if (err != PICL_SUCCESS)
931ae08745Sheppo 			break;
941ae08745Sheppo 	}
951ae08745Sheppo 
961ae08745Sheppo 	if (err != PICL_SUCCESS) {
971ae08745Sheppo 		for (i = 0; i < j; ++i)
981ae08745Sheppo 			(void) ptree_destroy_prop(proprow[i]);
991ae08745Sheppo 		(void) ptree_delete_prop(proph);
1001ae08745Sheppo 		(void) ptree_destroy_prop(proph);
1011ae08745Sheppo 		return (err);
1021ae08745Sheppo 	}
1031ae08745Sheppo 
1041ae08745Sheppo 	return (PICL_SUCCESS);
1051ae08745Sheppo }
1061ae08745Sheppo 
1071ae08745Sheppo /*
1081ae08745Sheppo  * This function is identical to the one in the picldevtree plugin.
1091ae08745Sheppo  * Unfortunately we can't just reuse that code.
1101ae08745Sheppo  */
1111ae08745Sheppo static void
add_devinfo_props(picl_nodehdl_t nodeh,di_node_t di_node)1121ae08745Sheppo add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node)
1131ae08745Sheppo {
1141ae08745Sheppo 	int			instance;
1151ae08745Sheppo 	char			*di_val;
1161ae08745Sheppo 	di_prop_t		di_prop;
1171ae08745Sheppo 	int			di_ptype;
1181ae08745Sheppo 	ptree_propinfo_t	propinfo;
1191ae08745Sheppo 
1201ae08745Sheppo 	instance = di_instance(di_node);
1211ae08745Sheppo 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1221ae08745Sheppo 	    PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE,
1231ae08745Sheppo 	    NULL, NULL);
1241ae08745Sheppo 	(void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL);
1251ae08745Sheppo 
1261ae08745Sheppo 	di_val = di_bus_addr(di_node);
1271ae08745Sheppo 	if (di_val) {
1281ae08745Sheppo 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1291ae08745Sheppo 		    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1301ae08745Sheppo 		    PICL_PROP_BUS_ADDR, NULL, NULL);
1311ae08745Sheppo 		(void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1321ae08745Sheppo 		    NULL);
1331ae08745Sheppo 	}
1341ae08745Sheppo 
1351ae08745Sheppo 	di_val = di_binding_name(di_node);
1361ae08745Sheppo 	if (di_val) {
1371ae08745Sheppo 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1381ae08745Sheppo 		    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1391ae08745Sheppo 		    PICL_PROP_BINDING_NAME, NULL, NULL);
1401ae08745Sheppo 		(void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1411ae08745Sheppo 		    NULL);
1421ae08745Sheppo 	}
1431ae08745Sheppo 
1441ae08745Sheppo 	di_val = di_driver_name(di_node);
1451ae08745Sheppo 	if (di_val) {
1461ae08745Sheppo 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1471ae08745Sheppo 		    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1481ae08745Sheppo 		    PICL_PROP_DRIVER_NAME, NULL, NULL);
1491ae08745Sheppo 		(void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1501ae08745Sheppo 		    NULL);
1511ae08745Sheppo 	}
1521ae08745Sheppo 
1531ae08745Sheppo 	di_val = di_devfs_path(di_node);
1541ae08745Sheppo 	if (di_val) {
1551ae08745Sheppo 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1561ae08745Sheppo 		    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1571ae08745Sheppo 		    PICL_PROP_DEVFS_PATH, NULL, NULL);
1581ae08745Sheppo 		(void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1591ae08745Sheppo 		    NULL);
1601ae08745Sheppo 		di_devfs_path_free(di_val);
1611ae08745Sheppo 	}
1621ae08745Sheppo 
1631ae08745Sheppo 	for (di_prop = di_prop_next(di_node, DI_PROP_NIL);
1641ae08745Sheppo 	    di_prop != DI_PROP_NIL;
165*535c87f8Smb 	    di_prop = di_prop_next(di_node, di_prop)) {
1661ae08745Sheppo 
1671ae08745Sheppo 		di_val = di_prop_name(di_prop);
1681ae08745Sheppo 		di_ptype = di_prop_type(di_prop);
1691ae08745Sheppo 		switch (di_ptype) {
1701ae08745Sheppo 		case DI_PROP_TYPE_BOOLEAN:
1711ae08745Sheppo 			(void) ptree_init_propinfo(&propinfo,
1721ae08745Sheppo 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID,
1731ae08745Sheppo 			    PICL_READ, (size_t)0, di_val, NULL, NULL);
1741ae08745Sheppo 			(void) ptree_create_and_add_prop(nodeh, &propinfo,
1751ae08745Sheppo 			    NULL, NULL);
1761ae08745Sheppo 			break;
1771ae08745Sheppo 		case DI_PROP_TYPE_INT: {
1781ae08745Sheppo 			int	*idata;
1791ae08745Sheppo 			int	len;
1801ae08745Sheppo 
1811ae08745Sheppo 			len = di_prop_ints(di_prop, &idata);
1821ae08745Sheppo 			if (len < 0)
1831ae08745Sheppo 				/* Recieved error, so ignore prop */
1841ae08745Sheppo 				break;
1851ae08745Sheppo 
1861ae08745Sheppo 			if (len == 1)
1871ae08745Sheppo 				(void) ptree_init_propinfo(&propinfo,
1881ae08745Sheppo 				    PTREE_PROPINFO_VERSION, PICL_PTYPE_INT,
1891ae08745Sheppo 				    PICL_READ, len * sizeof (int), di_val,
1901ae08745Sheppo 				    NULL, NULL);
1911ae08745Sheppo 			else
1921ae08745Sheppo 				(void) ptree_init_propinfo(&propinfo,
1931ae08745Sheppo 				    PTREE_PROPINFO_VERSION,
1941ae08745Sheppo 				    PICL_PTYPE_BYTEARRAY, PICL_READ,
1951ae08745Sheppo 				    len * sizeof (int), di_val,
1961ae08745Sheppo 				    NULL, NULL);
1971ae08745Sheppo 
1981ae08745Sheppo 			(void) ptree_create_and_add_prop(nodeh, &propinfo,
1991ae08745Sheppo 			    idata, NULL);
2001ae08745Sheppo 		}
2011ae08745Sheppo 		break;
2021ae08745Sheppo 		case DI_PROP_TYPE_STRING: {
2031ae08745Sheppo 			char	*sdata;
2041ae08745Sheppo 			int	len;
2051ae08745Sheppo 
2061ae08745Sheppo 			len = di_prop_strings(di_prop, &sdata);
2071ae08745Sheppo 			if (len < 0)
2081ae08745Sheppo 				break;
2091ae08745Sheppo 
2101ae08745Sheppo 			if (len == 1) {
2111ae08745Sheppo 				(void) ptree_init_propinfo(&propinfo,
2121ae08745Sheppo 				    PTREE_PROPINFO_VERSION,
2131ae08745Sheppo 				    PICL_PTYPE_CHARSTRING, PICL_READ,
2141ae08745Sheppo 				    strlen(sdata) + 1, di_val,
2151ae08745Sheppo 				    NULL, NULL);
2161ae08745Sheppo 				(void) ptree_create_and_add_prop(nodeh,
2171ae08745Sheppo 				    &propinfo, sdata, NULL);
2181ae08745Sheppo 			} else {
2191ae08745Sheppo 				(void) add_string_list_prop(nodeh, di_val,
2201ae08745Sheppo 				    sdata, len);
2211ae08745Sheppo 			}
2221ae08745Sheppo 		}
2231ae08745Sheppo 		break;
2241ae08745Sheppo 		case DI_PROP_TYPE_BYTE: {
2251ae08745Sheppo 			int		len;
2261ae08745Sheppo 			unsigned char *bdata;
2271ae08745Sheppo 
2281ae08745Sheppo 			len = di_prop_bytes(di_prop, &bdata);
2291ae08745Sheppo 			if (len < 0)
2301ae08745Sheppo 				break;
2311ae08745Sheppo 			(void) ptree_init_propinfo(&propinfo,
2321ae08745Sheppo 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY,
2331ae08745Sheppo 			    PICL_READ, len, di_val, NULL, NULL);
2341ae08745Sheppo 			(void) ptree_create_and_add_prop(nodeh, &propinfo,
2351ae08745Sheppo 			    bdata, NULL);
2361ae08745Sheppo 		}
2371ae08745Sheppo 		break;
2381ae08745Sheppo 		case DI_PROP_TYPE_UNKNOWN:
2391ae08745Sheppo 			break;
2401ae08745Sheppo 		case DI_PROP_TYPE_UNDEF_IT:
2411ae08745Sheppo 			break;
2421ae08745Sheppo 		default:
2431ae08745Sheppo 			break;
2441ae08745Sheppo 		}
2451ae08745Sheppo 	}
2461ae08745Sheppo }
2471ae08745Sheppo 
248*535c87f8Smb /*
249*535c87f8Smb  * add OBP_REG property to picl cpu node if it's not already there.
250*535c87f8Smb  */
251*535c87f8Smb static void
add_reg_prop(picl_nodehdl_t pn,di_node_t dn)252*535c87f8Smb add_reg_prop(picl_nodehdl_t pn, di_node_t dn)
253*535c87f8Smb {
254*535c87f8Smb 	int 			reg_prop[SUN4V_CPU_REGSIZE];
255*535c87f8Smb 	int 			status;
256*535c87f8Smb 	int 			dlen;
257*535c87f8Smb 	int			*pdata;
258*535c87f8Smb 	ptree_propinfo_t	propinfo;
259*535c87f8Smb 
260*535c87f8Smb 	status = ptree_get_propval_by_name(pn, OBP_REG, reg_prop,
261*535c87f8Smb 	    sizeof (reg_prop));
262*535c87f8Smb 	if (status == PICL_SUCCESS) {
263*535c87f8Smb 		return;
264*535c87f8Smb 	}
265*535c87f8Smb 	dlen = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata);
266*535c87f8Smb 	if (dlen < 0) {
267*535c87f8Smb 		return;
268*535c87f8Smb 	}
269*535c87f8Smb 	status = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
270*535c87f8Smb 	    PICL_PTYPE_BYTEARRAY, PICL_READ, dlen * sizeof (int), OBP_REG,
271*535c87f8Smb 	    NULL, NULL);
272*535c87f8Smb 	if (status != PICL_SUCCESS) {
273*535c87f8Smb 		return;
274*535c87f8Smb 	}
275*535c87f8Smb 	(void) ptree_create_and_add_prop(pn, &propinfo, pdata, NULL);
276*535c87f8Smb }
277*535c87f8Smb 
2781ae08745Sheppo /*
2791ae08745Sheppo  * Create a  picl node of type cpu and fill it.
2801ae08745Sheppo  * properties are filled from both the device tree and the
2811ae08745Sheppo  * Machine description.
2821ae08745Sheppo  */
2831ae08745Sheppo static int
construct_cpu_node(picl_nodehdl_t plath,di_node_t dn)2841ae08745Sheppo construct_cpu_node(picl_nodehdl_t plath, di_node_t dn)
2851ae08745Sheppo {
2861ae08745Sheppo 	int		err;
2871ae08745Sheppo 	char		*nodename;
2881ae08745Sheppo 	picl_nodehdl_t	anodeh;
2891ae08745Sheppo 
2901ae08745Sheppo 	nodename = di_node_name(dn);	/* PICL_PROP_NAME */
2911ae08745Sheppo 
2921ae08745Sheppo 	err = ptree_create_and_add_node(plath, nodename, PICL_CLASS_CPU,
2931ae08745Sheppo 	    &anodeh);
2941ae08745Sheppo 	if (err != PICL_SUCCESS)
2951ae08745Sheppo 		return (err);
2961ae08745Sheppo 
2971ae08745Sheppo 	add_devinfo_props(anodeh, dn);
298*535c87f8Smb 	add_reg_prop(anodeh, dn);
2991ae08745Sheppo 	(void) add_cpu_prop(anodeh, NULL);
3001ae08745Sheppo 
3011ae08745Sheppo 	return (err);
3021ae08745Sheppo }
3031ae08745Sheppo 
3041ae08745Sheppo /*
3051ae08745Sheppo  * Given a devinfo node find its reg property.
3061ae08745Sheppo  */
3071ae08745Sheppo static int
get_reg_prop(di_node_t dn,int ** pdata)3081ae08745Sheppo get_reg_prop(di_node_t dn, int **pdata)
3091ae08745Sheppo {
3101ae08745Sheppo 	int dret = 0;
3111ae08745Sheppo 
3121ae08745Sheppo 	dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, pdata);
3131ae08745Sheppo 	if (dret > 0)
3141ae08745Sheppo 		return (dret);
3151ae08745Sheppo 
3161ae08745Sheppo 	if (!ph)
3171ae08745Sheppo 		return (0);
3181ae08745Sheppo 	dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, pdata);
3191ae08745Sheppo 	return (dret < 0? 0 : dret);
3201ae08745Sheppo }
3211ae08745Sheppo 
3221ae08745Sheppo /*
3231ae08745Sheppo  * Given a devinfo cpu node find its cpuid property.
3241ae08745Sheppo  */
3251ae08745Sheppo int
get_cpuid(di_node_t di_node)3261ae08745Sheppo get_cpuid(di_node_t di_node)
3271ae08745Sheppo {
3281ae08745Sheppo 	int	len;
3291ae08745Sheppo 	int	*idata;
3301ae08745Sheppo 	int	dcpuid = -1;
3311ae08745Sheppo 
3321ae08745Sheppo 	len = get_reg_prop(di_node, &idata);
3331ae08745Sheppo 
3341ae08745Sheppo 	if (len != SUN4V_CPU_REGSIZE)
3351ae08745Sheppo 		return (dcpuid);
3361ae08745Sheppo 	if (len == SUN4V_CPU_REGSIZE)
3371ae08745Sheppo 		dcpuid = CFGHDL_TO_CPUID(idata[0]);
3381ae08745Sheppo 
3391ae08745Sheppo 	return (dcpuid);
3401ae08745Sheppo }
3411ae08745Sheppo 
3421ae08745Sheppo int
find_cpu(di_node_t node,int cpuid)3431ae08745Sheppo find_cpu(di_node_t node, int cpuid)
3441ae08745Sheppo {
3451ae08745Sheppo 	int	dcpuid;
3461ae08745Sheppo 	di_node_t cnode;
3471ae08745Sheppo 	char	*nodename;
3481ae08745Sheppo 
3491ae08745Sheppo 	for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
3501ae08745Sheppo 	    cnode = di_sibling_node(cnode)) {
3511ae08745Sheppo 		nodename = di_node_name(cnode);
3521ae08745Sheppo 		if (nodename == NULL)
3531ae08745Sheppo 			continue;
3541ae08745Sheppo 		if (strcmp(nodename, OBP_CPU) == 0) {
3551ae08745Sheppo 			dcpuid = get_cpuid(cnode);
3561ae08745Sheppo 			if (dcpuid == cpuid) {
3571ae08745Sheppo 				return (1);
3581ae08745Sheppo 			}
3591ae08745Sheppo 		}
3601ae08745Sheppo 	}
3611ae08745Sheppo 	return (0);
3621ae08745Sheppo }
3631ae08745Sheppo 
3641ae08745Sheppo /*
3651ae08745Sheppo  * Callback to the ptree walk function during remove_cpus.
3661ae08745Sheppo  * As a part of the args receives a picl nodeh, searches
3671ae08745Sheppo  * the device tree for a cpu whose cpuid matches the picl cpu node.
3681ae08745Sheppo  * Sets arg struct's result to 1 if it failed to match and terminates
3691ae08745Sheppo  * the walk.
3701ae08745Sheppo  */
3711ae08745Sheppo static int
remove_cpu_candidate(picl_nodehdl_t nodeh,void * c_args)3721ae08745Sheppo remove_cpu_candidate(picl_nodehdl_t nodeh, void *c_args)
3731ae08745Sheppo {
3741ae08745Sheppo 	di_node_t	di_node;
3751ae08745Sheppo 	cpu_lookup_t	*cpu_arg;
3761ae08745Sheppo 	int	err;
3771ae08745Sheppo 	int	pcpuid;
3781ae08745Sheppo 	int reg_prop[SUN4V_CPU_REGSIZE];
3791ae08745Sheppo 
3801ae08745Sheppo 	if (c_args == NULL)
3811ae08745Sheppo 		return (PICL_INVALIDARG);
3821ae08745Sheppo 
3831ae08745Sheppo 	cpu_arg = c_args;
3841ae08745Sheppo 	di_node = cpu_arg->di_node;
3851ae08745Sheppo 
3861ae08745Sheppo 	err = ptree_get_propval_by_name(nodeh, OBP_REG, reg_prop,
3871ae08745Sheppo 	    sizeof (reg_prop));
3881ae08745Sheppo 
3891ae08745Sheppo 	if (err != PICL_SUCCESS) {
3901ae08745Sheppo 		return (PICL_WALK_CONTINUE);
3911ae08745Sheppo 	}
3921ae08745Sheppo 
3931ae08745Sheppo 	pcpuid = CFGHDL_TO_CPUID(reg_prop[0]);
3941ae08745Sheppo 
3951ae08745Sheppo 	if (!find_cpu(di_node, pcpuid)) {
3961ae08745Sheppo 		cpu_arg->result = 1;
3971ae08745Sheppo 		cpu_arg->nodeh = nodeh;
3981ae08745Sheppo 		return (PICL_WALK_TERMINATE);
3991ae08745Sheppo 	}
4001ae08745Sheppo 
4011ae08745Sheppo 	cpu_arg->result = 0;
4021ae08745Sheppo 	return (PICL_WALK_CONTINUE);
4031ae08745Sheppo }
4041ae08745Sheppo 
4051ae08745Sheppo /*
4061ae08745Sheppo  * Given the start node of the device tree.
4071ae08745Sheppo  * find all cpus in the picl tree that don't have
4081ae08745Sheppo  * device tree counterparts and remove them.
4091ae08745Sheppo  */
4101ae08745Sheppo static void
remove_cpus(di_node_t di_start)4111ae08745Sheppo remove_cpus(di_node_t di_start)
4121ae08745Sheppo {
4131ae08745Sheppo 	int		err;
4141ae08745Sheppo 	picl_nodehdl_t	plath;
4151ae08745Sheppo 	cpu_lookup_t	cpu_arg;
4161ae08745Sheppo 
4171ae08745Sheppo 	err = ptree_get_node_by_path(PLATFORM_PATH, &plath);
4181ae08745Sheppo 	if (err != PICL_SUCCESS)
4191ae08745Sheppo 		return;
4201ae08745Sheppo 
4211ae08745Sheppo 	do {
4221ae08745Sheppo 		cpu_arg.di_node = di_start;
4231ae08745Sheppo 		cpu_arg.nodeh = 0;
4241ae08745Sheppo 		cpu_arg.result = 0;
4251ae08745Sheppo 
4261ae08745Sheppo 		if (ptree_walk_tree_by_class(plath,
4271ae08745Sheppo 		    PICL_CLASS_CPU, &cpu_arg, remove_cpu_candidate)
4281ae08745Sheppo 		    != PICL_SUCCESS)
4291ae08745Sheppo 			return;
4301ae08745Sheppo 
4311ae08745Sheppo 		if (cpu_arg.result == 1) {
4321ae08745Sheppo 			err = ptree_delete_node(cpu_arg.nodeh);
4331ae08745Sheppo 			if (err == PICL_SUCCESS)
4341ae08745Sheppo 				ptree_destroy_node(cpu_arg.nodeh);
4351ae08745Sheppo 		}
4361ae08745Sheppo 	} while (cpu_arg.result);
4371ae08745Sheppo }
4381ae08745Sheppo 
4391ae08745Sheppo /*
4401ae08745Sheppo  * Callback to the ptree walk function during add_cpus.
4411ae08745Sheppo  * As a part of the args receives a cpu di_node, compares
4421ae08745Sheppo  * each picl cpu node's cpuid to the device tree node's cpuid.
4431ae08745Sheppo  * Sets arg struct's result to 1 on a match.
4441ae08745Sheppo  */
4451ae08745Sheppo static int
cpu_exists(picl_nodehdl_t nodeh,void * c_args)4461ae08745Sheppo cpu_exists(picl_nodehdl_t nodeh, void *c_args)
4471ae08745Sheppo {
4481ae08745Sheppo 	di_node_t	di_node;
4491ae08745Sheppo 	cpu_lookup_t	*cpu_arg;
4501ae08745Sheppo 	int	err;
4511ae08745Sheppo 	int	dcpuid, pcpuid;
4521ae08745Sheppo 	int reg_prop[4];
4531ae08745Sheppo 
4541ae08745Sheppo 	if (c_args == NULL)
4551ae08745Sheppo 		return (PICL_INVALIDARG);
4561ae08745Sheppo 
4571ae08745Sheppo 	cpu_arg = c_args;
4581ae08745Sheppo 	di_node = cpu_arg->di_node;
4591ae08745Sheppo 	dcpuid = get_cpuid(di_node);
4601ae08745Sheppo 
4611ae08745Sheppo 	err = ptree_get_propval_by_name(nodeh, OBP_REG, reg_prop,
4621ae08745Sheppo 	    sizeof (reg_prop));
4631ae08745Sheppo 
4641ae08745Sheppo 	if (err != PICL_SUCCESS)
4651ae08745Sheppo 		return (PICL_WALK_CONTINUE);
4661ae08745Sheppo 
4671ae08745Sheppo 	pcpuid = CFGHDL_TO_CPUID(reg_prop[0]);
4681ae08745Sheppo 
4691ae08745Sheppo 	if (dcpuid == pcpuid) {
4701ae08745Sheppo 		cpu_arg->result = 1;
4711ae08745Sheppo 		return (PICL_WALK_TERMINATE);
4721ae08745Sheppo 	}
4731ae08745Sheppo 
4741ae08745Sheppo 	cpu_arg->result = 0;
4751ae08745Sheppo 	return (PICL_WALK_CONTINUE);
4761ae08745Sheppo }
4771ae08745Sheppo 
4781ae08745Sheppo /*
4791ae08745Sheppo  * Given the root node of the device tree.
4801ae08745Sheppo  * compare it to the picl tree and add to it cpus
4811ae08745Sheppo  * that are new.
4821ae08745Sheppo  */
4831ae08745Sheppo static void
add_cpus(di_node_t di_node)4841ae08745Sheppo add_cpus(di_node_t di_node)
4851ae08745Sheppo {
4861ae08745Sheppo 	int		err;
4871ae08745Sheppo 	di_node_t	cnode;
4881ae08745Sheppo 	picl_nodehdl_t	plath;
4891ae08745Sheppo 	cpu_lookup_t	cpu_arg;
4901ae08745Sheppo 	char		*nodename;
4911ae08745Sheppo 
4921ae08745Sheppo 	err = ptree_get_node_by_path(PLATFORM_PATH, &plath);
4931ae08745Sheppo 	if (err != PICL_SUCCESS)
4941ae08745Sheppo 		return;
4951ae08745Sheppo 
4961ae08745Sheppo 	for (cnode = di_child_node(di_node); cnode != DI_NODE_NIL;
4971ae08745Sheppo 	    cnode = di_sibling_node(cnode)) {
4981ae08745Sheppo 		nodename = di_node_name(cnode);
4991ae08745Sheppo 		if (nodename == NULL)
5001ae08745Sheppo 			continue;
5011ae08745Sheppo 		if (strcmp(nodename, OBP_CPU) == 0) {
5021ae08745Sheppo 			cpu_arg.di_node = cnode;
5031ae08745Sheppo 
5041ae08745Sheppo 			if (ptree_walk_tree_by_class(plath,
5051ae08745Sheppo 			    PICL_CLASS_CPU, &cpu_arg, cpu_exists)
5061ae08745Sheppo 			    != PICL_SUCCESS)
5071ae08745Sheppo 				return;
5081ae08745Sheppo 
5091ae08745Sheppo 			if (cpu_arg.result == 0)
5101ae08745Sheppo 				/*
5111ae08745Sheppo 				 * Didn't find a matching cpu, add it.
5121ae08745Sheppo 				 */
5131ae08745Sheppo 				(void) construct_cpu_node(plath,
5141ae08745Sheppo 				    cnode);
5151ae08745Sheppo 		}
5161ae08745Sheppo 	}
5171ae08745Sheppo }
5181ae08745Sheppo 
5191ae08745Sheppo /*
5201ae08745Sheppo  * Handle DR events. Only supports cpu add and remove.
5211ae08745Sheppo  */
5221ae08745Sheppo int
update_devices(char * dev,int op)5231ae08745Sheppo update_devices(char *dev, int op)
5241ae08745Sheppo {
5251ae08745Sheppo 	di_node_t	di_root;
5261ae08745Sheppo 
5271ae08745Sheppo 	if ((di_root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL)
5281ae08745Sheppo 		return (PICL_FAILURE);
5291ae08745Sheppo 
5301ae08745Sheppo 	if ((ph = di_prom_init()) == NULL)
5311ae08745Sheppo 		return (PICL_FAILURE);
5321ae08745Sheppo 
5331ae08745Sheppo 	if (op == DEV_ADD) {
5341ae08745Sheppo 		if (strcmp(dev, OBP_CPU) == 0)
5351ae08745Sheppo 			add_cpus(di_root);
5361ae08745Sheppo 	}
5371ae08745Sheppo 
5381ae08745Sheppo 	if (op == DEV_REMOVE) {
5391ae08745Sheppo 		if (strcmp(dev, OBP_CPU) == 0)
5401ae08745Sheppo 			remove_cpus(di_root);
5411ae08745Sheppo 	}
5421ae08745Sheppo 
5431ae08745Sheppo 	di_fini(di_root);
5441ae08745Sheppo 	di_prom_fini(ph);
5451ae08745Sheppo 	return (PICL_SUCCESS);
5461ae08745Sheppo }
547