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 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 1781ae08745Sheppo _info(struct modinfo *modinfop) 1791ae08745Sheppo { 1801ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 1811ae08745Sheppo } 1821ae08745Sheppo 1831ae08745Sheppo int dr_cpu_allow_unload; 1841ae08745Sheppo 1851ae08745Sheppo int 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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