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