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 /*
28c3377ee9SJohn Levon * Copyright 2019 Joyent, Inc.
29c3377ee9SJohn Levon */
30c3377ee9SJohn Levon
31c3377ee9SJohn Levon /*
321ae08745Sheppo * sun4v CPU DR Module
331ae08745Sheppo */
341ae08745Sheppo
351ae08745Sheppo #include <sys/modctl.h>
361ae08745Sheppo #include <sys/processor.h>
371ae08745Sheppo #include <sys/cpuvar.h>
380c86d1bbSrsmaeda #include <sys/cpupart.h>
391ae08745Sheppo #include <sys/sunddi.h>
401ae08745Sheppo #include <sys/sunndi.h>
411ae08745Sheppo #include <sys/note.h>
421ae08745Sheppo #include <sys/sysevent/dr.h>
431ae08745Sheppo #include <sys/hypervisor_api.h>
441ae08745Sheppo #include <sys/mach_descrip.h>
451ae08745Sheppo #include <sys/mdesc.h>
461ae08745Sheppo #include <sys/ds.h>
471d4b38e0Srsmaeda #include <sys/drctl.h>
481ae08745Sheppo #include <sys/dr_util.h>
491ae08745Sheppo #include <sys/dr_cpu.h>
501ae08745Sheppo #include <sys/promif.h>
511ae08745Sheppo #include <sys/machsystm.h>
521ae08745Sheppo
531ae08745Sheppo
541ae08745Sheppo static struct modlmisc modlmisc = {
551ae08745Sheppo &mod_miscops,
56f500b196SRichard Bean "sun4v CPU DR"
571ae08745Sheppo };
581ae08745Sheppo
591ae08745Sheppo static struct modlinkage modlinkage = {
601ae08745Sheppo MODREV_1,
611ae08745Sheppo (void *)&modlmisc,
621ae08745Sheppo NULL
631ae08745Sheppo };
641ae08745Sheppo
651d4b38e0Srsmaeda typedef int (*fn_t)(processorid_t, int *, boolean_t);
661d4b38e0Srsmaeda
671ae08745Sheppo /*
681ae08745Sheppo * Global DS Handle
691ae08745Sheppo */
701ae08745Sheppo static ds_svc_hdl_t ds_handle;
711ae08745Sheppo
721ae08745Sheppo /*
731ae08745Sheppo * Supported DS Capability Versions
741ae08745Sheppo */
7599c7e855SJames Marks - Sun Microsystems static ds_ver_t dr_cpu_vers[] = { { 1, 1 }, { 1, 0 } };
761ae08745Sheppo #define DR_CPU_NVERS (sizeof (dr_cpu_vers) / sizeof (dr_cpu_vers[0]))
771ae08745Sheppo
7899c7e855SJames Marks - Sun Microsystems static ds_ver_t version;
7999c7e855SJames Marks - Sun Microsystems
801ae08745Sheppo /*
811ae08745Sheppo * DS Capability Description
821ae08745Sheppo */
831ae08745Sheppo static ds_capability_t dr_cpu_cap = {
841ae08745Sheppo DR_CPU_DS_ID, /* svc_id */
851ae08745Sheppo dr_cpu_vers, /* vers */
861ae08745Sheppo DR_CPU_NVERS /* nvers */
871ae08745Sheppo };
881ae08745Sheppo
8999c7e855SJames Marks - Sun Microsystems #define DRCPU_VERS_EQ(_maj, _min) \
9099c7e855SJames Marks - Sun Microsystems ((version.major == (_maj)) && (version.minor == (_min)))
9199c7e855SJames Marks - Sun Microsystems
9299c7e855SJames Marks - Sun Microsystems #define DRCPU_VERS_GTEQ(_maj, _min) \
9399c7e855SJames Marks - Sun Microsystems ((version.major > (_maj)) || \
9499c7e855SJames Marks - Sun Microsystems ((version.major == (_maj)) && (version.minor >= (_min))))
9599c7e855SJames Marks - Sun Microsystems
961ae08745Sheppo /*
971ae08745Sheppo * DS Callbacks
981ae08745Sheppo */
991ae08745Sheppo static void dr_cpu_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
1001ae08745Sheppo static void dr_cpu_unreg_handler(ds_cb_arg_t arg);
1011ae08745Sheppo static void dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1021ae08745Sheppo
1031ae08745Sheppo /*
1041ae08745Sheppo * DS Client Ops Vector
1051ae08745Sheppo */
1061ae08745Sheppo static ds_clnt_ops_t dr_cpu_ops = {
1071ae08745Sheppo dr_cpu_reg_handler, /* ds_reg_cb */
1081ae08745Sheppo dr_cpu_unreg_handler, /* ds_unreg_cb */
1091ae08745Sheppo dr_cpu_data_handler, /* ds_data_cb */
1101ae08745Sheppo NULL /* cb_arg */
1111ae08745Sheppo };
1121ae08745Sheppo
1131ae08745Sheppo /*
1140c86d1bbSrsmaeda * Operation Results
1150c86d1bbSrsmaeda *
1160c86d1bbSrsmaeda * Used internally to gather results while an operation on a
1170c86d1bbSrsmaeda * list of CPUs is in progress. In particular, it is used to
1180c86d1bbSrsmaeda * keep track of which CPUs have already failed so that they are
1190c86d1bbSrsmaeda * not processed further, and the manner in which they failed.
1200c86d1bbSrsmaeda */
1210c86d1bbSrsmaeda typedef struct {
1220c86d1bbSrsmaeda uint32_t cpuid;
1230c86d1bbSrsmaeda uint32_t result;
1240c86d1bbSrsmaeda uint32_t status;
1250c86d1bbSrsmaeda char *string;
1260c86d1bbSrsmaeda } dr_cpu_res_t;
1270c86d1bbSrsmaeda
1280c86d1bbSrsmaeda #define DR_CPU_MAX_ERR_LEN 64 /* maximum error string length */
1290c86d1bbSrsmaeda
1300c86d1bbSrsmaeda /*
1311ae08745Sheppo * Internal Functions
1321ae08745Sheppo */
1331ae08745Sheppo static int dr_cpu_init(void);
1341ae08745Sheppo static int dr_cpu_fini(void);
1351ae08745Sheppo
1360c86d1bbSrsmaeda static int dr_cpu_list_wrk(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1371ae08745Sheppo static int dr_cpu_list_status(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1381ae08745Sheppo
1391ae08745Sheppo static int dr_cpu_unconfigure(processorid_t, int *status, boolean_t force);
1401d4b38e0Srsmaeda static int dr_cpu_configure(processorid_t, int *status, boolean_t force);
1411ae08745Sheppo static int dr_cpu_status(processorid_t, int *status);
1421ae08745Sheppo
1430c86d1bbSrsmaeda static void dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res);
1440c86d1bbSrsmaeda static void dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres);
1450c86d1bbSrsmaeda static int dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res);
1460c86d1bbSrsmaeda
1470c86d1bbSrsmaeda static dr_cpu_res_t *dr_cpu_res_array_init(dr_cpu_hdr_t *, drctl_rsrc_t *, int);
1480c86d1bbSrsmaeda static void dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres);
1490c86d1bbSrsmaeda static size_t dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res,
1500c86d1bbSrsmaeda dr_cpu_hdr_t **respp);
1510c86d1bbSrsmaeda
1521ae08745Sheppo static int dr_cpu_probe(processorid_t newcpuid);
1531ae08745Sheppo static int dr_cpu_deprobe(processorid_t cpuid);
1541ae08745Sheppo
1551ae08745Sheppo static dev_info_t *dr_cpu_find_node(processorid_t cpuid);
1561ae08745Sheppo static mde_cookie_t dr_cpu_find_node_md(processorid_t, md_t *, mde_cookie_t *);
1571ae08745Sheppo
1581ae08745Sheppo int
_init(void)1591ae08745Sheppo _init(void)
1601ae08745Sheppo {
1611ae08745Sheppo int status;
1621ae08745Sheppo
1631ae08745Sheppo /* check that CPU DR is enabled */
1641ae08745Sheppo if (dr_is_disabled(DR_TYPE_CPU)) {
1651ae08745Sheppo cmn_err(CE_CONT, "!CPU DR is disabled\n");
1661ae08745Sheppo return (-1);
1671ae08745Sheppo }
1681ae08745Sheppo
1691ae08745Sheppo if ((status = dr_cpu_init()) != 0) {
1701ae08745Sheppo cmn_err(CE_NOTE, "CPU DR initialization failed");
1711ae08745Sheppo return (status);
1721ae08745Sheppo }
1731ae08745Sheppo
1741ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) {
1751ae08745Sheppo (void) dr_cpu_fini();
1761ae08745Sheppo }
1771ae08745Sheppo
1781ae08745Sheppo return (status);
1791ae08745Sheppo }
1801ae08745Sheppo
1811ae08745Sheppo int
_info(struct modinfo * modinfop)1821ae08745Sheppo _info(struct modinfo *modinfop)
1831ae08745Sheppo {
1841ae08745Sheppo return (mod_info(&modlinkage, modinfop));
1851ae08745Sheppo }
1861ae08745Sheppo
1871ae08745Sheppo int dr_cpu_allow_unload;
1881ae08745Sheppo
1891ae08745Sheppo int
_fini(void)1901ae08745Sheppo _fini(void)
1911ae08745Sheppo {
1921ae08745Sheppo int status;
1931ae08745Sheppo
1941ae08745Sheppo if (dr_cpu_allow_unload == 0)
1951ae08745Sheppo return (EBUSY);
1961ae08745Sheppo
1971ae08745Sheppo if ((status = mod_remove(&modlinkage)) == 0) {
1981ae08745Sheppo (void) dr_cpu_fini();
1991ae08745Sheppo }
2001ae08745Sheppo
2011ae08745Sheppo return (status);
2021ae08745Sheppo }
2031ae08745Sheppo
2041ae08745Sheppo static int
dr_cpu_init(void)2051ae08745Sheppo dr_cpu_init(void)
2061ae08745Sheppo {
2071ae08745Sheppo int rv;
2081ae08745Sheppo
2091ae08745Sheppo if ((rv = ds_cap_init(&dr_cpu_cap, &dr_cpu_ops)) != 0) {
2101ae08745Sheppo cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
2111ae08745Sheppo return (-1);
2121ae08745Sheppo }
2131ae08745Sheppo
2141ae08745Sheppo return (0);
2151ae08745Sheppo }
2161ae08745Sheppo
2171ae08745Sheppo static int
dr_cpu_fini(void)2181ae08745Sheppo dr_cpu_fini(void)
2191ae08745Sheppo {
2201ae08745Sheppo int rv;
2211ae08745Sheppo
2221ae08745Sheppo if ((rv = ds_cap_fini(&dr_cpu_cap)) != 0) {
2231ae08745Sheppo cmn_err(CE_NOTE, "ds_cap_fini failed: %d", rv);
2241ae08745Sheppo return (-1);
2251ae08745Sheppo }
2261ae08745Sheppo
2271ae08745Sheppo return (0);
2281ae08745Sheppo }
2291ae08745Sheppo
2301ae08745Sheppo static void
dr_cpu_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)2311ae08745Sheppo dr_cpu_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
2321ae08745Sheppo {
2331ae08745Sheppo DR_DBG_CPU("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
2341ae08745Sheppo ver->major, ver->minor, hdl);
2351ae08745Sheppo
23699c7e855SJames Marks - Sun Microsystems version.major = ver->major;
23799c7e855SJames Marks - Sun Microsystems version.minor = ver->minor;
2381ae08745Sheppo ds_handle = hdl;
2391ae08745Sheppo }
2401ae08745Sheppo
2411ae08745Sheppo static void
dr_cpu_unreg_handler(ds_cb_arg_t arg)2421ae08745Sheppo dr_cpu_unreg_handler(ds_cb_arg_t arg)
2431ae08745Sheppo {
2441ae08745Sheppo DR_DBG_CPU("unreg_handler: arg=0x%p\n", arg);
2451ae08745Sheppo
2461ae08745Sheppo ds_handle = DS_INVALID_HDL;
2471ae08745Sheppo }
2481ae08745Sheppo
2491ae08745Sheppo static void
dr_cpu_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)2501ae08745Sheppo dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2511ae08745Sheppo {
2521ae08745Sheppo _NOTE(ARGUNUSED(arg))
2531ae08745Sheppo
2541ae08745Sheppo dr_cpu_hdr_t *req = buf;
2551ae08745Sheppo dr_cpu_hdr_t err_resp;
2561ae08745Sheppo dr_cpu_hdr_t *resp = &err_resp;
2571ae08745Sheppo int resp_len = 0;
2581ae08745Sheppo int rv;
2591ae08745Sheppo
2601ae08745Sheppo /*
2611ae08745Sheppo * Sanity check the message
2621ae08745Sheppo */
2631ae08745Sheppo if (buflen < sizeof (dr_cpu_hdr_t)) {
2641ae08745Sheppo DR_DBG_CPU("incoming message short: expected at least %ld "
2651ae08745Sheppo "bytes, received %ld\n", sizeof (dr_cpu_hdr_t), buflen);
2661ae08745Sheppo goto done;
2671ae08745Sheppo }
2681ae08745Sheppo
2691ae08745Sheppo if (req == NULL) {
2701ae08745Sheppo DR_DBG_CPU("empty message: expected at least %ld bytes\n",
2711ae08745Sheppo sizeof (dr_cpu_hdr_t));
2721ae08745Sheppo goto done;
2731ae08745Sheppo }
2741ae08745Sheppo
2751ae08745Sheppo DR_DBG_CPU("incoming request:\n");
2761ae08745Sheppo DR_DBG_DUMP_MSG(buf, buflen);
2771ae08745Sheppo
2781ae08745Sheppo if (req->num_records > NCPU) {
2791ae08745Sheppo DR_DBG_CPU("CPU list too long: %d when %d is the maximum\n",
2801ae08745Sheppo req->num_records, NCPU);
2811ae08745Sheppo goto done;
2821ae08745Sheppo }
2831ae08745Sheppo
2841ae08745Sheppo if (req->num_records == 0) {
2851ae08745Sheppo DR_DBG_CPU("No CPU specified for operation\n");
2861ae08745Sheppo goto done;
2871ae08745Sheppo }
2881ae08745Sheppo
2891ae08745Sheppo /*
2901ae08745Sheppo * Process the command
2911ae08745Sheppo */
2921ae08745Sheppo switch (req->msg_type) {
2931ae08745Sheppo case DR_CPU_CONFIGURE:
2941ae08745Sheppo case DR_CPU_UNCONFIGURE:
2951ae08745Sheppo case DR_CPU_FORCE_UNCONFIG:
2960c86d1bbSrsmaeda if ((rv = dr_cpu_list_wrk(req, &resp, &resp_len)) != 0) {
2970c86d1bbSrsmaeda DR_DBG_CPU("%s%s failed (%d)\n",
2980c86d1bbSrsmaeda (req->msg_type == DR_CPU_CONFIGURE) ?
2990c86d1bbSrsmaeda "CPU configure" : "CPU unconfigure",
3000c86d1bbSrsmaeda (req->msg_type == DR_CPU_FORCE_UNCONFIG) ?
3010c86d1bbSrsmaeda " (forced)" : "", rv);
3020c86d1bbSrsmaeda }
3031ae08745Sheppo break;
3041ae08745Sheppo
3051ae08745Sheppo case DR_CPU_STATUS:
3061ae08745Sheppo if ((rv = dr_cpu_list_status(req, &resp, &resp_len)) != 0)
3070c86d1bbSrsmaeda DR_DBG_CPU("CPU status failed (%d)\n", rv);
3081ae08745Sheppo break;
3091ae08745Sheppo
3101ae08745Sheppo default:
3111ae08745Sheppo cmn_err(CE_NOTE, "unsupported DR operation (%d)",
3121ae08745Sheppo req->msg_type);
3131ae08745Sheppo break;
3141ae08745Sheppo }
3151ae08745Sheppo
3161ae08745Sheppo done:
3171ae08745Sheppo /* check if an error occurred */
3181ae08745Sheppo if (resp == &err_resp) {
3191ae08745Sheppo resp->req_num = (req) ? req->req_num : 0;
3201ae08745Sheppo resp->msg_type = DR_CPU_ERROR;
3211ae08745Sheppo resp->num_records = 0;
3221ae08745Sheppo resp_len = sizeof (dr_cpu_hdr_t);
3231ae08745Sheppo }
3241ae08745Sheppo
3250c86d1bbSrsmaeda DR_DBG_CPU("outgoing response:\n");
3260c86d1bbSrsmaeda DR_DBG_DUMP_MSG(resp, resp_len);
3270c86d1bbSrsmaeda
3281ae08745Sheppo /* send back the response */
3291ae08745Sheppo if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
3301ae08745Sheppo DR_DBG_CPU("ds_send failed\n");
3311ae08745Sheppo }
3321ae08745Sheppo
3331ae08745Sheppo /* free any allocated memory */
33499c7e855SJames Marks - Sun Microsystems if (DRCPU_VERS_GTEQ(1, 1) || (resp != &err_resp)) {
33599c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
33699c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, resp_len);
3371ae08745Sheppo kmem_free(resp, resp_len);
3381ae08745Sheppo }
3391ae08745Sheppo }
3401ae08745Sheppo
3411ae08745Sheppo /*
34299c7e855SJames Marks - Sun Microsystems * Create a response message which consists of a header followed
34399c7e855SJames Marks - Sun Microsystems * by the error string passed in.
34499c7e855SJames Marks - Sun Microsystems */
34599c7e855SJames Marks - Sun Microsystems static size_t
dr_cpu_err_resp(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** respp,char * msg)34699c7e855SJames Marks - Sun Microsystems dr_cpu_err_resp(dr_cpu_hdr_t *req, dr_cpu_hdr_t **respp, char *msg)
34799c7e855SJames Marks - Sun Microsystems {
34899c7e855SJames Marks - Sun Microsystems size_t size;
34999c7e855SJames Marks - Sun Microsystems dr_cpu_hdr_t *resp;
35099c7e855SJames Marks - Sun Microsystems
35199c7e855SJames Marks - Sun Microsystems ASSERT((msg != NULL) && (strlen(msg) > 0));
35299c7e855SJames Marks - Sun Microsystems
35399c7e855SJames Marks - Sun Microsystems size = sizeof (*req) + strlen(msg) + 1;
35499c7e855SJames Marks - Sun Microsystems resp = kmem_alloc(size, KM_SLEEP);
35599c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
35699c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, size);
35799c7e855SJames Marks - Sun Microsystems
35899c7e855SJames Marks - Sun Microsystems resp->req_num = req->req_num;
35999c7e855SJames Marks - Sun Microsystems resp->msg_type = DR_CPU_ERROR;
36099c7e855SJames Marks - Sun Microsystems resp->num_records = 0;
36199c7e855SJames Marks - Sun Microsystems
36299c7e855SJames Marks - Sun Microsystems (void) strcpy((char *)(resp) + sizeof (*resp), msg);
36399c7e855SJames Marks - Sun Microsystems
36499c7e855SJames Marks - Sun Microsystems *respp = resp;
36599c7e855SJames Marks - Sun Microsystems
36699c7e855SJames Marks - Sun Microsystems return (size);
36799c7e855SJames Marks - Sun Microsystems }
36899c7e855SJames Marks - Sun Microsystems
36999c7e855SJames Marks - Sun Microsystems /*
3701d4b38e0Srsmaeda * Common routine to config or unconfig multiple cpus. The unconfig
3711d4b38e0Srsmaeda * case checks with the OS to see if the removal of cpus will be
3721d4b38e0Srsmaeda * permitted, but can be overridden by the "force" version of the
3731d4b38e0Srsmaeda * command. Otherwise, the logic for both cases is identical.
3741d4b38e0Srsmaeda *
3751d4b38e0Srsmaeda * Note: Do not modify result buffer or length on error.
3761ae08745Sheppo */
3771ae08745Sheppo static int
dr_cpu_list_wrk(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)3780c86d1bbSrsmaeda dr_cpu_list_wrk(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
3791ae08745Sheppo {
3801d4b38e0Srsmaeda int rv;
3810c86d1bbSrsmaeda int idx;
3820c86d1bbSrsmaeda int count;
3830c86d1bbSrsmaeda fn_t dr_fn;
3840c86d1bbSrsmaeda int se_hint;
3850c86d1bbSrsmaeda boolean_t force = B_FALSE;
3860c86d1bbSrsmaeda uint32_t *req_cpus;
3870c86d1bbSrsmaeda dr_cpu_res_t *res;
3880c86d1bbSrsmaeda int drctl_cmd;
3890c86d1bbSrsmaeda int drctl_flags = 0;
3900c86d1bbSrsmaeda drctl_rsrc_t *drctl_req;
3910c86d1bbSrsmaeda size_t drctl_req_len;
39299c7e855SJames Marks - Sun Microsystems drctl_resp_t *drctl_resp;
39399c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *drctl_rsrc;
39499c7e855SJames Marks - Sun Microsystems size_t drctl_resp_len = 0;
3950c86d1bbSrsmaeda drctl_cookie_t drctl_res_ck;
3960c86d1bbSrsmaeda
3970c86d1bbSrsmaeda ASSERT((req != NULL) && (req->num_records != 0));
3981ae08745Sheppo
3990c86d1bbSrsmaeda count = req->num_records;
4001ae08745Sheppo
4010c86d1bbSrsmaeda /*
4020c86d1bbSrsmaeda * Extract all information that is specific
4030c86d1bbSrsmaeda * to the various types of operations.
4040c86d1bbSrsmaeda */
4050c86d1bbSrsmaeda switch (req->msg_type) {
4061d4b38e0Srsmaeda case DR_CPU_CONFIGURE:
4070c86d1bbSrsmaeda dr_fn = dr_cpu_configure;
4080c86d1bbSrsmaeda drctl_cmd = DRCTL_CPU_CONFIG_REQUEST;
4090c86d1bbSrsmaeda se_hint = SE_HINT_INSERT;
4101d4b38e0Srsmaeda break;
4111d4b38e0Srsmaeda case DR_CPU_FORCE_UNCONFIG:
4120c86d1bbSrsmaeda drctl_flags = DRCTL_FLAG_FORCE;
4131d4b38e0Srsmaeda force = B_TRUE;
414acdc433cSToomas Soome /* FALLTHROUGH */
4151d4b38e0Srsmaeda case DR_CPU_UNCONFIGURE:
4160c86d1bbSrsmaeda dr_fn = dr_cpu_unconfigure;
4170c86d1bbSrsmaeda drctl_cmd = DRCTL_CPU_UNCONFIG_REQUEST;
4180c86d1bbSrsmaeda se_hint = SE_HINT_REMOVE;
4191d4b38e0Srsmaeda break;
4201d4b38e0Srsmaeda default:
4211d4b38e0Srsmaeda /* Programming error if we reach this. */
42299c7e855SJames Marks - Sun Microsystems cmn_err(CE_NOTE,
42399c7e855SJames Marks - Sun Microsystems "%s: bad msg_type %d\n", __func__, req->msg_type);
4241d4b38e0Srsmaeda ASSERT(0);
4251d4b38e0Srsmaeda return (-1);
4261ae08745Sheppo }
4271ae08745Sheppo
4280c86d1bbSrsmaeda /* the incoming array of cpuids to operate on */
4290c86d1bbSrsmaeda req_cpus = DR_CPU_CMD_CPUIDS(req);
4301d4b38e0Srsmaeda
4311d4b38e0Srsmaeda /* allocate drctl request msg based on incoming resource count */
4320c86d1bbSrsmaeda drctl_req_len = sizeof (drctl_rsrc_t) * count;
4330c86d1bbSrsmaeda drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
43499c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
43599c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
4361d4b38e0Srsmaeda
4371d4b38e0Srsmaeda /* copy the cpuids for the drctl call from the incoming request msg */
4381d4b38e0Srsmaeda for (idx = 0; idx < count; idx++)
4390c86d1bbSrsmaeda drctl_req[idx].res_cpu_id = req_cpus[idx];
4401d4b38e0Srsmaeda
44199c7e855SJames Marks - Sun Microsystems rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
44299c7e855SJames Marks - Sun Microsystems count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
44399c7e855SJames Marks - Sun Microsystems
44499c7e855SJames Marks - Sun Microsystems ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
44599c7e855SJames Marks - Sun Microsystems
44699c7e855SJames Marks - Sun Microsystems if (rv != 0) {
44799c7e855SJames Marks - Sun Microsystems DR_DBG_CPU("%s: drctl_config_init "
44899c7e855SJames Marks - Sun Microsystems "returned: %d\n", __func__, rv);
44999c7e855SJames Marks - Sun Microsystems
45099c7e855SJames Marks - Sun Microsystems if (DRCPU_VERS_EQ(1, 0)) {
45199c7e855SJames Marks - Sun Microsystems rv = -1;
45299c7e855SJames Marks - Sun Microsystems } else {
45399c7e855SJames Marks - Sun Microsystems ASSERT(DRCPU_VERS_GTEQ(1, 1));
45499c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
45599c7e855SJames Marks - Sun Microsystems
45699c7e855SJames Marks - Sun Microsystems *resp_len = dr_cpu_err_resp(req,
45799c7e855SJames Marks - Sun Microsystems resp, drctl_resp->resp_err_msg);
4581d4b38e0Srsmaeda }
4591d4b38e0Srsmaeda
46099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
46199c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len);
46299c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len);
46399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
46499c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
46599c7e855SJames Marks - Sun Microsystems kmem_free(drctl_req, drctl_req_len);
46699c7e855SJames Marks - Sun Microsystems
46799c7e855SJames Marks - Sun Microsystems return (rv);
46899c7e855SJames Marks - Sun Microsystems }
46999c7e855SJames Marks - Sun Microsystems
47099c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
47199c7e855SJames Marks - Sun Microsystems
47299c7e855SJames Marks - Sun Microsystems drctl_rsrc = drctl_resp->resp_resources;
4730c86d1bbSrsmaeda
4740c86d1bbSrsmaeda /* create the result scratch array */
47599c7e855SJames Marks - Sun Microsystems res = dr_cpu_res_array_init(req, drctl_rsrc, count);
4761d4b38e0Srsmaeda
4771d4b38e0Srsmaeda /*
4780c86d1bbSrsmaeda * For unconfigure, check if there are any conditions
4790c86d1bbSrsmaeda * that will cause the operation to fail. These are
4800c86d1bbSrsmaeda * performed before the actual unconfigure attempt so
4810c86d1bbSrsmaeda * that a meaningful error message can be generated.
4821d4b38e0Srsmaeda */
4830c86d1bbSrsmaeda if (req->msg_type != DR_CPU_CONFIGURE)
4840c86d1bbSrsmaeda dr_cpu_check_cpus(req, res);
4851d4b38e0Srsmaeda
4860c86d1bbSrsmaeda /* perform the specified operation on each of the CPUs */
4871d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) {
4880c86d1bbSrsmaeda int result;
4890c86d1bbSrsmaeda int status;
4901d4b38e0Srsmaeda
4911d4b38e0Srsmaeda /*
4920c86d1bbSrsmaeda * If no action will be taken against the current
4930c86d1bbSrsmaeda * CPU, update the drctl resource information to
4940c86d1bbSrsmaeda * ensure that it gets recovered properly during
4950c86d1bbSrsmaeda * the drctl fini() call.
4961d4b38e0Srsmaeda */
4970c86d1bbSrsmaeda if (res[idx].result != DR_CPU_RES_OK) {
4980c86d1bbSrsmaeda drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
4990c86d1bbSrsmaeda continue;
5001d4b38e0Srsmaeda }
5011d4b38e0Srsmaeda
5020c86d1bbSrsmaeda /* call the function to perform the actual operation */
5030c86d1bbSrsmaeda result = (*dr_fn)(req_cpus[idx], &status, force);
5041d4b38e0Srsmaeda
5050c86d1bbSrsmaeda /* save off results of the operation */
5060c86d1bbSrsmaeda res[idx].result = result;
5070c86d1bbSrsmaeda res[idx].status = status;
5081d4b38e0Srsmaeda
5090c86d1bbSrsmaeda /* save result for drctl fini() reusing init() msg memory */
5100c86d1bbSrsmaeda drctl_req[idx].status = (result != DR_CPU_RES_OK) ?
5110c86d1bbSrsmaeda DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
5121d4b38e0Srsmaeda
5130c86d1bbSrsmaeda DR_DBG_CPU("%s: cpuid %d status %d result %d off '%s'\n",
51499c7e855SJames Marks - Sun Microsystems __func__, req_cpus[idx], drctl_req[idx].status, result,
5150c86d1bbSrsmaeda (res[idx].string) ? res[idx].string : "");
5160c86d1bbSrsmaeda }
5171d4b38e0Srsmaeda
5180c86d1bbSrsmaeda if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
51999c7e855SJames Marks - Sun Microsystems DR_DBG_CPU("%s: drctl_config_fini "
52099c7e855SJames Marks - Sun Microsystems "returned: %d\n", __func__, rv);
5211ae08745Sheppo
5220c86d1bbSrsmaeda /*
5230c86d1bbSrsmaeda * Operation completed without any fatal errors.
5240c86d1bbSrsmaeda * Pack the response for transmission.
5250c86d1bbSrsmaeda */
5260c86d1bbSrsmaeda *resp_len = dr_cpu_pack_response(req, res, resp);
5270c86d1bbSrsmaeda
5280c86d1bbSrsmaeda /* notify interested parties about the operation */
5290c86d1bbSrsmaeda dr_generate_event(DR_TYPE_CPU, se_hint);
5300c86d1bbSrsmaeda
5310c86d1bbSrsmaeda /*
5320c86d1bbSrsmaeda * Deallocate any scratch memory.
5330c86d1bbSrsmaeda */
53499c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
53599c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len);
53699c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len);
53799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
53899c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len);
5390c86d1bbSrsmaeda kmem_free(drctl_req, drctl_req_len);
5400c86d1bbSrsmaeda
5410c86d1bbSrsmaeda dr_cpu_res_array_fini(res, count);
5421ae08745Sheppo
5431ae08745Sheppo return (0);
5441ae08745Sheppo }
5451ae08745Sheppo
5460c86d1bbSrsmaeda /*
5470c86d1bbSrsmaeda * Allocate and initialize a result array based on the initial
5480c86d1bbSrsmaeda * drctl operation. A valid result array is always returned.
5490c86d1bbSrsmaeda */
5500c86d1bbSrsmaeda static dr_cpu_res_t *
dr_cpu_res_array_init(dr_cpu_hdr_t * req,drctl_rsrc_t * rsrc,int nrsrc)5510c86d1bbSrsmaeda dr_cpu_res_array_init(dr_cpu_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
5521ae08745Sheppo {
5531ae08745Sheppo int idx;
5540c86d1bbSrsmaeda dr_cpu_res_t *res;
5550c86d1bbSrsmaeda char *err_str;
5560c86d1bbSrsmaeda size_t err_len;
5570c86d1bbSrsmaeda
5580c86d1bbSrsmaeda /* allocate zero filled buffer to initialize fields */
5590c86d1bbSrsmaeda res = kmem_zalloc(nrsrc * sizeof (dr_cpu_res_t), KM_SLEEP);
56099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
56199c7e855SJames Marks - Sun Microsystems __func__, (void *)res, nrsrc * sizeof (dr_cpu_res_t));
5620c86d1bbSrsmaeda
5630c86d1bbSrsmaeda /*
5640c86d1bbSrsmaeda * Fill in the result information for each resource.
5650c86d1bbSrsmaeda */
5660c86d1bbSrsmaeda for (idx = 0; idx < nrsrc; idx++) {
5670c86d1bbSrsmaeda res[idx].cpuid = rsrc[idx].res_cpu_id;
5680c86d1bbSrsmaeda res[idx].result = DR_CPU_RES_OK;
5690c86d1bbSrsmaeda
5700c86d1bbSrsmaeda if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
5710c86d1bbSrsmaeda continue;
5720c86d1bbSrsmaeda
5730c86d1bbSrsmaeda /*
5740c86d1bbSrsmaeda * Update the state information for this CPU.
5750c86d1bbSrsmaeda */
5760c86d1bbSrsmaeda res[idx].result = DR_CPU_RES_BLOCKED;
5770c86d1bbSrsmaeda res[idx].status = (req->msg_type == DR_CPU_CONFIGURE) ?
5780c86d1bbSrsmaeda DR_CPU_STAT_UNCONFIGURED : DR_CPU_STAT_CONFIGURED;
5790c86d1bbSrsmaeda
5800c86d1bbSrsmaeda /*
5810c86d1bbSrsmaeda * If an error string exists, copy it out of the
5820c86d1bbSrsmaeda * message buffer. This eliminates any dependency
5830c86d1bbSrsmaeda * on the memory allocated for the message buffer
5840c86d1bbSrsmaeda * itself.
5850c86d1bbSrsmaeda */
586a6c18717SToomas Soome if (rsrc[idx].offset != 0) {
5870c86d1bbSrsmaeda err_str = (char *)rsrc + rsrc[idx].offset;
5880c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
5890c86d1bbSrsmaeda
5900c86d1bbSrsmaeda res[idx].string = kmem_alloc(err_len, KM_SLEEP);
59199c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
59299c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[idx].string), err_len);
5930c86d1bbSrsmaeda bcopy(err_str, res[idx].string, err_len);
5940c86d1bbSrsmaeda }
5950c86d1bbSrsmaeda }
5960c86d1bbSrsmaeda
5970c86d1bbSrsmaeda return (res);
5980c86d1bbSrsmaeda }
5990c86d1bbSrsmaeda
6000c86d1bbSrsmaeda static void
dr_cpu_res_array_fini(dr_cpu_res_t * res,int nres)6010c86d1bbSrsmaeda dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres)
6020c86d1bbSrsmaeda {
6030c86d1bbSrsmaeda int idx;
6040c86d1bbSrsmaeda size_t str_len;
6050c86d1bbSrsmaeda
6060c86d1bbSrsmaeda for (idx = 0; idx < nres; idx++) {
6070c86d1bbSrsmaeda /* deallocate the error string if present */
6080c86d1bbSrsmaeda if (res[idx].string) {
6090c86d1bbSrsmaeda str_len = strlen(res[idx].string) + 1;
61099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
61199c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[idx].string), str_len);
6120c86d1bbSrsmaeda kmem_free(res[idx].string, str_len);
6130c86d1bbSrsmaeda }
6140c86d1bbSrsmaeda }
6150c86d1bbSrsmaeda
6160c86d1bbSrsmaeda /* deallocate the result array itself */
61799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
61899c7e855SJames Marks - Sun Microsystems __func__, (void *)res, sizeof (dr_cpu_res_t) * nres);
6190c86d1bbSrsmaeda kmem_free(res, sizeof (dr_cpu_res_t) * nres);
6200c86d1bbSrsmaeda }
6210c86d1bbSrsmaeda
6220c86d1bbSrsmaeda /*
6230c86d1bbSrsmaeda * Allocate and pack a response message for transmission based
6240c86d1bbSrsmaeda * on the specified result array. A valid response message and
6250c86d1bbSrsmaeda * valid size information is always returned.
6260c86d1bbSrsmaeda */
6270c86d1bbSrsmaeda static size_t
dr_cpu_pack_response(dr_cpu_hdr_t * req,dr_cpu_res_t * res,dr_cpu_hdr_t ** respp)6280c86d1bbSrsmaeda dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, dr_cpu_hdr_t **respp)
6290c86d1bbSrsmaeda {
6300c86d1bbSrsmaeda int idx;
6310c86d1bbSrsmaeda dr_cpu_hdr_t *resp;
6320c86d1bbSrsmaeda dr_cpu_stat_t *resp_stat;
6330c86d1bbSrsmaeda size_t resp_len;
6340c86d1bbSrsmaeda uint32_t curr_off;
6350c86d1bbSrsmaeda caddr_t curr_str;
6360c86d1bbSrsmaeda size_t str_len;
6370c86d1bbSrsmaeda size_t stat_len;
6380c86d1bbSrsmaeda int nstat = req->num_records;
6390c86d1bbSrsmaeda
6400c86d1bbSrsmaeda /*
6410c86d1bbSrsmaeda * Calculate the size of the response message
6420c86d1bbSrsmaeda * and allocate an appropriately sized buffer.
6430c86d1bbSrsmaeda */
6440c86d1bbSrsmaeda resp_len = 0;
6450c86d1bbSrsmaeda
6460c86d1bbSrsmaeda /* add the header size */
6470c86d1bbSrsmaeda resp_len += sizeof (dr_cpu_hdr_t);
6480c86d1bbSrsmaeda
6490c86d1bbSrsmaeda /* add the stat array size */
6500c86d1bbSrsmaeda stat_len = sizeof (dr_cpu_stat_t) * nstat;
6510c86d1bbSrsmaeda resp_len += stat_len;
6520c86d1bbSrsmaeda
6530c86d1bbSrsmaeda /* add the size of any error strings */
6540c86d1bbSrsmaeda for (idx = 0; idx < nstat; idx++) {
6550c86d1bbSrsmaeda if (res[idx].string != NULL) {
6560c86d1bbSrsmaeda resp_len += strlen(res[idx].string) + 1;
6570c86d1bbSrsmaeda }
6580c86d1bbSrsmaeda }
6590c86d1bbSrsmaeda
6600c86d1bbSrsmaeda /* allocate the message buffer */
6610c86d1bbSrsmaeda resp = kmem_zalloc(resp_len, KM_SLEEP);
66299c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
66399c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, resp_len);
6640c86d1bbSrsmaeda
6650c86d1bbSrsmaeda /*
6660c86d1bbSrsmaeda * Fill in the header information.
6670c86d1bbSrsmaeda */
6680c86d1bbSrsmaeda resp->req_num = req->req_num;
6690c86d1bbSrsmaeda resp->msg_type = DR_CPU_OK;
6700c86d1bbSrsmaeda resp->num_records = nstat;
6710c86d1bbSrsmaeda
6720c86d1bbSrsmaeda /*
6730c86d1bbSrsmaeda * Fill in the stat information.
6740c86d1bbSrsmaeda */
6750c86d1bbSrsmaeda resp_stat = DR_CPU_RESP_STATS(resp);
6760c86d1bbSrsmaeda
6770c86d1bbSrsmaeda /* string offsets start immediately after stat array */
6780c86d1bbSrsmaeda curr_off = sizeof (dr_cpu_hdr_t) + stat_len;
6790c86d1bbSrsmaeda curr_str = (char *)resp_stat + stat_len;
6800c86d1bbSrsmaeda
6810c86d1bbSrsmaeda for (idx = 0; idx < nstat; idx++) {
6820c86d1bbSrsmaeda resp_stat[idx].cpuid = res[idx].cpuid;
6830c86d1bbSrsmaeda resp_stat[idx].result = res[idx].result;
6840c86d1bbSrsmaeda resp_stat[idx].status = res[idx].status;
6850c86d1bbSrsmaeda
6860c86d1bbSrsmaeda if (res[idx].string != NULL) {
6870c86d1bbSrsmaeda /* copy over the error string */
6880c86d1bbSrsmaeda str_len = strlen(res[idx].string) + 1;
6890c86d1bbSrsmaeda bcopy(res[idx].string, curr_str, str_len);
6900c86d1bbSrsmaeda resp_stat[idx].string_off = curr_off;
6910c86d1bbSrsmaeda
6920c86d1bbSrsmaeda curr_off += str_len;
6930c86d1bbSrsmaeda curr_str += str_len;
6940c86d1bbSrsmaeda }
6950c86d1bbSrsmaeda }
6960c86d1bbSrsmaeda
6970c86d1bbSrsmaeda /* buffer should be exactly filled */
6980c86d1bbSrsmaeda ASSERT(curr_off == resp_len);
6990c86d1bbSrsmaeda
7000c86d1bbSrsmaeda *respp = resp;
7010c86d1bbSrsmaeda return (resp_len);
7020c86d1bbSrsmaeda }
7030c86d1bbSrsmaeda
7040c86d1bbSrsmaeda /*
7050c86d1bbSrsmaeda * Check for conditions that will prevent a CPU from being offlined.
7060c86d1bbSrsmaeda * This provides the opportunity to generate useful information to
7070c86d1bbSrsmaeda * help diagnose the failure rather than letting the offline attempt
7080c86d1bbSrsmaeda * fail in a more generic way.
7090c86d1bbSrsmaeda */
7100c86d1bbSrsmaeda static void
dr_cpu_check_cpus(dr_cpu_hdr_t * req,dr_cpu_res_t * res)7110c86d1bbSrsmaeda dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res)
7120c86d1bbSrsmaeda {
7130c86d1bbSrsmaeda int idx;
7140c86d1bbSrsmaeda cpu_t *cp;
7150c86d1bbSrsmaeda uint32_t *cpuids;
7160c86d1bbSrsmaeda
7170c86d1bbSrsmaeda ASSERT((req->msg_type == DR_CPU_UNCONFIGURE) ||
7180c86d1bbSrsmaeda (req->msg_type == DR_CPU_FORCE_UNCONFIG));
7191ae08745Sheppo
7201ae08745Sheppo DR_DBG_CPU("dr_cpu_check_cpus...\n");
7211ae08745Sheppo
7220c86d1bbSrsmaeda /* array of cpuids start just after the header */
7230c86d1bbSrsmaeda cpuids = DR_CPU_CMD_CPUIDS(req);
7240c86d1bbSrsmaeda
7251ae08745Sheppo mutex_enter(&cpu_lock);
7261ae08745Sheppo
7270c86d1bbSrsmaeda /*
7280c86d1bbSrsmaeda * Always check processor set membership first. The
7290c86d1bbSrsmaeda * last CPU in a processor set will fail to offline
7300c86d1bbSrsmaeda * even if the operation if forced, so any failures
7310c86d1bbSrsmaeda * should always be reported.
7320c86d1bbSrsmaeda */
7330c86d1bbSrsmaeda dr_cpu_check_psrset(cpuids, res, req->num_records);
7341ae08745Sheppo
7350c86d1bbSrsmaeda /* process each cpu that is part of the request */
7360c86d1bbSrsmaeda for (idx = 0; idx < req->num_records; idx++) {
7370c86d1bbSrsmaeda
7380c86d1bbSrsmaeda /* nothing to check if the CPU has already failed */
7390c86d1bbSrsmaeda if (res[idx].result != DR_CPU_RES_OK)
7401ae08745Sheppo continue;
7411ae08745Sheppo
7420c86d1bbSrsmaeda if ((cp = cpu_get(cpuids[idx])) == NULL)
7430c86d1bbSrsmaeda continue;
7441ae08745Sheppo
7451ae08745Sheppo /*
7460c86d1bbSrsmaeda * Only check if there are bound threads if the
7470c86d1bbSrsmaeda * operation is not a forced unconfigure. In a
7480c86d1bbSrsmaeda * forced request, threads are automatically
7490c86d1bbSrsmaeda * unbound before they are offlined.
7501ae08745Sheppo */
7510c86d1bbSrsmaeda if (req->msg_type == DR_CPU_UNCONFIGURE) {
7520c86d1bbSrsmaeda /*
7530c86d1bbSrsmaeda * The return value is only interesting if other
7540c86d1bbSrsmaeda * checks are added to this loop and a decision
7550c86d1bbSrsmaeda * is needed on whether to continue checking.
7560c86d1bbSrsmaeda */
7570c86d1bbSrsmaeda (void) dr_cpu_check_bound_thr(cp, &res[idx]);
7581ae08745Sheppo }
7591ae08745Sheppo }
7601ae08745Sheppo
7611ae08745Sheppo mutex_exit(&cpu_lock);
7621ae08745Sheppo }
7631ae08745Sheppo
7640c86d1bbSrsmaeda /*
7650c86d1bbSrsmaeda * Examine the processor set configuration for the specified
7660c86d1bbSrsmaeda * CPUs and see if the unconfigure operation would result in
7670c86d1bbSrsmaeda * trying to remove the last CPU in any processor set.
7680c86d1bbSrsmaeda */
7690c86d1bbSrsmaeda static void
dr_cpu_check_psrset(uint32_t * cpuids,dr_cpu_res_t * res,int nres)7700c86d1bbSrsmaeda dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres)
7710c86d1bbSrsmaeda {
7720c86d1bbSrsmaeda int cpu_idx;
7730c86d1bbSrsmaeda int set_idx;
7740c86d1bbSrsmaeda cpu_t *cp;
7750c86d1bbSrsmaeda cpupart_t *cpp;
7760c86d1bbSrsmaeda char err_str[DR_CPU_MAX_ERR_LEN];
7770c86d1bbSrsmaeda size_t err_len;
7780c86d1bbSrsmaeda struct {
7790c86d1bbSrsmaeda cpupart_t *cpp;
7800c86d1bbSrsmaeda int ncpus;
7810c86d1bbSrsmaeda } *psrset;
7820c86d1bbSrsmaeda
7830c86d1bbSrsmaeda ASSERT(MUTEX_HELD(&cpu_lock));
7840c86d1bbSrsmaeda
7850c86d1bbSrsmaeda /*
7860c86d1bbSrsmaeda * Allocate a scratch array to count the CPUs in
7870c86d1bbSrsmaeda * the various processor sets. A CPU always belongs
7880c86d1bbSrsmaeda * to exactly one processor set, so by definition,
7890c86d1bbSrsmaeda * the scratch array never needs to be larger than
7900c86d1bbSrsmaeda * the number of CPUs.
7910c86d1bbSrsmaeda */
7920c86d1bbSrsmaeda psrset = kmem_zalloc(sizeof (*psrset) * nres, KM_SLEEP);
79399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
79499c7e855SJames Marks - Sun Microsystems __func__, (void *)psrset, sizeof (*psrset) * nres);
7950c86d1bbSrsmaeda
7960c86d1bbSrsmaeda for (cpu_idx = 0; cpu_idx < nres; cpu_idx++) {
7970c86d1bbSrsmaeda
7980c86d1bbSrsmaeda /* skip any CPUs that have already failed */
7990c86d1bbSrsmaeda if (res[cpu_idx].result != DR_CPU_RES_OK)
8000c86d1bbSrsmaeda continue;
8010c86d1bbSrsmaeda
8020c86d1bbSrsmaeda if ((cp = cpu_get(cpuids[cpu_idx])) == NULL)
8030c86d1bbSrsmaeda continue;
8040c86d1bbSrsmaeda
8050c86d1bbSrsmaeda cpp = cp->cpu_part;
8060c86d1bbSrsmaeda
8070c86d1bbSrsmaeda /* lookup the set this CPU belongs to */
8080c86d1bbSrsmaeda for (set_idx = 0; set_idx < nres; set_idx++) {
8090c86d1bbSrsmaeda
8100c86d1bbSrsmaeda /* matching set found */
8110c86d1bbSrsmaeda if (cpp == psrset[set_idx].cpp)
8120c86d1bbSrsmaeda break;
8130c86d1bbSrsmaeda
8140c86d1bbSrsmaeda /* set not found, start a new entry */
8150c86d1bbSrsmaeda if (psrset[set_idx].cpp == NULL) {
8160c86d1bbSrsmaeda psrset[set_idx].cpp = cpp;
8170c86d1bbSrsmaeda psrset[set_idx].ncpus = cpp->cp_ncpus;
8180c86d1bbSrsmaeda break;
8190c86d1bbSrsmaeda }
8200c86d1bbSrsmaeda }
8210c86d1bbSrsmaeda
8220c86d1bbSrsmaeda ASSERT(set_idx != nres);
8230c86d1bbSrsmaeda
8240c86d1bbSrsmaeda /*
8250c86d1bbSrsmaeda * Remove the current CPU from the set total but only
8260c86d1bbSrsmaeda * generate an error for the last CPU. The correct CPU
8270c86d1bbSrsmaeda * will get the error because the unconfigure attempts
8280c86d1bbSrsmaeda * will occur in the same order in which the CPUs are
8295f1655c9SJames Marks - Sun Microsystems * examined in this loop. The cp_ncpus field of a
8305f1655c9SJames Marks - Sun Microsystems * cpupart_t counts only online cpus, so it is safe
8315f1655c9SJames Marks - Sun Microsystems * to remove an offline cpu without testing ncpus.
8320c86d1bbSrsmaeda */
8337de586caSJames Marks - Sun Microsystems if (cpu_is_offline(cp))
8345f1655c9SJames Marks - Sun Microsystems continue;
8355f1655c9SJames Marks - Sun Microsystems
8360c86d1bbSrsmaeda if (--psrset[set_idx].ncpus == 0) {
8370c86d1bbSrsmaeda /*
8380c86d1bbSrsmaeda * Fill in the various pieces of information
8390c86d1bbSrsmaeda * to report that the operation will fail.
8400c86d1bbSrsmaeda */
8410c86d1bbSrsmaeda res[cpu_idx].result = DR_CPU_RES_BLOCKED;
8420c86d1bbSrsmaeda res[cpu_idx].status = DR_CPU_STAT_CONFIGURED;
8430c86d1bbSrsmaeda
8440c86d1bbSrsmaeda (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN,
8450c86d1bbSrsmaeda "last online cpu in processor set %d", cpp->cp_id);
8460c86d1bbSrsmaeda
8470c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
8480c86d1bbSrsmaeda
8490c86d1bbSrsmaeda res[cpu_idx].string = kmem_alloc(err_len, KM_SLEEP);
85099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
85199c7e855SJames Marks - Sun Microsystems __func__, (void *)(res[cpu_idx].string), err_len);
8520c86d1bbSrsmaeda bcopy(err_str, res[cpu_idx].string, err_len);
8530c86d1bbSrsmaeda
8540c86d1bbSrsmaeda DR_DBG_CPU("cpu %d: %s\n", cpuids[cpu_idx], err_str);
8550c86d1bbSrsmaeda }
8560c86d1bbSrsmaeda }
8570c86d1bbSrsmaeda
85899c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n",
85999c7e855SJames Marks - Sun Microsystems __func__, (void *)psrset, sizeof (*psrset) * nres);
8600c86d1bbSrsmaeda kmem_free(psrset, sizeof (*psrset) * nres);
8610c86d1bbSrsmaeda }
8620c86d1bbSrsmaeda
8630c86d1bbSrsmaeda /*
8640c86d1bbSrsmaeda * Check if any threads are bound to the specified CPU. If the
8650c86d1bbSrsmaeda * condition is true, DR_CPU_RES_BLOCKED is returned and an error
8660c86d1bbSrsmaeda * string is generated and placed in the specified result structure.
8670c86d1bbSrsmaeda * Otherwise, DR_CPU_RES_OK is returned.
8680c86d1bbSrsmaeda */
8690c86d1bbSrsmaeda static int
dr_cpu_check_bound_thr(cpu_t * cp,dr_cpu_res_t * res)8700c86d1bbSrsmaeda dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res)
8710c86d1bbSrsmaeda {
8720c86d1bbSrsmaeda int nbound;
8730c86d1bbSrsmaeda proc_t *pp;
8740c86d1bbSrsmaeda kthread_t *tp;
8750c86d1bbSrsmaeda char err_str[DR_CPU_MAX_ERR_LEN];
8760c86d1bbSrsmaeda size_t err_len;
8770c86d1bbSrsmaeda
8780c86d1bbSrsmaeda /*
8790c86d1bbSrsmaeda * Error string allocation makes an assumption
8800c86d1bbSrsmaeda * that no blocking condition has been identified.
8810c86d1bbSrsmaeda */
8820c86d1bbSrsmaeda ASSERT(res->result == DR_CPU_RES_OK);
8830c86d1bbSrsmaeda ASSERT(res->string == NULL);
8840c86d1bbSrsmaeda
8850c86d1bbSrsmaeda ASSERT(MUTEX_HELD(&cpu_lock));
8860c86d1bbSrsmaeda
8870c86d1bbSrsmaeda mutex_enter(&pidlock);
8880c86d1bbSrsmaeda
8890c86d1bbSrsmaeda nbound = 0;
8900c86d1bbSrsmaeda
8910c86d1bbSrsmaeda /*
8920c86d1bbSrsmaeda * Walk the active processes, checking if each
8930c86d1bbSrsmaeda * thread belonging to the process is bound.
8940c86d1bbSrsmaeda */
8950c86d1bbSrsmaeda for (pp = practive; (pp != NULL) && (nbound <= 1); pp = pp->p_next) {
8960c86d1bbSrsmaeda mutex_enter(&pp->p_lock);
8970c86d1bbSrsmaeda
8980c86d1bbSrsmaeda tp = pp->p_tlist;
8990c86d1bbSrsmaeda
9000c86d1bbSrsmaeda if ((tp == NULL) || (pp->p_flag & SSYS)) {
9010c86d1bbSrsmaeda mutex_exit(&pp->p_lock);
9020c86d1bbSrsmaeda continue;
9030c86d1bbSrsmaeda }
9040c86d1bbSrsmaeda
9050c86d1bbSrsmaeda do {
9060c86d1bbSrsmaeda if (tp->t_bind_cpu != cp->cpu_id)
9070c86d1bbSrsmaeda continue;
9080c86d1bbSrsmaeda
9090c86d1bbSrsmaeda /*
9100c86d1bbSrsmaeda * Update the running total of bound
9110c86d1bbSrsmaeda * threads. Continue the search until
9120c86d1bbSrsmaeda * it can be determined if more than
9130c86d1bbSrsmaeda * one thread is bound to the CPU.
9140c86d1bbSrsmaeda */
9150c86d1bbSrsmaeda if (++nbound > 1)
9160c86d1bbSrsmaeda break;
9170c86d1bbSrsmaeda
9180c86d1bbSrsmaeda } while ((tp = tp->t_forw) != pp->p_tlist);
9190c86d1bbSrsmaeda
9200c86d1bbSrsmaeda mutex_exit(&pp->p_lock);
9210c86d1bbSrsmaeda }
9220c86d1bbSrsmaeda
9230c86d1bbSrsmaeda mutex_exit(&pidlock);
9240c86d1bbSrsmaeda
9250c86d1bbSrsmaeda if (nbound) {
9260c86d1bbSrsmaeda /*
9270c86d1bbSrsmaeda * Threads are bound to the CPU. Fill in
9280c86d1bbSrsmaeda * various pieces of information to report
9290c86d1bbSrsmaeda * that the operation will fail.
9300c86d1bbSrsmaeda */
9310c86d1bbSrsmaeda res->result = DR_CPU_RES_BLOCKED;
9320c86d1bbSrsmaeda res->status = DR_CPU_STAT_CONFIGURED;
9330c86d1bbSrsmaeda
9340c86d1bbSrsmaeda (void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, "cpu has bound "
9350c86d1bbSrsmaeda "thread%s", (nbound > 1) ? "s" : "");
9360c86d1bbSrsmaeda
9370c86d1bbSrsmaeda err_len = strlen(err_str) + 1;
9380c86d1bbSrsmaeda
9390c86d1bbSrsmaeda res->string = kmem_alloc(err_len, KM_SLEEP);
94099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
94199c7e855SJames Marks - Sun Microsystems __func__, (void *)(res->string), err_len);
9420c86d1bbSrsmaeda bcopy(err_str, res->string, err_len);
9430c86d1bbSrsmaeda
9440c86d1bbSrsmaeda DR_DBG_CPU("cpu %d: %s\n", cp->cpu_id, err_str);
9450c86d1bbSrsmaeda }
9460c86d1bbSrsmaeda
9470c86d1bbSrsmaeda return (res->result);
9480c86d1bbSrsmaeda }
9491ae08745Sheppo
9501ae08745Sheppo /*
9511ae08745Sheppo * Do not modify result buffer or length on error.
9521ae08745Sheppo */
9531ae08745Sheppo static int
dr_cpu_list_status(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)9541ae08745Sheppo dr_cpu_list_status(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
9551ae08745Sheppo {
9561ae08745Sheppo int idx;
9571ae08745Sheppo int result;
9581ae08745Sheppo int status;
9591ae08745Sheppo int rlen;
9601ae08745Sheppo uint32_t *cpuids;
9611ae08745Sheppo dr_cpu_hdr_t *rp;
9621ae08745Sheppo dr_cpu_stat_t *stat;
9631ae08745Sheppo md_t *mdp = NULL;
9641ae08745Sheppo int num_nodes;
9651ae08745Sheppo int listsz;
9661ae08745Sheppo mde_cookie_t *listp = NULL;
9671ae08745Sheppo mde_cookie_t cpunode;
9681ae08745Sheppo boolean_t walk_md = B_FALSE;
9691ae08745Sheppo
9701ae08745Sheppo /* the incoming array of cpuids to configure */
9710c86d1bbSrsmaeda cpuids = DR_CPU_CMD_CPUIDS(req);
9721ae08745Sheppo
9731ae08745Sheppo /* allocate a response message */
9741ae08745Sheppo rlen = sizeof (dr_cpu_hdr_t);
9751ae08745Sheppo rlen += req->num_records * sizeof (dr_cpu_stat_t);
9761ae08745Sheppo rp = kmem_zalloc(rlen, KM_SLEEP);
97799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n", __func__, (void *)rp, rlen);
9781ae08745Sheppo
9791ae08745Sheppo /* fill in the known data */
9801ae08745Sheppo rp->req_num = req->req_num;
9811ae08745Sheppo rp->msg_type = DR_CPU_STATUS;
9821ae08745Sheppo rp->num_records = req->num_records;
9831ae08745Sheppo
9841ae08745Sheppo /* stat array for the response */
9850c86d1bbSrsmaeda stat = DR_CPU_RESP_STATS(rp);
9861ae08745Sheppo
9871ae08745Sheppo /* get the status for each of the CPUs */
9881ae08745Sheppo for (idx = 0; idx < req->num_records; idx++) {
9891ae08745Sheppo
9901ae08745Sheppo result = dr_cpu_status(cpuids[idx], &status);
9911ae08745Sheppo
9921ae08745Sheppo if (result == DR_CPU_RES_FAILURE)
9931ae08745Sheppo walk_md = B_TRUE;
9941ae08745Sheppo
9951ae08745Sheppo /* save off results of the status */
9961ae08745Sheppo stat[idx].cpuid = cpuids[idx];
9971ae08745Sheppo stat[idx].result = result;
9981ae08745Sheppo stat[idx].status = status;
9991ae08745Sheppo }
10001ae08745Sheppo
10011ae08745Sheppo if (walk_md == B_FALSE)
10021ae08745Sheppo goto done;
10031ae08745Sheppo
10041ae08745Sheppo /*
10051ae08745Sheppo * At least one of the cpus did not have a CPU
10061ae08745Sheppo * structure. So, consult the MD to determine if
10071ae08745Sheppo * they are present.
10081ae08745Sheppo */
10091ae08745Sheppo
10101ae08745Sheppo if ((mdp = md_get_handle()) == NULL) {
10111ae08745Sheppo DR_DBG_CPU("unable to initialize MD\n");
10121ae08745Sheppo goto done;
10131ae08745Sheppo }
10141ae08745Sheppo
10151ae08745Sheppo num_nodes = md_node_count(mdp);
10161ae08745Sheppo ASSERT(num_nodes > 0);
10171ae08745Sheppo
10181ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
10191ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP);
102099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
102199c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
10221ae08745Sheppo
10231ae08745Sheppo for (idx = 0; idx < req->num_records; idx++) {
10241ae08745Sheppo
10251ae08745Sheppo if (stat[idx].result != DR_CPU_RES_FAILURE)
10261ae08745Sheppo continue;
10271ae08745Sheppo
10281ae08745Sheppo /* check the MD for the current cpuid */
10291ae08745Sheppo cpunode = dr_cpu_find_node_md(stat[idx].cpuid, mdp, listp);
10301ae08745Sheppo
10311ae08745Sheppo stat[idx].result = DR_CPU_RES_OK;
10321ae08745Sheppo
10331ae08745Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) {
10341ae08745Sheppo stat[idx].status = DR_CPU_STAT_NOT_PRESENT;
10351ae08745Sheppo } else {
10361ae08745Sheppo stat[idx].status = DR_CPU_STAT_UNCONFIGURED;
10371ae08745Sheppo }
10381ae08745Sheppo }
10391ae08745Sheppo
104099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
104199c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
10421ae08745Sheppo kmem_free(listp, listsz);
10431ae08745Sheppo
10441ae08745Sheppo (void) md_fini_handle(mdp);
10451ae08745Sheppo
10461ae08745Sheppo done:
10471ae08745Sheppo *resp = rp;
10481ae08745Sheppo *resp_len = rlen;
10491ae08745Sheppo
10501ae08745Sheppo return (0);
10511ae08745Sheppo }
10521ae08745Sheppo
10531ae08745Sheppo static int
dr_cpu_configure(processorid_t cpuid,int * status,boolean_t force)10541d4b38e0Srsmaeda dr_cpu_configure(processorid_t cpuid, int *status, boolean_t force)
10551ae08745Sheppo {
10561d4b38e0Srsmaeda _NOTE(ARGUNUSED(force))
10571ae08745Sheppo struct cpu *cp;
10581ae08745Sheppo int rv = 0;
10591ae08745Sheppo
10601ae08745Sheppo DR_DBG_CPU("dr_cpu_configure...\n");
10611ae08745Sheppo
10621ae08745Sheppo /*
10631ae08745Sheppo * Build device tree node for the CPU
10641ae08745Sheppo */
10651ae08745Sheppo if ((rv = dr_cpu_probe(cpuid)) != 0) {
10661ae08745Sheppo DR_DBG_CPU("failed to probe CPU %d (%d)\n", cpuid, rv);
10671ae08745Sheppo if (rv == EINVAL) {
10681ae08745Sheppo *status = DR_CPU_STAT_NOT_PRESENT;
10691ae08745Sheppo return (DR_CPU_RES_NOT_IN_MD);
10701ae08745Sheppo }
10711ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
10721ae08745Sheppo return (DR_CPU_RES_FAILURE);
10731ae08745Sheppo }
10741ae08745Sheppo
10751ae08745Sheppo mutex_enter(&cpu_lock);
10761ae08745Sheppo
10771ae08745Sheppo /*
10781ae08745Sheppo * Configure the CPU
10791ae08745Sheppo */
10801ae08745Sheppo if ((cp = cpu_get(cpuid)) == NULL) {
10811ae08745Sheppo
10821ae08745Sheppo if ((rv = cpu_configure(cpuid)) != 0) {
10831ae08745Sheppo DR_DBG_CPU("failed to configure CPU %d (%d)\n",
10841ae08745Sheppo cpuid, rv);
10851ae08745Sheppo rv = DR_CPU_RES_FAILURE;
10861ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
10871ae08745Sheppo goto done;
10881ae08745Sheppo }
10891ae08745Sheppo
10901ae08745Sheppo DR_DBG_CPU("CPU %d configured\n", cpuid);
10911ae08745Sheppo
10921ae08745Sheppo /* CPU struct should exist now */
10931ae08745Sheppo cp = cpu_get(cpuid);
10941ae08745Sheppo }
10951ae08745Sheppo
10961ae08745Sheppo ASSERT(cp);
10971ae08745Sheppo
10981ae08745Sheppo /*
10991ae08745Sheppo * Power on the CPU. In sun4v, this brings the stopped
11001ae08745Sheppo * CPU into the guest from the Hypervisor.
11011ae08745Sheppo */
11021ae08745Sheppo if (cpu_is_poweredoff(cp)) {
11031ae08745Sheppo
11041ae08745Sheppo if ((rv = cpu_poweron(cp)) != 0) {
11051ae08745Sheppo DR_DBG_CPU("failed to power on CPU %d (%d)\n",
11061ae08745Sheppo cpuid, rv);
11071ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11081ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
11091ae08745Sheppo goto done;
11101ae08745Sheppo }
11111ae08745Sheppo
11121ae08745Sheppo DR_DBG_CPU("CPU %d powered on\n", cpuid);
11131ae08745Sheppo }
11141ae08745Sheppo
11151ae08745Sheppo /*
11161ae08745Sheppo * Online the CPU
11171ae08745Sheppo */
11181ae08745Sheppo if (cpu_is_offline(cp)) {
11191ae08745Sheppo
1120c3377ee9SJohn Levon if ((rv = cpu_online(cp, 0)) != 0) {
11211ae08745Sheppo DR_DBG_CPU("failed to online CPU %d (%d)\n",
11221ae08745Sheppo cpuid, rv);
11231ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11241ae08745Sheppo /* offline is still configured */
11251ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
11261ae08745Sheppo goto done;
11271ae08745Sheppo }
11281ae08745Sheppo
11291ae08745Sheppo DR_DBG_CPU("CPU %d online\n", cpuid);
11301ae08745Sheppo }
11311ae08745Sheppo
11321ae08745Sheppo rv = DR_CPU_RES_OK;
11331ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
11341ae08745Sheppo
11351ae08745Sheppo done:
11361ae08745Sheppo mutex_exit(&cpu_lock);
11371ae08745Sheppo
11381ae08745Sheppo return (rv);
11391ae08745Sheppo }
11401ae08745Sheppo
11411ae08745Sheppo static int
dr_cpu_unconfigure(processorid_t cpuid,int * status,boolean_t force)11421ae08745Sheppo dr_cpu_unconfigure(processorid_t cpuid, int *status, boolean_t force)
11431ae08745Sheppo {
11441ae08745Sheppo struct cpu *cp;
11451ae08745Sheppo int rv = 0;
11461ae08745Sheppo int cpu_flags;
11471ae08745Sheppo
11481ae08745Sheppo DR_DBG_CPU("dr_cpu_unconfigure%s...\n", (force) ? " (force)" : "");
11491ae08745Sheppo
11501ae08745Sheppo mutex_enter(&cpu_lock);
11511ae08745Sheppo
11521ae08745Sheppo cp = cpu_get(cpuid);
11531ae08745Sheppo
11541ae08745Sheppo if (cp == NULL) {
11551ae08745Sheppo /*
11564a9fd251SVijay Balakrishna, SG-RPE * As OS CPU structures are already torn down proceed
11574a9fd251SVijay Balakrishna, SG-RPE * to deprobe device tree to make sure the device tree
11584a9fd251SVijay Balakrishna, SG-RPE * is up do date.
11591ae08745Sheppo */
11604a9fd251SVijay Balakrishna, SG-RPE goto deprobe;
11611ae08745Sheppo }
11621ae08745Sheppo
11631ae08745Sheppo ASSERT(cp->cpu_id == cpuid);
11641ae08745Sheppo
11651ae08745Sheppo /*
11661ae08745Sheppo * Offline the CPU
11671ae08745Sheppo */
11681ae08745Sheppo if (cpu_is_active(cp)) {
11691ae08745Sheppo
11701ae08745Sheppo /* set the force flag correctly */
11711ae08745Sheppo cpu_flags = (force) ? CPU_FORCED : 0;
11721ae08745Sheppo
11737de586caSJames Marks - Sun Microsystems /*
11747de586caSJames Marks - Sun Microsystems * Before we take the CPU offline, we first enable interrupts.
11757de586caSJames Marks - Sun Microsystems * Otherwise, cpu_offline() might reject the request. Note:
11767de586caSJames Marks - Sun Microsystems * if the offline subsequently fails, the target cpu will be
11777de586caSJames Marks - Sun Microsystems * left with interrupts enabled. This is consistent with the
1178*bbf21555SRichard Lowe * behavior of psradm(8) and p_online(2).
11797de586caSJames Marks - Sun Microsystems */
11807de586caSJames Marks - Sun Microsystems cpu_intr_enable(cp);
11817de586caSJames Marks - Sun Microsystems
11821ae08745Sheppo if ((rv = cpu_offline(cp, cpu_flags)) != 0) {
11831ae08745Sheppo DR_DBG_CPU("failed to offline CPU %d (%d)\n",
11841ae08745Sheppo cpuid, rv);
11851ae08745Sheppo
11861ae08745Sheppo rv = DR_CPU_RES_FAILURE;
11871ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
11884a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
11894a9fd251SVijay Balakrishna, SG-RPE return (rv);
11901ae08745Sheppo }
11911ae08745Sheppo
11921ae08745Sheppo DR_DBG_CPU("CPU %d offline\n", cpuid);
11931ae08745Sheppo }
11941ae08745Sheppo
11951ae08745Sheppo /*
11961ae08745Sheppo * Power off the CPU. In sun4v, this puts the running
11971ae08745Sheppo * CPU into the stopped state in the Hypervisor.
11981ae08745Sheppo */
11991ae08745Sheppo if (!cpu_is_poweredoff(cp)) {
12001ae08745Sheppo
12011ae08745Sheppo if ((rv = cpu_poweroff(cp)) != 0) {
12021ae08745Sheppo DR_DBG_CPU("failed to power off CPU %d (%d)\n",
12031ae08745Sheppo cpuid, rv);
12041ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12051ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
12064a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
12074a9fd251SVijay Balakrishna, SG-RPE return (rv);
12081ae08745Sheppo }
12091ae08745Sheppo
12101ae08745Sheppo DR_DBG_CPU("CPU %d powered off\n", cpuid);
12111ae08745Sheppo }
12121ae08745Sheppo
12131ae08745Sheppo /*
12141ae08745Sheppo * Unconfigure the CPU
12151ae08745Sheppo */
12161ae08745Sheppo if ((rv = cpu_unconfigure(cpuid)) != 0) {
12171ae08745Sheppo DR_DBG_CPU("failed to unconfigure CPU %d (%d)\n", cpuid, rv);
12181ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12191ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12204a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
12214a9fd251SVijay Balakrishna, SG-RPE return (rv);
12221ae08745Sheppo }
12231ae08745Sheppo
12241ae08745Sheppo DR_DBG_CPU("CPU %d unconfigured\n", cpuid);
12251ae08745Sheppo
12264a9fd251SVijay Balakrishna, SG-RPE deprobe:
12274a9fd251SVijay Balakrishna, SG-RPE mutex_exit(&cpu_lock);
12281ae08745Sheppo /*
12291ae08745Sheppo * Tear down device tree.
12301ae08745Sheppo */
12311ae08745Sheppo if ((rv = dr_cpu_deprobe(cpuid)) != 0) {
12321ae08745Sheppo DR_DBG_CPU("failed to deprobe CPU %d (%d)\n", cpuid, rv);
12331ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12341ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12354a9fd251SVijay Balakrishna, SG-RPE return (rv);
12361ae08745Sheppo }
12371ae08745Sheppo
12381ae08745Sheppo rv = DR_CPU_RES_OK;
12391ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12401ae08745Sheppo
12411ae08745Sheppo return (rv);
12421ae08745Sheppo }
12431ae08745Sheppo
12441ae08745Sheppo /*
12451ae08745Sheppo * Determine the state of a CPU. If the CPU structure is not present,
12461ae08745Sheppo * it does not attempt to determine whether or not the CPU is in the
12471ae08745Sheppo * MD. It is more efficient to do this at the higher level for all
12481ae08745Sheppo * CPUs since it may not even be necessary to search the MD if all
12491ae08745Sheppo * the CPUs are accounted for. Returns DR_CPU_RES_OK if the CPU
12501ae08745Sheppo * structure is present, and DR_CPU_RES_FAILURE otherwise as a signal
12511ae08745Sheppo * that an MD walk is necessary.
12521ae08745Sheppo */
12531ae08745Sheppo static int
dr_cpu_status(processorid_t cpuid,int * status)12541ae08745Sheppo dr_cpu_status(processorid_t cpuid, int *status)
12551ae08745Sheppo {
12561ae08745Sheppo int rv;
12571ae08745Sheppo struct cpu *cp;
12581ae08745Sheppo
12591ae08745Sheppo DR_DBG_CPU("dr_cpu_status...\n");
12601ae08745Sheppo
12611ae08745Sheppo mutex_enter(&cpu_lock);
12621ae08745Sheppo
12631ae08745Sheppo if ((cp = cpu_get(cpuid)) == NULL) {
12641ae08745Sheppo /* need to check if cpu is in the MD */
12651ae08745Sheppo rv = DR_CPU_RES_FAILURE;
12661ae08745Sheppo goto done;
12671ae08745Sheppo }
12681ae08745Sheppo
12691ae08745Sheppo if (cpu_is_poweredoff(cp)) {
12701ae08745Sheppo /*
12711ae08745Sheppo * The CPU is powered off, so it is considered
12721ae08745Sheppo * unconfigured from the service entity point of
12731ae08745Sheppo * view. The CPU is not available to the system
12741ae08745Sheppo * and intervention by the service entity would
12751ae08745Sheppo * be required to change that.
12761ae08745Sheppo */
12771ae08745Sheppo *status = DR_CPU_STAT_UNCONFIGURED;
12781ae08745Sheppo } else {
12791ae08745Sheppo /*
12801ae08745Sheppo * The CPU is powered on, so it is considered
12811ae08745Sheppo * configured from the service entity point of
12821ae08745Sheppo * view. It is available for use by the system
12831ae08745Sheppo * and service entities are not concerned about
12841ae08745Sheppo * the operational status (offline, online, etc.)
12851ae08745Sheppo * of the CPU in terms of DR.
12861ae08745Sheppo */
12871ae08745Sheppo *status = DR_CPU_STAT_CONFIGURED;
12881ae08745Sheppo }
12891ae08745Sheppo
12901ae08745Sheppo rv = DR_CPU_RES_OK;
12911ae08745Sheppo
12921ae08745Sheppo done:
12931ae08745Sheppo mutex_exit(&cpu_lock);
12941ae08745Sheppo
12951ae08745Sheppo return (rv);
12961ae08745Sheppo }
12971ae08745Sheppo
12981ae08745Sheppo typedef struct {
12991ae08745Sheppo md_t *mdp;
13001ae08745Sheppo mde_cookie_t cpunode;
13011ae08745Sheppo dev_info_t *dip;
13021ae08745Sheppo } cb_arg_t;
13031ae08745Sheppo
13041ae08745Sheppo #define STR_ARR_LEN 5
13051ae08745Sheppo
13061ae08745Sheppo static int
new_cpu_node(dev_info_t * new_node,void * arg,uint_t flags)13071ae08745Sheppo new_cpu_node(dev_info_t *new_node, void *arg, uint_t flags)
13081ae08745Sheppo {
13091ae08745Sheppo _NOTE(ARGUNUSED(flags))
13101ae08745Sheppo
13111ae08745Sheppo char *compat;
13121ae08745Sheppo uint64_t freq;
13131ae08745Sheppo uint64_t cpuid = 0;
13141ae08745Sheppo int regbuf[4];
13151ae08745Sheppo int len = 0;
13161ae08745Sheppo cb_arg_t *cba;
13171ae08745Sheppo char *str_arr[STR_ARR_LEN];
13181ae08745Sheppo char *curr;
13191ae08745Sheppo int idx = 0;
13201ae08745Sheppo
13211ae08745Sheppo DR_DBG_CPU("new_cpu_node...\n");
13221ae08745Sheppo
13231ae08745Sheppo cba = (cb_arg_t *)arg;
13241ae08745Sheppo
13251ae08745Sheppo /*
13261ae08745Sheppo * Add 'name' property
13271ae08745Sheppo */
13281ae08745Sheppo if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13291ae08745Sheppo "name", "cpu") != DDI_SUCCESS) {
13301ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'name' property\n");
13311ae08745Sheppo return (DDI_WALK_ERROR);
13321ae08745Sheppo }
13331ae08745Sheppo
13341ae08745Sheppo /*
13351ae08745Sheppo * Add 'compatible' property
13361ae08745Sheppo */
13371ae08745Sheppo if (md_get_prop_data(cba->mdp, cba->cpunode, "compatible",
13381ae08745Sheppo (uint8_t **)(&compat), &len)) {
13391ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'compatible' property "
13401ae08745Sheppo "from MD\n");
13411ae08745Sheppo return (DDI_WALK_ERROR);
13421ae08745Sheppo }
13431ae08745Sheppo
13441ae08745Sheppo DR_DBG_CPU("'compatible' len is %d\n", len);
13451ae08745Sheppo
13461ae08745Sheppo /* parse the MD string array */
13471ae08745Sheppo curr = compat;
13481ae08745Sheppo while (curr < (compat + len)) {
13491ae08745Sheppo
13501ae08745Sheppo DR_DBG_CPU("adding '%s' to 'compatible' property\n", curr);
13511ae08745Sheppo
13521ae08745Sheppo str_arr[idx++] = curr;
13531ae08745Sheppo curr += strlen(curr) + 1;
13541ae08745Sheppo
13551ae08745Sheppo if (idx == STR_ARR_LEN) {
13561ae08745Sheppo DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
13571ae08745Sheppo break;
13581ae08745Sheppo }
13591ae08745Sheppo }
13601ae08745Sheppo
13611ae08745Sheppo if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
13621ae08745Sheppo "compatible", str_arr, idx) != DDI_SUCCESS) {
13631ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'compatible' "
13641ae08745Sheppo "property\n");
13651ae08745Sheppo return (DDI_WALK_ERROR);
13661ae08745Sheppo }
13671ae08745Sheppo
13681ae08745Sheppo /*
13691ae08745Sheppo * Add 'device_type' property
13701ae08745Sheppo */
13711ae08745Sheppo if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13721ae08745Sheppo "device_type", "cpu") != DDI_SUCCESS) {
13731ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'device_type' "
13741ae08745Sheppo "property\n");
13751ae08745Sheppo return (DDI_WALK_ERROR);
13761ae08745Sheppo }
13771ae08745Sheppo
13781ae08745Sheppo /*
13791ae08745Sheppo * Add 'clock-frequency' property
13801ae08745Sheppo */
13811ae08745Sheppo if (md_get_prop_val(cba->mdp, cba->cpunode, "clock-frequency", &freq)) {
13821ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'clock-frequency' "
13831ae08745Sheppo "property from MD\n");
13841ae08745Sheppo return (DDI_WALK_ERROR);
13851ae08745Sheppo }
13861ae08745Sheppo
13871ae08745Sheppo if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node,
13881ae08745Sheppo "clock-frequency", freq) != DDI_SUCCESS) {
13891ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'clock-frequency' "
13901ae08745Sheppo "property\n");
13911ae08745Sheppo return (DDI_WALK_ERROR);
13921ae08745Sheppo }
13931ae08745Sheppo
13941ae08745Sheppo /*
13951ae08745Sheppo * Add 'reg' (cpuid) property
13961ae08745Sheppo */
13971ae08745Sheppo if (md_get_prop_val(cba->mdp, cba->cpunode, "id", &cpuid)) {
13981ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to read 'id' property "
13991ae08745Sheppo "from MD\n");
14001ae08745Sheppo return (DDI_WALK_ERROR);
14011ae08745Sheppo }
14021ae08745Sheppo
14031ae08745Sheppo DR_DBG_CPU("new cpuid=0x%lx\n", cpuid);
14041ae08745Sheppo
14051ae08745Sheppo bzero(regbuf, 4 * sizeof (int));
14061ae08745Sheppo regbuf[0] = 0xc0000000 | cpuid;
14071ae08745Sheppo
14081ae08745Sheppo if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_node,
14091ae08745Sheppo "reg", regbuf, 4) != DDI_SUCCESS) {
14101ae08745Sheppo DR_DBG_CPU("new_cpu_node: failed to create 'reg' property\n");
14111ae08745Sheppo return (DDI_WALK_ERROR);
14121ae08745Sheppo }
14131ae08745Sheppo
14141ae08745Sheppo cba->dip = new_node;
14151ae08745Sheppo
14161ae08745Sheppo return (DDI_WALK_TERMINATE);
14171ae08745Sheppo }
14181ae08745Sheppo
14191ae08745Sheppo static int
dr_cpu_probe(processorid_t cpuid)14201ae08745Sheppo dr_cpu_probe(processorid_t cpuid)
14211ae08745Sheppo {
14221ae08745Sheppo dev_info_t *pdip;
14231ae08745Sheppo dev_info_t *dip;
14241ae08745Sheppo devi_branch_t br;
14251ae08745Sheppo md_t *mdp = NULL;
14261ae08745Sheppo int num_nodes;
14271ae08745Sheppo int rv = 0;
14281ae08745Sheppo int listsz;
14291ae08745Sheppo mde_cookie_t *listp = NULL;
14301ae08745Sheppo cb_arg_t cba;
14311ae08745Sheppo mde_cookie_t cpunode;
14321ae08745Sheppo
14331ae08745Sheppo if ((dip = dr_cpu_find_node(cpuid)) != NULL) {
14341ae08745Sheppo /* nothing to do */
14351ae08745Sheppo e_ddi_branch_rele(dip);
14361ae08745Sheppo return (0);
14371ae08745Sheppo }
14381ae08745Sheppo
14391ae08745Sheppo if ((mdp = md_get_handle()) == NULL) {
14401ae08745Sheppo DR_DBG_CPU("unable to initialize machine description\n");
14411ae08745Sheppo return (-1);
14421ae08745Sheppo }
14431ae08745Sheppo
14441ae08745Sheppo num_nodes = md_node_count(mdp);
14451ae08745Sheppo ASSERT(num_nodes > 0);
14461ae08745Sheppo
14471ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
14481ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP);
144999c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
145099c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
14511ae08745Sheppo
14521ae08745Sheppo cpunode = dr_cpu_find_node_md(cpuid, mdp, listp);
14531ae08745Sheppo
14541ae08745Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) {
14551ae08745Sheppo rv = EINVAL;
14561ae08745Sheppo goto done;
14571ae08745Sheppo }
14581ae08745Sheppo
14591ae08745Sheppo /* pass in MD cookie for CPU */
14601ae08745Sheppo cba.mdp = mdp;
14611ae08745Sheppo cba.cpunode = cpunode;
14621ae08745Sheppo
14631ae08745Sheppo br.arg = (void *)&cba;
14641ae08745Sheppo br.type = DEVI_BRANCH_SID;
14651ae08745Sheppo br.create.sid_branch_create = new_cpu_node;
14661ae08745Sheppo br.devi_branch_callback = NULL;
14671ae08745Sheppo pdip = ddi_root_node();
14681ae08745Sheppo
14691ae08745Sheppo if ((rv = e_ddi_branch_create(pdip, &br, NULL, 0))) {
14701ae08745Sheppo DR_DBG_CPU("e_ddi_branch_create failed: %d\n", rv);
14711ae08745Sheppo rv = -1;
14721ae08745Sheppo goto done;
14731ae08745Sheppo }
14741ae08745Sheppo
14751ae08745Sheppo DR_DBG_CPU("CPU %d probed\n", cpuid);
14761ae08745Sheppo
14771ae08745Sheppo rv = 0;
14781ae08745Sheppo
14791ae08745Sheppo done:
148099c7e855SJames Marks - Sun Microsystems if (listp) {
148199c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
148299c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz);
14831ae08745Sheppo kmem_free(listp, listsz);
148499c7e855SJames Marks - Sun Microsystems }
14851ae08745Sheppo
14861ae08745Sheppo if (mdp)
14871ae08745Sheppo (void) md_fini_handle(mdp);
14881ae08745Sheppo
14891ae08745Sheppo return (rv);
14901ae08745Sheppo }
14911ae08745Sheppo
14921ae08745Sheppo static int
dr_cpu_deprobe(processorid_t cpuid)14931ae08745Sheppo dr_cpu_deprobe(processorid_t cpuid)
14941ae08745Sheppo {
14951ae08745Sheppo dev_info_t *fdip = NULL;
14961ae08745Sheppo dev_info_t *dip;
14971ae08745Sheppo
14981ae08745Sheppo if ((dip = dr_cpu_find_node(cpuid)) == NULL) {
14991ae08745Sheppo DR_DBG_CPU("cpuid %d already deprobed\n", cpuid);
15001ae08745Sheppo return (0);
15011ae08745Sheppo }
15021ae08745Sheppo
15031ae08745Sheppo ASSERT(e_ddi_branch_held(dip));
15041ae08745Sheppo
15051ae08745Sheppo if (e_ddi_branch_destroy(dip, &fdip, 0)) {
15061ae08745Sheppo char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15071ae08745Sheppo
150899c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n",
150999c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN);
15101ae08745Sheppo /*
15111ae08745Sheppo * If non-NULL, fdip is held and must be released.
15121ae08745Sheppo */
15131ae08745Sheppo if (fdip != NULL) {
15141ae08745Sheppo (void) ddi_pathname(fdip, path);
15151ae08745Sheppo ddi_release_devi(fdip);
15161ae08745Sheppo } else {
15171ae08745Sheppo (void) ddi_pathname(dip, path);
15181ae08745Sheppo }
15191ae08745Sheppo cmn_err(CE_NOTE, "node removal failed: %s (%p)",
15201ae08745Sheppo path, (fdip) ? (void *)fdip : (void *)dip);
15211ae08745Sheppo
152299c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n",
152399c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN);
15241ae08745Sheppo kmem_free(path, MAXPATHLEN);
15251ae08745Sheppo
15261ae08745Sheppo return (-1);
15271ae08745Sheppo }
15281ae08745Sheppo
15291ae08745Sheppo DR_DBG_CPU("CPU %d deprobed\n", cpuid);
15301ae08745Sheppo
15311ae08745Sheppo return (0);
15321ae08745Sheppo }
15331ae08745Sheppo
15341ae08745Sheppo typedef struct {
15351ae08745Sheppo processorid_t cpuid;
15361ae08745Sheppo dev_info_t *dip;
15371ae08745Sheppo } dr_search_arg_t;
15381ae08745Sheppo
15391ae08745Sheppo static int
dr_cpu_check_node(dev_info_t * dip,void * arg)15401ae08745Sheppo dr_cpu_check_node(dev_info_t *dip, void *arg)
15411ae08745Sheppo {
15421ae08745Sheppo char *name;
15431ae08745Sheppo processorid_t cpuid;
15441ae08745Sheppo dr_search_arg_t *sarg = (dr_search_arg_t *)arg;
15451ae08745Sheppo
15461ae08745Sheppo if (dip == ddi_root_node()) {
15471ae08745Sheppo return (DDI_WALK_CONTINUE);
15481ae08745Sheppo }
15491ae08745Sheppo
15501ae08745Sheppo name = ddi_node_name(dip);
15511ae08745Sheppo
15521ae08745Sheppo if (strcmp(name, "cpu") != 0) {
15531ae08745Sheppo return (DDI_WALK_PRUNECHILD);
15541ae08745Sheppo }
15551ae08745Sheppo
15561ae08745Sheppo cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
15571ae08745Sheppo "reg", -1);
15581ae08745Sheppo
15591ae08745Sheppo cpuid = PROM_CFGHDL_TO_CPUID(cpuid);
15601ae08745Sheppo
15611ae08745Sheppo DR_DBG_CPU("found cpuid=0x%x, looking for 0x%x\n", cpuid, sarg->cpuid);
15621ae08745Sheppo
15631ae08745Sheppo if (cpuid == sarg->cpuid) {
15641ae08745Sheppo DR_DBG_CPU("matching node\n");
15651ae08745Sheppo
15661ae08745Sheppo /* matching node must be returned held */
15671ae08745Sheppo if (!e_ddi_branch_held(dip))
15681ae08745Sheppo e_ddi_branch_hold(dip);
15691ae08745Sheppo
15701ae08745Sheppo sarg->dip = dip;
15711ae08745Sheppo return (DDI_WALK_TERMINATE);
15721ae08745Sheppo }
15731ae08745Sheppo
15741ae08745Sheppo return (DDI_WALK_CONTINUE);
15751ae08745Sheppo }
15761ae08745Sheppo
15771ae08745Sheppo /*
15781ae08745Sheppo * Walk the device tree to find the dip corresponding to the cpuid
15791ae08745Sheppo * passed in. If present, the dip is returned held. The caller must
15801ae08745Sheppo * release the hold on the dip once it is no longer required. If no
15811ae08745Sheppo * matching node if found, NULL is returned.
15821ae08745Sheppo */
15831ae08745Sheppo static dev_info_t *
dr_cpu_find_node(processorid_t cpuid)15841ae08745Sheppo dr_cpu_find_node(processorid_t cpuid)
15851ae08745Sheppo {
15861ae08745Sheppo dr_search_arg_t arg;
15871ae08745Sheppo
15881ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node...\n");
15891ae08745Sheppo
15901ae08745Sheppo arg.cpuid = cpuid;
15911ae08745Sheppo arg.dip = NULL;
15921ae08745Sheppo
15931ae08745Sheppo ddi_walk_devs(ddi_root_node(), dr_cpu_check_node, &arg);
15941ae08745Sheppo
15951ae08745Sheppo ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
15961ae08745Sheppo
15971ae08745Sheppo return ((arg.dip) ? arg.dip : NULL);
15981ae08745Sheppo }
15991ae08745Sheppo
16001ae08745Sheppo /*
16011ae08745Sheppo * Look up a particular cpuid in the MD. Returns the mde_cookie_t
16021ae08745Sheppo * representing that CPU if present, and MDE_INVAL_ELEM_COOKIE
16031ae08745Sheppo * otherwise. It is assumed the scratch array has already been
16041ae08745Sheppo * allocated so that it can accommodate the worst case scenario,
16051ae08745Sheppo * every node in the MD.
16061ae08745Sheppo */
16071ae08745Sheppo static mde_cookie_t
dr_cpu_find_node_md(processorid_t cpuid,md_t * mdp,mde_cookie_t * listp)16081ae08745Sheppo dr_cpu_find_node_md(processorid_t cpuid, md_t *mdp, mde_cookie_t *listp)
16091ae08745Sheppo {
16101ae08745Sheppo int idx;
16111ae08745Sheppo int nnodes;
16121ae08745Sheppo mde_cookie_t rootnode;
16131ae08745Sheppo uint64_t cpuid_prop;
16141ae08745Sheppo mde_cookie_t result = MDE_INVAL_ELEM_COOKIE;
16151ae08745Sheppo
16161ae08745Sheppo rootnode = md_root_node(mdp);
16171ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
16181ae08745Sheppo
16191ae08745Sheppo /*
16201ae08745Sheppo * Scan the DAG for all the CPU nodes
16211ae08745Sheppo */
16221ae08745Sheppo nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
16231ae08745Sheppo md_find_name(mdp, "fwd"), listp);
16241ae08745Sheppo
16251ae08745Sheppo if (nnodes < 0) {
16261ae08745Sheppo DR_DBG_CPU("Scan for CPUs failed\n");
16271ae08745Sheppo return (result);
16281ae08745Sheppo }
16291ae08745Sheppo
16301ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node_md: found %d CPUs in the MD\n", nnodes);
16311ae08745Sheppo
16321ae08745Sheppo /*
16331ae08745Sheppo * Find the CPU of interest
16341ae08745Sheppo */
16351ae08745Sheppo for (idx = 0; idx < nnodes; idx++) {
16361ae08745Sheppo
16371ae08745Sheppo if (md_get_prop_val(mdp, listp[idx], "id", &cpuid_prop)) {
16381ae08745Sheppo DR_DBG_CPU("Missing 'id' property for CPU node %d\n",
16391ae08745Sheppo idx);
16401ae08745Sheppo break;
16411ae08745Sheppo }
16421ae08745Sheppo
16431ae08745Sheppo if (cpuid_prop == cpuid) {
16441ae08745Sheppo /* found a match */
16451ae08745Sheppo DR_DBG_CPU("dr_cpu_find_node_md: found CPU %d "
16461ae08745Sheppo "in MD\n", cpuid);
16471ae08745Sheppo result = listp[idx];
16481ae08745Sheppo break;
16491ae08745Sheppo }
16501ae08745Sheppo }
16511ae08745Sheppo
16521ae08745Sheppo if (result == MDE_INVAL_ELEM_COOKIE) {
16531ae08745Sheppo DR_DBG_CPU("CPU %d not in MD\n", cpuid);
16541ae08745Sheppo }
16551ae08745Sheppo
16561ae08745Sheppo return (result);
16571ae08745Sheppo }
1658