xref: /onnv-gate/usr/src/uts/sun4v/io/dr_cpu.c (revision 3414:ff9ba99c65c7)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
23*3414Srsmaeda  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo /*
301991Sheppo  * sun4v CPU DR Module
311991Sheppo  */
321991Sheppo 
331991Sheppo #include <sys/modctl.h>
341991Sheppo #include <sys/processor.h>
351991Sheppo #include <sys/cpuvar.h>
36*3414Srsmaeda #include <sys/cpupart.h>
371991Sheppo #include <sys/sunddi.h>
381991Sheppo #include <sys/sunndi.h>
391991Sheppo #include <sys/note.h>
401991Sheppo #include <sys/sysevent/dr.h>
411991Sheppo #include <sys/hypervisor_api.h>
421991Sheppo #include <sys/mach_descrip.h>
431991Sheppo #include <sys/mdesc.h>
441991Sheppo #include <sys/ds.h>
452309Srsmaeda #include <sys/drctl.h>
461991Sheppo #include <sys/dr_util.h>
471991Sheppo #include <sys/dr_cpu.h>
481991Sheppo #include <sys/promif.h>
491991Sheppo #include <sys/machsystm.h>
501991Sheppo 
511991Sheppo 
521991Sheppo static struct modlmisc modlmisc = {
531991Sheppo 	&mod_miscops,
541991Sheppo 	"sun4v CPU DR %I%"
551991Sheppo };
561991Sheppo 
571991Sheppo static struct modlinkage modlinkage = {
581991Sheppo 	MODREV_1,
591991Sheppo 	(void *)&modlmisc,
601991Sheppo 	NULL
611991Sheppo };
621991Sheppo 
632309Srsmaeda typedef int (*fn_t)(processorid_t, int *, boolean_t);
642309Srsmaeda 
651991Sheppo /*
661991Sheppo  * Global DS Handle
671991Sheppo  */
681991Sheppo static ds_svc_hdl_t ds_handle;
691991Sheppo 
701991Sheppo /*
711991Sheppo  * Supported DS Capability Versions
721991Sheppo  */
731991Sheppo static ds_ver_t		dr_cpu_vers[] = { { 1, 0 } };
741991Sheppo #define	DR_CPU_NVERS	(sizeof (dr_cpu_vers) / sizeof (dr_cpu_vers[0]))
751991Sheppo 
761991Sheppo /*
771991Sheppo  * DS Capability Description
781991Sheppo  */
791991Sheppo static ds_capability_t dr_cpu_cap = {
801991Sheppo 	DR_CPU_DS_ID,		/* svc_id */
811991Sheppo 	dr_cpu_vers,		/* vers */
821991Sheppo 	DR_CPU_NVERS		/* nvers */
831991Sheppo };
841991Sheppo 
851991Sheppo /*
861991Sheppo  * DS Callbacks
871991Sheppo  */
881991Sheppo static void dr_cpu_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
891991Sheppo static void dr_cpu_unreg_handler(ds_cb_arg_t arg);
901991Sheppo static void dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
911991Sheppo 
921991Sheppo /*
931991Sheppo  * DS Client Ops Vector
941991Sheppo  */
951991Sheppo static ds_clnt_ops_t dr_cpu_ops = {
961991Sheppo 	dr_cpu_reg_handler,	/* ds_reg_cb */
971991Sheppo 	dr_cpu_unreg_handler,	/* ds_unreg_cb */
981991Sheppo 	dr_cpu_data_handler,	/* ds_data_cb */
991991Sheppo 	NULL			/* cb_arg */
1001991Sheppo };
1011991Sheppo 
1021991Sheppo /*
103*3414Srsmaeda  * Operation Results
104*3414Srsmaeda  *
105*3414Srsmaeda  * Used internally to gather results while an operation on a
106*3414Srsmaeda  * list of CPUs is in progress. In particular, it is used to
107*3414Srsmaeda  * keep track of which CPUs have already failed so that they are
108*3414Srsmaeda  * not processed further, and the manner in which they failed.
109*3414Srsmaeda  */
110*3414Srsmaeda typedef struct {
111*3414Srsmaeda 	uint32_t	cpuid;
112*3414Srsmaeda 	uint32_t	result;
113*3414Srsmaeda 	uint32_t	status;
114*3414Srsmaeda 	char		*string;
115*3414Srsmaeda } dr_cpu_res_t;
116*3414Srsmaeda 
117*3414Srsmaeda #define	DR_CPU_MAX_ERR_LEN	64	/* maximum error string length */
118*3414Srsmaeda 
119*3414Srsmaeda /*
1201991Sheppo  * Internal Functions
1211991Sheppo  */
1221991Sheppo static int dr_cpu_init(void);
1231991Sheppo static int dr_cpu_fini(void);
1241991Sheppo 
125*3414Srsmaeda static int dr_cpu_list_wrk(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1261991Sheppo static int dr_cpu_list_status(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1271991Sheppo 
1281991Sheppo static int dr_cpu_unconfigure(processorid_t, int *status, boolean_t force);
1292309Srsmaeda static int dr_cpu_configure(processorid_t, int *status, boolean_t force);
1301991Sheppo static int dr_cpu_status(processorid_t, int *status);
1311991Sheppo 
132*3414Srsmaeda static void dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res);
133*3414Srsmaeda static void dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres);
134*3414Srsmaeda static int dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res);
135*3414Srsmaeda 
136*3414Srsmaeda static dr_cpu_res_t *dr_cpu_res_array_init(dr_cpu_hdr_t *, drctl_rsrc_t *, int);
137*3414Srsmaeda static void dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres);
138*3414Srsmaeda static size_t dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res,
139*3414Srsmaeda     dr_cpu_hdr_t **respp);
140*3414Srsmaeda 
1411991Sheppo static int dr_cpu_probe(processorid_t newcpuid);
1421991Sheppo static int dr_cpu_deprobe(processorid_t cpuid);
1431991Sheppo 
1441991Sheppo static dev_info_t *dr_cpu_find_node(processorid_t cpuid);
1451991Sheppo static mde_cookie_t dr_cpu_find_node_md(processorid_t, md_t *, mde_cookie_t *);
1461991Sheppo 
1471991Sheppo int
1481991Sheppo _init(void)
1491991Sheppo {
1501991Sheppo 	int	status;
1511991Sheppo 
1521991Sheppo 	/* check that CPU DR is enabled */
1531991Sheppo 	if (dr_is_disabled(DR_TYPE_CPU)) {
1541991Sheppo 		cmn_err(CE_CONT, "!CPU DR is disabled\n");
1551991Sheppo 		return (-1);
1561991Sheppo 	}
1571991Sheppo 
1581991Sheppo 	if ((status = dr_cpu_init()) != 0) {
1591991Sheppo 		cmn_err(CE_NOTE, "CPU DR initialization failed");
1601991Sheppo 		return (status);
1611991Sheppo 	}
1621991Sheppo 
1631991Sheppo 	if ((status = mod_install(&modlinkage)) != 0) {
1641991Sheppo 		(void) dr_cpu_fini();
1651991Sheppo 	}
1661991Sheppo 
1671991Sheppo 	return (status);
1681991Sheppo }
1691991Sheppo 
1701991Sheppo int
1711991Sheppo _info(struct modinfo *modinfop)
1721991Sheppo {
1731991Sheppo 	return (mod_info(&modlinkage, modinfop));
1741991Sheppo }
1751991Sheppo 
1761991Sheppo int dr_cpu_allow_unload;
1771991Sheppo 
1781991Sheppo int
1791991Sheppo _fini(void)
1801991Sheppo {
1811991Sheppo 	int	status;
1821991Sheppo 
1831991Sheppo 	if (dr_cpu_allow_unload == 0)
1841991Sheppo 		return (EBUSY);
1851991Sheppo 
1861991Sheppo 	if ((status = mod_remove(&modlinkage)) == 0) {
1871991Sheppo 		(void) dr_cpu_fini();
1881991Sheppo 	}
1891991Sheppo 
1901991Sheppo 	return (status);
1911991Sheppo }
1921991Sheppo 
1931991Sheppo static int
1941991Sheppo dr_cpu_init(void)
1951991Sheppo {
1961991Sheppo 	int	rv;
1971991Sheppo 
1981991Sheppo 	if ((rv = ds_cap_init(&dr_cpu_cap, &dr_cpu_ops)) != 0) {
1991991Sheppo 		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
2001991Sheppo 		return (-1);
2011991Sheppo 	}
2021991Sheppo 
2031991Sheppo 	return (0);
2041991Sheppo }
2051991Sheppo 
2061991Sheppo static int
2071991Sheppo dr_cpu_fini(void)
2081991Sheppo {
2091991Sheppo 	int	rv;
2101991Sheppo 
2111991Sheppo 	if ((rv = ds_cap_fini(&dr_cpu_cap)) != 0) {
2121991Sheppo 		cmn_err(CE_NOTE, "ds_cap_fini failed: %d", rv);
2131991Sheppo 		return (-1);
2141991Sheppo 	}
2151991Sheppo 
2161991Sheppo 	return (0);
2171991Sheppo }
2181991Sheppo 
2191991Sheppo static void
2201991Sheppo dr_cpu_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
2211991Sheppo {
2221991Sheppo 	DR_DBG_CPU("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
2231991Sheppo 	    ver->major, ver->minor, hdl);
2241991Sheppo 
2251991Sheppo 	ds_handle = hdl;
2261991Sheppo }
2271991Sheppo 
2281991Sheppo static void
2291991Sheppo dr_cpu_unreg_handler(ds_cb_arg_t arg)
2301991Sheppo {
2311991Sheppo 	DR_DBG_CPU("unreg_handler: arg=0x%p\n", arg);
2321991Sheppo 
2331991Sheppo 	ds_handle = DS_INVALID_HDL;
2341991Sheppo }
2351991Sheppo 
2361991Sheppo static void
2371991Sheppo dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2381991Sheppo {
2391991Sheppo 	_NOTE(ARGUNUSED(arg))
2401991Sheppo 
2411991Sheppo 	dr_cpu_hdr_t	*req = buf;
2421991Sheppo 	dr_cpu_hdr_t	err_resp;
2431991Sheppo 	dr_cpu_hdr_t	*resp = &err_resp;
2441991Sheppo 	int		resp_len = 0;
2451991Sheppo 	int		rv;
2461991Sheppo 
2471991Sheppo 	/*
2481991Sheppo 	 * Sanity check the message
2491991Sheppo 	 */
2501991Sheppo 	if (buflen < sizeof (dr_cpu_hdr_t)) {
2511991Sheppo 		DR_DBG_CPU("incoming message short: expected at least %ld "
2521991Sheppo 		    "bytes, received %ld\n", sizeof (dr_cpu_hdr_t), buflen);
2531991Sheppo 		goto done;
2541991Sheppo 	}
2551991Sheppo 
2561991Sheppo 	if (req == NULL) {
2571991Sheppo 		DR_DBG_CPU("empty message: expected at least %ld bytes\n",
2581991Sheppo 		    sizeof (dr_cpu_hdr_t));
2591991Sheppo 		goto done;
2601991Sheppo 	}
2611991Sheppo 
2621991Sheppo 	DR_DBG_CPU("incoming request:\n");
2631991Sheppo 	DR_DBG_DUMP_MSG(buf, buflen);
2641991Sheppo 
2651991Sheppo 	if (req->num_records > NCPU) {
2661991Sheppo 		DR_DBG_CPU("CPU list too long: %d when %d is the maximum\n",
2671991Sheppo 		    req->num_records, NCPU);
2681991Sheppo 		goto done;
2691991Sheppo 	}
2701991Sheppo 
2711991Sheppo 	if (req->num_records == 0) {
2721991Sheppo 		DR_DBG_CPU("No CPU specified for operation\n");
2731991Sheppo 		goto done;
2741991Sheppo 	}
2751991Sheppo 
2761991Sheppo 	/*
2771991Sheppo 	 * Process the command
2781991Sheppo 	 */
2791991Sheppo 	switch (req->msg_type) {
2801991Sheppo 	case DR_CPU_CONFIGURE:
2811991Sheppo 	case DR_CPU_UNCONFIGURE:
2821991Sheppo 	case DR_CPU_FORCE_UNCONFIG:
283*3414Srsmaeda 		if ((rv = dr_cpu_list_wrk(req, &resp, &resp_len)) != 0) {
284*3414Srsmaeda 			DR_DBG_CPU("%s%s failed (%d)\n",
285*3414Srsmaeda 			    (req->msg_type == DR_CPU_CONFIGURE) ?
286*3414Srsmaeda 			    "CPU configure" : "CPU unconfigure",
287*3414Srsmaeda 			    (req->msg_type == DR_CPU_FORCE_UNCONFIG) ?
288*3414Srsmaeda 			    " (forced)" : "", rv);
289*3414Srsmaeda 		}
2901991Sheppo 		break;
2911991Sheppo 
2921991Sheppo 	case DR_CPU_STATUS:
2931991Sheppo 		if ((rv = dr_cpu_list_status(req, &resp, &resp_len)) != 0)
294*3414Srsmaeda 			DR_DBG_CPU("CPU status failed (%d)\n", rv);
2951991Sheppo 		break;
2961991Sheppo 
2971991Sheppo 	default:
2981991Sheppo 		cmn_err(CE_NOTE, "unsupported DR operation (%d)",
2991991Sheppo 		    req->msg_type);
3001991Sheppo 		break;
3011991Sheppo 	}
3021991Sheppo 
3031991Sheppo done:
3041991Sheppo 	/* check if an error occurred */
3051991Sheppo 	if (resp == &err_resp) {
3061991Sheppo 		resp->req_num = (req) ? req->req_num : 0;
3071991Sheppo 		resp->msg_type = DR_CPU_ERROR;
3081991Sheppo 		resp->num_records = 0;
3091991Sheppo 		resp_len = sizeof (dr_cpu_hdr_t);
3101991Sheppo 	}
3111991Sheppo 
312*3414Srsmaeda 	DR_DBG_CPU("outgoing response:\n");
313*3414Srsmaeda 	DR_DBG_DUMP_MSG(resp, resp_len);
314*3414Srsmaeda 
3151991Sheppo 	/* send back the response */
3161991Sheppo 	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
3171991Sheppo 		DR_DBG_CPU("ds_send failed\n");
3181991Sheppo 	}
3191991Sheppo 
3201991Sheppo 	/* free any allocated memory */
3211991Sheppo 	if (resp != &err_resp) {
3221991Sheppo 		kmem_free(resp, resp_len);
3231991Sheppo 	}
3241991Sheppo }
3251991Sheppo 
3261991Sheppo /*
3272309Srsmaeda  * Common routine to config or unconfig multiple cpus.  The unconfig
3282309Srsmaeda  * case checks with the OS to see if the removal of cpus will be
3292309Srsmaeda  * permitted, but can be overridden by the "force" version of the
3302309Srsmaeda  * command.  Otherwise, the logic for both cases is identical.
3312309Srsmaeda  *
3322309Srsmaeda  * Note: Do not modify result buffer or length on error.
3331991Sheppo  */
3341991Sheppo static int
335*3414Srsmaeda dr_cpu_list_wrk(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
3361991Sheppo {
337*3414Srsmaeda 	int		rv;
338*3414Srsmaeda 	int		idx;
339*3414Srsmaeda 	int		count;
340*3414Srsmaeda 	fn_t		dr_fn;
341*3414Srsmaeda 	int		se_hint;
342*3414Srsmaeda 	boolean_t	force = B_FALSE;
343*3414Srsmaeda 	uint32_t	*req_cpus;
344*3414Srsmaeda 	dr_cpu_res_t	*res;
345*3414Srsmaeda 	int		drctl_cmd;
346*3414Srsmaeda 	int		drctl_flags = 0;
347*3414Srsmaeda 	drctl_rsrc_t	*drctl_req;
348*3414Srsmaeda 	size_t		drctl_req_len;
349*3414Srsmaeda 	drctl_rsrc_t	*drctl_res;
350*3414Srsmaeda 	size_t		drctl_res_len = 0;
351*3414Srsmaeda 	drctl_cookie_t	drctl_res_ck;
3522309Srsmaeda 
3532309Srsmaeda 	static const char me[] = "dr_cpu_list_wrk";
3542309Srsmaeda 
355*3414Srsmaeda 	ASSERT((req != NULL) && (req->num_records != 0));
3562309Srsmaeda 
357*3414Srsmaeda 	count = req->num_records;
3582309Srsmaeda 
359*3414Srsmaeda 	/*
360*3414Srsmaeda 	 * Extract all information that is specific
361*3414Srsmaeda 	 * to the various types of operations.
362*3414Srsmaeda 	 */
363*3414Srsmaeda 	switch (req->msg_type) {
3642309Srsmaeda 	case DR_CPU_CONFIGURE:
365*3414Srsmaeda 		dr_fn = dr_cpu_configure;
366*3414Srsmaeda 		drctl_cmd = DRCTL_CPU_CONFIG_REQUEST;
367*3414Srsmaeda 		se_hint = SE_HINT_INSERT;
3682309Srsmaeda 		break;
3692309Srsmaeda 	case DR_CPU_FORCE_UNCONFIG:
370*3414Srsmaeda 		drctl_flags = DRCTL_FLAG_FORCE;
3712309Srsmaeda 		force = B_TRUE;
3722309Srsmaeda 		_NOTE(FALLTHROUGH)
3732309Srsmaeda 	case DR_CPU_UNCONFIGURE:
374*3414Srsmaeda 		dr_fn = dr_cpu_unconfigure;
375*3414Srsmaeda 		drctl_cmd = DRCTL_CPU_UNCONFIG_REQUEST;
376*3414Srsmaeda 		se_hint = SE_HINT_REMOVE;
3772309Srsmaeda 		break;
3782309Srsmaeda 	default:
3792309Srsmaeda 		/* Programming error if we reach this. */
380*3414Srsmaeda 		cmn_err(CE_NOTE, "%s: bad msg_type %d\n", me, req->msg_type);
3812309Srsmaeda 		ASSERT(0);
3822309Srsmaeda 		return (-1);
3832309Srsmaeda 	}
3841991Sheppo 
385*3414Srsmaeda 	/* the incoming array of cpuids to operate on */
386*3414Srsmaeda 	req_cpus = DR_CPU_CMD_CPUIDS(req);
3872309Srsmaeda 
3882309Srsmaeda 	/* allocate drctl request msg based on incoming resource count */
389*3414Srsmaeda 	drctl_req_len = sizeof (drctl_rsrc_t) * count;
390*3414Srsmaeda 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
3912309Srsmaeda 
3922309Srsmaeda 	/* copy the cpuids for the drctl call from the incoming request msg */
3932309Srsmaeda 	for (idx = 0; idx < count; idx++)
394*3414Srsmaeda 		drctl_req[idx].res_cpu_id = req_cpus[idx];
3951991Sheppo 
396*3414Srsmaeda 	if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
397*3414Srsmaeda 	    count, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) {
398*3414Srsmaeda 		DR_DBG_CPU("%s: drctl_config_init returned: %d\n", me, rv);
399*3414Srsmaeda 		kmem_free(drctl_req, drctl_req_len);
4002309Srsmaeda 		return (-1);
4012309Srsmaeda 	}
4022309Srsmaeda 
403*3414Srsmaeda 	ASSERT((drctl_res != NULL) && (drctl_res_len != 0));
404*3414Srsmaeda 
405*3414Srsmaeda 	/* create the result scratch array */
406*3414Srsmaeda 	res = dr_cpu_res_array_init(req, drctl_res, count);
4072309Srsmaeda 
4082309Srsmaeda 	/*
409*3414Srsmaeda 	 * For unconfigure, check if there are any conditions
410*3414Srsmaeda 	 * that will cause the operation to fail. These are
411*3414Srsmaeda 	 * performed before the actual unconfigure attempt so
412*3414Srsmaeda 	 * that a meaningful error message can be generated.
4132309Srsmaeda 	 */
414*3414Srsmaeda 	if (req->msg_type != DR_CPU_CONFIGURE)
415*3414Srsmaeda 		dr_cpu_check_cpus(req, res);
4161991Sheppo 
417*3414Srsmaeda 	/* perform the specified operation on each of the CPUs */
418*3414Srsmaeda 	for (idx = 0; idx < count; idx++) {
419*3414Srsmaeda 		int result;
420*3414Srsmaeda 		int status;
4212309Srsmaeda 
422*3414Srsmaeda 		/*
423*3414Srsmaeda 		 * If no action will be taken against the current
424*3414Srsmaeda 		 * CPU, update the drctl resource information to
425*3414Srsmaeda 		 * ensure that it gets recovered properly during
426*3414Srsmaeda 		 * the drctl fini() call.
427*3414Srsmaeda 		 */
428*3414Srsmaeda 		if (res[idx].result != DR_CPU_RES_OK) {
429*3414Srsmaeda 			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
430*3414Srsmaeda 			continue;
4312309Srsmaeda 		}
4321991Sheppo 
433*3414Srsmaeda 		/* call the function to perform the actual operation */
434*3414Srsmaeda 		result = (*dr_fn)(req_cpus[idx], &status, force);
435*3414Srsmaeda 
436*3414Srsmaeda 		/* save off results of the operation */
437*3414Srsmaeda 		res[idx].result = result;
438*3414Srsmaeda 		res[idx].status = status;
4392309Srsmaeda 
440*3414Srsmaeda 		/* save result for drctl fini() reusing init() msg memory */
441*3414Srsmaeda 		drctl_req[idx].status = (result != DR_CPU_RES_OK) ?
442*3414Srsmaeda 		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
4432309Srsmaeda 
444*3414Srsmaeda 		DR_DBG_CPU("%s: cpuid %d status %d result %d off '%s'\n",
445*3414Srsmaeda 		    me, req_cpus[idx], drctl_req[idx].status, result,
446*3414Srsmaeda 		    (res[idx].string) ? res[idx].string : "");
4471991Sheppo 	}
4481991Sheppo 
449*3414Srsmaeda 	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
450*3414Srsmaeda 		DR_DBG_CPU("%s: drctl_config_fini returned: %d\n", me, rv);
451*3414Srsmaeda 
452*3414Srsmaeda 	/*
453*3414Srsmaeda 	 * Operation completed without any fatal errors.
454*3414Srsmaeda 	 * Pack the response for transmission.
455*3414Srsmaeda 	 */
456*3414Srsmaeda 	*resp_len = dr_cpu_pack_response(req, res, resp);
4572309Srsmaeda 
458*3414Srsmaeda 	/* notify interested parties about the operation */
459*3414Srsmaeda 	dr_generate_event(DR_TYPE_CPU, se_hint);
4602309Srsmaeda 
461*3414Srsmaeda 	/*
462*3414Srsmaeda 	 * Deallocate any scratch memory.
463*3414Srsmaeda 	 */
464*3414Srsmaeda 	kmem_free(drctl_res, drctl_res_len);
465*3414Srsmaeda 	kmem_free(drctl_req, drctl_req_len);
4662309Srsmaeda 
467*3414Srsmaeda 	dr_cpu_res_array_fini(res, count);
4681991Sheppo 
4691991Sheppo 	return (0);
4701991Sheppo }
4711991Sheppo 
472*3414Srsmaeda /*
473*3414Srsmaeda  * Allocate and initialize a result array based on the initial
474*3414Srsmaeda  * drctl operation. A valid result array is always returned.
475*3414Srsmaeda  */
476*3414Srsmaeda static dr_cpu_res_t *
477*3414Srsmaeda dr_cpu_res_array_init(dr_cpu_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
478*3414Srsmaeda {
479*3414Srsmaeda 	int		idx;
480*3414Srsmaeda 	dr_cpu_res_t	*res;
481*3414Srsmaeda 	char		*err_str;
482*3414Srsmaeda 	size_t		err_len;
483*3414Srsmaeda 
484*3414Srsmaeda 	/* allocate zero filled buffer to initialize fields */
485*3414Srsmaeda 	res = kmem_zalloc(nrsrc * sizeof (dr_cpu_res_t), KM_SLEEP);
486*3414Srsmaeda 
487*3414Srsmaeda 	/*
488*3414Srsmaeda 	 * Fill in the result information for each resource.
489*3414Srsmaeda 	 */
490*3414Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
491*3414Srsmaeda 		res[idx].cpuid = rsrc[idx].res_cpu_id;
492*3414Srsmaeda 		res[idx].result = DR_CPU_RES_OK;
493*3414Srsmaeda 
494*3414Srsmaeda 		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
495*3414Srsmaeda 			continue;
496*3414Srsmaeda 
497*3414Srsmaeda 		/*
498*3414Srsmaeda 		 * Update the state information for this CPU.
499*3414Srsmaeda 		 */
500*3414Srsmaeda 		res[idx].result = DR_CPU_RES_BLOCKED;
501*3414Srsmaeda 		res[idx].status = (req->msg_type == DR_CPU_CONFIGURE) ?
502*3414Srsmaeda 		    DR_CPU_STAT_UNCONFIGURED : DR_CPU_STAT_CONFIGURED;
503*3414Srsmaeda 
504*3414Srsmaeda 		/*
505*3414Srsmaeda 		 * If an error string exists, copy it out of the
506*3414Srsmaeda 		 * message buffer. This eliminates any dependency
507*3414Srsmaeda 		 * on the memory allocated for the message buffer
508*3414Srsmaeda 		 * itself.
509*3414Srsmaeda 		 */
510*3414Srsmaeda 		if (rsrc[idx].offset != NULL) {
511*3414Srsmaeda 			err_str = (char *)rsrc + rsrc[idx].offset;
512*3414Srsmaeda 			err_len = strlen(err_str) + 1;
513*3414Srsmaeda 
514*3414Srsmaeda 			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
515*3414Srsmaeda 			bcopy(err_str, res[idx].string, err_len);
516*3414Srsmaeda 		}
517*3414Srsmaeda 	}
518*3414Srsmaeda 
519*3414Srsmaeda 	return (res);
520*3414Srsmaeda }
521*3414Srsmaeda 
5221991Sheppo static void
523*3414Srsmaeda dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres)
524*3414Srsmaeda {
525*3414Srsmaeda 	int	idx;
526*3414Srsmaeda 	size_t	str_len;
527*3414Srsmaeda 
528*3414Srsmaeda 	for (idx = 0; idx < nres; idx++) {
529*3414Srsmaeda 		/* deallocate the error string if present */
530*3414Srsmaeda 		if (res[idx].string) {
531*3414Srsmaeda 			str_len = strlen(res[idx].string) + 1;
532*3414Srsmaeda 			kmem_free(res[idx].string, str_len);
533*3414Srsmaeda 		}
534*3414Srsmaeda 	}
535*3414Srsmaeda 
536*3414Srsmaeda 	/* deallocate the result array itself */
537*3414Srsmaeda 	kmem_free(res, sizeof (dr_cpu_res_t) * nres);
538*3414Srsmaeda }
539*3414Srsmaeda 
540*3414Srsmaeda /*
541*3414Srsmaeda  * Allocate and pack a response message for transmission based
542*3414Srsmaeda  * on the specified result array. A valid response message and
543*3414Srsmaeda  * valid size information is always returned.
544*3414Srsmaeda  */
545*3414Srsmaeda static size_t
546*3414Srsmaeda dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, dr_cpu_hdr_t **respp)
5471991Sheppo {
5481991Sheppo 	int		idx;
549*3414Srsmaeda 	dr_cpu_hdr_t	*resp;
550*3414Srsmaeda 	dr_cpu_stat_t	*resp_stat;
551*3414Srsmaeda 	size_t		resp_len;
552*3414Srsmaeda 	uint32_t	curr_off;
553*3414Srsmaeda 	caddr_t		curr_str;
554*3414Srsmaeda 	size_t		str_len;
555*3414Srsmaeda 	size_t		stat_len;
556*3414Srsmaeda 	int		nstat = req->num_records;
557*3414Srsmaeda 
558*3414Srsmaeda 	/*
559*3414Srsmaeda 	 * Calculate the size of the response message
560*3414Srsmaeda 	 * and allocate an appropriately sized buffer.
561*3414Srsmaeda 	 */
562*3414Srsmaeda 	resp_len = 0;
563*3414Srsmaeda 
564*3414Srsmaeda 	/* add the header size */
565*3414Srsmaeda 	resp_len += sizeof (dr_cpu_hdr_t);
566*3414Srsmaeda 
567*3414Srsmaeda 	/* add the stat array size */
568*3414Srsmaeda 	stat_len = sizeof (dr_cpu_stat_t) * nstat;
569*3414Srsmaeda 	resp_len += stat_len;
570*3414Srsmaeda 
571*3414Srsmaeda 	/* add the size of any error strings */
572*3414Srsmaeda 	for (idx = 0; idx < nstat; idx++) {
573*3414Srsmaeda 		if (res[idx].string != NULL) {
574*3414Srsmaeda 			resp_len += strlen(res[idx].string) + 1;
575*3414Srsmaeda 		}
576*3414Srsmaeda 	}
577*3414Srsmaeda 
578*3414Srsmaeda 	/* allocate the message buffer */
579*3414Srsmaeda 	resp = kmem_zalloc(resp_len, KM_SLEEP);
580*3414Srsmaeda 
581*3414Srsmaeda 	/*
582*3414Srsmaeda 	 * Fill in the header information.
583*3414Srsmaeda 	 */
584*3414Srsmaeda 	resp->req_num = req->req_num;
585*3414Srsmaeda 	resp->msg_type = DR_CPU_OK;
586*3414Srsmaeda 	resp->num_records = nstat;
587*3414Srsmaeda 
588*3414Srsmaeda 	/*
589*3414Srsmaeda 	 * Fill in the stat information.
590*3414Srsmaeda 	 */
591*3414Srsmaeda 	resp_stat = DR_CPU_RESP_STATS(resp);
592*3414Srsmaeda 
593*3414Srsmaeda 	/* string offsets start immediately after stat array */
594*3414Srsmaeda 	curr_off = sizeof (dr_cpu_hdr_t) + stat_len;
595*3414Srsmaeda 	curr_str = (char *)resp_stat + stat_len;
596*3414Srsmaeda 
597*3414Srsmaeda 	for (idx = 0; idx < nstat; idx++) {
598*3414Srsmaeda 		resp_stat[idx].cpuid = res[idx].cpuid;
599*3414Srsmaeda 		resp_stat[idx].result = res[idx].result;
600*3414Srsmaeda 		resp_stat[idx].status = res[idx].status;
601*3414Srsmaeda 
602*3414Srsmaeda 		if (res[idx].string != NULL) {
603*3414Srsmaeda 			/* copy over the error string */
604*3414Srsmaeda 			str_len = strlen(res[idx].string) + 1;
605*3414Srsmaeda 			bcopy(res[idx].string, curr_str, str_len);
606*3414Srsmaeda 			resp_stat[idx].string_off = curr_off;
607*3414Srsmaeda 
608*3414Srsmaeda 			curr_off += str_len;
609*3414Srsmaeda 			curr_str += str_len;
610*3414Srsmaeda 		}
611*3414Srsmaeda 	}
612*3414Srsmaeda 
613*3414Srsmaeda 	/* buffer should be exactly filled */
614*3414Srsmaeda 	ASSERT(curr_off == resp_len);
615*3414Srsmaeda 
616*3414Srsmaeda 	*respp = resp;
617*3414Srsmaeda 	return (resp_len);
618*3414Srsmaeda }
619*3414Srsmaeda 
620*3414Srsmaeda /*
621*3414Srsmaeda  * Check for conditions that will prevent a CPU from being offlined.
622*3414Srsmaeda  * This provides the opportunity to generate useful information to
623*3414Srsmaeda  * help diagnose the failure rather than letting the offline attempt
624*3414Srsmaeda  * fail in a more generic way.
625*3414Srsmaeda  */
626*3414Srsmaeda static void
627*3414Srsmaeda dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res)
628*3414Srsmaeda {
629*3414Srsmaeda 	int		idx;
630*3414Srsmaeda 	cpu_t		*cp;
631*3414Srsmaeda 	uint32_t	*cpuids;
632*3414Srsmaeda 
633*3414Srsmaeda 	ASSERT((req->msg_type == DR_CPU_UNCONFIGURE) ||
634*3414Srsmaeda 	    (req->msg_type == DR_CPU_FORCE_UNCONFIG));
6351991Sheppo 
6361991Sheppo 	DR_DBG_CPU("dr_cpu_check_cpus...\n");
6371991Sheppo 
638*3414Srsmaeda 	/* array of cpuids start just after the header */
639*3414Srsmaeda 	cpuids = DR_CPU_CMD_CPUIDS(req);
640*3414Srsmaeda 
6411991Sheppo 	mutex_enter(&cpu_lock);
6421991Sheppo 
643*3414Srsmaeda 	/*
644*3414Srsmaeda 	 * Always check processor set membership first. The
645*3414Srsmaeda 	 * last CPU in a processor set will fail to offline
646*3414Srsmaeda 	 * even if the operation if forced, so any failures
647*3414Srsmaeda 	 * should always be reported.
648*3414Srsmaeda 	 */
649*3414Srsmaeda 	dr_cpu_check_psrset(cpuids, res, req->num_records);
650*3414Srsmaeda 
6511991Sheppo 	/* process each cpu that is part of the request */
652*3414Srsmaeda 	for (idx = 0; idx < req->num_records; idx++) {
6531991Sheppo 
654*3414Srsmaeda 		/* nothing to check if the CPU has already failed */
655*3414Srsmaeda 		if (res[idx].result != DR_CPU_RES_OK)
6561991Sheppo 			continue;
6571991Sheppo 
658*3414Srsmaeda 		if ((cp = cpu_get(cpuids[idx])) == NULL)
659*3414Srsmaeda 			continue;
6601991Sheppo 
6611991Sheppo 		/*
662*3414Srsmaeda 		 * Only check if there are bound threads if the
663*3414Srsmaeda 		 * operation is not a forced unconfigure. In a
664*3414Srsmaeda 		 * forced request, threads are automatically
665*3414Srsmaeda 		 * unbound before they are offlined.
6661991Sheppo 		 */
667*3414Srsmaeda 		if (req->msg_type == DR_CPU_UNCONFIGURE) {
668*3414Srsmaeda 			/*
669*3414Srsmaeda 			 * The return value is only interesting if other
670*3414Srsmaeda 			 * checks are added to this loop and a decision
671*3414Srsmaeda 			 * is needed on whether to continue checking.
672*3414Srsmaeda 			 */
673*3414Srsmaeda 			(void) dr_cpu_check_bound_thr(cp, &res[idx]);
6741991Sheppo 		}
6751991Sheppo 	}
6761991Sheppo 
6771991Sheppo 	mutex_exit(&cpu_lock);
6781991Sheppo }
6791991Sheppo 
680*3414Srsmaeda /*
681*3414Srsmaeda  * Examine the processor set configuration for the specified
682*3414Srsmaeda  * CPUs and see if the unconfigure operation would result in
683*3414Srsmaeda  * trying to remove the last CPU in any processor set.
684*3414Srsmaeda  */
685*3414Srsmaeda static void
686*3414Srsmaeda dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres)
687*3414Srsmaeda {
688*3414Srsmaeda 	int		cpu_idx;
689*3414Srsmaeda 	int		set_idx;
690*3414Srsmaeda 	cpu_t		*cp;
691*3414Srsmaeda 	cpupart_t	*cpp;
692*3414Srsmaeda 	char		err_str[DR_CPU_MAX_ERR_LEN];
693*3414Srsmaeda 	size_t		err_len;
694*3414Srsmaeda 	struct {
695*3414Srsmaeda 		cpupart_t	*cpp;
696*3414Srsmaeda 		int		ncpus;
697*3414Srsmaeda 	} *psrset;
698*3414Srsmaeda 
699*3414Srsmaeda 	ASSERT(MUTEX_HELD(&cpu_lock));
700*3414Srsmaeda 
701*3414Srsmaeda 	/*
702*3414Srsmaeda 	 * Allocate a scratch array to count the CPUs in
703*3414Srsmaeda 	 * the various processor sets. A CPU always belongs
704*3414Srsmaeda 	 * to exactly one processor set, so by definition,
705*3414Srsmaeda 	 * the scratch array never needs to be larger than
706*3414Srsmaeda 	 * the number of CPUs.
707*3414Srsmaeda 	 */
708*3414Srsmaeda 	psrset = kmem_zalloc(sizeof (*psrset) * nres, KM_SLEEP);
709*3414Srsmaeda 
710*3414Srsmaeda 	for (cpu_idx = 0; cpu_idx < nres; cpu_idx++) {
711*3414Srsmaeda 
712*3414Srsmaeda 		/* skip any CPUs that have already failed */
713*3414Srsmaeda 		if (res[cpu_idx].result != DR_CPU_RES_OK)
714*3414Srsmaeda 			continue;
715*3414Srsmaeda 
716*3414Srsmaeda 		if ((cp = cpu_get(cpuids[cpu_idx])) == NULL)
717*3414Srsmaeda 			continue;
718*3414Srsmaeda 
719*3414Srsmaeda 		cpp = cp->cpu_part;
720*3414Srsmaeda 
721*3414Srsmaeda 		/* lookup the set this CPU belongs to */
722*3414Srsmaeda 		for (set_idx = 0; set_idx < nres; set_idx++) {
723*3414Srsmaeda 
724*3414Srsmaeda 			/* matching set found */
725*3414Srsmaeda 			if (cpp == psrset[set_idx].cpp)
726*3414Srsmaeda 				break;
727*3414Srsmaeda 
728*3414Srsmaeda 			/* set not found, start a new entry */
729*3414Srsmaeda 			if (psrset[set_idx].cpp == NULL) {
730*3414Srsmaeda 				psrset[set_idx].cpp = cpp;
731*3414Srsmaeda 				psrset[set_idx].ncpus = cpp->cp_ncpus;
732*3414Srsmaeda 				break;
733*3414Srsmaeda 			}
734*3414Srsmaeda 		}
735*3414Srsmaeda 
736*3414Srsmaeda 		ASSERT(set_idx != nres);
737*3414Srsmaeda 
738*3414Srsmaeda 		/*
739*3414Srsmaeda 		 * Remove the current CPU from the set total but only
740*3414Srsmaeda 		 * generate an error for the last CPU. The correct CPU
741*3414Srsmaeda 		 * will get the error because the unconfigure attempts
742*3414Srsmaeda 		 * will occur in the same order in which the CPUs are
743*3414Srsmaeda 		 * examined in this loop.
744*3414Srsmaeda 		 */
745*3414Srsmaeda 		if (--psrset[set_idx].ncpus == 0) {
746*3414Srsmaeda 			/*
747*3414Srsmaeda 			 * Fill in the various pieces of information
748*3414Srsmaeda 			 * to report that the operation will fail.
749*3414Srsmaeda 			 */
750*3414Srsmaeda 			res[cpu_idx].result = DR_CPU_RES_BLOCKED;
751*3414Srsmaeda 			res[cpu_idx].status = DR_CPU_STAT_CONFIGURED;
752*3414Srsmaeda 
753*3414Srsmaeda 			(void) snprintf(err_str, DR_CPU_MAX_ERR_LEN,
754*3414Srsmaeda 			    "last online cpu in processor set %d", cpp->cp_id);
755*3414Srsmaeda 
756*3414Srsmaeda 			err_len = strlen(err_str) + 1;
757*3414Srsmaeda 
758*3414Srsmaeda 			res[cpu_idx].string = kmem_alloc(err_len, KM_SLEEP);
759*3414Srsmaeda 			bcopy(err_str, res[cpu_idx].string, err_len);
760*3414Srsmaeda 
761*3414Srsmaeda 			DR_DBG_CPU("cpu %d: %s\n", cpuids[cpu_idx], err_str);
762*3414Srsmaeda 		}
763*3414Srsmaeda 	}
764*3414Srsmaeda 
765*3414Srsmaeda 	kmem_free(psrset, sizeof (*psrset) * nres);
766*3414Srsmaeda }
767*3414Srsmaeda 
768*3414Srsmaeda /*
769*3414Srsmaeda  * Check if any threads are bound to the specified CPU. If the
770*3414Srsmaeda  * condition is true, DR_CPU_RES_BLOCKED is returned and an error
771*3414Srsmaeda  * string is generated and placed in the specified result structure.
772*3414Srsmaeda  * Otherwise, DR_CPU_RES_OK is returned.
773*3414Srsmaeda  */
774*3414Srsmaeda static int
775*3414Srsmaeda dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res)
776*3414Srsmaeda {
777*3414Srsmaeda 	int		nbound;
778*3414Srsmaeda 	proc_t		*pp;
779*3414Srsmaeda 	kthread_t	*tp;
780*3414Srsmaeda 	char		err_str[DR_CPU_MAX_ERR_LEN];
781*3414Srsmaeda 	size_t		err_len;
782*3414Srsmaeda 
783*3414Srsmaeda 	/*
784*3414Srsmaeda 	 * Error string allocation makes an assumption
785*3414Srsmaeda 	 * that no blocking condition has been identified.
786*3414Srsmaeda 	 */
787*3414Srsmaeda 	ASSERT(res->result == DR_CPU_RES_OK);
788*3414Srsmaeda 	ASSERT(res->string == NULL);
789*3414Srsmaeda 
790*3414Srsmaeda 	ASSERT(MUTEX_HELD(&cpu_lock));
791*3414Srsmaeda 
792*3414Srsmaeda 	mutex_enter(&pidlock);
793*3414Srsmaeda 
794*3414Srsmaeda 	nbound = 0;
795*3414Srsmaeda 
796*3414Srsmaeda 	/*
797*3414Srsmaeda 	 * Walk the active processes, checking if each
798*3414Srsmaeda 	 * thread belonging to the process is bound.
799*3414Srsmaeda 	 */
800*3414Srsmaeda 	for (pp = practive; (pp != NULL) && (nbound <= 1); pp = pp->p_next) {
801*3414Srsmaeda 		mutex_enter(&pp->p_lock);
802*3414Srsmaeda 
803*3414Srsmaeda 		tp = pp->p_tlist;
804*3414Srsmaeda 
805*3414Srsmaeda 		if ((tp == NULL) || (pp->p_flag & SSYS)) {
806*3414Srsmaeda 			mutex_exit(&pp->p_lock);
807*3414Srsmaeda 			continue;
808*3414Srsmaeda 		}
809*3414Srsmaeda 
810*3414Srsmaeda 		do {
811*3414Srsmaeda 			if (tp->t_bind_cpu != cp->cpu_id)
812*3414Srsmaeda 				continue;
813*3414Srsmaeda 
814*3414Srsmaeda 			/*
815*3414Srsmaeda 			 * Update the running total of bound
816*3414Srsmaeda 			 * threads. Continue the search until
817*3414Srsmaeda 			 * it can be determined if more than
818*3414Srsmaeda 			 * one thread is bound to the CPU.
819*3414Srsmaeda 			 */
820*3414Srsmaeda 			if (++nbound > 1)
821*3414Srsmaeda 				break;
822*3414Srsmaeda 
823*3414Srsmaeda 		} while ((tp = tp->t_forw) != pp->p_tlist);
824*3414Srsmaeda 
825*3414Srsmaeda 		mutex_exit(&pp->p_lock);
826*3414Srsmaeda 	}
827*3414Srsmaeda 
828*3414Srsmaeda 	mutex_exit(&pidlock);
829*3414Srsmaeda 
830*3414Srsmaeda 	if (nbound) {
831*3414Srsmaeda 		/*
832*3414Srsmaeda 		 * Threads are bound to the CPU. Fill in
833*3414Srsmaeda 		 * various pieces of information to report
834*3414Srsmaeda 		 * that the operation will fail.
835*3414Srsmaeda 		 */
836*3414Srsmaeda 		res->result = DR_CPU_RES_BLOCKED;
837*3414Srsmaeda 		res->status = DR_CPU_STAT_CONFIGURED;
838*3414Srsmaeda 
839*3414Srsmaeda 		(void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, "cpu has bound "
840*3414Srsmaeda 		    "thread%s", (nbound > 1) ? "s" : "");
841*3414Srsmaeda 
842*3414Srsmaeda 		err_len = strlen(err_str) + 1;
843*3414Srsmaeda 
844*3414Srsmaeda 		res->string = kmem_alloc(err_len, KM_SLEEP);
845*3414Srsmaeda 		bcopy(err_str, res->string, err_len);
846*3414Srsmaeda 
847*3414Srsmaeda 		DR_DBG_CPU("cpu %d: %s\n", cp->cpu_id, err_str);
848*3414Srsmaeda 	}
849*3414Srsmaeda 
850*3414Srsmaeda 	return (res->result);
851*3414Srsmaeda }
8521991Sheppo 
8531991Sheppo /*
8541991Sheppo  * Do not modify result buffer or length on error.
8551991Sheppo  */
8561991Sheppo static int
8571991Sheppo dr_cpu_list_status(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
8581991Sheppo {
8591991Sheppo 	int		idx;
8601991Sheppo 	int		result;
8611991Sheppo 	int		status;
8621991Sheppo 	int		rlen;
8631991Sheppo 	uint32_t	*cpuids;
8641991Sheppo 	dr_cpu_hdr_t	*rp;
8651991Sheppo 	dr_cpu_stat_t	*stat;
8661991Sheppo 	md_t		*mdp = NULL;
8671991Sheppo 	int		num_nodes;
8681991Sheppo 	int		listsz;
8691991Sheppo 	mde_cookie_t	*listp = NULL;
8701991Sheppo 	mde_cookie_t	cpunode;
8711991Sheppo 	boolean_t	walk_md = B_FALSE;
8721991Sheppo 
8731991Sheppo 	/* the incoming array of cpuids to configure */
874*3414Srsmaeda 	cpuids = DR_CPU_CMD_CPUIDS(req);
8751991Sheppo 
8761991Sheppo 	/* allocate a response message */
8771991Sheppo 	rlen = sizeof (dr_cpu_hdr_t);
8781991Sheppo 	rlen += req->num_records * sizeof (dr_cpu_stat_t);
8791991Sheppo 	rp = kmem_zalloc(rlen, KM_SLEEP);
8801991Sheppo 
8811991Sheppo 	/* fill in the known data */
8821991Sheppo 	rp->req_num = req->req_num;
8831991Sheppo 	rp->msg_type = DR_CPU_STATUS;
8841991Sheppo 	rp->num_records = req->num_records;
8851991Sheppo 
8861991Sheppo 	/* stat array for the response */
887*3414Srsmaeda 	stat = DR_CPU_RESP_STATS(rp);
8881991Sheppo 
8891991Sheppo 	/* get the status for each of the CPUs */
8901991Sheppo 	for (idx = 0; idx < req->num_records; idx++) {
8911991Sheppo 
8921991Sheppo 		result = dr_cpu_status(cpuids[idx], &status);
8931991Sheppo 
8941991Sheppo 		if (result == DR_CPU_RES_FAILURE)
8951991Sheppo 			walk_md = B_TRUE;
8961991Sheppo 
8971991Sheppo 		/* save off results of the status */
8981991Sheppo 		stat[idx].cpuid = cpuids[idx];
8991991Sheppo 		stat[idx].result = result;
9001991Sheppo 		stat[idx].status = status;
9011991Sheppo 	}
9021991Sheppo 
9031991Sheppo 	if (walk_md == B_FALSE)
9041991Sheppo 		goto done;
9051991Sheppo 
9061991Sheppo 	/*
9071991Sheppo 	 * At least one of the cpus did not have a CPU
9081991Sheppo 	 * structure. So, consult the MD to determine if
9091991Sheppo 	 * they are present.
9101991Sheppo 	 */
9111991Sheppo 
9121991Sheppo 	if ((mdp = md_get_handle()) == NULL) {
9131991Sheppo 		DR_DBG_CPU("unable to initialize MD\n");
9141991Sheppo 		goto done;
9151991Sheppo 	}
9161991Sheppo 
9171991Sheppo 	num_nodes = md_node_count(mdp);
9181991Sheppo 	ASSERT(num_nodes > 0);
9191991Sheppo 
9201991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
9211991Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
9221991Sheppo 
9231991Sheppo 	for (idx = 0; idx < req->num_records; idx++) {
9241991Sheppo 
9251991Sheppo 		if (stat[idx].result != DR_CPU_RES_FAILURE)
9261991Sheppo 			continue;
9271991Sheppo 
9281991Sheppo 		/* check the MD for the current cpuid */
9291991Sheppo 		cpunode = dr_cpu_find_node_md(stat[idx].cpuid, mdp, listp);
9301991Sheppo 
9311991Sheppo 		stat[idx].result = DR_CPU_RES_OK;
9321991Sheppo 
9331991Sheppo 		if (cpunode == MDE_INVAL_ELEM_COOKIE) {
9341991Sheppo 			stat[idx].status = DR_CPU_STAT_NOT_PRESENT;
9351991Sheppo 		} else {
9361991Sheppo 			stat[idx].status = DR_CPU_STAT_UNCONFIGURED;
9371991Sheppo 		}
9381991Sheppo 	}
9391991Sheppo 
9401991Sheppo 	kmem_free(listp, listsz);
9411991Sheppo 
9421991Sheppo 	(void) md_fini_handle(mdp);
9431991Sheppo 
9441991Sheppo done:
9451991Sheppo 	*resp = rp;
9461991Sheppo 	*resp_len = rlen;
9471991Sheppo 
9481991Sheppo 	return (0);
9491991Sheppo }
9501991Sheppo 
9511991Sheppo static int
9522309Srsmaeda dr_cpu_configure(processorid_t cpuid, int *status, boolean_t force)
9531991Sheppo {
9542309Srsmaeda 	 _NOTE(ARGUNUSED(force))
9551991Sheppo 	struct cpu	*cp;
9561991Sheppo 	int		rv = 0;
9571991Sheppo 
9581991Sheppo 	DR_DBG_CPU("dr_cpu_configure...\n");
9591991Sheppo 
9601991Sheppo 	/*
9611991Sheppo 	 * Build device tree node for the CPU
9621991Sheppo 	 */
9631991Sheppo 	if ((rv = dr_cpu_probe(cpuid)) != 0) {
9641991Sheppo 		DR_DBG_CPU("failed to probe CPU %d (%d)\n", cpuid, rv);
9651991Sheppo 		if (rv == EINVAL) {
9661991Sheppo 			*status = DR_CPU_STAT_NOT_PRESENT;
9671991Sheppo 			return (DR_CPU_RES_NOT_IN_MD);
9681991Sheppo 		}
9691991Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
9701991Sheppo 		return (DR_CPU_RES_FAILURE);
9711991Sheppo 	}
9721991Sheppo 
9731991Sheppo 	mutex_enter(&cpu_lock);
9741991Sheppo 
9751991Sheppo 	/*
9761991Sheppo 	 * Configure the CPU
9771991Sheppo 	 */
9781991Sheppo 	if ((cp = cpu_get(cpuid)) == NULL) {
9791991Sheppo 
9801991Sheppo 		if ((rv = cpu_configure(cpuid)) != 0) {
9811991Sheppo 			DR_DBG_CPU("failed to configure CPU %d (%d)\n",
9821991Sheppo 			    cpuid, rv);
9831991Sheppo 			rv = DR_CPU_RES_FAILURE;
9841991Sheppo 			*status = DR_CPU_STAT_UNCONFIGURED;
9851991Sheppo 			goto done;
9861991Sheppo 		}
9871991Sheppo 
9881991Sheppo 		DR_DBG_CPU("CPU %d configured\n", cpuid);
9891991Sheppo 
9901991Sheppo 		/* CPU struct should exist now */
9911991Sheppo 		cp = cpu_get(cpuid);
9921991Sheppo 	}
9931991Sheppo 
9941991Sheppo 	ASSERT(cp);
9951991Sheppo 
9961991Sheppo 	/*
9971991Sheppo 	 * Power on the CPU. In sun4v, this brings the stopped
9981991Sheppo 	 * CPU into the guest from the Hypervisor.
9991991Sheppo 	 */
10001991Sheppo 	if (cpu_is_poweredoff(cp)) {
10011991Sheppo 
10021991Sheppo 		if ((rv = cpu_poweron(cp)) != 0) {
10031991Sheppo 			DR_DBG_CPU("failed to power on CPU %d (%d)\n",
10041991Sheppo 			    cpuid, rv);
10051991Sheppo 			rv = DR_CPU_RES_FAILURE;
10061991Sheppo 			*status = DR_CPU_STAT_UNCONFIGURED;
10071991Sheppo 			goto done;
10081991Sheppo 		}
10091991Sheppo 
10101991Sheppo 		DR_DBG_CPU("CPU %d powered on\n", cpuid);
10111991Sheppo 	}
10121991Sheppo 
10131991Sheppo 	/*
10141991Sheppo 	 * Online the CPU
10151991Sheppo 	 */
10161991Sheppo 	if (cpu_is_offline(cp)) {
10171991Sheppo 
10181991Sheppo 		if ((rv = cpu_online(cp)) != 0) {
10191991Sheppo 			DR_DBG_CPU("failed to online CPU %d (%d)\n",
10201991Sheppo 			    cpuid, rv);
10211991Sheppo 			rv = DR_CPU_RES_FAILURE;
10221991Sheppo 			/* offline is still configured */
10231991Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
10241991Sheppo 			goto done;
10251991Sheppo 		}
10261991Sheppo 
10271991Sheppo 		DR_DBG_CPU("CPU %d online\n", cpuid);
10281991Sheppo 	}
10291991Sheppo 
10301991Sheppo 	rv = DR_CPU_RES_OK;
10311991Sheppo 	*status = DR_CPU_STAT_CONFIGURED;
10321991Sheppo 
10331991Sheppo done:
10341991Sheppo 	mutex_exit(&cpu_lock);
10351991Sheppo 
10361991Sheppo 	return (rv);
10371991Sheppo }
10381991Sheppo 
10391991Sheppo static int
10401991Sheppo dr_cpu_unconfigure(processorid_t cpuid, int *status, boolean_t force)
10411991Sheppo {
10421991Sheppo 	struct cpu	*cp;
10431991Sheppo 	int		rv = 0;
10441991Sheppo 	int		cpu_flags;
10451991Sheppo 
10461991Sheppo 	DR_DBG_CPU("dr_cpu_unconfigure%s...\n", (force) ? " (force)" : "");
10471991Sheppo 
10481991Sheppo 	mutex_enter(&cpu_lock);
10491991Sheppo 
10501991Sheppo 	cp = cpu_get(cpuid);
10511991Sheppo 
10521991Sheppo 	if (cp == NULL) {
10531991Sheppo 
10541991Sheppo 		/*
10551991Sheppo 		 * The OS CPU structures are already torn down,
10561991Sheppo 		 * Attempt to deprobe the CPU to make sure the
10571991Sheppo 		 * device tree is up to date.
10581991Sheppo 		 */
10591991Sheppo 		if (dr_cpu_deprobe(cpuid) != 0) {
10601991Sheppo 			DR_DBG_CPU("failed to deprobe CPU %d\n", cpuid);
10611991Sheppo 			rv = DR_CPU_RES_FAILURE;
10621991Sheppo 			*status = DR_CPU_STAT_UNCONFIGURED;
10631991Sheppo 			goto done;
10641991Sheppo 		}
10651991Sheppo 
10661991Sheppo 		goto done;
10671991Sheppo 	}
10681991Sheppo 
10691991Sheppo 	ASSERT(cp->cpu_id == cpuid);
10701991Sheppo 
10711991Sheppo 	/*
10721991Sheppo 	 * Offline the CPU
10731991Sheppo 	 */
10741991Sheppo 	if (cpu_is_active(cp)) {
10751991Sheppo 
10761991Sheppo 		/* set the force flag correctly */
10771991Sheppo 		cpu_flags = (force) ? CPU_FORCED : 0;
10781991Sheppo 
10791991Sheppo 		if ((rv = cpu_offline(cp, cpu_flags)) != 0) {
10801991Sheppo 			DR_DBG_CPU("failed to offline CPU %d (%d)\n",
10811991Sheppo 			    cpuid, rv);
10821991Sheppo 
10831991Sheppo 			rv = DR_CPU_RES_FAILURE;
10841991Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
10851991Sheppo 			goto done;
10861991Sheppo 		}
10871991Sheppo 
10881991Sheppo 		DR_DBG_CPU("CPU %d offline\n", cpuid);
10891991Sheppo 	}
10901991Sheppo 
10911991Sheppo 	/*
10921991Sheppo 	 * Power off the CPU. In sun4v, this puts the running
10931991Sheppo 	 * CPU into the stopped state in the Hypervisor.
10941991Sheppo 	 */
10951991Sheppo 	if (!cpu_is_poweredoff(cp)) {
10961991Sheppo 
10971991Sheppo 		if ((rv = cpu_poweroff(cp)) != 0) {
10981991Sheppo 			DR_DBG_CPU("failed to power off CPU %d (%d)\n",
10991991Sheppo 			    cpuid, rv);
11001991Sheppo 			rv = DR_CPU_RES_FAILURE;
11011991Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
11021991Sheppo 			goto done;
11031991Sheppo 		}
11041991Sheppo 
11051991Sheppo 		DR_DBG_CPU("CPU %d powered off\n", cpuid);
11061991Sheppo 	}
11071991Sheppo 
11081991Sheppo 	/*
11091991Sheppo 	 * Unconfigure the CPU
11101991Sheppo 	 */
11111991Sheppo 	if ((rv = cpu_unconfigure(cpuid)) != 0) {
11121991Sheppo 		DR_DBG_CPU("failed to unconfigure CPU %d (%d)\n", cpuid, rv);
11131991Sheppo 		rv = DR_CPU_RES_FAILURE;
11141991Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
11151991Sheppo 		goto done;
11161991Sheppo 	}
11171991Sheppo 
11181991Sheppo 	DR_DBG_CPU("CPU %d unconfigured\n", cpuid);
11191991Sheppo 
11201991Sheppo 	/*
11211991Sheppo 	 * Tear down device tree.
11221991Sheppo 	 */
11231991Sheppo 	if ((rv = dr_cpu_deprobe(cpuid)) != 0) {
11241991Sheppo 		DR_DBG_CPU("failed to deprobe CPU %d (%d)\n", cpuid, rv);
11251991Sheppo 		rv = DR_CPU_RES_FAILURE;
11261991Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
11271991Sheppo 		goto done;
11281991Sheppo 	}
11291991Sheppo 
11301991Sheppo 	rv = DR_CPU_RES_OK;
11311991Sheppo 	*status = DR_CPU_STAT_UNCONFIGURED;
11321991Sheppo 
11331991Sheppo done:
11341991Sheppo 	mutex_exit(&cpu_lock);
11351991Sheppo 
11361991Sheppo 	return (rv);
11371991Sheppo }
11381991Sheppo 
11391991Sheppo /*
11401991Sheppo  * Determine the state of a CPU. If the CPU structure is not present,
11411991Sheppo  * it does not attempt to determine whether or not the CPU is in the
11421991Sheppo  * MD. It is more efficient to do this at the higher level for all
11431991Sheppo  * CPUs since it may not even be necessary to search the MD if all
11441991Sheppo  * the CPUs are accounted for. Returns DR_CPU_RES_OK if the CPU
11451991Sheppo  * structure is present, and DR_CPU_RES_FAILURE otherwise as a signal
11461991Sheppo  * that an MD walk is necessary.
11471991Sheppo  */
11481991Sheppo static int
11491991Sheppo dr_cpu_status(processorid_t cpuid, int *status)
11501991Sheppo {
11511991Sheppo 	int		rv;
11521991Sheppo 	struct cpu	*cp;
11531991Sheppo 
11541991Sheppo 	DR_DBG_CPU("dr_cpu_status...\n");
11551991Sheppo 
11561991Sheppo 	mutex_enter(&cpu_lock);
11571991Sheppo 
11581991Sheppo 	if ((cp = cpu_get(cpuid)) == NULL) {
11591991Sheppo 		/* need to check if cpu is in the MD */
11601991Sheppo 		rv = DR_CPU_RES_FAILURE;
11611991Sheppo 		goto done;
11621991Sheppo 	}
11631991Sheppo 
11641991Sheppo 	if (cpu_is_poweredoff(cp)) {
11651991Sheppo 		/*
11661991Sheppo 		 * The CPU is powered off, so it is considered
11671991Sheppo 		 * unconfigured from the service entity point of
11681991Sheppo 		 * view. The CPU is not available to the system
11691991Sheppo 		 * and intervention by the service entity would
11701991Sheppo 		 * be required to change that.
11711991Sheppo 		 */
11721991Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
11731991Sheppo 	} else {
11741991Sheppo 		/*
11751991Sheppo 		 * The CPU is powered on, so it is considered
11761991Sheppo 		 * configured from the service entity point of
11771991Sheppo 		 * view. It is available for use by the system
11781991Sheppo 		 * and service entities are not concerned about
11791991Sheppo 		 * the operational status (offline, online, etc.)
11801991Sheppo 		 * of the CPU in terms of DR.
11811991Sheppo 		 */
11821991Sheppo 		*status = DR_CPU_STAT_CONFIGURED;
11831991Sheppo 	}
11841991Sheppo 
11851991Sheppo 	rv = DR_CPU_RES_OK;
11861991Sheppo 
11871991Sheppo done:
11881991Sheppo 	mutex_exit(&cpu_lock);
11891991Sheppo 
11901991Sheppo 	return (rv);
11911991Sheppo }
11921991Sheppo 
11931991Sheppo typedef struct {
11941991Sheppo 	md_t		*mdp;
11951991Sheppo 	mde_cookie_t	cpunode;
11961991Sheppo 	dev_info_t	*dip;
11971991Sheppo } cb_arg_t;
11981991Sheppo 
11991991Sheppo #define	STR_ARR_LEN	5
12001991Sheppo 
12011991Sheppo static int
12021991Sheppo new_cpu_node(dev_info_t *new_node, void *arg, uint_t flags)
12031991Sheppo {
12041991Sheppo 	_NOTE(ARGUNUSED(flags))
12051991Sheppo 
12061991Sheppo 	char		*compat;
12071991Sheppo 	uint64_t	freq;
12081991Sheppo 	uint64_t	cpuid = 0;
12091991Sheppo 	int		regbuf[4];
12101991Sheppo 	int		len = 0;
12111991Sheppo 	cb_arg_t	*cba;
12121991Sheppo 	char		*str_arr[STR_ARR_LEN];
12131991Sheppo 	char		*curr;
12141991Sheppo 	int		idx = 0;
12151991Sheppo 
12161991Sheppo 	DR_DBG_CPU("new_cpu_node...\n");
12171991Sheppo 
12181991Sheppo 	cba = (cb_arg_t *)arg;
12191991Sheppo 
12201991Sheppo 	/*
12211991Sheppo 	 * Add 'name' property
12221991Sheppo 	 */
12231991Sheppo 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
12241991Sheppo 	    "name", "cpu") != DDI_SUCCESS) {
12251991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'name' property\n");
12261991Sheppo 		return (DDI_WALK_ERROR);
12271991Sheppo 	}
12281991Sheppo 
12291991Sheppo 	/*
12301991Sheppo 	 * Add 'compatible' property
12311991Sheppo 	 */
12321991Sheppo 	if (md_get_prop_data(cba->mdp, cba->cpunode, "compatible",
12331991Sheppo 	    (uint8_t **)(&compat), &len)) {
12341991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'compatible' property "
12351991Sheppo 		    "from MD\n");
12361991Sheppo 		return (DDI_WALK_ERROR);
12371991Sheppo 	}
12381991Sheppo 
12391991Sheppo 	DR_DBG_CPU("'compatible' len is %d\n", len);
12401991Sheppo 
12411991Sheppo 	/* parse the MD string array */
12421991Sheppo 	curr = compat;
12431991Sheppo 	while (curr < (compat + len)) {
12441991Sheppo 
12451991Sheppo 		DR_DBG_CPU("adding '%s' to 'compatible' property\n", curr);
12461991Sheppo 
12471991Sheppo 		str_arr[idx++] = curr;
12481991Sheppo 		curr += strlen(curr) + 1;
12491991Sheppo 
12501991Sheppo 		if (idx == STR_ARR_LEN) {
12511991Sheppo 			DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
12521991Sheppo 			break;
12531991Sheppo 		}
12541991Sheppo 	}
12551991Sheppo 
12561991Sheppo 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
12571991Sheppo 	    "compatible", str_arr, idx) != DDI_SUCCESS) {
12581991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'compatible' "
12591991Sheppo 		    "property\n");
12601991Sheppo 		return (DDI_WALK_ERROR);
12611991Sheppo 	}
12621991Sheppo 
12631991Sheppo 	/*
12641991Sheppo 	 * Add 'device_type' property
12651991Sheppo 	 */
12661991Sheppo 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
12671991Sheppo 	    "device_type", "cpu") != DDI_SUCCESS) {
12681991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'device_type' "
12691991Sheppo 		    "property\n");
12701991Sheppo 		return (DDI_WALK_ERROR);
12711991Sheppo 	}
12721991Sheppo 
12731991Sheppo 	/*
12741991Sheppo 	 * Add 'clock-frequency' property
12751991Sheppo 	 */
12761991Sheppo 	if (md_get_prop_val(cba->mdp, cba->cpunode, "clock-frequency", &freq)) {
12771991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'clock-frequency' "
12781991Sheppo 		    "property from MD\n");
12791991Sheppo 		return (DDI_WALK_ERROR);
12801991Sheppo 	}
12811991Sheppo 
12821991Sheppo 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node,
12831991Sheppo 	    "clock-frequency", freq) != DDI_SUCCESS) {
12841991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'clock-frequency' "
12851991Sheppo 		    "property\n");
12861991Sheppo 		return (DDI_WALK_ERROR);
12871991Sheppo 	}
12881991Sheppo 
12891991Sheppo 	/*
12901991Sheppo 	 * Add 'reg' (cpuid) property
12911991Sheppo 	 */
12921991Sheppo 	if (md_get_prop_val(cba->mdp, cba->cpunode, "id", &cpuid)) {
12931991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'id' property "
12941991Sheppo 		    "from MD\n");
12951991Sheppo 		return (DDI_WALK_ERROR);
12961991Sheppo 	}
12971991Sheppo 
12981991Sheppo 	DR_DBG_CPU("new cpuid=0x%lx\n", cpuid);
12991991Sheppo 
13001991Sheppo 	bzero(regbuf, 4 * sizeof (int));
13011991Sheppo 	regbuf[0] = 0xc0000000 | cpuid;
13021991Sheppo 
13031991Sheppo 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_node,
13041991Sheppo 	    "reg", regbuf, 4) != DDI_SUCCESS) {
13051991Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'reg' property\n");
13061991Sheppo 		return (DDI_WALK_ERROR);
13071991Sheppo 	}
13081991Sheppo 
13091991Sheppo 	cba->dip = new_node;
13101991Sheppo 
13111991Sheppo 	return (DDI_WALK_TERMINATE);
13121991Sheppo }
13131991Sheppo 
13141991Sheppo static int
13151991Sheppo dr_cpu_probe(processorid_t cpuid)
13161991Sheppo {
13171991Sheppo 	dev_info_t	*pdip;
13181991Sheppo 	dev_info_t	*dip;
13191991Sheppo 	devi_branch_t	br;
13201991Sheppo 	md_t		*mdp = NULL;
13211991Sheppo 	int		num_nodes;
13221991Sheppo 	int		rv = 0;
13231991Sheppo 	int		listsz;
13241991Sheppo 	mde_cookie_t	*listp = NULL;
13251991Sheppo 	cb_arg_t	cba;
13261991Sheppo 	mde_cookie_t	cpunode;
13271991Sheppo 
13281991Sheppo 	if ((dip = dr_cpu_find_node(cpuid)) != NULL) {
13291991Sheppo 		/* nothing to do */
13301991Sheppo 		e_ddi_branch_rele(dip);
13311991Sheppo 		return (0);
13321991Sheppo 	}
13331991Sheppo 
13341991Sheppo 	if ((mdp = md_get_handle()) == NULL) {
13351991Sheppo 		DR_DBG_CPU("unable to initialize machine description\n");
13361991Sheppo 		return (-1);
13371991Sheppo 	}
13381991Sheppo 
13391991Sheppo 	num_nodes = md_node_count(mdp);
13401991Sheppo 	ASSERT(num_nodes > 0);
13411991Sheppo 
13421991Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
13431991Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
13441991Sheppo 
13451991Sheppo 	cpunode = dr_cpu_find_node_md(cpuid, mdp, listp);
13461991Sheppo 
13471991Sheppo 	if (cpunode == MDE_INVAL_ELEM_COOKIE) {
13481991Sheppo 		rv = EINVAL;
13491991Sheppo 		goto done;
13501991Sheppo 	}
13511991Sheppo 
13521991Sheppo 	/* pass in MD cookie for CPU */
13531991Sheppo 	cba.mdp = mdp;
13541991Sheppo 	cba.cpunode = cpunode;
13551991Sheppo 
13561991Sheppo 	br.arg = (void *)&cba;
13571991Sheppo 	br.type = DEVI_BRANCH_SID;
13581991Sheppo 	br.create.sid_branch_create = new_cpu_node;
13591991Sheppo 	br.devi_branch_callback = NULL;
13601991Sheppo 	pdip = ddi_root_node();
13611991Sheppo 
13621991Sheppo 	if ((rv = e_ddi_branch_create(pdip, &br, NULL, 0))) {
13631991Sheppo 		DR_DBG_CPU("e_ddi_branch_create failed: %d\n", rv);
13641991Sheppo 		rv = -1;
13651991Sheppo 		goto done;
13661991Sheppo 	}
13671991Sheppo 
13681991Sheppo 	DR_DBG_CPU("CPU %d probed\n", cpuid);
13691991Sheppo 
13701991Sheppo 	rv = 0;
13711991Sheppo 
13721991Sheppo done:
13731991Sheppo 	if (listp)
13741991Sheppo 		kmem_free(listp, listsz);
13751991Sheppo 
13761991Sheppo 	if (mdp)
13771991Sheppo 		(void) md_fini_handle(mdp);
13781991Sheppo 
13791991Sheppo 	return (rv);
13801991Sheppo }
13811991Sheppo 
13821991Sheppo static int
13831991Sheppo dr_cpu_deprobe(processorid_t cpuid)
13841991Sheppo {
13851991Sheppo 	dev_info_t	*fdip = NULL;
13861991Sheppo 	dev_info_t	*dip;
13871991Sheppo 
13881991Sheppo 	if ((dip = dr_cpu_find_node(cpuid)) == NULL) {
13891991Sheppo 		DR_DBG_CPU("cpuid %d already deprobed\n", cpuid);
13901991Sheppo 		return (0);
13911991Sheppo 	}
13921991Sheppo 
13931991Sheppo 	ASSERT(e_ddi_branch_held(dip));
13941991Sheppo 
13951991Sheppo 	if (e_ddi_branch_destroy(dip, &fdip, 0)) {
13961991Sheppo 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
13971991Sheppo 
13981991Sheppo 		/*
13991991Sheppo 		 * If non-NULL, fdip is held and must be released.
14001991Sheppo 		 */
14011991Sheppo 		if (fdip != NULL) {
14021991Sheppo 			(void) ddi_pathname(fdip, path);
14031991Sheppo 			ddi_release_devi(fdip);
14041991Sheppo 		} else {
14051991Sheppo 			(void) ddi_pathname(dip, path);
14061991Sheppo 		}
14071991Sheppo 		cmn_err(CE_NOTE, "node removal failed: %s (%p)",
14081991Sheppo 		    path, (fdip) ? (void *)fdip : (void *)dip);
14091991Sheppo 
14101991Sheppo 		kmem_free(path, MAXPATHLEN);
14111991Sheppo 
14121991Sheppo 		return (-1);
14131991Sheppo 	}
14141991Sheppo 
14151991Sheppo 	DR_DBG_CPU("CPU %d deprobed\n", cpuid);
14161991Sheppo 
14171991Sheppo 	return (0);
14181991Sheppo }
14191991Sheppo 
14201991Sheppo typedef struct {
14211991Sheppo 	processorid_t	cpuid;
14221991Sheppo 	dev_info_t	*dip;
14231991Sheppo } dr_search_arg_t;
14241991Sheppo 
14251991Sheppo static int
14261991Sheppo dr_cpu_check_node(dev_info_t *dip, void *arg)
14271991Sheppo {
14281991Sheppo 	char 		*name;
14291991Sheppo 	processorid_t	cpuid;
14301991Sheppo 	dr_search_arg_t	*sarg = (dr_search_arg_t *)arg;
14311991Sheppo 
14321991Sheppo 	if (dip == ddi_root_node()) {
14331991Sheppo 		return (DDI_WALK_CONTINUE);
14341991Sheppo 	}
14351991Sheppo 
14361991Sheppo 	name = ddi_node_name(dip);
14371991Sheppo 
14381991Sheppo 	if (strcmp(name, "cpu") != 0) {
14391991Sheppo 		return (DDI_WALK_PRUNECHILD);
14401991Sheppo 	}
14411991Sheppo 
14421991Sheppo 	cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
14431991Sheppo 	    "reg", -1);
14441991Sheppo 
14451991Sheppo 	cpuid = PROM_CFGHDL_TO_CPUID(cpuid);
14461991Sheppo 
14471991Sheppo 	DR_DBG_CPU("found cpuid=0x%x, looking for 0x%x\n", cpuid, sarg->cpuid);
14481991Sheppo 
14491991Sheppo 	if (cpuid == sarg->cpuid) {
14501991Sheppo 		DR_DBG_CPU("matching node\n");
14511991Sheppo 
14521991Sheppo 		/* matching node must be returned held */
14531991Sheppo 		if (!e_ddi_branch_held(dip))
14541991Sheppo 			e_ddi_branch_hold(dip);
14551991Sheppo 
14561991Sheppo 		sarg->dip = dip;
14571991Sheppo 		return (DDI_WALK_TERMINATE);
14581991Sheppo 	}
14591991Sheppo 
14601991Sheppo 	return (DDI_WALK_CONTINUE);
14611991Sheppo }
14621991Sheppo 
14631991Sheppo /*
14641991Sheppo  * Walk the device tree to find the dip corresponding to the cpuid
14651991Sheppo  * passed in. If present, the dip is returned held. The caller must
14661991Sheppo  * release the hold on the dip once it is no longer required. If no
14671991Sheppo  * matching node if found, NULL is returned.
14681991Sheppo  */
14691991Sheppo static dev_info_t *
14701991Sheppo dr_cpu_find_node(processorid_t cpuid)
14711991Sheppo {
14721991Sheppo 	dr_search_arg_t	arg;
14731991Sheppo 
14741991Sheppo 	DR_DBG_CPU("dr_cpu_find_node...\n");
14751991Sheppo 
14761991Sheppo 	arg.cpuid = cpuid;
14771991Sheppo 	arg.dip = NULL;
14781991Sheppo 
14791991Sheppo 	ddi_walk_devs(ddi_root_node(), dr_cpu_check_node, &arg);
14801991Sheppo 
14811991Sheppo 	ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
14821991Sheppo 
14831991Sheppo 	return ((arg.dip) ? arg.dip : NULL);
14841991Sheppo }
14851991Sheppo 
14861991Sheppo /*
14871991Sheppo  * Look up a particular cpuid in the MD. Returns the mde_cookie_t
14881991Sheppo  * representing that CPU if present, and MDE_INVAL_ELEM_COOKIE
14891991Sheppo  * otherwise. It is assumed the scratch array has already been
14901991Sheppo  * allocated so that it can accommodate the worst case scenario,
14911991Sheppo  * every node in the MD.
14921991Sheppo  */
14931991Sheppo static mde_cookie_t
14941991Sheppo dr_cpu_find_node_md(processorid_t cpuid, md_t *mdp, mde_cookie_t *listp)
14951991Sheppo {
14961991Sheppo 	int		idx;
14971991Sheppo 	int		nnodes;
14981991Sheppo 	mde_cookie_t	rootnode;
14991991Sheppo 	uint64_t	cpuid_prop;
15001991Sheppo 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
15011991Sheppo 
15021991Sheppo 	rootnode = md_root_node(mdp);
15031991Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
15041991Sheppo 
15051991Sheppo 	/*
15061991Sheppo 	 * Scan the DAG for all the CPU nodes
15071991Sheppo 	 */
15081991Sheppo 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
15091991Sheppo 	    md_find_name(mdp, "fwd"), listp);
15101991Sheppo 
15111991Sheppo 	if (nnodes < 0) {
15121991Sheppo 		DR_DBG_CPU("Scan for CPUs failed\n");
15131991Sheppo 		return (result);
15141991Sheppo 	}
15151991Sheppo 
15161991Sheppo 	DR_DBG_CPU("dr_cpu_find_node_md: found %d CPUs in the MD\n", nnodes);
15171991Sheppo 
15181991Sheppo 	/*
15191991Sheppo 	 * Find the CPU of interest
15201991Sheppo 	 */
15211991Sheppo 	for (idx = 0; idx < nnodes; idx++) {
15221991Sheppo 
15231991Sheppo 		if (md_get_prop_val(mdp, listp[idx], "id", &cpuid_prop)) {
15241991Sheppo 			DR_DBG_CPU("Missing 'id' property for CPU node %d\n",
15251991Sheppo 			    idx);
15261991Sheppo 			break;
15271991Sheppo 		}
15281991Sheppo 
15291991Sheppo 		if (cpuid_prop == cpuid) {
15301991Sheppo 			/* found a match */
15311991Sheppo 			DR_DBG_CPU("dr_cpu_find_node_md: found CPU %d "
15321991Sheppo 			    "in MD\n", cpuid);
15331991Sheppo 			result = listp[idx];
15341991Sheppo 			break;
15351991Sheppo 		}
15361991Sheppo 	}
15371991Sheppo 
15381991Sheppo 	if (result == MDE_INVAL_ELEM_COOKIE) {
15391991Sheppo 		DR_DBG_CPU("CPU %d not in MD\n", cpuid);
15401991Sheppo 	}
15411991Sheppo 
15421991Sheppo 	return (result);
15431991Sheppo }
1544