10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51772Sjl139090 * Common Development and Distribution License (the "License"). 61772Sjl139090 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3811Sbm42561 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * CPU support routines for DR 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/note.h> 330Sstevel@tonic-gate #include <sys/debug.h> 340Sstevel@tonic-gate #include <sys/types.h> 350Sstevel@tonic-gate #include <sys/errno.h> 360Sstevel@tonic-gate #include <sys/cred.h> 370Sstevel@tonic-gate #include <sys/dditypes.h> 380Sstevel@tonic-gate #include <sys/devops.h> 390Sstevel@tonic-gate #include <sys/modctl.h> 400Sstevel@tonic-gate #include <sys/poll.h> 410Sstevel@tonic-gate #include <sys/conf.h> 420Sstevel@tonic-gate #include <sys/ddi.h> 430Sstevel@tonic-gate #include <sys/sunddi.h> 440Sstevel@tonic-gate #include <sys/sunndi.h> 450Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/kmem.h> 480Sstevel@tonic-gate #include <sys/processor.h> 490Sstevel@tonic-gate #include <sys/cpuvar.h> 500Sstevel@tonic-gate #include <sys/mem_config.h> 510Sstevel@tonic-gate #include <sys/promif.h> 520Sstevel@tonic-gate #include <sys/x_call.h> 530Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 540Sstevel@tonic-gate #include <sys/membar.h> 550Sstevel@tonic-gate #include <sys/stack.h> 560Sstevel@tonic-gate #include <sys/sysmacros.h> 570Sstevel@tonic-gate #include <sys/machsystm.h> 580Sstevel@tonic-gate #include <sys/spitregs.h> 590Sstevel@tonic-gate 600Sstevel@tonic-gate #include <sys/archsystm.h> 610Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 620Sstevel@tonic-gate #include <sys/pte.h> 630Sstevel@tonic-gate #include <sys/mmu.h> 640Sstevel@tonic-gate #include <sys/x_call.h> 650Sstevel@tonic-gate #include <sys/cpu_module.h> 661772Sjl139090 #include <sys/cpu_impl.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #include <sys/autoconf.h> 690Sstevel@tonic-gate #include <sys/cmn_err.h> 700Sstevel@tonic-gate 710Sstevel@tonic-gate #include <sys/dr.h> 720Sstevel@tonic-gate #include <sys/dr_util.h> 730Sstevel@tonic-gate 740Sstevel@tonic-gate #ifdef _STARFIRE 750Sstevel@tonic-gate #include <sys/starfire.h> 760Sstevel@tonic-gate extern struct cpu *SIGBCPU; 770Sstevel@tonic-gate #else 780Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ 790Sstevel@tonic-gate static char *dr_ie_fmt = "dr_cpu.c %d"; 800Sstevel@tonic-gate #endif /* _STARFIRE */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate int 830Sstevel@tonic-gate dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp) 840Sstevel@tonic-gate { 850Sstevel@tonic-gate #ifdef DEBUG 860Sstevel@tonic-gate processorid_t cpuid; 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * cpuid and unit number should never be different 900Sstevel@tonic-gate * than they were at discovery/connect time 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate ASSERT(drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid) == 0); 930Sstevel@tonic-gate 940Sstevel@tonic-gate ASSERT(cp->sbc_cm.sbdev_bp == bp); 950Sstevel@tonic-gate ASSERT(cp->sbc_cm.sbdev_type == SBD_COMP_CPU); 960Sstevel@tonic-gate ASSERT(cp->sbc_cpu_id == cpuid); 970Sstevel@tonic-gate #else 980Sstevel@tonic-gate _NOTE(ARGUNUSED(bp)) 990Sstevel@tonic-gate _NOTE(ARGUNUSED(cp)) 1000Sstevel@tonic-gate #endif 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate return (1); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate static int 1060Sstevel@tonic-gate dr_errno2ecode(int error) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate int rv; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate switch (error) { 1110Sstevel@tonic-gate case EBUSY: 1120Sstevel@tonic-gate rv = ESBD_BUSY; 1130Sstevel@tonic-gate break; 1140Sstevel@tonic-gate case EINVAL: 1150Sstevel@tonic-gate rv = ESBD_INVAL; 1160Sstevel@tonic-gate break; 1170Sstevel@tonic-gate case EALREADY: 1180Sstevel@tonic-gate rv = ESBD_ALREADY; 1190Sstevel@tonic-gate break; 1200Sstevel@tonic-gate case ENODEV: 1210Sstevel@tonic-gate rv = ESBD_NODEV; 1220Sstevel@tonic-gate break; 1230Sstevel@tonic-gate case ENOMEM: 1240Sstevel@tonic-gate rv = ESBD_NOMEM; 1250Sstevel@tonic-gate break; 1260Sstevel@tonic-gate default: 1270Sstevel@tonic-gate rv = ESBD_INVAL; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate return (rv); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate static void 1340Sstevel@tonic-gate dr_cpu_set_prop(dr_cpu_unit_t *cp) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate sbd_error_t *err; 1370Sstevel@tonic-gate dev_info_t *dip; 1380Sstevel@tonic-gate uint64_t clock_freq; 1390Sstevel@tonic-gate int ecache_size = 0; 1400Sstevel@tonic-gate char *cache_str = NULL; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate err = drmach_get_dip(cp->sbc_cm.sbdev_id, &dip); 1430Sstevel@tonic-gate if (err) { 1440Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 1450Sstevel@tonic-gate return; 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate if (dip == NULL) { 1490Sstevel@tonic-gate #ifndef _STARFIRE 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * Do not report an error on Starfire since 1520Sstevel@tonic-gate * the dip will not be created until after 1530Sstevel@tonic-gate * the CPU has been configured. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&cp->sbc_cm); 1560Sstevel@tonic-gate #endif /* !_STARFIRE */ 1570Sstevel@tonic-gate return; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* read in the CPU speed */ 1611772Sjl139090 1621772Sjl139090 /* 1631772Sjl139090 * If the property is not found in the CPU node, it has to be 1641772Sjl139090 * kept in the core or cmp node so we just keep looking. 1651772Sjl139090 */ 1661772Sjl139090 clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, 1671772Sjl139090 dip, 0, "clock-frequency", 0); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate ASSERT(clock_freq != 0); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * The ecache property string is not the same 1730Sstevel@tonic-gate * for all CPU implementations. 1740Sstevel@tonic-gate */ 1751772Sjl139090 1760Sstevel@tonic-gate switch (cp->sbc_cpu_impl) { 1770Sstevel@tonic-gate case BLACKBIRD_IMPL: 1780Sstevel@tonic-gate case CHEETAH_IMPL: 1790Sstevel@tonic-gate case CHEETAH_PLUS_IMPL: 1800Sstevel@tonic-gate cache_str = "ecache-size"; 1810Sstevel@tonic-gate break; 1820Sstevel@tonic-gate case JAGUAR_IMPL: 1831772Sjl139090 case OLYMPUS_C_IMPL: 1840Sstevel@tonic-gate cache_str = "l2-cache-size"; 1850Sstevel@tonic-gate break; 1860Sstevel@tonic-gate case PANTHER_IMPL: 1870Sstevel@tonic-gate cache_str = "l3-cache-size"; 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate default: 1900Sstevel@tonic-gate cmn_err(CE_WARN, "Unknown cpu implementation=0x%x", 1910Sstevel@tonic-gate cp->sbc_cpu_impl); 1920Sstevel@tonic-gate ASSERT(0); 1930Sstevel@tonic-gate break; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (cache_str != NULL) { 1970Sstevel@tonic-gate /* read in the ecache size */ 1981772Sjl139090 /* 1991772Sjl139090 * If the property is not found in the CPU node, 2001772Sjl139090 * it has to be kept in the core or cmp node so 2011772Sjl139090 * we just keep looking. 2021772Sjl139090 */ 2031772Sjl139090 2041772Sjl139090 ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, 2051772Sjl139090 dip, 0, cache_str, 0); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate ASSERT(ecache_size != 0); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* convert to the proper units */ 2110Sstevel@tonic-gate cp->sbc_speed = (clock_freq + 500000) / 1000000; 2120Sstevel@tonic-gate cp->sbc_ecache = ecache_size / (1024 * 1024); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate void 2160Sstevel@tonic-gate dr_init_cpu_unit(dr_cpu_unit_t *cp) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate sbd_error_t *err; 2190Sstevel@tonic-gate dr_state_t new_state; 2200Sstevel@tonic-gate int cpuid; 2210Sstevel@tonic-gate int impl; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (DR_DEV_IS_ATTACHED(&cp->sbc_cm)) { 2240Sstevel@tonic-gate new_state = DR_STATE_CONFIGURED; 2250Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_OK; 2260Sstevel@tonic-gate } else if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 2270Sstevel@tonic-gate new_state = DR_STATE_CONNECTED; 2280Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_OK; 2290Sstevel@tonic-gate } else { 2300Sstevel@tonic-gate new_state = DR_STATE_EMPTY; 2310Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_UNKNOWN; 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 2350Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid); 2360Sstevel@tonic-gate if (err) { 2370Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 2380Sstevel@tonic-gate new_state = DR_STATE_FATAL; 2390Sstevel@tonic-gate goto done; 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate err = drmach_cpu_get_impl(cp->sbc_cm.sbdev_id, &impl); 2430Sstevel@tonic-gate if (err) { 2440Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 2450Sstevel@tonic-gate new_state = DR_STATE_FATAL; 2460Sstevel@tonic-gate goto done; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } else { 2490Sstevel@tonic-gate cp->sbc_cpu_id = -1; 2500Sstevel@tonic-gate cp->sbc_cpu_impl = -1; 2510Sstevel@tonic-gate goto done; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate cp->sbc_cpu_id = cpuid; 2550Sstevel@tonic-gate cp->sbc_cpu_impl = impl; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* if true at init time, it must always be true */ 2580Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(cp->sbc_cm.sbdev_bp, cp)); 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate mutex_enter(&cpu_lock); 2610Sstevel@tonic-gate if ((cpuid >= 0) && cpu[cpuid]) 2620Sstevel@tonic-gate cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 2630Sstevel@tonic-gate else 2640Sstevel@tonic-gate cp->sbc_cpu_flags = P_OFFLINE | P_POWEROFF; 2650Sstevel@tonic-gate mutex_exit(&cpu_lock); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate dr_cpu_set_prop(cp); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate done: 2700Sstevel@tonic-gate /* delay transition until fully initialized */ 2710Sstevel@tonic-gate dr_device_transition(&cp->sbc_cm, new_state); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate int 2750Sstevel@tonic-gate dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 2760Sstevel@tonic-gate { 2770Sstevel@tonic-gate int i; 2780Sstevel@tonic-gate int curr_cpu; 2790Sstevel@tonic-gate int next_cpu; 2800Sstevel@tonic-gate static fn_t f = "dr_pre_attach_cpu"; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate PR_CPU("%s...\n", f); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate for (next_cpu = 0, i = 0; i < devnum; i++) { 2850Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * Print a console message for each attachment 2910Sstevel@tonic-gate * point. For CMP devices, this means that only 2920Sstevel@tonic-gate * one message should be printed, no matter how 2930Sstevel@tonic-gate * many cores are actually present. 2940Sstevel@tonic-gate */ 2951772Sjl139090 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 2961772Sjl139090 SBD_COMP_CPU); 2970Sstevel@tonic-gate if (curr_cpu >= next_cpu) { 2980Sstevel@tonic-gate cmn_err(CE_CONT, "OS configure %s", 2990Sstevel@tonic-gate up->sbc_cm.sbdev_path); 3000Sstevel@tonic-gate next_cpu = curr_cpu + 1; 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED) { 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * If we're coming from the UNCONFIGURED 3060Sstevel@tonic-gate * state then the cpu's sigblock will 3070Sstevel@tonic-gate * still be mapped in. Need to unmap it 3080Sstevel@tonic-gate * before continuing with attachment. 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate PR_CPU("%s: unmapping sigblk for cpu %d\n", 3110Sstevel@tonic-gate f, up->sbc_cpu_id); 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate CPU_SGN_MAPOUT(up->sbc_cpu_id); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Block out status threads while creating 3190Sstevel@tonic-gate * devinfo tree branches 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate dr_lock_status(hp->h_bd); 322*3811Sbm42561 ndi_devi_enter(ddi_root_node(), (int *)(&hp->h_ndi)); 3230Sstevel@tonic-gate mutex_enter(&cpu_lock); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate return (0); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /*ARGSUSED*/ 3290Sstevel@tonic-gate void 3300Sstevel@tonic-gate dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate sbd_error_t *err; 3330Sstevel@tonic-gate processorid_t cpuid; 3340Sstevel@tonic-gate int rv; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate err = drmach_configure(cp->sbdev_id, 0); 3390Sstevel@tonic-gate if (err) { 3400Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3410Sstevel@tonic-gate return; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 3450Sstevel@tonic-gate if (err) { 3460Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3470Sstevel@tonic-gate 3481772Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 3490Sstevel@tonic-gate if (err) 3500Sstevel@tonic-gate sbd_err_clear(&err); 3510Sstevel@tonic-gate } else if ((rv = cpu_configure(cpuid)) != 0) { 3520Sstevel@tonic-gate dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv)); 3531772Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 3540Sstevel@tonic-gate if (err) 3550Sstevel@tonic-gate sbd_err_clear(&err); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * dr_post_attach_cpu 3610Sstevel@tonic-gate * 3620Sstevel@tonic-gate * sbd error policy: Does not stop on error. Processes all units in list. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate int 3650Sstevel@tonic-gate dr_post_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate int i; 3680Sstevel@tonic-gate int errflag = 0; 3690Sstevel@tonic-gate static fn_t f = "dr_post_attach_cpu"; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate PR_CPU("%s...\n", f); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* Startup and online newly-attached CPUs */ 3740Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 3750Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 3760Sstevel@tonic-gate struct cpu *cp; 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate cp = cpu_get(up->sbc_cpu_id); 3810Sstevel@tonic-gate if (cp == NULL) { 3820Sstevel@tonic-gate cmn_err(CE_WARN, "%s: cpu_get failed for cpu %d", 3830Sstevel@tonic-gate f, up->sbc_cpu_id); 3840Sstevel@tonic-gate continue; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 3880Sstevel@tonic-gate if (cpu_poweron(cp) != 0) { 3890Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTART); 3900Sstevel@tonic-gate errflag = 1; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate PR_CPU("%s: cpu %d powered ON\n", f, up->sbc_cpu_id); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (cpu_is_offline(cp)) { 3960Sstevel@tonic-gate PR_CPU("%s: onlining cpu %d...\n", f, up->sbc_cpu_id); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate if (cpu_online(cp) != 0) { 3990Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_ONLINE); 4000Sstevel@tonic-gate errflag = 1; 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate mutex_exit(&cpu_lock); 407*3811Sbm42561 ndi_devi_exit(ddi_root_node(), hp->h_ndi); 4080Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (errflag) 4110Sstevel@tonic-gate return (-1); 4120Sstevel@tonic-gate else 4130Sstevel@tonic-gate return (0); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * dr_pre_release_cpu 4180Sstevel@tonic-gate * 4190Sstevel@tonic-gate * sbd error policy: Stops on first error. 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate int 4220Sstevel@tonic-gate dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate int c, cix, i, lastoffline = -1, rv = 0; 4250Sstevel@tonic-gate processorid_t cpuid; 4260Sstevel@tonic-gate struct cpu *cp; 4270Sstevel@tonic-gate dr_cpu_unit_t *up; 4280Sstevel@tonic-gate dr_devset_t devset; 4290Sstevel@tonic-gate sbd_dev_stat_t *ds; 4300Sstevel@tonic-gate static fn_t f = "dr_pre_release_cpu"; 4310Sstevel@tonic-gate int cpu_flags = 0; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate devset = DR_DEVS_PRESENT(hp->h_bd); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* allocate status struct storage. */ 4360Sstevel@tonic-gate ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) * 4371772Sjl139090 MAX_CPU_UNITS_PER_BOARD, KM_SLEEP); 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate cix = dr_cpu_status(hp, devset, ds); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate mutex_enter(&cpu_lock); 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 4440Sstevel@tonic-gate up = (dr_cpu_unit_t *)devlist[i]; 4450Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * The STARCAT platform borrows cpus for use by POST in 4490Sstevel@tonic-gate * iocage testing. These cpus cannot be unconfigured 4500Sstevel@tonic-gate * while they are in use for the iocage. 4510Sstevel@tonic-gate * This check determines if a CPU is currently in use 4520Sstevel@tonic-gate * for iocage testing, and if so, returns a "Device busy" 4530Sstevel@tonic-gate * error. 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate for (c = 0; c < cix; c++) { 4560Sstevel@tonic-gate if (ds[c].d_cpu.cs_unit == up->sbc_cm.sbdev_unum) { 4570Sstevel@tonic-gate if (ds[c].d_cpu.cs_busy) { 4580Sstevel@tonic-gate dr_dev_err(CE_WARN, 4590Sstevel@tonic-gate &up->sbc_cm, ESBD_BUSY); 4600Sstevel@tonic-gate rv = -1; 4610Sstevel@tonic-gate break; 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate if (c < cix) 4660Sstevel@tonic-gate break; 4670Sstevel@tonic-gate cpuid = up->sbc_cpu_id; 4680Sstevel@tonic-gate if ((cp = cpu_get(cpuid)) == NULL) { 4690Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 4700Sstevel@tonic-gate rv = -1; 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* used by dr_cancel_cpu during error flow */ 4750Sstevel@tonic-gate up->sbc_cpu_flags = cp->cpu_flags; 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate if (CPU_ACTIVE(cp)) { 4780Sstevel@tonic-gate if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 4790Sstevel@tonic-gate cpu_flags = CPU_FORCED; 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate PR_CPU("%s: offlining cpu %d\n", f, cpuid); 4820Sstevel@tonic-gate if (cpu_offline(cp, cpu_flags)) { 4830Sstevel@tonic-gate PR_CPU("%s: failed to offline cpu %d\n", 4840Sstevel@tonic-gate f, cpuid); 4850Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 4860Sstevel@tonic-gate if (disp_bound_threads(cp, 0)) { 4870Sstevel@tonic-gate cmn_err(CE_WARN, "%s: thread(s) " 4880Sstevel@tonic-gate "bound to cpu %d", 4891772Sjl139090 f, cp->cpu_id); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate rv = -1; 4920Sstevel@tonic-gate break; 4930Sstevel@tonic-gate } else 4940Sstevel@tonic-gate lastoffline = i; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if (!rv) { 4980Sstevel@tonic-gate sbd_error_t *err; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate err = drmach_release(up->sbc_cm.sbdev_id); 5010Sstevel@tonic-gate if (err) { 5020Sstevel@tonic-gate DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 5030Sstevel@tonic-gate rv = -1; 5040Sstevel@tonic-gate break; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate mutex_exit(&cpu_lock); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate if (rv) { 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * Need to unwind others since at this level (pre-release) 5140Sstevel@tonic-gate * the device state has not yet transitioned and failures 5150Sstevel@tonic-gate * will prevent us from reaching the "post" release 5160Sstevel@tonic-gate * function where states are normally transitioned. 5170Sstevel@tonic-gate */ 5180Sstevel@tonic-gate for (i = lastoffline; i >= 0; i--) { 5190Sstevel@tonic-gate up = (dr_cpu_unit_t *)devlist[i]; 5200Sstevel@tonic-gate (void) dr_cancel_cpu(up); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate kmem_free(ds, sizeof (sbd_dev_stat_t) * MAX_CPU_UNITS_PER_BOARD); 5250Sstevel@tonic-gate return (rv); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * dr_pre_detach_cpu 5300Sstevel@tonic-gate * 5310Sstevel@tonic-gate * sbd error policy: Stops on first error. 5320Sstevel@tonic-gate */ 5330Sstevel@tonic-gate int 5340Sstevel@tonic-gate dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 5350Sstevel@tonic-gate { 5360Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate int i; 5390Sstevel@tonic-gate int curr_cpu; 5400Sstevel@tonic-gate int next_cpu; 5410Sstevel@tonic-gate int cpu_flags = 0; 5420Sstevel@tonic-gate static fn_t f = "dr_pre_detach_cpu"; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate PR_CPU("%s...\n", f); 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * Block out status threads while destroying devinfo tree 5480Sstevel@tonic-gate * branches 5490Sstevel@tonic-gate */ 5500Sstevel@tonic-gate dr_lock_status(hp->h_bd); 5510Sstevel@tonic-gate mutex_enter(&cpu_lock); 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate for (next_cpu = 0, i = 0; i < devnum; i++) { 5540Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 5550Sstevel@tonic-gate struct cpu *cp; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate cp = cpu_get(up->sbc_cpu_id); 5600Sstevel@tonic-gate if (cp == NULL) 5610Sstevel@tonic-gate continue; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * Print a console message for each attachment 5650Sstevel@tonic-gate * point. For CMP devices, this means that only 5660Sstevel@tonic-gate * one message should be printed, no matter how 5670Sstevel@tonic-gate * many cores are actually present. 5680Sstevel@tonic-gate */ 5691772Sjl139090 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 5701772Sjl139090 SBD_COMP_CPU); 5710Sstevel@tonic-gate if (curr_cpu >= next_cpu) { 5720Sstevel@tonic-gate cmn_err(CE_CONT, "OS unconfigure %s\n", 5730Sstevel@tonic-gate up->sbc_cm.sbdev_path); 5740Sstevel@tonic-gate next_cpu = curr_cpu + 1; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * CPUs were offlined during Release. 5790Sstevel@tonic-gate */ 5800Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 5810Sstevel@tonic-gate PR_CPU("%s: cpu %d already powered OFF\n", 5820Sstevel@tonic-gate f, up->sbc_cpu_id); 5830Sstevel@tonic-gate continue; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (!cpu_is_offline(cp)) { 5870Sstevel@tonic-gate if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 5880Sstevel@tonic-gate cpu_flags = CPU_FORCED; 5890Sstevel@tonic-gate /* cpu was onlined after release. Offline it again */ 5900Sstevel@tonic-gate PR_CPU("%s: offlining cpu %d\n", f, up->sbc_cpu_id); 5910Sstevel@tonic-gate if (cpu_offline(cp, cpu_flags)) { 5920Sstevel@tonic-gate PR_CPU("%s: failed to offline cpu %d\n", 5930Sstevel@tonic-gate f, up->sbc_cpu_id); 5940Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 5950Sstevel@tonic-gate if (disp_bound_threads(cp, 0)) { 5960Sstevel@tonic-gate cmn_err(CE_WARN, "%s: thread(s) " 5970Sstevel@tonic-gate "bound to cpu %d", 5981772Sjl139090 f, cp->cpu_id); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate goto err; 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate if (cpu_poweroff(cp) != 0) { 6040Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTOP); 6050Sstevel@tonic-gate goto err; 6060Sstevel@tonic-gate } else { 6070Sstevel@tonic-gate PR_CPU("%s: cpu %d powered OFF\n", f, up->sbc_cpu_id); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate return (0); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate err: 6140Sstevel@tonic-gate mutex_exit(&cpu_lock); 6150Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 6160Sstevel@tonic-gate return (-1); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate /*ARGSUSED*/ 6200Sstevel@tonic-gate void 6210Sstevel@tonic-gate dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 6220Sstevel@tonic-gate { 6230Sstevel@tonic-gate sbd_error_t *err; 6240Sstevel@tonic-gate processorid_t cpuid; 6250Sstevel@tonic-gate int rv; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 6300Sstevel@tonic-gate if (err) { 6310Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 6320Sstevel@tonic-gate } else if ((rv = cpu_unconfigure(cpuid)) != 0) { 6330Sstevel@tonic-gate dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv)); 6340Sstevel@tonic-gate } else { 6351772Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 6360Sstevel@tonic-gate if (err) { 6370Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /*ARGSUSED1*/ 6430Sstevel@tonic-gate int 6440Sstevel@tonic-gate dr_post_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 6450Sstevel@tonic-gate { 6460Sstevel@tonic-gate static fn_t f = "dr_post_detach_cpu"; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate PR_CPU("%s...\n", f); 6490Sstevel@tonic-gate hp->h_ndi = 0; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate mutex_exit(&cpu_lock); 6520Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate return (0); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate static void 6580Sstevel@tonic-gate dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate ASSERT(cp && pstat && csp); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* Fill in the common status information */ 6630Sstevel@tonic-gate bzero((caddr_t)csp, sizeof (*csp)); 6640Sstevel@tonic-gate csp->cs_type = cp->sbc_cm.sbdev_type; 6650Sstevel@tonic-gate csp->cs_unit = cp->sbc_cm.sbdev_unum; 6660Sstevel@tonic-gate strncpy(csp->cs_name, pstat->type, sizeof (csp->cs_name)); 6670Sstevel@tonic-gate csp->cs_cond = cp->sbc_cm.sbdev_cond; 6680Sstevel@tonic-gate csp->cs_busy = cp->sbc_cm.sbdev_busy | pstat->busy; 6690Sstevel@tonic-gate csp->cs_time = cp->sbc_cm.sbdev_time; 6700Sstevel@tonic-gate csp->cs_ostate = cp->sbc_cm.sbdev_ostate; 6710Sstevel@tonic-gate csp->cs_suspend = 0; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* CPU specific status data */ 6740Sstevel@tonic-gate csp->cs_cpuid = cp->sbc_cpu_id; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate #ifdef _STARFIRE 6770Sstevel@tonic-gate csp->cs_isbootproc = (SIGBCPU->cpu_id == cp->sbc_cpu_id) ? 1 : 0; 6780Sstevel@tonic-gate #endif /* _STARFIRE */ 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* 6810Sstevel@tonic-gate * If the speed and ecache properties have not been 6820Sstevel@tonic-gate * cached yet, read them in from the device tree. 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0)) 6850Sstevel@tonic-gate dr_cpu_set_prop(cp); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* use the cached speed and ecache values */ 6880Sstevel@tonic-gate csp->cs_speed = cp->sbc_speed; 6890Sstevel@tonic-gate csp->cs_ecache = cp->sbc_ecache; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate mutex_enter(&cpu_lock); 6920Sstevel@tonic-gate if (!cpu_get(csp->cs_cpuid)) { 6930Sstevel@tonic-gate /* ostate must be UNCONFIGURED */ 6940Sstevel@tonic-gate csp->cs_cm.c_ostate = SBD_STAT_UNCONFIGURED; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate mutex_exit(&cpu_lock); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate static void 7000Sstevel@tonic-gate dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp) 7010Sstevel@tonic-gate { 7020Sstevel@tonic-gate int core; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate ASSERT(csp && psp && (ncores >= 1)); 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate bzero((caddr_t)psp, sizeof (*psp)); 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * Fill in the common status information based 7100Sstevel@tonic-gate * on the data for the first core. 7110Sstevel@tonic-gate */ 7120Sstevel@tonic-gate psp->ps_type = SBD_COMP_CMP; 7131772Sjl139090 psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP); 7140Sstevel@tonic-gate strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name)); 7150Sstevel@tonic-gate psp->ps_cond = csp->cs_cond; 7160Sstevel@tonic-gate psp->ps_busy = csp->cs_busy; 7170Sstevel@tonic-gate psp->ps_time = csp->cs_time; 7180Sstevel@tonic-gate psp->ps_ostate = csp->cs_ostate; 7190Sstevel@tonic-gate psp->ps_suspend = csp->cs_suspend; 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* CMP specific status data */ 7220Sstevel@tonic-gate *psp->ps_cpuid = csp->cs_cpuid; 7230Sstevel@tonic-gate psp->ps_ncores = 1; 7240Sstevel@tonic-gate psp->ps_speed = csp->cs_speed; 7250Sstevel@tonic-gate psp->ps_ecache = csp->cs_ecache; 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* 7280Sstevel@tonic-gate * Walk through the data for the remaining cores. 7290Sstevel@tonic-gate * Make any adjustments to the common status data, 7300Sstevel@tonic-gate * or the shared CMP specific data if necessary. 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate for (core = 1; core < ncores; core++) { 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * The following properties should be the same 7360Sstevel@tonic-gate * for all the cores of the CMP. 7370Sstevel@tonic-gate */ 7381772Sjl139090 ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM( 7391772Sjl139090 csp[core].cs_unit, SBD_COMP_CMP)); 7400Sstevel@tonic-gate ASSERT(psp->ps_speed == csp[core].cs_speed); 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate psp->ps_cpuid[core] = csp[core].cs_cpuid; 7430Sstevel@tonic-gate psp->ps_ncores++; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate /* 7460Sstevel@tonic-gate * Jaguar has a split ecache, so the ecache 7470Sstevel@tonic-gate * for each core must be added together to 7480Sstevel@tonic-gate * get the total ecache for the whole chip. 7490Sstevel@tonic-gate */ 7500Sstevel@tonic-gate if (IS_JAGUAR(impl)) { 7510Sstevel@tonic-gate psp->ps_ecache += csp[core].cs_ecache; 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* adjust time if necessary */ 7550Sstevel@tonic-gate if (csp[core].cs_time > psp->ps_time) { 7560Sstevel@tonic-gate psp->ps_time = csp[core].cs_time; 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate psp->ps_busy |= csp[core].cs_busy; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate /* 7620Sstevel@tonic-gate * If any of the cores are configured, the 7630Sstevel@tonic-gate * entire CMP is marked as configured. 7640Sstevel@tonic-gate */ 7650Sstevel@tonic-gate if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) { 7660Sstevel@tonic-gate psp->ps_ostate = csp[core].cs_ostate; 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate int 7720Sstevel@tonic-gate dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) 7730Sstevel@tonic-gate { 7740Sstevel@tonic-gate int cmp; 7750Sstevel@tonic-gate int core; 7760Sstevel@tonic-gate int ncpu; 7770Sstevel@tonic-gate dr_board_t *bp; 7780Sstevel@tonic-gate sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP]; 7791772Sjl139090 int impl; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate bp = hp->h_bd; 7820Sstevel@tonic-gate ncpu = 0; 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate devset &= DR_DEVS_PRESENT(bp); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate /* 7870Sstevel@tonic-gate * Treat every CPU as a CMP. In the case where the 7880Sstevel@tonic-gate * device is not a CMP, treat it as a CMP with only 7890Sstevel@tonic-gate * one core. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate for (cmp = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) { 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate int ncores; 7940Sstevel@tonic-gate dr_cpu_unit_t *cp; 7950Sstevel@tonic-gate drmach_status_t pstat; 7960Sstevel@tonic-gate sbd_error_t *err; 7970Sstevel@tonic-gate sbd_cmp_stat_t *psp; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate if ((devset & DEVSET(SBD_COMP_CMP, cmp)) == 0) { 8000Sstevel@tonic-gate continue; 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate ncores = 0; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate for (core = 0; core < MAX_CORES_PER_CMP; core++) { 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, DR_CMP_CORE_UNUM(cmp, core)); 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate if (cp->sbc_cm.sbdev_state == DR_STATE_EMPTY) { 8100Sstevel@tonic-gate /* present, but not fully initialized */ 8110Sstevel@tonic-gate continue; 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, cp)); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* skip if not present */ 8170Sstevel@tonic-gate if (cp->sbc_cm.sbdev_id == (drmachid_t)0) { 8180Sstevel@tonic-gate continue; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* fetch platform status */ 8220Sstevel@tonic-gate err = drmach_status(cp->sbc_cm.sbdev_id, &pstat); 8230Sstevel@tonic-gate if (err) { 8240Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 8250Sstevel@tonic-gate continue; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]); 8291772Sjl139090 /* 8301772Sjl139090 * We should set impl here because the last core 8311772Sjl139090 * found might be EMPTY or not present. 8321772Sjl139090 */ 8331772Sjl139090 impl = cp->sbc_cpu_impl; 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate if (ncores == 0) { 8370Sstevel@tonic-gate continue; 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * Store the data to the outgoing array. If the 8420Sstevel@tonic-gate * device is a CMP, combine all the data for the 8430Sstevel@tonic-gate * cores into a single stat structure. 8440Sstevel@tonic-gate * 8450Sstevel@tonic-gate * The check for a CMP device uses the last core 8460Sstevel@tonic-gate * found, assuming that all cores will have the 8470Sstevel@tonic-gate * same implementation. 8480Sstevel@tonic-gate */ 8491772Sjl139090 8501772Sjl139090 if (CPU_IMPL_IS_CMP(impl)) { 8510Sstevel@tonic-gate psp = (sbd_cmp_stat_t *)dsp; 8521772Sjl139090 dr_fill_cmp_stat(cstat, ncores, impl, psp); 8530Sstevel@tonic-gate } else { 8540Sstevel@tonic-gate ASSERT(ncores == 1); 8550Sstevel@tonic-gate bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t)); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate dsp++; 8590Sstevel@tonic-gate ncpu++; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate return (ncpu); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* 8660Sstevel@tonic-gate * Cancel previous release operation for cpu. 8670Sstevel@tonic-gate * For cpus this means simply bringing cpus that 8680Sstevel@tonic-gate * were offline back online. Note that they had 8690Sstevel@tonic-gate * to have been online at the time there were 8700Sstevel@tonic-gate * released. 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate int 8730Sstevel@tonic-gate dr_cancel_cpu(dr_cpu_unit_t *up) 8740Sstevel@tonic-gate { 8750Sstevel@tonic-gate int rv = 0; 8760Sstevel@tonic-gate static fn_t f = "dr_cancel_cpu"; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate if (cpu_flagged_active(up->sbc_cpu_flags)) { 8810Sstevel@tonic-gate struct cpu *cp; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate /* 8840Sstevel@tonic-gate * CPU had been online, go ahead 8850Sstevel@tonic-gate * bring it back online. 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate PR_CPU("%s: bringing cpu %d back ONLINE\n", 8880Sstevel@tonic-gate f, up->sbc_cpu_id); 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate mutex_enter(&cpu_lock); 8910Sstevel@tonic-gate cp = cpu[up->sbc_cpu_id]; 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 8940Sstevel@tonic-gate if (cpu_poweron(cp)) { 8950Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to power-on " 8960Sstevel@tonic-gate "cpu %d", f, up->sbc_cpu_id); 8970Sstevel@tonic-gate rv = -1; 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate if (cpu_is_offline(cp)) { 9020Sstevel@tonic-gate if (cpu_online(cp)) { 9030Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to online cpu %d", 9040Sstevel@tonic-gate f, up->sbc_cpu_id); 9050Sstevel@tonic-gate rv = -1; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (cpu_is_online(cp)) { 9100Sstevel@tonic-gate if (cpu_flagged_nointr(up->sbc_cpu_flags)) { 9110Sstevel@tonic-gate if (cpu_intr_disable(cp) != 0) { 9120Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to " 9131772Sjl139090 "disable interrupts on cpu %d", 9141772Sjl139090 f, up->sbc_cpu_id); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate mutex_exit(&cpu_lock); 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate return (rv); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate int 9260Sstevel@tonic-gate dr_disconnect_cpu(dr_cpu_unit_t *up) 9270Sstevel@tonic-gate { 9280Sstevel@tonic-gate sbd_error_t *err; 9290Sstevel@tonic-gate static fn_t f = "dr_disconnect_cpu"; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate PR_CPU("%s...\n", f); 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate ASSERT((up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) || 9340Sstevel@tonic-gate (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED)); 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate if (up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) { 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * Cpus were never brought in and so are still 9410Sstevel@tonic-gate * effectively disconnected, so nothing to do here. 9420Sstevel@tonic-gate */ 9430Sstevel@tonic-gate PR_CPU("%s: cpu %d never brought in\n", 9440Sstevel@tonic-gate f, up->sbc_cpu_id); 9450Sstevel@tonic-gate return (0); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate err = drmach_cpu_disconnect(up->sbc_cm.sbdev_id); 9490Sstevel@tonic-gate if (err == NULL) 9500Sstevel@tonic-gate return (0); 9510Sstevel@tonic-gate else { 9520Sstevel@tonic-gate DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 9530Sstevel@tonic-gate return (-1); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate /*NOTREACHED*/ 9560Sstevel@tonic-gate } 957