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 /*
237de586caSJames Marks - Sun Microsystems * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241ae08745Sheppo * Use is subject to license terms.
251ae08745Sheppo */
261ae08745Sheppo
271ae08745Sheppo /*
281ae08745Sheppo * sun4v CPU DR Module
291ae08745Sheppo */
301ae08745Sheppo
311ae08745Sheppo #include <sys/modctl.h>
321ae08745Sheppo #include <sys/processor.h>
331ae08745Sheppo #include <sys/cpuvar.h>
340c86d1bbSrsmaeda #include <sys/cpupart.h>
351ae08745Sheppo #include <sys/sunddi.h>
361ae08745Sheppo #include <sys/sunndi.h>
371ae08745Sheppo #include <sys/note.h>
381ae08745Sheppo #include <sys/sysevent/dr.h>
391ae08745Sheppo #include <sys/hypervisor_api.h>
401ae08745Sheppo #include <sys/mach_descrip.h>
411ae08745Sheppo #include <sys/mdesc.h>
421ae08745Sheppo #include <sys/ds.h>
431d4b38e0Srsmaeda #include <sys/drctl.h>
441ae08745Sheppo #include <sys/dr_util.h>
451ae08745Sheppo #include <sys/dr_cpu.h>
461ae08745Sheppo #include <sys/promif.h>
471ae08745Sheppo #include <sys/machsystm.h>
481ae08745Sheppo
491ae08745Sheppo
501ae08745Sheppo static struct modlmisc modlmisc = {
511ae08745Sheppo &mod_miscops,
52f500b196SRichard Bean "sun4v CPU DR"
531ae08745Sheppo };
541ae08745Sheppo
551ae08745Sheppo static struct modlinkage modlinkage = {
561ae08745Sheppo MODREV_1,
571ae08745Sheppo (void *)&modlmisc,
581ae08745Sheppo NULL
591ae08745Sheppo };
601ae08745Sheppo
611d4b38e0Srsmaeda typedef int (*fn_t)(processorid_t, int *, boolean_t);
621d4b38e0Srsmaeda
631ae08745Sheppo /*
641ae08745Sheppo * Global DS Handle
651ae08745Sheppo */
661ae08745Sheppo static ds_svc_hdl_t ds_handle;
671ae08745Sheppo
681ae08745Sheppo /*
691ae08745Sheppo * Supported DS Capability Versions
701ae08745Sheppo */
7199c7e855SJames Marks - Sun Microsystems static ds_ver_t dr_cpu_vers[] = { { 1, 1 }, { 1, 0 } };
721ae08745Sheppo #define DR_CPU_NVERS (sizeof (dr_cpu_vers) / sizeof (dr_cpu_vers[0]))
731ae08745Sheppo
7499c7e855SJames Marks - Sun Microsystems static ds_ver_t version;
7599c7e855SJames Marks - Sun Microsystems
761ae08745Sheppo /*
771ae08745Sheppo * DS Capability Description
781ae08745Sheppo */
791ae08745Sheppo static ds_capability_t dr_cpu_cap = {
801ae08745Sheppo DR_CPU_DS_ID, /* svc_id */
811ae08745Sheppo dr_cpu_vers, /* vers */
821ae08745Sheppo DR_CPU_NVERS /* nvers */
831ae08745Sheppo };
841ae08745Sheppo
8599c7e855SJames Marks - Sun Microsystems #define DRCPU_VERS_EQ(_maj, _min) \
8699c7e855SJames Marks - Sun Microsystems ((version.major == (_maj)) && (version.minor == (_min)))
8799c7e855SJames Marks - Sun Microsystems
8899c7e855SJames Marks - Sun Microsystems #define DRCPU_VERS_GTEQ(_maj, _min) \
8999c7e855SJames Marks - Sun Microsystems ((version.major > (_maj)) || \
9099c7e855SJames Marks - Sun Microsystems ((version.major == (_maj)) && (version.minor >= (_min))))
9199c7e855SJames Marks - Sun Microsystems
921ae08745Sheppo /*
931ae08745Sheppo * DS Callbacks
941ae08745Sheppo */
951ae08745Sheppo static void dr_cpu_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
961ae08745Sheppo static void dr_cpu_unreg_handler(ds_cb_arg_t arg);
971ae08745Sheppo static void dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
981ae08745Sheppo
991ae08745Sheppo /*
1001ae08745Sheppo * DS Client Ops Vector
1011ae08745Sheppo */
1021ae08745Sheppo static ds_clnt_ops_t dr_cpu_ops = {
1031ae08745Sheppo dr_cpu_reg_handler, /* ds_reg_cb */
1041ae08745Sheppo dr_cpu_unreg_handler, /* ds_unreg_cb */
1051ae08745Sheppo dr_cpu_data_handler, /* ds_data_cb */
1061ae08745Sheppo NULL /* cb_arg */
1071ae08745Sheppo };
1081ae08745Sheppo
1091ae08745Sheppo /*
1100c86d1bbSrsmaeda * Operation Results
1110c86d1bbSrsmaeda *
1120c86d1bbSrsmaeda * Used internally to gather results while an operation on a
1130c86d1bbSrsmaeda * list of CPUs is in progress. In particular, it is used to
1140c86d1bbSrsmaeda * keep track of which CPUs have already failed so that they are
1150c86d1bbSrsmaeda * not processed further, and the manner in which they failed.
1160c86d1bbSrsmaeda */
1170c86d1bbSrsmaeda typedef struct {
1180c86d1bbSrsmaeda uint32_t cpuid;
1190c86d1bbSrsmaeda uint32_t result;
1200c86d1bbSrsmaeda uint32_t status;
1210c86d1bbSrsmaeda char *string;
1220c86d1bbSrsmaeda } dr_cpu_res_t;
1230c86d1bbSrsmaeda
1240c86d1bbSrsmaeda #define DR_CPU_MAX_ERR_LEN 64 /* maximum error string length */
1250c86d1bbSrsmaeda
1260c86d1bbSrsmaeda /*
1271ae08745Sheppo * Internal Functions
1281ae08745Sheppo */
1291ae08745Sheppo static int dr_cpu_init(void);
1301ae08745Sheppo static int dr_cpu_fini(void);
1311ae08745Sheppo
1320c86d1bbSrsmaeda static int dr_cpu_list_wrk(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1331ae08745Sheppo static int dr_cpu_list_status(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1341ae08745Sheppo
1351ae08745Sheppo static int dr_cpu_unconfigure(processorid_t, int *status, boolean_t force);
1361d4b38e0Srsmaeda static int dr_cpu_configure(processorid_t, int *status, boolean_t force);
1371ae08745Sheppo static int dr_cpu_status(processorid_t, int *status);
1381ae08745Sheppo
1390c86d1bbSrsmaeda static void dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res);
1400c86d1bbSrsmaeda static void dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres);
1410c86d1bbSrsmaeda static int dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res);
1420c86d1bbSrsmaeda
1430c86d1bbSrsmaeda static dr_cpu_res_t *dr_cpu_res_array_init(dr_cpu_hdr_t *, drctl_rsrc_t *, int);
1440c86d1bbSrsmaeda static void dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres);
1450c86d1bbSrsmaeda static size_t dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res,
1460c86d1bbSrsmaeda dr_cpu_hdr_t **respp);
1470c86d1bbSrsmaeda
1481ae08745Sheppo static int dr_cpu_probe(processorid_t newcpuid);
1491ae08745Sheppo static int dr_cpu_deprobe(processorid_t cpuid);
1501ae08745Sheppo
1511ae08745Sheppo static dev_info_t *dr_cpu_find_node(processorid_t cpuid);
1521ae08745Sheppo static mde_cookie_t dr_cpu_find_node_md(processorid_t, md_t *, mde_cookie_t *);
1531ae08745Sheppo
1541ae08745Sheppo int
_init(void)1551ae08745Sheppo _init(void)
1561ae08745Sheppo {
1571ae08745Sheppo int status;
1581ae08745Sheppo
1591ae08745Sheppo /* check that CPU DR is enabled */
1601ae08745Sheppo if (dr_is_disabled(DR_TYPE_CPU)) {
1611ae08745Sheppo cmn_err(CE_CONT, "!CPU DR is disabled\n");
1621ae08745Sheppo return (-1);
1631ae08745Sheppo }
1641ae08745Sheppo
1651ae08745Sheppo if ((status = dr_cpu_init()) != 0) {
1661ae08745Sheppo cmn_err(CE_NOTE, "CPU DR initialization failed");
1671ae08745Sheppo return (status);
1681ae08745Sheppo }
1691ae08745Sheppo
1701ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) {
1711ae08745Sheppo (void) dr_cpu_fini();
1721ae08745Sheppo }
1731ae08745Sheppo
1741ae08745Sheppo return (status);
1751ae08745Sheppo }
1761ae08745Sheppo
1771ae08745Sheppo int
_info(struct modinfo * modinfop)1781ae08745Sheppo _info(struct modinfo *modinfop)
1791ae08745Sheppo {
1801ae08745Sheppo return (mod_info(&modlinkage, modinfop));
1811ae08745Sheppo }
1821ae08745Sheppo
1831ae08745Sheppo int dr_cpu_allow_unload;
1841ae08745Sheppo
1851ae08745Sheppo int
_fini(void)1861ae08745Sheppo _fini(void)
1871ae08745Sheppo {
1881ae08745Sheppo int status;
1891ae08745Sheppo
1901ae08745Sheppo if (dr_cpu_allow_unload == 0)
1911ae08745Sheppo return (EBUSY);
1921ae08745Sheppo
1931ae08745Sheppo if ((status = mod_remove(&modlinkage)) == 0) {
1941ae08745Sheppo (void) dr_cpu_fini();
1951ae08745Sheppo }
1961ae08745Sheppo
1971ae08745Sheppo return (status);
1981ae08745Sheppo }
1991ae08745Sheppo
2001ae08745Sheppo static int
dr_cpu_init(void)2011ae08745Sheppo dr_cpu_init(void)
2021ae08745Sheppo {
2031ae08745Sheppo int rv;
2041ae08745Sheppo
2051ae08745Sheppo if ((rv = ds_cap_init(&dr_cpu_cap, &dr_cpu_ops)) != 0) {
2061ae08745Sheppo cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
2071ae08745Sheppo return (-1);
2081ae08745Sheppo }
2091ae08745Sheppo
2101ae08745Sheppo return (0);
2111ae08745Sheppo }
2121ae08745Sheppo
2131ae08745Sheppo static int
dr_cpu_fini(void)2141ae08745Sheppo dr_cpu_fini(void)
2151ae08745Sheppo {
2161ae08745Sheppo int rv;
2171ae08745Sheppo
2181ae08745Sheppo if ((rv = ds_cap_fini(&dr_cpu_cap)) != 0) {
2191ae08745Sheppo cmn_err(CE_NOTE, "ds_cap_fini failed: %d", rv);
2201ae08745Sheppo return (-1);
2211ae08745Sheppo }
2221ae08745Sheppo
2231ae08745Sheppo return (0);
2241ae08745Sheppo }
2251ae08745Sheppo
2261ae08745Sheppo static void
dr_cpu_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)2271ae08745Sheppo dr_cpu_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
2281ae08745Sheppo {
2291ae08745Sheppo DR_DBG_CPU("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
2301ae08745Sheppo ver->major, ver->minor, hdl);
2311ae08745Sheppo
23299c7e855SJames Marks - Sun Microsystems version.major = ver->major;
23399c7e855SJames Marks - Sun Microsystems version.minor = ver->minor;
2341ae08745Sheppo ds_handle = hdl;
2351ae08745Sheppo }
2361ae08745Sheppo
2371ae08745Sheppo static void
dr_cpu_unreg_handler(ds_cb_arg_t arg)2381ae08745Sheppo dr_cpu_unreg_handler(ds_cb_arg_t arg)
2391ae08745Sheppo {
2401ae08745Sheppo DR_DBG_CPU("unreg_handler: arg=0x%p\n", arg);
2411ae08745Sheppo
2421ae08745Sheppo ds_handle = DS_INVALID_HDL;
2431ae08745Sheppo }
2441ae08745Sheppo
2451ae08745Sheppo static void
dr_cpu_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)2461ae08745Sheppo dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2471ae08745Sheppo {
2481ae08745Sheppo _NOTE(ARGUNUSED(arg))
2491ae08745Sheppo
2501ae08745Sheppo dr_cpu_hdr_t *req = buf;
2511ae08745Sheppo dr_cpu_hdr_t err_resp;
2521ae08745Sheppo dr_cpu_hdr_t *resp = &err_resp;
2531ae08745Sheppo int resp_len = 0;
2541ae08745Sheppo int rv;
2551ae08745Sheppo
2561ae08745Sheppo /*
2571ae08745Sheppo * Sanity check the message
2581ae08745Sheppo */
2591ae08745Sheppo if (buflen < sizeof (dr_cpu_hdr_t)) {
2601ae08745Sheppo DR_DBG_CPU("incoming message short: expected at least %ld "
2611ae08745Sheppo "bytes, received %ld\n", sizeof (dr_cpu_hdr_t), buflen);
2621ae08745Sheppo goto done;
2631ae08745Sheppo }
2641ae08745Sheppo
2651ae08745Sheppo if (req == NULL) {
2661ae08745Sheppo DR_DBG_CPU("empty message: expected at least %ld bytes\n",
2671ae08745Sheppo sizeof (dr_cpu_hdr_t));
2681ae08745Sheppo goto done;
2691ae08745Sheppo }
2701ae08745Sheppo
2711ae08745Sheppo DR_DBG_CPU("incoming request:\n");
2721ae08745Sheppo DR_DBG_DUMP_MSG(buf, buflen);
2731ae08745Sheppo
2741ae08745Sheppo if (req->num_records > NCPU) {
2751ae08745Sheppo DR_DBG_CPU("CPU list too long: %d when %d is the maximum\n",
2761ae08745Sheppo req->num_records, NCPU);
2771ae08745Sheppo goto done;
2781ae08745Sheppo }
2791ae08745Sheppo
2801ae08745Sheppo if (req->num_records == 0) {
2811ae08745Sheppo DR_DBG_CPU("No CPU specified for operation\n");
2821ae08745Sheppo goto done;
2831ae08745Sheppo }
2841ae08745Sheppo
2851ae08745Sheppo /*
2861ae08745Sheppo * Process the command
2871ae08745Sheppo */
2881ae08745Sheppo switch (req->msg_type) {
2891ae08745Sheppo case DR_CPU_CONFIGURE:
2901ae08745Sheppo case DR_CPU_UNCONFIGURE:
2911ae08745Sheppo case DR_CPU_FORCE_UNCONFIG:
2920c86d1bbSrsmaeda if ((rv = dr_cpu_list_wrk(req, &resp, &resp_len)) != 0) {
2930c86d1bbSrsmaeda DR_DBG_CPU("%s%s failed (%d)\n",
2940c86d1bbSrsmaeda (req->msg_type == DR_CPU_CONFIGURE) ?
2950c86d1bbSrsmaeda "CPU configure" : "CPU unconfigure",
2960c86d1bbSrsmaeda (req->msg_type == DR_CPU_FORCE_UNCONFIG) ?
2970c86d1bbSrsmaeda " (forced)" : "", rv);
2980c86d1bbSrsmaeda }
2991ae08745Sheppo break;
3001ae08745Sheppo
3011ae08745Sheppo case DR_CPU_STATUS:
3021ae08745Sheppo if ((rv = dr_cpu_list_status(req, &resp, &resp_len)) != 0)
3030c86d1bbSrsmaeda DR_DBG_CPU("CPU status failed (%d)\n", rv);
3041ae08745Sheppo break;
3051ae08745Sheppo
3061ae08745Sheppo default:
3071ae08745Sheppo cmn_err(CE_NOTE, "unsupported DR operation (%d)",
3081ae08745Sheppo req->msg_type);
3091ae08745Sheppo break;
3101ae08745Sheppo }
3111ae08745Sheppo
3121ae08745Sheppo done:
3131ae08745Sheppo /* check if an error occurred */
3141ae08745Sheppo if (resp == &err_resp) {
3151ae08745Sheppo resp->req_num = (req) ? req->req_num : 0;
3161ae08745Sheppo resp->msg_type = DR_CPU_ERROR;
3171ae08745Sheppo resp->num_records = 0;
3181ae08745Sheppo resp_len = sizeof (dr_cpu_hdr_t);
3191ae08745Sheppo }
3201ae08745Sheppo
3210c86d1bbSrsmaeda DR_DBG_CPU("outgoing response:\n");
3220c86d1bbSrsmaeda DR_DBG_DUMP_MSG(resp, resp_len);
3230c86d1bbSrsmaeda
3241ae08745Sheppo /* send back the response */
3251ae08745Sheppo if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
3261ae08745Sheppo DR_DBG_CPU("ds_send failed\n");
3271ae08745Sheppo }
3281ae08745Sheppo
3291ae08745Sheppo /* free any allocated memory */
33099c7e855SJames Marks - Sun Microsystems if (DRCPU_VERS_GTEQ(1, 1) || (resp != &err_resp)) {
33199c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
33299c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, resp_len);
3331ae08745Sheppo kmem_free(resp, resp_len);
3341ae08745Sheppo }
3351ae08745Sheppo }
3361ae08745Sheppo
3371ae08745Sheppo /*
33899c7e855SJames Marks - Sun Microsystems * Create a response message which consists of a header followed
33999c7e855SJames Marks - Sun Microsystems * by the error string passed in.
34099c7e855SJames Marks - Sun Microsystems */
34199c7e855SJames Marks - Sun Microsystems static size_t
dr_cpu_err_resp(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** respp,char * msg)34299c7e855SJames Marks - Sun Microsystems dr_cpu_err_resp(dr_cpu_hdr_t *req, dr_cpu_hdr_t **respp, char *msg)
34399c7e855SJames Marks - Sun Microsystems {
34499c7e855SJames Marks - Sun Microsystems size_t size;
34599c7e855SJames Marks - Sun Microsystems dr_cpu_hdr_t *resp;
34699c7e855SJames Marks - Sun Microsystems
34799c7e855SJames Marks - Sun Microsystems ASSERT((msg != NULL) && (strlen(msg) > 0));
34899c7e855SJames Marks - Sun Microsystems
34999c7e855SJames Marks - Sun Microsystems size = sizeof (*req) + strlen(msg) + 1;
35099c7e855SJames Marks - Sun Microsystems resp = kmem_alloc(size, KM_SLEEP);
35199c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
35299c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, size);
35399c7e855SJames Marks - Sun Microsystems
35499c7e855SJames Marks - Sun Microsystems resp->req_num = req->req_num;
35599c7e855SJames Marks - Sun Microsystems resp->msg_type = DR_CPU_ERROR;
35699c7e855SJames Marks - Sun Microsystems resp->num_records = 0;
35799c7e855SJames Marks - Sun Microsystems
35899c7e855SJames Marks - Sun Microsystems (void) strcpy((char *)(resp) + sizeof (*resp), msg);
35999c7e855SJames Marks - Sun Microsystems
36099c7e855SJames Marks - Sun Microsystems *respp = resp;
36199c7e855SJames Marks - Sun Microsystems
36299c7e855SJames Marks - Sun Microsystems return (size);
36399c7e855SJames Marks - Sun Microsystems }
36499c7e855SJames Marks - Sun Microsystems
36599c7e855SJames Marks - Sun Microsystems /*
3661d4b38e0Srsmaeda * Common routine to config or unconfig multiple cpus. The unconfig
3671d4b38e0Srsmaeda * case checks with the OS to see if the removal of cpus will be
3681d4b38e0Srsmaeda * permitted, but can be overridden by the "force" version of the
3691d4b38e0Srsmaeda * command. Otherwise, the logic for both cases is identical.
3701d4b38e0Srsmaeda *
3711d4b38e0Srsmaeda * Note: Do not modify result buffer or length on error.
3721ae08745Sheppo */
3731ae08745Sheppo static int
dr_cpu_list_wrk(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)3740c86d1bbSrsmaeda dr_cpu_list_wrk(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
3751ae08745Sheppo {
3761d4b38e0Srsmaeda int rv;
3770c86d1bbSrsmaeda int idx;
3780c86d1bbSrsmaeda int count;
3790c86d1bbSrsmaeda fn_t dr_fn;
3800c86d1bbSrsmaeda int se_hint;
3810c86d1bbSrsmaeda boolean_t force = B_FALSE;
3820c86d1bbSrsmaeda uint32_t *req_cpus;
3830c86d1bbSrsmaeda dr_cpu_res_t *res;
3840c86d1bbSrsmaeda int drctl_cmd;
3850c86d1bbSrsmaeda int drctl_flags = 0;
3860c86d1bbSrsmaeda drctl_rsrc_t *drctl_req;
3870c86d1bbSrsmaeda size_t drctl_req_len;
38899c7e855SJames Marks - Sun Microsystems drctl_resp_t *drctl_resp;
38999c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *drctl_rsrc;
39099c7e855SJames Marks - Sun Microsystems size_t drctl_resp_len = 0;
3910c86d1bbSrsmaeda drctl_cookie_t drctl_res_ck;
3920c86d1bbSrsmaeda
3930c86d1bbSrsmaeda ASSERT((req != NULL) && (req->num_records != 0));
3941ae08745Sheppo
3950c86d1bbSrsmaeda count = req->num_records;
3961ae08745Sheppo
3970c86d1bbSrsmaeda /*
3980c86d1bbSrsmaeda * Extract all information that is specific
3990c86d1bbSrsmaeda * to the various types of operations.
4000c86d1bbSrsmaeda */
4010c86d1bbSrsmaeda switch (req->msg_type) {
4021d4b38e0Srsmaeda case DR_CPU_CONFIGURE:
4030c86d1bbSrsmaeda dr_fn = dr_cpu_configure;
4040c86d1bbSrsmaeda drctl_cmd = DRCTL_CPU_CONFIG_REQUEST;
4050c86d1bbSrsmaeda se_hint = SE_HINT_INSERT;
4061d4b38e0Srsmaeda break;
4071d4b38e0Srsmaeda case DR_CPU_FORCE_UNCONFIG:
4080c86d1bbSrsmaeda drctl_flags = DRCTL_FLAG_FORCE;
4091d4b38e0Srsmaeda force = B_TRUE;
4101d4b38e0Srsmaeda _NOTE(FALLTHROUGH)
4111d4b38e0Srsmaeda case DR_CPU_UNCONFIGURE:
4120c86d1bbSrsmaeda dr_fn = dr_cpu_unconfigure;
4130c86d1bbSrsmaeda drctl_cmd = DRCTL_CPU_UNCONFIG_REQUEST;
4140c86d1bbSrsmaeda se_hint = SE_HINT_REMOVE;
4151d4b38e0Srsmaeda break;
4161d4b38e0Srsmaeda default:
4171d4b38e0Srsmaeda /* Programming error if we reach this. */
41899c7e855SJames Marks - Sun Microsystems cmn_err(CE_NOTE,
41999c7e855SJames Marks - Sun Microsystems "%s: bad msg_type %d\n", __func__, req->msg_type);
4201d4b38e0Srsmaeda ASSERT(0);
4211d4b38e0Srsmaeda return (-1);
4221ae08745Sheppo }
4231ae08745Sheppo
4240c86d1bbSrsmaeda /* the incoming array of cpuids to operate on */
4250c86d1bbSrsmaeda req_cpus = DR_CPU_CMD_CPUIDS(req);
4261d4b38e0Srsmaeda
4271d4b38e0Srsmaeda /* allocate drctl request msg based on incoming resource count */
4280c86d1bbSrsmaeda drctl_req_len = sizeof (drctl_rsrc_t) * count;
4290c86d1bbSrsmaeda drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
43099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
43199c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
4321d4b38e0Srsmaeda
4331d4b38e0Srsmaeda /* copy the cpuids for the drctl call from the incoming request msg */
4341d4b38e0Srsmaeda for (idx = 0; idx < count; idx++)
4350c86d1bbSrsmaeda drctl_req[idx].res_cpu_id = req_cpus[idx];
4361d4b38e0Srsmaeda
43799c7e855SJames Marks - Sun Microsystems rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
43899c7e855SJames Marks - Sun Microsystems count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
43999c7e855SJames Marks - Sun Microsystems
44099c7e855SJames Marks - Sun Microsystems ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
44199c7e855SJames Marks - Sun Microsystems
44299c7e855SJames Marks - Sun Microsystems if (rv != 0) {
44399c7e855SJames Marks - Sun Microsystems DR_DBG_CPU("%s: drctl_config_init "
44499c7e855SJames Marks - Sun Microsystems "returned: %d\n", __func__, rv);
44599c7e855SJames Marks - Sun Microsystems
44699c7e855SJames Marks - Sun Microsystems if (DRCPU_VERS_EQ(1, 0)) {
44799c7e855SJames Marks - Sun Microsystems rv = -1;
44899c7e855SJames Marks - Sun Microsystems } else {
44999c7e855SJames Marks - Sun Microsystems ASSERT(DRCPU_VERS_GTEQ(1, 1));
45099c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
45199c7e855SJames Marks - Sun Microsystems
45299c7e855SJames Marks - Sun Microsystems *resp_len = dr_cpu_err_resp(req,
45399c7e855SJames Marks - Sun Microsystems resp, drctl_resp->resp_err_msg);
4541d4b38e0Srsmaeda }
4551d4b38e0Srsmaeda
45699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
45799c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len);
45899c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len);
45999c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
46099c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
46199c7e855SJames Marks - Sun Microsystems kmem_free(drctl_req, drctl_req_len);
46299c7e855SJames Marks - Sun Microsystems
46399c7e855SJames Marks - Sun Microsystems return (rv);
46499c7e855SJames Marks - Sun Microsystems }
46599c7e855SJames Marks - Sun Microsystems
46699c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
46799c7e855SJames Marks - Sun Microsystems
46899c7e855SJames Marks - Sun Microsystems drctl_rsrc = drctl_resp->resp_resources;
4690c86d1bbSrsmaeda
4700c86d1bbSrsmaeda /* create the result scratch array */
47199c7e855SJames Marks - Sun Microsystems res = dr_cpu_res_array_init(req, drctl_rsrc, count);
4721d4b38e0Srsmaeda
4731d4b38e0Srsmaeda /*
4740c86d1bbSrsmaeda * For unconfigure, check if there are any conditions
4750c86d1bbSrsmaeda * that will cause the operation to fail. These are
4760c86d1bbSrsmaeda * performed before the actual unconfigure attempt so
4770c86d1bbSrsmaeda * that a meaningful error message can be generated.
4781d4b38e0Srsmaeda */
4790c86d1bbSrsmaeda if (req->msg_type != DR_CPU_CONFIGURE)
4800c86d1bbSrsmaeda dr_cpu_check_cpus(req, res);
4811d4b38e0Srsmaeda
4820c86d1bbSrsmaeda /* perform the specified operation on each of the CPUs */
4831d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) {
4840c86d1bbSrsmaeda int result;
4850c86d1bbSrsmaeda int status;
4861d4b38e0Srsmaeda
4871d4b38e0Srsmaeda /*
4880c86d1bbSrsmaeda * If no action will be taken against the current
4890c86d1bbSrsmaeda * CPU, update the drctl resource information to
4900c86d1bbSrsmaeda * ensure that it gets recovered properly during
4910c86d1bbSrsmaeda * the drctl fini() call.
4921d4b38e0Srsmaeda */
4930c86d1bbSrsmaeda if (res[idx].result != DR_CPU_RES_OK) {
4940c86d1bbSrsmaeda drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
4950c86d1bbSrsmaeda continue;
4961d4b38e0Srsmaeda }
4971d4b38e0Srsmaeda
4980c86d1bbSrsmaeda /* call the function to perform the actual operation */
4990c86d1bbSrsmaeda result = (*dr_fn)(req_cpus[idx], &status, force);
5001d4b38e0Srsmaeda
5010c86d1bbSrsmaeda /* save off results of the operation */
5020c86d1bbSrsmaeda res[idx].result = result;
5030c86d1bbSrsmaeda res[idx].status = status;
5041d4b38e0Srsmaeda
5050c86d1bbSrsmaeda /* save result for drctl fini() reusing init() msg memory */
5060c86d1bbSrsmaeda drctl_req[idx].status = (result != DR_CPU_RES_OK) ?
5070c86d1bbSrsmaeda DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
5081d4b38e0Srsmaeda
5090c86d1bbSrsmaeda DR_DBG_CPU("%s: cpuid %d status %d result %d off '%s'\n",
51099c7e855SJames Marks - Sun Microsystems __func__, req_cpus[idx], drctl_req[idx].status, result,
5110c86d1bbSrsmaeda (res[idx].string) ? res[idx].string : "");
5120c86d1bbSrsmaeda }
5131d4b38e0Srsmaeda
5140c86d1bbSrsmaeda if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
51599c7e855SJames Marks - Sun Microsystems DR_DBG_CPU("%s: drctl_config_fini "
51699c7e855SJames Marks - Sun Microsystems "returned: %d\n", __func__, rv);
5171ae08745Sheppo
5180c86d1bbSrsmaeda /*
5190c86d1bbSrsmaeda * Operation completed without any fatal errors.
5200c86d1bbSrsmaeda * Pack the response for transmission.
5210c86d1bbSrsmaeda */
5220c86d1bbSrsmaeda *resp_len = dr_cpu_pack_response(req, res, resp);
5230c86d1bbSrsmaeda
5240c86d1bbSrsmaeda /* notify interested parties about the operation */
5250c86d1bbSrsmaeda dr_generate_event(DR_TYPE_CPU, se_hint);
5260c86d1bbSrsmaeda
5270c86d1bbSrsmaeda /*
5280c86d1bbSrsmaeda * Deallocate any scratch memory.
5290c86d1bbSrsmaeda */
53099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
53199c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len);
53299c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len);
53399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
53499c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
5350c86d1bbSrsmaeda kmem_free(drctl_req, drctl_req_len);
5360c86d1bbSrsmaeda
5370c86d1bbSrsmaeda dr_cpu_res_array_fini(res, count);
5381ae08745Sheppo
5391ae08745Sheppo return (0);
5401ae08745Sheppo }
5411ae08745Sheppo
5420c86d1bbSrsmaeda /*
5430c86d1bbSrsmaeda * Allocate and initialize a result array based on the initial
5440c86d1bbSrsmaeda * drctl operation. A valid result array is always returned.
5450c86d1bbSrsmaeda */
5460c86d1bbSrsmaeda static dr_cpu_res_t *
dr_cpu_res_array_init(dr_cpu_hdr_t * req,drctl_rsrc_t * rsrc,int nrsrc)5470c86d1bbSrsmaeda dr_cpu_res_array_init(dr_cpu_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
5481ae08745Sheppo {
5491ae08745Sheppo int idx;
5500c86d1bbSrsmaeda dr_cpu_res_t *res;
5510c86d1bbSrsmaeda char *err_str;
5520c86d1bbSrsmaeda size_t err_len;
5530c86d1bbSrsmaeda
5540c86d1bbSrsmaeda /* allocate zero filled buffer to initialize fields */
5550c86d1bbSrsmaeda res = kmem_zalloc(nrsrc * sizeof (dr_cpu_res_t), KM_SLEEP);
55699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
55799c7e855SJames Marks - Sun Microsystems __func__, (void *)res, nrsrc * sizeof (dr_cpu_res_t));
5580c86d1bbSrsmaeda
5590c86d1bbSrsmaeda /*
5600c86d1bbSrsmaeda * Fill in the result information for each resource.
5610c86d1bbSrsmaeda */
5620c86d1bbSrsmaeda for (idx = 0; idx < nrsrc; idx++) {
5630c86d1bbSrsmaeda res[idx].cpuid = rsrc[idx].res_cpu_id;
5640c86d1bbSrsmaeda res[idx].result = DR_CPU_RES_OK;
5650c86d1bbSrsmaeda
5660c86d1bbSrsmaeda if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
5670c86d1bbSrsmaeda continue;
5680c86d1bbSrsmaeda
5690c86d1bbSrsmaeda /*
5700c86d1bbSrsmaeda * Update the state information for this CPU.
5710c86d1bbSrsmaeda */
5720c86d1bbSrsmaeda res[idx].result = DR_CPU_RES_BLOCKED;
5730c86d1bbSrsmaeda res[idx].status = (req->msg_type == DR_CPU_CONFIGURE) ?
5740c86d1bbSrsmaeda DR_CPU_STAT_UNCONFIGURED : DR_CPU_STAT_CONFIGURED;
5750c86d1bbSrsmaeda
5760c86d1bbSrsmaeda /*
5770c86d1bbSrsmaeda * If an error string exists, copy it out of the
5780c86d1bbSrsmaeda * message buffer. This eliminates any dependency
5790c86d1bbSrsmaeda * on the memory allocated for the message buffer
5800c86d1bbSrsmaeda * itself.
5810c86d1bbSrsmaeda */
5820c86d1bbSrsmaeda if (rsrc[idx].offset != NULL) {
5830c86d1bbSrsmaeda err_str = (char *)rsrc + rsrc[idx].offset;
5840c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
5850c86d1bbSrsmaeda
5860c86d1bbSrsmaeda res[idx].string = kmem_alloc(err_len, KM_SLEEP);
58799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
58899c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[idx].string), err_len);
5890c86d1bbSrsmaeda bcopy(err_str, res[idx].string, err_len);
5900c86d1bbSrsmaeda }
5910c86d1bbSrsmaeda }
5920c86d1bbSrsmaeda
5930c86d1bbSrsmaeda return (res);
5940c86d1bbSrsmaeda }
5950c86d1bbSrsmaeda
5960c86d1bbSrsmaeda static void
dr_cpu_res_array_fini(dr_cpu_res_t * res,int nres)5970c86d1bbSrsmaeda dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres)
5980c86d1bbSrsmaeda {
5990c86d1bbSrsmaeda int idx;
6000c86d1bbSrsmaeda size_t str_len;
6010c86d1bbSrsmaeda
6020c86d1bbSrsmaeda for (idx = 0; idx < nres; idx++) {
6030c86d1bbSrsmaeda /* deallocate the error string if present */
6040c86d1bbSrsmaeda if (res[idx].string) {
6050c86d1bbSrsmaeda str_len = strlen(res[idx].string) + 1;
60699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
60799c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[idx].string), str_len);
6080c86d1bbSrsmaeda kmem_free(res[idx].string, str_len);
6090c86d1bbSrsmaeda }
6100c86d1bbSrsmaeda }
6110c86d1bbSrsmaeda
6120c86d1bbSrsmaeda /* deallocate the result array itself */
61399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
61499c7e855SJames Marks - Sun Microsystems __func__, (void *)res, sizeof (dr_cpu_res_t) * nres);
6150c86d1bbSrsmaeda kmem_free(res, sizeof (dr_cpu_res_t) * nres);
6160c86d1bbSrsmaeda }
6170c86d1bbSrsmaeda
6180c86d1bbSrsmaeda /*
6190c86d1bbSrsmaeda * Allocate and pack a response message for transmission based
6200c86d1bbSrsmaeda * on the specified result array. A valid response message and
6210c86d1bbSrsmaeda * valid size information is always returned.
6220c86d1bbSrsmaeda */
6230c86d1bbSrsmaeda static size_t
dr_cpu_pack_response(dr_cpu_hdr_t * req,dr_cpu_res_t * res,dr_cpu_hdr_t ** respp)6240c86d1bbSrsmaeda dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, dr_cpu_hdr_t **respp)
6250c86d1bbSrsmaeda {
6260c86d1bbSrsmaeda int idx;
6270c86d1bbSrsmaeda dr_cpu_hdr_t *resp;
6280c86d1bbSrsmaeda dr_cpu_stat_t *resp_stat;
6290c86d1bbSrsmaeda size_t resp_len;
6300c86d1bbSrsmaeda uint32_t curr_off;
6310c86d1bbSrsmaeda caddr_t curr_str;
6320c86d1bbSrsmaeda size_t str_len;
6330c86d1bbSrsmaeda size_t stat_len;
6340c86d1bbSrsmaeda int nstat = req->num_records;
6350c86d1bbSrsmaeda
6360c86d1bbSrsmaeda /*
6370c86d1bbSrsmaeda * Calculate the size of the response message
6380c86d1bbSrsmaeda * and allocate an appropriately sized buffer.
6390c86d1bbSrsmaeda */
6400c86d1bbSrsmaeda resp_len = 0;
6410c86d1bbSrsmaeda
6420c86d1bbSrsmaeda /* add the header size */
6430c86d1bbSrsmaeda resp_len += sizeof (dr_cpu_hdr_t);
6440c86d1bbSrsmaeda
6450c86d1bbSrsmaeda /* add the stat array size */
6460c86d1bbSrsmaeda stat_len = sizeof (dr_cpu_stat_t) * nstat;
6470c86d1bbSrsmaeda resp_len += stat_len;
6480c86d1bbSrsmaeda
6490c86d1bbSrsmaeda /* add the size of any error strings */
6500c86d1bbSrsmaeda for (idx = 0; idx < nstat; idx++) {
6510c86d1bbSrsmaeda if (res[idx].string != NULL) {
6520c86d1bbSrsmaeda resp_len += strlen(res[idx].string) + 1;
6530c86d1bbSrsmaeda }
6540c86d1bbSrsmaeda }
6550c86d1bbSrsmaeda
6560c86d1bbSrsmaeda /* allocate the message buffer */
6570c86d1bbSrsmaeda resp = kmem_zalloc(resp_len, KM_SLEEP);
65899c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
65999c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, resp_len);
6600c86d1bbSrsmaeda
6610c86d1bbSrsmaeda /*
6620c86d1bbSrsmaeda * Fill in the header information.
6630c86d1bbSrsmaeda */
6640c86d1bbSrsmaeda resp->req_num = req->req_num;
6650c86d1bbSrsmaeda resp->msg_type = DR_CPU_OK;
6660c86d1bbSrsmaeda resp->num_records = nstat;
6670c86d1bbSrsmaeda
6680c86d1bbSrsmaeda /*
6690c86d1bbSrsmaeda * Fill in the stat information.
6700c86d1bbSrsmaeda */
6710c86d1bbSrsmaeda resp_stat = DR_CPU_RESP_STATS(resp);
6720c86d1bbSrsmaeda
6730c86d1bbSrsmaeda /* string offsets start immediately after stat array */
6740c86d1bbSrsmaeda curr_off = sizeof (dr_cpu_hdr_t) + stat_len;
6750c86d1bbSrsmaeda curr_str = (char *)resp_stat + stat_len;
6760c86d1bbSrsmaeda
6770c86d1bbSrsmaeda for (idx = 0; idx < nstat; idx++) {
6780c86d1bbSrsmaeda resp_stat[idx].cpuid = res[idx].cpuid;
6790c86d1bbSrsmaeda resp_stat[idx].result = res[idx].result;
6800c86d1bbSrsmaeda resp_stat[idx].status = res[idx].status;
6810c86d1bbSrsmaeda
6820c86d1bbSrsmaeda if (res[idx].string != NULL) {
6830c86d1bbSrsmaeda /* copy over the error string */
6840c86d1bbSrsmaeda str_len = strlen(res[idx].string) + 1;
6850c86d1bbSrsmaeda bcopy(res[idx].string, curr_str, str_len);
6860c86d1bbSrsmaeda resp_stat[idx].string_off = curr_off;
6870c86d1bbSrsmaeda
6880c86d1bbSrsmaeda curr_off += str_len;
6890c86d1bbSrsmaeda curr_str += str_len;
6900c86d1bbSrsmaeda }
6910c86d1bbSrsmaeda }
6920c86d1bbSrsmaeda
6930c86d1bbSrsmaeda /* buffer should be exactly filled */
6940c86d1bbSrsmaeda ASSERT(curr_off == resp_len);
6950c86d1bbSrsmaeda
6960c86d1bbSrsmaeda *respp = resp;
6970c86d1bbSrsmaeda return (resp_len);
6980c86d1bbSrsmaeda }
6990c86d1bbSrsmaeda
7000c86d1bbSrsmaeda /*
7010c86d1bbSrsmaeda * Check for conditions that will prevent a CPU from being offlined.
7020c86d1bbSrsmaeda * This provides the opportunity to generate useful information to
7030c86d1bbSrsmaeda * help diagnose the failure rather than letting the offline attempt
7040c86d1bbSrsmaeda * fail in a more generic way.
7050c86d1bbSrsmaeda */
7060c86d1bbSrsmaeda static void
dr_cpu_check_cpus(dr_cpu_hdr_t * req,dr_cpu_res_t * res)7070c86d1bbSrsmaeda dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res)
7080c86d1bbSrsmaeda {
7090c86d1bbSrsmaeda int idx;
7100c86d1bbSrsmaeda cpu_t *cp;
7110c86d1bbSrsmaeda uint32_t *cpuids;
7120c86d1bbSrsmaeda
7130c86d1bbSrsmaeda ASSERT((req->msg_type == DR_CPU_UNCONFIGURE) ||
7140c86d1bbSrsmaeda (req->msg_type == DR_CPU_FORCE_UNCONFIG));
7151ae08745Sheppo
7161ae08745Sheppo DR_DBG_CPU("dr_cpu_check_cpus...\n");
7171ae08745Sheppo
7180c86d1bbSrsmaeda /* array of cpuids start just after the header */
7190c86d1bbSrsmaeda cpuids = DR_CPU_CMD_CPUIDS(req);
7200c86d1bbSrsmaeda
7211ae08745Sheppo mutex_enter(&cpu_lock);
7221ae08745Sheppo
7230c86d1bbSrsmaeda /*
7240c86d1bbSrsmaeda * Always check processor set membership first. The
7250c86d1bbSrsmaeda * last CPU in a processor set will fail to offline
7260c86d1bbSrsmaeda * even if the operation if forced, so any failures
7270c86d1bbSrsmaeda * should always be reported.
7280c86d1bbSrsmaeda */
7290c86d1bbSrsmaeda dr_cpu_check_psrset(cpuids, res, req->num_records);
7301ae08745Sheppo
7310c86d1bbSrsmaeda /* process each cpu that is part of the request */
7320c86d1bbSrsmaeda for (idx = 0; idx < req->num_records; idx++) {
7330c86d1bbSrsmaeda
7340c86d1bbSrsmaeda /* nothing to check if the CPU has already failed */
7350c86d1bbSrsmaeda if (res[idx].result != DR_CPU_RES_OK)
7361ae08745Sheppo continue;
7371ae08745Sheppo
7380c86d1bbSrsmaeda if ((cp = cpu_get(cpuids[idx])) == NULL)
7390c86d1bbSrsmaeda continue;
7401ae08745Sheppo
7411ae08745Sheppo /*
7420c86d1bbSrsmaeda * Only check if there are bound threads if the
7430c86d1bbSrsmaeda * operation is not a forced unconfigure. In a
7440c86d1bbSrsmaeda * forced request, threads are automatically
7450c86d1bbSrsmaeda * unbound before they are offlined.
7461ae08745Sheppo */
7470c86d1bbSrsmaeda if (req->msg_type == DR_CPU_UNCONFIGURE) {
7480c86d1bbSrsmaeda /*
7490c86d1bbSrsmaeda * The return value is only interesting if other
7500c86d1bbSrsmaeda * checks are added to this loop and a decision
7510c86d1bbSrsmaeda * is needed on whether to continue checking.
7520c86d1bbSrsmaeda */
7530c86d1bbSrsmaeda (void) dr_cpu_check_bound_thr(cp, &res[idx]);
7541ae08745Sheppo }
7551ae08745Sheppo }
7561ae08745Sheppo
7571ae08745Sheppo mutex_exit(&cpu_lock);
7581ae08745Sheppo }
7591ae08745Sheppo
7600c86d1bbSrsmaeda /*
7610c86d1bbSrsmaeda * Examine the processor set configuration for the specified
7620c86d1bbSrsmaeda * CPUs and see if the unconfigure operation would result in
7630c86d1bbSrsmaeda * trying to remove the last CPU in any processor set.
7640c86d1bbSrsmaeda */
7650c86d1bbSrsmaeda static void
dr_cpu_check_psrset(uint32_t * cpuids,dr_cpu_res_t * res,int nres)7660c86d1bbSrsmaeda dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres)
7670c86d1bbSrsmaeda {
7680c86d1bbSrsmaeda int cpu_idx;
7690c86d1bbSrsmaeda int set_idx;
7700c86d1bbSrsmaeda cpu_t *cp;
7710c86d1bbSrsmaeda cpupart_t *cpp;
7720c86d1bbSrsmaeda char err_str[DR_CPU_MAX_ERR_LEN];
7730c86d1bbSrsmaeda size_t err_len;
7740c86d1bbSrsmaeda struct {
7750c86d1bbSrsmaeda cpupart_t *cpp;
7760c86d1bbSrsmaeda int ncpus;
7770c86d1bbSrsmaeda } *psrset;
7780c86d1bbSrsmaeda
7790c86d1bbSrsmaeda ASSERT(MUTEX_HELD(&cpu_lock));
7800c86d1bbSrsmaeda
7810c86d1bbSrsmaeda /*
7820c86d1bbSrsmaeda * Allocate a scratch array to count the CPUs in
7830c86d1bbSrsmaeda * the various processor sets. A CPU always belongs
7840c86d1bbSrsmaeda * to exactly one processor set, so by definition,
7850c86d1bbSrsmaeda * the scratch array never needs to be larger than
7860c86d1bbSrsmaeda * the number of CPUs.
7870c86d1bbSrsmaeda */
7880c86d1bbSrsmaeda psrset = kmem_zalloc(sizeof (*psrset) * nres, KM_SLEEP);
78999c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
79099c7e855SJames Marks - Sun Microsystems __func__, (void *)psrset, sizeof (*psrset) * nres);
7910c86d1bbSrsmaeda
7920c86d1bbSrsmaeda for (cpu_idx = 0; cpu_idx < nres; cpu_idx++) {
7930c86d1bbSrsmaeda
7940c86d1bbSrsmaeda /* skip any CPUs that have already failed */
7950c86d1bbSrsmaeda if (res[cpu_idx].result != DR_CPU_RES_OK)
7960c86d1bbSrsmaeda continue;
7970c86d1bbSrsmaeda
7980c86d1bbSrsmaeda if ((cp = cpu_get(cpuids[cpu_idx])) == NULL)
7990c86d1bbSrsmaeda continue;
8000c86d1bbSrsmaeda
8010c86d1bbSrsmaeda cpp = cp->cpu_part;
8020c86d1bbSrsmaeda
8030c86d1bbSrsmaeda /* lookup the set this CPU belongs to */
8040c86d1bbSrsmaeda for (set_idx = 0; set_idx < nres; set_idx++) {
8050c86d1bbSrsmaeda
8060c86d1bbSrsmaeda /* matching set found */
8070c86d1bbSrsmaeda if (cpp == psrset[set_idx].cpp)
8080c86d1bbSrsmaeda break;
8090c86d1bbSrsmaeda
8100c86d1bbSrsmaeda /* set not found, start a new entry */
8110c86d1bbSrsmaeda if (psrset[set_idx].cpp == NULL) {
8120c86d1bbSrsmaeda psrset[set_idx].cpp = cpp;
8130c86d1bbSrsmaeda psrset[set_idx].ncpus = cpp->cp_ncpus;
8140c86d1bbSrsmaeda break;
8150c86d1bbSrsmaeda }
8160c86d1bbSrsmaeda }
8170c86d1bbSrsmaeda
8180c86d1bbSrsmaeda ASSERT(set_idx != nres);
8190c86d1bbSrsmaeda
8200c86d1bbSrsmaeda /*
8210c86d1bbSrsmaeda * Remove the current CPU from the set total but only
8220c86d1bbSrsmaeda * generate an error for the last CPU. The correct CPU
8230c86d1bbSrsmaeda * will get the error because the unconfigure attempts
8240c86d1bbSrsmaeda * will occur in the same order in which the CPUs are
8255f1655c9SJames Marks - Sun Microsystems * examined in this loop. The cp_ncpus field of a
8265f1655c9SJames Marks - Sun Microsystems * cpupart_t counts only online cpus, so it is safe
8275f1655c9SJames Marks - Sun Microsystems * to remove an offline cpu without testing ncpus.
8280c86d1bbSrsmaeda */
8297de586caSJames Marks - Sun Microsystems if (cpu_is_offline(cp))
8305f1655c9SJames Marks - Sun Microsystems continue;
8315f1655c9SJames Marks - Sun Microsystems
8320c86d1bbSrsmaeda if (--psrset[set_idx].ncpus == 0) {
8330c86d1bbSrsmaeda /*
8340c86d1bbSrsmaeda * Fill in the various pieces of information
8350c86d1bbSrsmaeda * to report that the operation will fail.
8360c86d1bbSrsmaeda */
8370c86d1bbSrsmaeda res[cpu_idx].result = DR_CPU_RES_BLOCKED;
8380c86d1bbSrsmaeda res[cpu_idx].status = DR_CPU_STAT_CONFIGURED;
8390c86d1bbSrsmaeda
8400c86d1bbSrsmaeda (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN,
8410c86d1bbSrsmaeda "last online cpu in processor set %d", cpp->cp_id);
8420c86d1bbSrsmaeda
8430c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
8440c86d1bbSrsmaeda
8450c86d1bbSrsmaeda res[cpu_idx].string = kmem_alloc(err_len, KM_SLEEP);
84699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
84799c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[cpu_idx].string), err_len);
8480c86d1bbSrsmaeda bcopy(err_str, res[cpu_idx].string, err_len);
8490c86d1bbSrsmaeda
8500c86d1bbSrsmaeda DR_DBG_CPU("cpu %d: %s\n", cpuids[cpu_idx], err_str);
8510c86d1bbSrsmaeda }
8520c86d1bbSrsmaeda }
8530c86d1bbSrsmaeda
85499c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
85599c7e855SJames Marks - Sun Microsystems __func__, (void *)psrset, sizeof (*psrset) * nres);
8560c86d1bbSrsmaeda kmem_free(psrset, sizeof (*psrset) * nres);
8570c86d1bbSrsmaeda }
8580c86d1bbSrsmaeda
8590c86d1bbSrsmaeda /*
8600c86d1bbSrsmaeda * Check if any threads are bound to the specified CPU. If the
8610c86d1bbSrsmaeda * condition is true, DR_CPU_RES_BLOCKED is returned and an error
8620c86d1bbSrsmaeda * string is generated and placed in the specified result structure.
8630c86d1bbSrsmaeda * Otherwise, DR_CPU_RES_OK is returned.
8640c86d1bbSrsmaeda */
8650c86d1bbSrsmaeda static int
dr_cpu_check_bound_thr(cpu_t * cp,dr_cpu_res_t * res)8660c86d1bbSrsmaeda dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res)
8670c86d1bbSrsmaeda {
8680c86d1bbSrsmaeda int nbound;
8690c86d1bbSrsmaeda proc_t *pp;
8700c86d1bbSrsmaeda kthread_t *tp;
8710c86d1bbSrsmaeda char err_str[DR_CPU_MAX_ERR_LEN];
8720c86d1bbSrsmaeda size_t err_len;
8730c86d1bbSrsmaeda
8740c86d1bbSrsmaeda /*
8750c86d1bbSrsmaeda * Error string allocation makes an assumption
8760c86d1bbSrsmaeda * that no blocking condition has been identified.
8770c86d1bbSrsmaeda */
8780c86d1bbSrsmaeda ASSERT(res->result == DR_CPU_RES_OK);
8790c86d1bbSrsmaeda ASSERT(res->string == NULL);
8800c86d1bbSrsmaeda
8810c86d1bbSrsmaeda ASSERT(MUTEX_HELD(&cpu_lock));
8820c86d1bbSrsmaeda
8830c86d1bbSrsmaeda mutex_enter(&pidlock);
8840c86d1bbSrsmaeda
8850c86d1bbSrsmaeda nbound = 0;
8860c86d1bbSrsmaeda
8870c86d1bbSrsmaeda /*
8880c86d1bbSrsmaeda * Walk the active processes, checking if each
8890c86d1bbSrsmaeda * thread belonging to the process is bound.
8900c86d1bbSrsmaeda */
8910c86d1bbSrsmaeda for (pp = practive; (pp != NULL) && (nbound <= 1); pp = pp->p_next) {
8920c86d1bbSrsmaeda mutex_enter(&pp->p_lock);
8930c86d1bbSrsmaeda
8940c86d1bbSrsmaeda tp = pp->p_tlist;
8950c86d1bbSrsmaeda
8960c86d1bbSrsmaeda if ((tp == NULL) || (pp->p_flag & SSYS)) {
8970c86d1bbSrsmaeda mutex_exit(&pp->p_lock);
8980c86d1bbSrsmaeda continue;
8990c86d1bbSrsmaeda }
9000c86d1bbSrsmaeda
9010c86d1bbSrsmaeda do {
9020c86d1bbSrsmaeda if (tp->t_bind_cpu != cp->cpu_id)
9030c86d1bbSrsmaeda continue;
9040c86d1bbSrsmaeda
9050c86d1bbSrsmaeda /*
9060c86d1bbSrsmaeda * Update the running total of bound
9070c86d1bbSrsmaeda * threads. Continue the search until
9080c86d1bbSrsmaeda * it can be determined if more than
9090c86d1bbSrsmaeda * one thread is bound to the CPU.
9100c86d1bbSrsmaeda */
9110c86d1bbSrsmaeda if (++nbound > 1)
9120c86d1bbSrsmaeda break;
9130c86d1bbSrsmaeda
9140c86d1bbSrsmaeda } while ((tp = tp->t_forw) != pp->p_tlist);
9150c86d1bbSrsmaeda
9160c86d1bbSrsmaeda mutex_exit(&pp->p_lock);
9170c86d1bbSrsmaeda }
9180c86d1bbSrsmaeda
9190c86d1bbSrsmaeda mutex_exit(&pidlock);
9200c86d1bbSrsmaeda
9210c86d1bbSrsmaeda if (nbound) {
9220c86d1bbSrsmaeda /*
9230c86d1bbSrsmaeda * Threads are bound to the CPU. Fill in
9240c86d1bbSrsmaeda * various pieces of information to report
9250c86d1bbSrsmaeda * that the operation will fail.
9260c86d1bbSrsmaeda */
9270c86d1bbSrsmaeda res->result = DR_CPU_RES_BLOCKED;
9280c86d1bbSrsmaeda res->status = DR_CPU_STAT_CONFIGURED;
9290c86d1bbSrsmaeda
9300c86d1bbSrsmaeda (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, "cpu has bound "
9310c86d1bbSrsmaeda "thread%s", (nbound > 1) ? "s" : "");
9320c86d1bbSrsmaeda
9330c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
9340c86d1bbSrsmaeda
9350c86d1bbSrsmaeda res->string = kmem_alloc(err_len, KM_SLEEP);
93699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
93799c7e855SJames Marks - Sun Microsystems __func__, (void *)(res->string), err_len);
9380c86d1bbSrsmaeda bcopy(err_str, res->string, err_len);
9390c86d1bbSrsmaeda
9400c86d1bbSrsmaeda DR_DBG_CPU("cpu %d: %s\n", cp->cpu_id, err_str);
9410c86d1bbSrsmaeda }
9420c86d1bbSrsmaeda
9430c86d1bbSrsmaeda return (res->result);
9440c86d1bbSrsmaeda }
9451ae08745Sheppo
9461ae08745Sheppo /*
9471ae08745Sheppo * Do not modify result buffer or length on error.
9481ae08745Sheppo */
9491ae08745Sheppo static int
dr_cpu_list_status(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)9501ae08745Sheppo dr_cpu_list_status(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
9511ae08745Sheppo {
9521ae08745Sheppo int idx;
9531ae08745Sheppo int result;
9541ae08745Sheppo int status;
9551ae08745Sheppo int rlen;
9561ae08745Sheppo uint32_t *cpuids;
9571ae08745Sheppo dr_cpu_hdr_t *rp;
9581ae08745Sheppo dr_cpu_stat_t *stat;
9591ae08745Sheppo md_t *mdp = NULL;
9601ae08745Sheppo int num_nodes;
9611ae08745Sheppo int listsz;
9621ae08745Sheppo mde_cookie_t *listp = NULL;
9631ae08745Sheppo mde_cookie_t cpunode;
9641ae08745Sheppo boolean_t walk_md = B_FALSE;
9651ae08745Sheppo
9661ae08745Sheppo /* the incoming array of cpuids to configure */
9670c86d1bbSrsmaeda cpuids = DR_CPU_CMD_CPUIDS(req);
9681ae08745Sheppo
9691ae08745Sheppo /* allocate a response message */
9701ae08745Sheppo rlen = sizeof (dr_cpu_hdr_t);
9711ae08745Sheppo rlen += req->num_records * sizeof (dr_cpu_stat_t);
9721ae08745Sheppo rp = kmem_zalloc(rlen, KM_SLEEP);
97399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n", __func__, (void *)rp, rlen);
9741ae08745Sheppo
9751ae08745Sheppo /* fill in the known data */
9761ae08745Sheppo rp->req_num = req->req_num;
9771ae08745Sheppo rp->msg_type = DR_CPU_STATUS;
9781ae08745Sheppo rp->num_records = req->num_records;
9791ae08745Sheppo
9801ae08745Sheppo /* stat array for the response */
9810c86d1bbSrsmaeda stat = DR_CPU_RESP_STATS(rp);
9821ae08745Sheppo
9831ae08745Sheppo /* get the status for each of the CPUs */
9841ae08745Sheppo for (idx = 0; idx < req->num_records; idx++) {
9851ae08745Sheppo
9861ae08745Sheppo result = dr_cpu_status(cpuids[idx], &status);
9871ae08745Sheppo
9881ae08745Sheppo if (result == DR_CPU_RES_FAILURE)
9891ae08745Sheppo walk_md = B_TRUE;
9901ae08745Sheppo
9911ae08745Sheppo /* save off results of the status */
9921ae08745Sheppo stat[idx].cpuid = cpuids[idx];
9931ae08745Sheppo stat[idx].result = result;
9941ae08745Sheppo stat[idx].status = status;
9951ae08745Sheppo }
9961ae08745Sheppo
9971ae08745Sheppo if (walk_md == B_FALSE)
9981ae08745Sheppo goto done;
9991ae08745Sheppo
10001ae08745Sheppo /*
10011ae08745Sheppo * At least one of the cpus did not have a CPU
10021ae08745Sheppo * structure. So, consult the MD to determine if
10031ae08745Sheppo * they are present.
10041ae08745Sheppo */
10051ae08745Sheppo
10061ae08745Sheppo if ((mdp = md_get_handle()) == NULL) {
10071ae08745Sheppo DR_DBG_CPU("unable to initialize MD\n");
10081ae08745Sheppo goto done;
10091ae08745Sheppo }
10101ae08745Sheppo
10111ae08745Sheppo num_nodes = md_node_count(mdp);
10121ae08745Sheppo ASSERT(num_nodes > 0);
10131ae08745Sheppo
10141ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
10151ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP);
101699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
101799c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
10181ae08745Sheppo
10191ae08745Sheppo for (idx = 0; idx < req->num_records; idx++) {
10201ae08745Sheppo
10211ae08745Sheppo if (stat[idx].result != DR_CPU_RES_FAILURE)
10221ae08745Sheppo continue;
10231ae08745Sheppo
10241ae08745Sheppo /* check the MD for the current cpuid */
10251ae08745Sheppo cpunode = dr_cpu_find_node_md(stat[idx].cpuid, mdp, listp);
10261ae08745Sheppo
10271ae08745Sheppo stat[idx].result = DR_CPU_RES_OK;
10281ae08745Sheppo
10291ae08745Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) {
10301ae08745Sheppo stat[idx].status = DR_CPU_STAT_NOT_PRESENT;
10311ae08745Sheppo } else {
10321ae08745Sheppo stat[idx].status = DR_CPU_STAT_UNCONFIGURED;
10331ae08745Sheppo }
10341ae08745Sheppo }
10351ae08745Sheppo
103699c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
103799c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
10381ae08745Sheppo kmem_free(listp, listsz);
10391ae08745Sheppo
10401ae08745Sheppo (void) md_fini_handle(mdp);
10411ae08745Sheppo
10421ae08745Sheppo done:
10431ae08745Sheppo *resp = rp;
10441ae08745Sheppo *resp_len = rlen;
10451ae08745Sheppo
10461ae08745Sheppo return (0);
10471ae08745Sheppo }
10481ae08745Sheppo
10491ae08745Sheppo static int
dr_cpu_configure(processorid_t cpuid,int * status,boolean_t force)10501d4b38e0Srsmaeda dr_cpu_configure(processorid_t cpuid, int *status, boolean_t force)
10511ae08745Sheppo {
10521d4b38e0Srsmaeda _NOTE(ARGUNUSED(force))
10531ae08745Sheppo struct cpu *cp;
10541ae08745Sheppo int rv = 0;
10551ae08745Sheppo
10561ae08745Sheppo DR_DBG_CPU("dr_cpu_configure...\n");
10571ae08745Sheppo
10581ae08745Sheppo /*
10591ae08745Sheppo * Build device tree node for the CPU
10601ae08745Sheppo */
10611ae08745Sheppo if ((rv = dr_cpu_probe(cpuid)) != 0) {
10621ae08745Sheppo DR_DBG_CPU("failed to probe CPU %d (%d)\n", cpuid, rv);
10631ae08745Sheppo if (rv == EINVAL) {
10641ae08745Sheppo *status = DR_CPU_STAT_NOT_PRESENT;
10651ae08745Sheppo return (DR_CPU_RES_NOT_IN_MD);
10661ae08745Sheppo }
10671ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
10681ae08745Sheppo return (DR_CPU_RES_FAILURE);
10691ae08745Sheppo }
10701ae08745Sheppo
10711ae08745Sheppo mutex_enter(&cpu_lock);
10721ae08745Sheppo
10731ae08745Sheppo /*
10741ae08745Sheppo * Configure the CPU
10751ae08745Sheppo */
10761ae08745Sheppo if ((cp = cpu_get(cpuid)) == NULL) {
10771ae08745Sheppo
10781ae08745Sheppo if ((rv = cpu_configure(cpuid)) != 0) {
10791ae08745Sheppo DR_DBG_CPU("failed to configure CPU %d (%d)\n",
10801ae08745Sheppo cpuid, rv);
10811ae08745Sheppo rv = DR_CPU_RES_FAILURE;
10821ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
10831ae08745Sheppo goto done;
10841ae08745Sheppo }
10851ae08745Sheppo
10861ae08745Sheppo DR_DBG_CPU("CPU %d configured\n", cpuid);
10871ae08745Sheppo
10881ae08745Sheppo /* CPU struct should exist now */
10891ae08745Sheppo cp = cpu_get(cpuid);
10901ae08745Sheppo }
10911ae08745Sheppo
10921ae08745Sheppo ASSERT(cp);
10931ae08745Sheppo
10941ae08745Sheppo /*
10951ae08745Sheppo * Power on the CPU. In sun4v, this brings the stopped
10961ae08745Sheppo * CPU into the guest from the Hypervisor.
10971ae08745Sheppo */
10981ae08745Sheppo if (cpu_is_poweredoff(cp)) {
10991ae08745Sheppo
11001ae08745Sheppo if ((rv = cpu_poweron(cp)) != 0) {
11011ae08745Sheppo DR_DBG_CPU("failed to power on CPU %d (%d)\n",
11021ae08745Sheppo cpuid, rv);
11031ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11041ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
11051ae08745Sheppo goto done;
11061ae08745Sheppo }
11071ae08745Sheppo
11081ae08745Sheppo DR_DBG_CPU("CPU %d powered on\n", cpuid);
11091ae08745Sheppo }
11101ae08745Sheppo
11111ae08745Sheppo /*
11121ae08745Sheppo * Online the CPU
11131ae08745Sheppo */
11141ae08745Sheppo if (cpu_is_offline(cp)) {
11151ae08745Sheppo
11161ae08745Sheppo if ((rv = cpu_online(cp)) != 0) {
11171ae08745Sheppo DR_DBG_CPU("failed to online CPU %d (%d)\n",
11181ae08745Sheppo cpuid, rv);
11191ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11201ae08745Sheppo /* offline is still configured */
11211ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
11221ae08745Sheppo goto done;
11231ae08745Sheppo }
11241ae08745Sheppo
11251ae08745Sheppo DR_DBG_CPU("CPU %d online\n", cpuid);
11261ae08745Sheppo }
11271ae08745Sheppo
11281ae08745Sheppo rv = DR_CPU_RES_OK;
11291ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
11301ae08745Sheppo
11311ae08745Sheppo done:
11321ae08745Sheppo mutex_exit(&cpu_lock);
11331ae08745Sheppo
11341ae08745Sheppo return (rv);
11351ae08745Sheppo }
11361ae08745Sheppo
11371ae08745Sheppo static int
dr_cpu_unconfigure(processorid_t cpuid,int * status,boolean_t force)11381ae08745Sheppo dr_cpu_unconfigure(processorid_t cpuid, int *status, boolean_t force)
11391ae08745Sheppo {
11401ae08745Sheppo struct cpu *cp;
11411ae08745Sheppo int rv = 0;
11421ae08745Sheppo int cpu_flags;
11431ae08745Sheppo
11441ae08745Sheppo DR_DBG_CPU("dr_cpu_unconfigure%s...\n", (force) ? " (force)" : "");
11451ae08745Sheppo
11461ae08745Sheppo mutex_enter(&cpu_lock);
11471ae08745Sheppo
11481ae08745Sheppo cp = cpu_get(cpuid);
11491ae08745Sheppo
11501ae08745Sheppo if (cp == NULL) {
11511ae08745Sheppo /*
1152*4a9fd251SVijay Balakrishna, SG-RPE * As OS CPU structures are already torn down proceed
1153*4a9fd251SVijay Balakrishna, SG-RPE * to deprobe device tree to make sure the device tree
1154*4a9fd251SVijay Balakrishna, SG-RPE * is up do date.
11551ae08745Sheppo */
1156*4a9fd251SVijay Balakrishna, SG-RPE goto deprobe;
11571ae08745Sheppo }
11581ae08745Sheppo
11591ae08745Sheppo ASSERT(cp->cpu_id == cpuid);
11601ae08745Sheppo
11611ae08745Sheppo /*
11621ae08745Sheppo * Offline the CPU
11631ae08745Sheppo */
11641ae08745Sheppo if (cpu_is_active(cp)) {
11651ae08745Sheppo
11661ae08745Sheppo /* set the force flag correctly */
11671ae08745Sheppo cpu_flags = (force) ? CPU_FORCED : 0;
11681ae08745Sheppo
11697de586caSJames Marks - Sun Microsystems /*
11707de586caSJames Marks - Sun Microsystems * Before we take the CPU offline, we first enable interrupts.
11717de586caSJames Marks - Sun Microsystems * Otherwise, cpu_offline() might reject the request. Note:
11727de586caSJames Marks - Sun Microsystems * if the offline subsequently fails, the target cpu will be
11737de586caSJames Marks - Sun Microsystems * left with interrupts enabled. This is consistent with the
11747de586caSJames Marks - Sun Microsystems * behavior of psradm(1M) and p_online(2).
11757de586caSJames Marks - Sun Microsystems */
11767de586caSJames Marks - Sun Microsystems cpu_intr_enable(cp);
11777de586caSJames Marks - Sun Microsystems
11781ae08745Sheppo if ((rv = cpu_offline(cp, cpu_flags)) != 0) {
11791ae08745Sheppo DR_DBG_CPU("failed to offline CPU %d (%d)\n",
11801ae08745Sheppo cpuid, rv);
11811ae08745Sheppo
11821ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11831ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
1184*4a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
1185*4a9fd251SVijay Balakrishna, SG-RPE return (rv);
11861ae08745Sheppo }
11871ae08745Sheppo
11881ae08745Sheppo DR_DBG_CPU("CPU %d offline\n", cpuid);
11891ae08745Sheppo }
11901ae08745Sheppo
11911ae08745Sheppo /*
11921ae08745Sheppo * Power off the CPU. In sun4v, this puts the running
11931ae08745Sheppo * CPU into the stopped state in the Hypervisor.
11941ae08745Sheppo */
11951ae08745Sheppo if (!cpu_is_poweredoff(cp)) {
11961ae08745Sheppo
11971ae08745Sheppo if ((rv = cpu_poweroff(cp)) != 0) {
11981ae08745Sheppo DR_DBG_CPU("failed to power off CPU %d (%d)\n",
11991ae08745Sheppo cpuid, rv);
12001ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12011ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
1202*4a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
1203*4a9fd251SVijay Balakrishna, SG-RPE return (rv);
12041ae08745Sheppo }
12051ae08745Sheppo
12061ae08745Sheppo DR_DBG_CPU("CPU %d powered off\n", cpuid);
12071ae08745Sheppo }
12081ae08745Sheppo
12091ae08745Sheppo /*
12101ae08745Sheppo * Unconfigure the CPU
12111ae08745Sheppo */
12121ae08745Sheppo if ((rv = cpu_unconfigure(cpuid)) != 0) {
12131ae08745Sheppo DR_DBG_CPU("failed to unconfigure CPU %d (%d)\n", cpuid, rv);
12141ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12151ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
1216*4a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
1217*4a9fd251SVijay Balakrishna, SG-RPE return (rv);
12181ae08745Sheppo }
12191ae08745Sheppo
12201ae08745Sheppo DR_DBG_CPU("CPU %d unconfigured\n", cpuid);
12211ae08745Sheppo
1222*4a9fd251SVijay Balakrishna, SG-RPE deprobe:
1223*4a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
12241ae08745Sheppo /*
12251ae08745Sheppo * Tear down device tree.
12261ae08745Sheppo */
12271ae08745Sheppo if ((rv = dr_cpu_deprobe(cpuid)) != 0) {
12281ae08745Sheppo DR_DBG_CPU("failed to deprobe CPU %d (%d)\n", cpuid, rv);
12291ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12301ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
1231*4a9fd251SVijay Balakrishna, SG-RPE return (rv);
12321ae08745Sheppo }
12331ae08745Sheppo
12341ae08745Sheppo rv = DR_CPU_RES_OK;
12351ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12361ae08745Sheppo
12371ae08745Sheppo return (rv);
12381ae08745Sheppo }
12391ae08745Sheppo
12401ae08745Sheppo /*
12411ae08745Sheppo * Determine the state of a CPU. If the CPU structure is not present,
12421ae08745Sheppo * it does not attempt to determine whether or not the CPU is in the
12431ae08745Sheppo * MD. It is more efficient to do this at the higher level for all
12441ae08745Sheppo * CPUs since it may not even be necessary to search the MD if all
12451ae08745Sheppo * the CPUs are accounted for. Returns DR_CPU_RES_OK if the CPU
12461ae08745Sheppo * structure is present, and DR_CPU_RES_FAILURE otherwise as a signal
12471ae08745Sheppo * that an MD walk is necessary.
12481ae08745Sheppo */
12491ae08745Sheppo static int
dr_cpu_status(processorid_t cpuid,int * status)12501ae08745Sheppo dr_cpu_status(processorid_t cpuid, int *status)
12511ae08745Sheppo {
12521ae08745Sheppo int rv;
12531ae08745Sheppo struct cpu *cp;
12541ae08745Sheppo
12551ae08745Sheppo DR_DBG_CPU("dr_cpu_status...\n");
12561ae08745Sheppo
12571ae08745Sheppo mutex_enter(&cpu_lock);
12581ae08745Sheppo
12591ae08745Sheppo if ((cp = cpu_get(cpuid)) == NULL) {
12601ae08745Sheppo /* need to check if cpu is in the MD */
12611ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12621ae08745Sheppo goto done;
12631ae08745Sheppo }
12641ae08745Sheppo
12651ae08745Sheppo if (cpu_is_poweredoff(cp)) {
12661ae08745Sheppo /*
12671ae08745Sheppo * The CPU is powered off, so it is considered
12681ae08745Sheppo * unconfigured from the service entity point of
12691ae08745Sheppo * view. The CPU is not available to the system
12701ae08745Sheppo * and intervention by the service entity would
12711ae08745Sheppo * be required to change that.
12721ae08745Sheppo */
12731ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12741ae08745Sheppo } else {
12751ae08745Sheppo /*
12761ae08745Sheppo * The CPU is powered on, so it is considered
12771ae08745Sheppo * configured from the service entity point of
12781ae08745Sheppo * view. It is available for use by the system
12791ae08745Sheppo * and service entities are not concerned about
12801ae08745Sheppo * the operational status (offline, online, etc.)
12811ae08745Sheppo * of the CPU in terms of DR.
12821ae08745Sheppo */
12831ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
12841ae08745Sheppo }
12851ae08745Sheppo
12861ae08745Sheppo rv = DR_CPU_RES_OK;
12871ae08745Sheppo
12881ae08745Sheppo done:
12891ae08745Sheppo mutex_exit(&cpu_lock);
12901ae08745Sheppo
12911ae08745Sheppo return (rv);
12921ae08745Sheppo }
12931ae08745Sheppo
12941ae08745Sheppo typedef struct {
12951ae08745Sheppo md_t *mdp;
12961ae08745Sheppo mde_cookie_t cpunode;
12971ae08745Sheppo dev_info_t *dip;
12981ae08745Sheppo } cb_arg_t;
12991ae08745Sheppo
13001ae08745Sheppo #define STR_ARR_LEN 5
13011ae08745Sheppo
13021ae08745Sheppo static int
new_cpu_node(dev_info_t * new_node,void * arg,uint_t flags)13031ae08745Sheppo new_cpu_node(dev_info_t *new_node, void *arg, uint_t flags)
13041ae08745Sheppo {
13051ae08745Sheppo _NOTE(ARGUNUSED(flags))
13061ae08745Sheppo
13071ae08745Sheppo char *compat;
13081ae08745Sheppo uint64_t freq;
13091ae08745Sheppo uint64_t cpuid = 0;
13101ae08745Sheppo int regbuf[4];
13111ae08745Sheppo int len = 0;
13121ae08745Sheppo cb_arg_t *cba;
13131ae08745Sheppo char *str_arr[STR_ARR_LEN];
13141ae08745Sheppo char *curr;
13151ae08745Sheppo int idx = 0;
13161ae08745Sheppo
13171ae08745Sheppo DR_DBG_CPU("new_cpu_node...\n");
13181ae08745Sheppo
13191ae08745Sheppo cba = (cb_arg_t *)arg;
13201ae08745Sheppo
13211ae08745Sheppo /*
13221ae08745Sheppo * Add 'name' property
13231ae08745Sheppo */
13241ae08745Sheppo if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13251ae08745Sheppo "name", "cpu") != DDI_SUCCESS) {
13261ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'name' property\n");
13271ae08745Sheppo return (DDI_WALK_ERROR);
13281ae08745Sheppo }
13291ae08745Sheppo
13301ae08745Sheppo /*
13311ae08745Sheppo * Add 'compatible' property
13321ae08745Sheppo */
13331ae08745Sheppo if (md_get_prop_data(cba->mdp, cba->cpunode, "compatible",
13341ae08745Sheppo (uint8_t **)(&compat), &len)) {
13351ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'compatible' property "
13361ae08745Sheppo "from MD\n");
13371ae08745Sheppo return (DDI_WALK_ERROR);
13381ae08745Sheppo }
13391ae08745Sheppo
13401ae08745Sheppo DR_DBG_CPU("'compatible' len is %d\n", len);
13411ae08745Sheppo
13421ae08745Sheppo /* parse the MD string array */
13431ae08745Sheppo curr = compat;
13441ae08745Sheppo while (curr < (compat + len)) {
13451ae08745Sheppo
13461ae08745Sheppo DR_DBG_CPU("adding '%s' to 'compatible' property\n", curr);
13471ae08745Sheppo
13481ae08745Sheppo str_arr[idx++] = curr;
13491ae08745Sheppo curr += strlen(curr) + 1;
13501ae08745Sheppo
13511ae08745Sheppo if (idx == STR_ARR_LEN) {
13521ae08745Sheppo DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
13531ae08745Sheppo break;
13541ae08745Sheppo }
13551ae08745Sheppo }
13561ae08745Sheppo
13571ae08745Sheppo if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
13581ae08745Sheppo "compatible", str_arr, idx) != DDI_SUCCESS) {
13591ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'compatible' "
13601ae08745Sheppo "property\n");
13611ae08745Sheppo return (DDI_WALK_ERROR);
13621ae08745Sheppo }
13631ae08745Sheppo
13641ae08745Sheppo /*
13651ae08745Sheppo * Add 'device_type' property
13661ae08745Sheppo */
13671ae08745Sheppo if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13681ae08745Sheppo "device_type", "cpu") != DDI_SUCCESS) {
13691ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'device_type' "
13701ae08745Sheppo "property\n");
13711ae08745Sheppo return (DDI_WALK_ERROR);
13721ae08745Sheppo }
13731ae08745Sheppo
13741ae08745Sheppo /*
13751ae08745Sheppo * Add 'clock-frequency' property
13761ae08745Sheppo */
13771ae08745Sheppo if (md_get_prop_val(cba->mdp, cba->cpunode, "clock-frequency", &freq)) {
13781ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'clock-frequency' "
13791ae08745Sheppo "property from MD\n");
13801ae08745Sheppo return (DDI_WALK_ERROR);
13811ae08745Sheppo }
13821ae08745Sheppo
13831ae08745Sheppo if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node,
13841ae08745Sheppo "clock-frequency", freq) != DDI_SUCCESS) {
13851ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'clock-frequency' "
13861ae08745Sheppo "property\n");
13871ae08745Sheppo return (DDI_WALK_ERROR);
13881ae08745Sheppo }
13891ae08745Sheppo
13901ae08745Sheppo /*
13911ae08745Sheppo * Add 'reg' (cpuid) property
13921ae08745Sheppo */
13931ae08745Sheppo if (md_get_prop_val(cba->mdp, cba->cpunode, "id", &cpuid)) {
13941ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'id' property "
13951ae08745Sheppo "from MD\n");
13961ae08745Sheppo return (DDI_WALK_ERROR);
13971ae08745Sheppo }
13981ae08745Sheppo
13991ae08745Sheppo DR_DBG_CPU("new cpuid=0x%lx\n", cpuid);
14001ae08745Sheppo
14011ae08745Sheppo bzero(regbuf, 4 * sizeof (int));
14021ae08745Sheppo regbuf[0] = 0xc0000000 | cpuid;
14031ae08745Sheppo
14041ae08745Sheppo if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_node,
14051ae08745Sheppo "reg", regbuf, 4) != DDI_SUCCESS) {
14061ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'reg' property\n");
14071ae08745Sheppo return (DDI_WALK_ERROR);
14081ae08745Sheppo }
14091ae08745Sheppo
14101ae08745Sheppo cba->dip = new_node;
14111ae08745Sheppo
14121ae08745Sheppo return (DDI_WALK_TERMINATE);
14131ae08745Sheppo }
14141ae08745Sheppo
14151ae08745Sheppo static int
dr_cpu_probe(processorid_t cpuid)14161ae08745Sheppo dr_cpu_probe(processorid_t cpuid)
14171ae08745Sheppo {
14181ae08745Sheppo dev_info_t *pdip;
14191ae08745Sheppo dev_info_t *dip;
14201ae08745Sheppo devi_branch_t br;
14211ae08745Sheppo md_t *mdp = NULL;
14221ae08745Sheppo int num_nodes;
14231ae08745Sheppo int rv = 0;
14241ae08745Sheppo int listsz;
14251ae08745Sheppo mde_cookie_t *listp = NULL;
14261ae08745Sheppo cb_arg_t cba;
14271ae08745Sheppo mde_cookie_t cpunode;
14281ae08745Sheppo
14291ae08745Sheppo if ((dip = dr_cpu_find_node(cpuid)) != NULL) {
14301ae08745Sheppo /* nothing to do */
14311ae08745Sheppo e_ddi_branch_rele(dip);
14321ae08745Sheppo return (0);
14331ae08745Sheppo }
14341ae08745Sheppo
14351ae08745Sheppo if ((mdp = md_get_handle()) == NULL) {
14361ae08745Sheppo DR_DBG_CPU("unable to initialize machine description\n");
14371ae08745Sheppo return (-1);
14381ae08745Sheppo }
14391ae08745Sheppo
14401ae08745Sheppo num_nodes = md_node_count(mdp);
14411ae08745Sheppo ASSERT(num_nodes > 0);
14421ae08745Sheppo
14431ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
14441ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP);
144599c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
144699c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
14471ae08745Sheppo
14481ae08745Sheppo cpunode = dr_cpu_find_node_md(cpuid, mdp, listp);
14491ae08745Sheppo
14501ae08745Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) {
14511ae08745Sheppo rv = EINVAL;
14521ae08745Sheppo goto done;
14531ae08745Sheppo }
14541ae08745Sheppo
14551ae08745Sheppo /* pass in MD cookie for CPU */
14561ae08745Sheppo cba.mdp = mdp;
14571ae08745Sheppo cba.cpunode = cpunode;
14581ae08745Sheppo
14591ae08745Sheppo br.arg = (void *)&cba;
14601ae08745Sheppo br.type = DEVI_BRANCH_SID;
14611ae08745Sheppo br.create.sid_branch_create = new_cpu_node;
14621ae08745Sheppo br.devi_branch_callback = NULL;
14631ae08745Sheppo pdip = ddi_root_node();
14641ae08745Sheppo
14651ae08745Sheppo if ((rv = e_ddi_branch_create(pdip, &br, NULL, 0))) {
14661ae08745Sheppo DR_DBG_CPU("e_ddi_branch_create failed: %d\n", rv);
14671ae08745Sheppo rv = -1;
14681ae08745Sheppo goto done;
14691ae08745Sheppo }
14701ae08745Sheppo
14711ae08745Sheppo DR_DBG_CPU("CPU %d probed\n", cpuid);
14721ae08745Sheppo
14731ae08745Sheppo rv = 0;
14741ae08745Sheppo
14751ae08745Sheppo done:
147699c7e855SJames Marks - Sun Microsystems if (listp) {
147799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
147899c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
14791ae08745Sheppo kmem_free(listp, listsz);
148099c7e855SJames Marks - Sun Microsystems }
14811ae08745Sheppo
14821ae08745Sheppo if (mdp)
14831ae08745Sheppo (void) md_fini_handle(mdp);
14841ae08745Sheppo
14851ae08745Sheppo return (rv);
14861ae08745Sheppo }
14871ae08745Sheppo
14881ae08745Sheppo static int
dr_cpu_deprobe(processorid_t cpuid)14891ae08745Sheppo dr_cpu_deprobe(processorid_t cpuid)
14901ae08745Sheppo {
14911ae08745Sheppo dev_info_t *fdip = NULL;
14921ae08745Sheppo dev_info_t *dip;
14931ae08745Sheppo
14941ae08745Sheppo if ((dip = dr_cpu_find_node(cpuid)) == NULL) {
14951ae08745Sheppo DR_DBG_CPU("cpuid %d already deprobed\n", cpuid);
14961ae08745Sheppo return (0);
14971ae08745Sheppo }
14981ae08745Sheppo
14991ae08745Sheppo ASSERT(e_ddi_branch_held(dip));
15001ae08745Sheppo
15011ae08745Sheppo if (e_ddi_branch_destroy(dip, &fdip, 0)) {
15021ae08745Sheppo char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15031ae08745Sheppo
150499c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
150599c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN);
15061ae08745Sheppo /*
15071ae08745Sheppo * If non-NULL, fdip is held and must be released.
15081ae08745Sheppo */
15091ae08745Sheppo if (fdip != NULL) {
15101ae08745Sheppo (void) ddi_pathname(fdip, path);
15111ae08745Sheppo ddi_release_devi(fdip);
15121ae08745Sheppo } else {
15131ae08745Sheppo (void) ddi_pathname(dip, path);
15141ae08745Sheppo }
15151ae08745Sheppo cmn_err(CE_NOTE, "node removal failed: %s (%p)",
15161ae08745Sheppo path, (fdip) ? (void *)fdip : (void *)dip);
15171ae08745Sheppo
151899c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
151999c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN);
15201ae08745Sheppo kmem_free(path, MAXPATHLEN);
15211ae08745Sheppo
15221ae08745Sheppo return (-1);
15231ae08745Sheppo }
15241ae08745Sheppo
15251ae08745Sheppo DR_DBG_CPU("CPU %d deprobed\n", cpuid);
15261ae08745Sheppo
15271ae08745Sheppo return (0);
15281ae08745Sheppo }
15291ae08745Sheppo
15301ae08745Sheppo typedef struct {
15311ae08745Sheppo processorid_t cpuid;
15321ae08745Sheppo dev_info_t *dip;
15331ae08745Sheppo } dr_search_arg_t;
15341ae08745Sheppo
15351ae08745Sheppo static int
dr_cpu_check_node(dev_info_t * dip,void * arg)15361ae08745Sheppo dr_cpu_check_node(dev_info_t *dip, void *arg)
15371ae08745Sheppo {
15381ae08745Sheppo char *name;
15391ae08745Sheppo processorid_t cpuid;
15401ae08745Sheppo dr_search_arg_t *sarg = (dr_search_arg_t *)arg;
15411ae08745Sheppo
15421ae08745Sheppo if (dip == ddi_root_node()) {
15431ae08745Sheppo return (DDI_WALK_CONTINUE);
15441ae08745Sheppo }
15451ae08745Sheppo
15461ae08745Sheppo name = ddi_node_name(dip);
15471ae08745Sheppo
15481ae08745Sheppo if (strcmp(name, "cpu") != 0) {
15491ae08745Sheppo return (DDI_WALK_PRUNECHILD);
15501ae08745Sheppo }
15511ae08745Sheppo
15521ae08745Sheppo cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
15531ae08745Sheppo "reg", -1);
15541ae08745Sheppo
15551ae08745Sheppo cpuid = PROM_CFGHDL_TO_CPUID(cpuid);
15561ae08745Sheppo
15571ae08745Sheppo DR_DBG_CPU("found cpuid=0x%x, looking for 0x%x\n", cpuid, sarg->cpuid);
15581ae08745Sheppo
15591ae08745Sheppo if (cpuid == sarg->cpuid) {
15601ae08745Sheppo DR_DBG_CPU("matching node\n");
15611ae08745Sheppo
15621ae08745Sheppo /* matching node must be returned held */
15631ae08745Sheppo if (!e_ddi_branch_held(dip))
15641ae08745Sheppo e_ddi_branch_hold(dip);
15651ae08745Sheppo
15661ae08745Sheppo sarg->dip = dip;
15671ae08745Sheppo return (DDI_WALK_TERMINATE);
15681ae08745Sheppo }
15691ae08745Sheppo
15701ae08745Sheppo return (DDI_WALK_CONTINUE);
15711ae08745Sheppo }
15721ae08745Sheppo
15731ae08745Sheppo /*
15741ae08745Sheppo * Walk the device tree to find the dip corresponding to the cpuid
15751ae08745Sheppo * passed in. If present, the dip is returned held. The caller must
15761ae08745Sheppo * release the hold on the dip once it is no longer required. If no
15771ae08745Sheppo * matching node if found, NULL is returned.
15781ae08745Sheppo */
15791ae08745Sheppo static dev_info_t *
dr_cpu_find_node(processorid_t cpuid)15801ae08745Sheppo dr_cpu_find_node(processorid_t cpuid)
15811ae08745Sheppo {
15821ae08745Sheppo dr_search_arg_t arg;
15831ae08745Sheppo
15841ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node...\n");
15851ae08745Sheppo
15861ae08745Sheppo arg.cpuid = cpuid;
15871ae08745Sheppo arg.dip = NULL;
15881ae08745Sheppo
15891ae08745Sheppo ddi_walk_devs(ddi_root_node(), dr_cpu_check_node, &arg);
15901ae08745Sheppo
15911ae08745Sheppo ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
15921ae08745Sheppo
15931ae08745Sheppo return ((arg.dip) ? arg.dip : NULL);
15941ae08745Sheppo }
15951ae08745Sheppo
15961ae08745Sheppo /*
15971ae08745Sheppo * Look up a particular cpuid in the MD. Returns the mde_cookie_t
15981ae08745Sheppo * representing that CPU if present, and MDE_INVAL_ELEM_COOKIE
15991ae08745Sheppo * otherwise. It is assumed the scratch array has already been
16001ae08745Sheppo * allocated so that it can accommodate the worst case scenario,
16011ae08745Sheppo * every node in the MD.
16021ae08745Sheppo */
16031ae08745Sheppo static mde_cookie_t
dr_cpu_find_node_md(processorid_t cpuid,md_t * mdp,mde_cookie_t * listp)16041ae08745Sheppo dr_cpu_find_node_md(processorid_t cpuid, md_t *mdp, mde_cookie_t *listp)
16051ae08745Sheppo {
16061ae08745Sheppo int idx;
16071ae08745Sheppo int nnodes;
16081ae08745Sheppo mde_cookie_t rootnode;
16091ae08745Sheppo uint64_t cpuid_prop;
16101ae08745Sheppo mde_cookie_t result = MDE_INVAL_ELEM_COOKIE;
16111ae08745Sheppo
16121ae08745Sheppo rootnode = md_root_node(mdp);
16131ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
16141ae08745Sheppo
16151ae08745Sheppo /*
16161ae08745Sheppo * Scan the DAG for all the CPU nodes
16171ae08745Sheppo */
16181ae08745Sheppo nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
16191ae08745Sheppo md_find_name(mdp, "fwd"), listp);
16201ae08745Sheppo
16211ae08745Sheppo if (nnodes < 0) {
16221ae08745Sheppo DR_DBG_CPU("Scan for CPUs failed\n");
16231ae08745Sheppo return (result);
16241ae08745Sheppo }
16251ae08745Sheppo
16261ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node_md: found %d CPUs in the MD\n", nnodes);
16271ae08745Sheppo
16281ae08745Sheppo /*
16291ae08745Sheppo * Find the CPU of interest
16301ae08745Sheppo */
16311ae08745Sheppo for (idx = 0; idx < nnodes; idx++) {
16321ae08745Sheppo
16331ae08745Sheppo if (md_get_prop_val(mdp, listp[idx], "id", &cpuid_prop)) {
16341ae08745Sheppo DR_DBG_CPU("Missing 'id' property for CPU node %d\n",
16351ae08745Sheppo idx);
16361ae08745Sheppo break;
16371ae08745Sheppo }
16381ae08745Sheppo
16391ae08745Sheppo if (cpuid_prop == cpuid) {
16401ae08745Sheppo /* found a match */
16411ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node_md: found CPU %d "
16421ae08745Sheppo "in MD\n", cpuid);
16431ae08745Sheppo result = listp[idx];
16441ae08745Sheppo break;
16451ae08745Sheppo }
16461ae08745Sheppo }
16471ae08745Sheppo
16481ae08745Sheppo if (result == MDE_INVAL_ELEM_COOKIE) {
16491ae08745Sheppo DR_DBG_CPU("CPU %d not in MD\n", cpuid);
16501ae08745Sheppo }
16511ae08745Sheppo
16521ae08745Sheppo return (result);
16531ae08745Sheppo }
1654