17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*07d06da5SSurya Prakki 227c478bd9Sstevel@tonic-gate /* 23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * CPU support routines for DR 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/note.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 377c478bd9Sstevel@tonic-gate #include <sys/devops.h> 387c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 397c478bd9Sstevel@tonic-gate #include <sys/poll.h> 407c478bd9Sstevel@tonic-gate #include <sys/conf.h> 417c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 427c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 437c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 447c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 457c478bd9Sstevel@tonic-gate #include <sys/stat.h> 467c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 477c478bd9Sstevel@tonic-gate #include <sys/processor.h> 487c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 497c478bd9Sstevel@tonic-gate #include <sys/mem_config.h> 507c478bd9Sstevel@tonic-gate #include <sys/promif.h> 517c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 527c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 537c478bd9Sstevel@tonic-gate #include <sys/membar.h> 547c478bd9Sstevel@tonic-gate #include <sys/stack.h> 557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 567c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 577c478bd9Sstevel@tonic-gate #include <sys/spitregs.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 607c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 617c478bd9Sstevel@tonic-gate #include <sys/pte.h> 627c478bd9Sstevel@tonic-gate #include <sys/mmu.h> 637c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 647c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 6525cf1a30Sjl139090 #include <sys/cpu_impl.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 687c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #include <sys/dr.h> 717c478bd9Sstevel@tonic-gate #include <sys/dr_util.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 747c478bd9Sstevel@tonic-gate #include <sys/starfire.h> 757c478bd9Sstevel@tonic-gate extern struct cpu *SIGBCPU; 767c478bd9Sstevel@tonic-gate #else 777c478bd9Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ 787c478bd9Sstevel@tonic-gate static char *dr_ie_fmt = "dr_cpu.c %d"; 797c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate int 827c478bd9Sstevel@tonic-gate dr_cpu_unit_is_sane(dr_board_t *bp, dr_cpu_unit_t *cp) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate #ifdef DEBUG 857c478bd9Sstevel@tonic-gate processorid_t cpuid; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * cpuid and unit number should never be different 897c478bd9Sstevel@tonic-gate * than they were at discovery/connect time 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate ASSERT(drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid) == 0); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate ASSERT(cp->sbc_cm.sbdev_bp == bp); 947c478bd9Sstevel@tonic-gate ASSERT(cp->sbc_cm.sbdev_type == SBD_COMP_CPU); 957c478bd9Sstevel@tonic-gate ASSERT(cp->sbc_cpu_id == cpuid); 967c478bd9Sstevel@tonic-gate #else 977c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(bp)) 987c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(cp)) 997c478bd9Sstevel@tonic-gate #endif 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate return (1); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static int 1057c478bd9Sstevel@tonic-gate dr_errno2ecode(int error) 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate int rv; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate switch (error) { 1107c478bd9Sstevel@tonic-gate case EBUSY: 1117c478bd9Sstevel@tonic-gate rv = ESBD_BUSY; 1127c478bd9Sstevel@tonic-gate break; 1137c478bd9Sstevel@tonic-gate case EINVAL: 1147c478bd9Sstevel@tonic-gate rv = ESBD_INVAL; 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate case EALREADY: 1177c478bd9Sstevel@tonic-gate rv = ESBD_ALREADY; 1187c478bd9Sstevel@tonic-gate break; 1197c478bd9Sstevel@tonic-gate case ENODEV: 1207c478bd9Sstevel@tonic-gate rv = ESBD_NODEV; 1217c478bd9Sstevel@tonic-gate break; 1227c478bd9Sstevel@tonic-gate case ENOMEM: 1237c478bd9Sstevel@tonic-gate rv = ESBD_NOMEM; 1247c478bd9Sstevel@tonic-gate break; 1257c478bd9Sstevel@tonic-gate default: 1267c478bd9Sstevel@tonic-gate rv = ESBD_INVAL; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate return (rv); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static void 1337c478bd9Sstevel@tonic-gate dr_cpu_set_prop(dr_cpu_unit_t *cp) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate sbd_error_t *err; 1367c478bd9Sstevel@tonic-gate dev_info_t *dip; 1377c478bd9Sstevel@tonic-gate uint64_t clock_freq; 1387c478bd9Sstevel@tonic-gate int ecache_size = 0; 1397c478bd9Sstevel@tonic-gate char *cache_str = NULL; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate err = drmach_get_dip(cp->sbc_cm.sbdev_id, &dip); 1427c478bd9Sstevel@tonic-gate if (err) { 1437c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 1447c478bd9Sstevel@tonic-gate return; 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if (dip == NULL) { 1487c478bd9Sstevel@tonic-gate #ifndef _STARFIRE 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * Do not report an error on Starfire since 1517c478bd9Sstevel@tonic-gate * the dip will not be created until after 1527c478bd9Sstevel@tonic-gate * the CPU has been configured. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate DR_DEV_INTERNAL_ERROR(&cp->sbc_cm); 1557c478bd9Sstevel@tonic-gate #endif /* !_STARFIRE */ 1567c478bd9Sstevel@tonic-gate return; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* read in the CPU speed */ 16025cf1a30Sjl139090 16125cf1a30Sjl139090 /* 16225cf1a30Sjl139090 * If the property is not found in the CPU node, it has to be 16325cf1a30Sjl139090 * kept in the core or cmp node so we just keep looking. 16425cf1a30Sjl139090 */ 165e98fafb9Sjl139090 clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 166e98fafb9Sjl139090 "clock-frequency", 0); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate ASSERT(clock_freq != 0); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * The ecache property string is not the same 1727c478bd9Sstevel@tonic-gate * for all CPU implementations. 1737c478bd9Sstevel@tonic-gate */ 17425cf1a30Sjl139090 1757c478bd9Sstevel@tonic-gate switch (cp->sbc_cpu_impl) { 1767c478bd9Sstevel@tonic-gate case BLACKBIRD_IMPL: 1777c478bd9Sstevel@tonic-gate case CHEETAH_IMPL: 1787c478bd9Sstevel@tonic-gate case CHEETAH_PLUS_IMPL: 1797c478bd9Sstevel@tonic-gate cache_str = "ecache-size"; 1807c478bd9Sstevel@tonic-gate break; 1817c478bd9Sstevel@tonic-gate case JAGUAR_IMPL: 18225cf1a30Sjl139090 case OLYMPUS_C_IMPL: 183e98fafb9Sjl139090 case JUPITER_IMPL: 1847c478bd9Sstevel@tonic-gate cache_str = "l2-cache-size"; 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate case PANTHER_IMPL: 1877c478bd9Sstevel@tonic-gate cache_str = "l3-cache-size"; 1887c478bd9Sstevel@tonic-gate break; 1897c478bd9Sstevel@tonic-gate default: 1907c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Unknown cpu implementation=0x%x", 1917c478bd9Sstevel@tonic-gate cp->sbc_cpu_impl); 1927c478bd9Sstevel@tonic-gate ASSERT(0); 1937c478bd9Sstevel@tonic-gate break; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if (cache_str != NULL) { 1977c478bd9Sstevel@tonic-gate /* read in the ecache size */ 19825cf1a30Sjl139090 /* 19925cf1a30Sjl139090 * If the property is not found in the CPU node, 20025cf1a30Sjl139090 * it has to be kept in the core or cmp node so 20125cf1a30Sjl139090 * we just keep looking. 20225cf1a30Sjl139090 */ 20325cf1a30Sjl139090 204e98fafb9Sjl139090 ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 205e98fafb9Sjl139090 cache_str, 0); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate ASSERT(ecache_size != 0); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* convert to the proper units */ 2117c478bd9Sstevel@tonic-gate cp->sbc_speed = (clock_freq + 500000) / 1000000; 2127c478bd9Sstevel@tonic-gate cp->sbc_ecache = ecache_size / (1024 * 1024); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate void 2167c478bd9Sstevel@tonic-gate dr_init_cpu_unit(dr_cpu_unit_t *cp) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate sbd_error_t *err; 2197c478bd9Sstevel@tonic-gate dr_state_t new_state; 2207c478bd9Sstevel@tonic-gate int cpuid; 2217c478bd9Sstevel@tonic-gate int impl; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (DR_DEV_IS_ATTACHED(&cp->sbc_cm)) { 2247c478bd9Sstevel@tonic-gate new_state = DR_STATE_CONFIGURED; 2257c478bd9Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_OK; 2267c478bd9Sstevel@tonic-gate } else if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 2277c478bd9Sstevel@tonic-gate new_state = DR_STATE_CONNECTED; 2287c478bd9Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_OK; 2297c478bd9Sstevel@tonic-gate } else { 2307c478bd9Sstevel@tonic-gate new_state = DR_STATE_EMPTY; 2317c478bd9Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = SBD_COND_UNKNOWN; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (DR_DEV_IS_PRESENT(&cp->sbc_cm)) { 2357c478bd9Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbc_cm.sbdev_id, &cpuid); 2367c478bd9Sstevel@tonic-gate if (err) { 2377c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 2387c478bd9Sstevel@tonic-gate new_state = DR_STATE_FATAL; 2397c478bd9Sstevel@tonic-gate goto done; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate err = drmach_cpu_get_impl(cp->sbc_cm.sbdev_id, &impl); 2437c478bd9Sstevel@tonic-gate if (err) { 2447c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 2457c478bd9Sstevel@tonic-gate new_state = DR_STATE_FATAL; 2467c478bd9Sstevel@tonic-gate goto done; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate } else { 2497c478bd9Sstevel@tonic-gate cp->sbc_cpu_id = -1; 2507c478bd9Sstevel@tonic-gate cp->sbc_cpu_impl = -1; 2517c478bd9Sstevel@tonic-gate goto done; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate cp->sbc_cpu_id = cpuid; 2557c478bd9Sstevel@tonic-gate cp->sbc_cpu_impl = impl; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* if true at init time, it must always be true */ 2587c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(cp->sbc_cm.sbdev_bp, cp)); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 2617c478bd9Sstevel@tonic-gate if ((cpuid >= 0) && cpu[cpuid]) 2627c478bd9Sstevel@tonic-gate cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 2637c478bd9Sstevel@tonic-gate else 2647c478bd9Sstevel@tonic-gate cp->sbc_cpu_flags = P_OFFLINE | P_POWEROFF; 2657c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate dr_cpu_set_prop(cp); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate done: 2707c478bd9Sstevel@tonic-gate /* delay transition until fully initialized */ 2717c478bd9Sstevel@tonic-gate dr_device_transition(&cp->sbc_cm, new_state); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate int 2757c478bd9Sstevel@tonic-gate dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate int i; 2787c478bd9Sstevel@tonic-gate int curr_cpu; 2797c478bd9Sstevel@tonic-gate int next_cpu; 2807c478bd9Sstevel@tonic-gate static fn_t f = "dr_pre_attach_cpu"; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate PR_CPU("%s...\n", f); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate for (next_cpu = 0, i = 0; i < devnum; i++) { 2857c478bd9Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * Print a console message for each attachment 2917c478bd9Sstevel@tonic-gate * point. For CMP devices, this means that only 2927c478bd9Sstevel@tonic-gate * one message should be printed, no matter how 2937c478bd9Sstevel@tonic-gate * many cores are actually present. 2947c478bd9Sstevel@tonic-gate */ 29525cf1a30Sjl139090 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 29625cf1a30Sjl139090 SBD_COMP_CPU); 2977c478bd9Sstevel@tonic-gate if (curr_cpu >= next_cpu) { 2987c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "OS configure %s", 2997c478bd9Sstevel@tonic-gate up->sbc_cm.sbdev_path); 3007c478bd9Sstevel@tonic-gate next_cpu = curr_cpu + 1; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED) { 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * If we're coming from the UNCONFIGURED 3067c478bd9Sstevel@tonic-gate * state then the cpu's sigblock will 3077c478bd9Sstevel@tonic-gate * still be mapped in. Need to unmap it 3087c478bd9Sstevel@tonic-gate * before continuing with attachment. 3097c478bd9Sstevel@tonic-gate */ 310e98fafb9Sjl139090 PR_CPU("%s: unmapping sigblk for cpu %d\n", f, 311e98fafb9Sjl139090 up->sbc_cpu_id); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate CPU_SGN_MAPOUT(up->sbc_cpu_id); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * Block out status threads while creating 3197c478bd9Sstevel@tonic-gate * devinfo tree branches 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate dr_lock_status(hp->h_bd); 322afc2fd2aSbm42561 ndi_devi_enter(ddi_root_node(), (int *)(&hp->h_ndi)); 3237c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate return (0); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3297c478bd9Sstevel@tonic-gate void 3307c478bd9Sstevel@tonic-gate dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 3317c478bd9Sstevel@tonic-gate { 3327c478bd9Sstevel@tonic-gate sbd_error_t *err; 3337c478bd9Sstevel@tonic-gate processorid_t cpuid; 3347c478bd9Sstevel@tonic-gate int rv; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate err = drmach_configure(cp->sbdev_id, 0); 3397c478bd9Sstevel@tonic-gate if (err) { 3407c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3417c478bd9Sstevel@tonic-gate return; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 3457c478bd9Sstevel@tonic-gate if (err) { 3467c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3477c478bd9Sstevel@tonic-gate 34825cf1a30Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 3497c478bd9Sstevel@tonic-gate if (err) 3507c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 3517c478bd9Sstevel@tonic-gate } else if ((rv = cpu_configure(cpuid)) != 0) { 3527c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv)); 35325cf1a30Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 3547c478bd9Sstevel@tonic-gate if (err) 3557c478bd9Sstevel@tonic-gate sbd_err_clear(&err); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * dr_post_attach_cpu 3617c478bd9Sstevel@tonic-gate * 3627c478bd9Sstevel@tonic-gate * sbd error policy: Does not stop on error. Processes all units in list. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate int 3657c478bd9Sstevel@tonic-gate dr_post_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate int i; 3687c478bd9Sstevel@tonic-gate int errflag = 0; 3697c478bd9Sstevel@tonic-gate static fn_t f = "dr_post_attach_cpu"; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate PR_CPU("%s...\n", f); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* Startup and online newly-attached CPUs */ 3747c478bd9Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 3757c478bd9Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 3767c478bd9Sstevel@tonic-gate struct cpu *cp; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate cp = cpu_get(up->sbc_cpu_id); 3817c478bd9Sstevel@tonic-gate if (cp == NULL) { 3827c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: cpu_get failed for cpu %d", 3837c478bd9Sstevel@tonic-gate f, up->sbc_cpu_id); 3847c478bd9Sstevel@tonic-gate continue; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 3887c478bd9Sstevel@tonic-gate if (cpu_poweron(cp) != 0) { 3897c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTART); 3907c478bd9Sstevel@tonic-gate errflag = 1; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate PR_CPU("%s: cpu %d powered ON\n", f, up->sbc_cpu_id); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate if (cpu_is_offline(cp)) { 3967c478bd9Sstevel@tonic-gate PR_CPU("%s: onlining cpu %d...\n", f, up->sbc_cpu_id); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate if (cpu_online(cp) != 0) { 3997c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_ONLINE); 4007c478bd9Sstevel@tonic-gate errflag = 1; 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 407afc2fd2aSbm42561 ndi_devi_exit(ddi_root_node(), hp->h_ndi); 4087c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (errflag) 4117c478bd9Sstevel@tonic-gate return (-1); 4127c478bd9Sstevel@tonic-gate else 4137c478bd9Sstevel@tonic-gate return (0); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * dr_pre_release_cpu 4187c478bd9Sstevel@tonic-gate * 4197c478bd9Sstevel@tonic-gate * sbd error policy: Stops on first error. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate int 4227c478bd9Sstevel@tonic-gate dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate int c, cix, i, lastoffline = -1, rv = 0; 4257c478bd9Sstevel@tonic-gate processorid_t cpuid; 4267c478bd9Sstevel@tonic-gate struct cpu *cp; 4277c478bd9Sstevel@tonic-gate dr_cpu_unit_t *up; 4287c478bd9Sstevel@tonic-gate dr_devset_t devset; 4297c478bd9Sstevel@tonic-gate sbd_dev_stat_t *ds; 4307c478bd9Sstevel@tonic-gate static fn_t f = "dr_pre_release_cpu"; 4317c478bd9Sstevel@tonic-gate int cpu_flags = 0; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate devset = DR_DEVS_PRESENT(hp->h_bd); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* allocate status struct storage. */ 4367c478bd9Sstevel@tonic-gate ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) * 4377c478bd9Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, KM_SLEEP); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate cix = dr_cpu_status(hp, devset, ds); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 4447c478bd9Sstevel@tonic-gate up = (dr_cpu_unit_t *)devlist[i]; 4457c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * The STARCAT platform borrows cpus for use by POST in 4497c478bd9Sstevel@tonic-gate * iocage testing. These cpus cannot be unconfigured 4507c478bd9Sstevel@tonic-gate * while they are in use for the iocage. 4517c478bd9Sstevel@tonic-gate * This check determines if a CPU is currently in use 4527c478bd9Sstevel@tonic-gate * for iocage testing, and if so, returns a "Device busy" 4537c478bd9Sstevel@tonic-gate * error. 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate for (c = 0; c < cix; c++) { 4567c478bd9Sstevel@tonic-gate if (ds[c].d_cpu.cs_unit == up->sbc_cm.sbdev_unum) { 4577c478bd9Sstevel@tonic-gate if (ds[c].d_cpu.cs_busy) { 458e98fafb9Sjl139090 dr_dev_err(CE_WARN, &up->sbc_cm, 459e98fafb9Sjl139090 ESBD_BUSY); 4607c478bd9Sstevel@tonic-gate rv = -1; 4617c478bd9Sstevel@tonic-gate break; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate if (c < cix) 4667c478bd9Sstevel@tonic-gate break; 4677c478bd9Sstevel@tonic-gate cpuid = up->sbc_cpu_id; 4687c478bd9Sstevel@tonic-gate if ((cp = cpu_get(cpuid)) == NULL) { 4697c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 4707c478bd9Sstevel@tonic-gate rv = -1; 4717c478bd9Sstevel@tonic-gate break; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* used by dr_cancel_cpu during error flow */ 4757c478bd9Sstevel@tonic-gate up->sbc_cpu_flags = cp->cpu_flags; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (CPU_ACTIVE(cp)) { 4787c478bd9Sstevel@tonic-gate if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 4797c478bd9Sstevel@tonic-gate cpu_flags = CPU_FORCED; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate PR_CPU("%s: offlining cpu %d\n", f, cpuid); 4827c478bd9Sstevel@tonic-gate if (cpu_offline(cp, cpu_flags)) { 483e98fafb9Sjl139090 PR_CPU("%s: failed to offline cpu %d\n", f, 484e98fafb9Sjl139090 cpuid); 4857c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 4867c478bd9Sstevel@tonic-gate if (disp_bound_threads(cp, 0)) { 487e98fafb9Sjl139090 cmn_err(CE_WARN, "%s: thread(s) bound " 488e98fafb9Sjl139090 "to cpu %d", f, cp->cpu_id); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate rv = -1; 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate } else 4937c478bd9Sstevel@tonic-gate lastoffline = i; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if (!rv) { 4977c478bd9Sstevel@tonic-gate sbd_error_t *err; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate err = drmach_release(up->sbc_cm.sbdev_id); 5007c478bd9Sstevel@tonic-gate if (err) { 5017c478bd9Sstevel@tonic-gate DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 5027c478bd9Sstevel@tonic-gate rv = -1; 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (rv) { 5117c478bd9Sstevel@tonic-gate /* 5127c478bd9Sstevel@tonic-gate * Need to unwind others since at this level (pre-release) 5137c478bd9Sstevel@tonic-gate * the device state has not yet transitioned and failures 5147c478bd9Sstevel@tonic-gate * will prevent us from reaching the "post" release 5157c478bd9Sstevel@tonic-gate * function where states are normally transitioned. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate for (i = lastoffline; i >= 0; i--) { 5187c478bd9Sstevel@tonic-gate up = (dr_cpu_unit_t *)devlist[i]; 5197c478bd9Sstevel@tonic-gate (void) dr_cancel_cpu(up); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate kmem_free(ds, sizeof (sbd_dev_stat_t) * MAX_CPU_UNITS_PER_BOARD); 5247c478bd9Sstevel@tonic-gate return (rv); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* 5287c478bd9Sstevel@tonic-gate * dr_pre_detach_cpu 5297c478bd9Sstevel@tonic-gate * 5307c478bd9Sstevel@tonic-gate * sbd error policy: Stops on first error. 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate int 5337c478bd9Sstevel@tonic-gate dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate int i; 5387c478bd9Sstevel@tonic-gate int curr_cpu; 5397c478bd9Sstevel@tonic-gate int next_cpu; 5407c478bd9Sstevel@tonic-gate int cpu_flags = 0; 5417c478bd9Sstevel@tonic-gate static fn_t f = "dr_pre_detach_cpu"; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate PR_CPU("%s...\n", f); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * Block out status threads while destroying devinfo tree 5477c478bd9Sstevel@tonic-gate * branches 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate dr_lock_status(hp->h_bd); 5507c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate for (next_cpu = 0, i = 0; i < devnum; i++) { 5537c478bd9Sstevel@tonic-gate dr_cpu_unit_t *up = (dr_cpu_unit_t *)devlist[i]; 5547c478bd9Sstevel@tonic-gate struct cpu *cp; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, up)); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate cp = cpu_get(up->sbc_cpu_id); 5597c478bd9Sstevel@tonic-gate if (cp == NULL) 5607c478bd9Sstevel@tonic-gate continue; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * Print a console message for each attachment 5647c478bd9Sstevel@tonic-gate * point. For CMP devices, this means that only 5657c478bd9Sstevel@tonic-gate * one message should be printed, no matter how 5667c478bd9Sstevel@tonic-gate * many cores are actually present. 5677c478bd9Sstevel@tonic-gate */ 56825cf1a30Sjl139090 curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, 56925cf1a30Sjl139090 SBD_COMP_CPU); 5707c478bd9Sstevel@tonic-gate if (curr_cpu >= next_cpu) { 5717c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "OS unconfigure %s\n", 5727c478bd9Sstevel@tonic-gate up->sbc_cm.sbdev_path); 5737c478bd9Sstevel@tonic-gate next_cpu = curr_cpu + 1; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * CPUs were offlined during Release. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 5807c478bd9Sstevel@tonic-gate PR_CPU("%s: cpu %d already powered OFF\n", 5817c478bd9Sstevel@tonic-gate f, up->sbc_cpu_id); 5827c478bd9Sstevel@tonic-gate continue; 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate if (!cpu_is_offline(cp)) { 5867c478bd9Sstevel@tonic-gate if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) 5877c478bd9Sstevel@tonic-gate cpu_flags = CPU_FORCED; 5887c478bd9Sstevel@tonic-gate /* cpu was onlined after release. Offline it again */ 5897c478bd9Sstevel@tonic-gate PR_CPU("%s: offlining cpu %d\n", f, up->sbc_cpu_id); 5907c478bd9Sstevel@tonic-gate if (cpu_offline(cp, cpu_flags)) { 5917c478bd9Sstevel@tonic-gate PR_CPU("%s: failed to offline cpu %d\n", 5927c478bd9Sstevel@tonic-gate f, up->sbc_cpu_id); 5937c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_OFFLINE); 5947c478bd9Sstevel@tonic-gate if (disp_bound_threads(cp, 0)) { 595e98fafb9Sjl139090 cmn_err(CE_WARN, "%s: thread(s) bound " 596e98fafb9Sjl139090 "to cpu %d", f, cp->cpu_id); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate goto err; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate if (cpu_poweroff(cp) != 0) { 6027c478bd9Sstevel@tonic-gate dr_dev_err(CE_WARN, &up->sbc_cm, ESBD_CPUSTOP); 6037c478bd9Sstevel@tonic-gate goto err; 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate PR_CPU("%s: cpu %d powered OFF\n", f, up->sbc_cpu_id); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate return (0); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate err: 6127c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 6137c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 6147c478bd9Sstevel@tonic-gate return (-1); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6187c478bd9Sstevel@tonic-gate void 6197c478bd9Sstevel@tonic-gate dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) 6207c478bd9Sstevel@tonic-gate { 6217c478bd9Sstevel@tonic-gate sbd_error_t *err; 6227c478bd9Sstevel@tonic-gate processorid_t cpuid; 6237c478bd9Sstevel@tonic-gate int rv; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 6287c478bd9Sstevel@tonic-gate if (err) { 6297c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 6307c478bd9Sstevel@tonic-gate } else if ((rv = cpu_unconfigure(cpuid)) != 0) { 6317c478bd9Sstevel@tonic-gate dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv)); 6327c478bd9Sstevel@tonic-gate } else { 63325cf1a30Sjl139090 err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 6347c478bd9Sstevel@tonic-gate if (err) { 6357c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 6417c478bd9Sstevel@tonic-gate int 6427c478bd9Sstevel@tonic-gate dr_post_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate static fn_t f = "dr_post_detach_cpu"; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate PR_CPU("%s...\n", f); 6477c478bd9Sstevel@tonic-gate hp->h_ndi = 0; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 6507c478bd9Sstevel@tonic-gate dr_unlock_status(hp->h_bd); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate return (0); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate static void 6567c478bd9Sstevel@tonic-gate dr_fill_cpu_stat(dr_cpu_unit_t *cp, drmach_status_t *pstat, sbd_cpu_stat_t *csp) 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate ASSERT(cp && pstat && csp); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* Fill in the common status information */ 6617c478bd9Sstevel@tonic-gate bzero((caddr_t)csp, sizeof (*csp)); 6627c478bd9Sstevel@tonic-gate csp->cs_type = cp->sbc_cm.sbdev_type; 6637c478bd9Sstevel@tonic-gate csp->cs_unit = cp->sbc_cm.sbdev_unum; 664*07d06da5SSurya Prakki (void) strncpy(csp->cs_name, pstat->type, sizeof (csp->cs_name)); 6657c478bd9Sstevel@tonic-gate csp->cs_cond = cp->sbc_cm.sbdev_cond; 6667c478bd9Sstevel@tonic-gate csp->cs_busy = cp->sbc_cm.sbdev_busy | pstat->busy; 6677c478bd9Sstevel@tonic-gate csp->cs_time = cp->sbc_cm.sbdev_time; 6687c478bd9Sstevel@tonic-gate csp->cs_ostate = cp->sbc_cm.sbdev_ostate; 6697c478bd9Sstevel@tonic-gate csp->cs_suspend = 0; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* CPU specific status data */ 6727c478bd9Sstevel@tonic-gate csp->cs_cpuid = cp->sbc_cpu_id; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 6757c478bd9Sstevel@tonic-gate csp->cs_isbootproc = (SIGBCPU->cpu_id == cp->sbc_cpu_id) ? 1 : 0; 6767c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * If the speed and ecache properties have not been 6807c478bd9Sstevel@tonic-gate * cached yet, read them in from the device tree. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate if ((cp->sbc_speed == 0) || (cp->sbc_ecache == 0)) 6837c478bd9Sstevel@tonic-gate dr_cpu_set_prop(cp); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* use the cached speed and ecache values */ 6867c478bd9Sstevel@tonic-gate csp->cs_speed = cp->sbc_speed; 6877c478bd9Sstevel@tonic-gate csp->cs_ecache = cp->sbc_ecache; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 6907c478bd9Sstevel@tonic-gate if (!cpu_get(csp->cs_cpuid)) { 6917c478bd9Sstevel@tonic-gate /* ostate must be UNCONFIGURED */ 6927c478bd9Sstevel@tonic-gate csp->cs_cm.c_ostate = SBD_STAT_UNCONFIGURED; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate static void 6987c478bd9Sstevel@tonic-gate dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp) 6997c478bd9Sstevel@tonic-gate { 7007c478bd9Sstevel@tonic-gate int core; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate ASSERT(csp && psp && (ncores >= 1)); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate bzero((caddr_t)psp, sizeof (*psp)); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * Fill in the common status information based 7087c478bd9Sstevel@tonic-gate * on the data for the first core. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate psp->ps_type = SBD_COMP_CMP; 71125cf1a30Sjl139090 psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP); 712*07d06da5SSurya Prakki (void) strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name)); 7137c478bd9Sstevel@tonic-gate psp->ps_cond = csp->cs_cond; 7147c478bd9Sstevel@tonic-gate psp->ps_busy = csp->cs_busy; 7157c478bd9Sstevel@tonic-gate psp->ps_time = csp->cs_time; 7167c478bd9Sstevel@tonic-gate psp->ps_ostate = csp->cs_ostate; 7177c478bd9Sstevel@tonic-gate psp->ps_suspend = csp->cs_suspend; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* CMP specific status data */ 7207c478bd9Sstevel@tonic-gate *psp->ps_cpuid = csp->cs_cpuid; 7217c478bd9Sstevel@tonic-gate psp->ps_ncores = 1; 7227c478bd9Sstevel@tonic-gate psp->ps_speed = csp->cs_speed; 7237c478bd9Sstevel@tonic-gate psp->ps_ecache = csp->cs_ecache; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * Walk through the data for the remaining cores. 7277c478bd9Sstevel@tonic-gate * Make any adjustments to the common status data, 7287c478bd9Sstevel@tonic-gate * or the shared CMP specific data if necessary. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate for (core = 1; core < ncores; core++) { 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate /* 7337c478bd9Sstevel@tonic-gate * The following properties should be the same 7347c478bd9Sstevel@tonic-gate * for all the cores of the CMP. 7357c478bd9Sstevel@tonic-gate */ 736e98fafb9Sjl139090 ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM(csp[core].cs_unit, 737e98fafb9Sjl139090 SBD_COMP_CMP)); 7387c478bd9Sstevel@tonic-gate ASSERT(psp->ps_speed == csp[core].cs_speed); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate psp->ps_cpuid[core] = csp[core].cs_cpuid; 7417c478bd9Sstevel@tonic-gate psp->ps_ncores++; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * Jaguar has a split ecache, so the ecache 7457c478bd9Sstevel@tonic-gate * for each core must be added together to 7467c478bd9Sstevel@tonic-gate * get the total ecache for the whole chip. 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate if (IS_JAGUAR(impl)) { 7497c478bd9Sstevel@tonic-gate psp->ps_ecache += csp[core].cs_ecache; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* adjust time if necessary */ 7537c478bd9Sstevel@tonic-gate if (csp[core].cs_time > psp->ps_time) { 7547c478bd9Sstevel@tonic-gate psp->ps_time = csp[core].cs_time; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate psp->ps_busy |= csp[core].cs_busy; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate * If any of the cores are configured, the 7617c478bd9Sstevel@tonic-gate * entire CMP is marked as configured. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate if (csp[core].cs_ostate == SBD_STAT_CONFIGURED) { 7647c478bd9Sstevel@tonic-gate psp->ps_ostate = csp[core].cs_ostate; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate int 7707c478bd9Sstevel@tonic-gate dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) 7717c478bd9Sstevel@tonic-gate { 7727c478bd9Sstevel@tonic-gate int cmp; 7737c478bd9Sstevel@tonic-gate int core; 7747c478bd9Sstevel@tonic-gate int ncpu; 7757c478bd9Sstevel@tonic-gate dr_board_t *bp; 7767c478bd9Sstevel@tonic-gate sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP]; 77725cf1a30Sjl139090 int impl; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate bp = hp->h_bd; 7807c478bd9Sstevel@tonic-gate ncpu = 0; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate devset &= DR_DEVS_PRESENT(bp); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * Treat every CPU as a CMP. In the case where the 7867c478bd9Sstevel@tonic-gate * device is not a CMP, treat it as a CMP with only 7877c478bd9Sstevel@tonic-gate * one core. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate for (cmp = 0; cmp < MAX_CMP_UNITS_PER_BOARD; cmp++) { 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate int ncores; 7927c478bd9Sstevel@tonic-gate dr_cpu_unit_t *cp; 7937c478bd9Sstevel@tonic-gate drmach_status_t pstat; 7947c478bd9Sstevel@tonic-gate sbd_error_t *err; 7957c478bd9Sstevel@tonic-gate sbd_cmp_stat_t *psp; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate if ((devset & DEVSET(SBD_COMP_CMP, cmp)) == 0) { 7987c478bd9Sstevel@tonic-gate continue; 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate ncores = 0; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate for (core = 0; core < MAX_CORES_PER_CMP; core++) { 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, DR_CMP_CORE_UNUM(cmp, core)); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate if (cp->sbc_cm.sbdev_state == DR_STATE_EMPTY) { 8087c478bd9Sstevel@tonic-gate /* present, but not fully initialized */ 8097c478bd9Sstevel@tonic-gate continue; 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(hp->h_bd, cp)); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* skip if not present */ 8157c478bd9Sstevel@tonic-gate if (cp->sbc_cm.sbdev_id == (drmachid_t)0) { 8167c478bd9Sstevel@tonic-gate continue; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate /* fetch platform status */ 8207c478bd9Sstevel@tonic-gate err = drmach_status(cp->sbc_cm.sbdev_id, &pstat); 8217c478bd9Sstevel@tonic-gate if (err) { 8227c478bd9Sstevel@tonic-gate DRERR_SET_C(&cp->sbc_cm.sbdev_error, &err); 8237c478bd9Sstevel@tonic-gate continue; 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]); 82725cf1a30Sjl139090 /* 82825cf1a30Sjl139090 * We should set impl here because the last core 82925cf1a30Sjl139090 * found might be EMPTY or not present. 83025cf1a30Sjl139090 */ 83125cf1a30Sjl139090 impl = cp->sbc_cpu_impl; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if (ncores == 0) { 8357c478bd9Sstevel@tonic-gate continue; 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Store the data to the outgoing array. If the 8407c478bd9Sstevel@tonic-gate * device is a CMP, combine all the data for the 8417c478bd9Sstevel@tonic-gate * cores into a single stat structure. 8427c478bd9Sstevel@tonic-gate * 8437c478bd9Sstevel@tonic-gate * The check for a CMP device uses the last core 8447c478bd9Sstevel@tonic-gate * found, assuming that all cores will have the 8457c478bd9Sstevel@tonic-gate * same implementation. 8467c478bd9Sstevel@tonic-gate */ 84725cf1a30Sjl139090 84825cf1a30Sjl139090 if (CPU_IMPL_IS_CMP(impl)) { 8497c478bd9Sstevel@tonic-gate psp = (sbd_cmp_stat_t *)dsp; 85025cf1a30Sjl139090 dr_fill_cmp_stat(cstat, ncores, impl, psp); 8517c478bd9Sstevel@tonic-gate } else { 8527c478bd9Sstevel@tonic-gate ASSERT(ncores == 1); 8537c478bd9Sstevel@tonic-gate bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t)); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate dsp++; 8577c478bd9Sstevel@tonic-gate ncpu++; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate return (ncpu); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * Cancel previous release operation for cpu. 8657c478bd9Sstevel@tonic-gate * For cpus this means simply bringing cpus that 8667c478bd9Sstevel@tonic-gate * were offline back online. Note that they had 8677c478bd9Sstevel@tonic-gate * to have been online at the time there were 8687c478bd9Sstevel@tonic-gate * released. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate int 8717c478bd9Sstevel@tonic-gate dr_cancel_cpu(dr_cpu_unit_t *up) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate int rv = 0; 8747c478bd9Sstevel@tonic-gate static fn_t f = "dr_cancel_cpu"; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate if (cpu_flagged_active(up->sbc_cpu_flags)) { 8797c478bd9Sstevel@tonic-gate struct cpu *cp; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * CPU had been online, go ahead 8837c478bd9Sstevel@tonic-gate * bring it back online. 8847c478bd9Sstevel@tonic-gate */ 885e98fafb9Sjl139090 PR_CPU("%s: bringing cpu %d back ONLINE\n", f, up->sbc_cpu_id); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 8887c478bd9Sstevel@tonic-gate cp = cpu[up->sbc_cpu_id]; 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate if (cpu_is_poweredoff(cp)) { 8917c478bd9Sstevel@tonic-gate if (cpu_poweron(cp)) { 8927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to power-on " 8937c478bd9Sstevel@tonic-gate "cpu %d", f, up->sbc_cpu_id); 8947c478bd9Sstevel@tonic-gate rv = -1; 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (cpu_is_offline(cp)) { 8997c478bd9Sstevel@tonic-gate if (cpu_online(cp)) { 9007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to online cpu %d", 9017c478bd9Sstevel@tonic-gate f, up->sbc_cpu_id); 9027c478bd9Sstevel@tonic-gate rv = -1; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (cpu_is_online(cp)) { 9077c478bd9Sstevel@tonic-gate if (cpu_flagged_nointr(up->sbc_cpu_flags)) { 9087c478bd9Sstevel@tonic-gate if (cpu_intr_disable(cp) != 0) { 9097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to " 910e98fafb9Sjl139090 "disable interrupts on cpu %d", f, 911e98fafb9Sjl139090 up->sbc_cpu_id); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate } 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate return (rv); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate int 9237c478bd9Sstevel@tonic-gate dr_disconnect_cpu(dr_cpu_unit_t *up) 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate sbd_error_t *err; 9267c478bd9Sstevel@tonic-gate static fn_t f = "dr_disconnect_cpu"; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate PR_CPU("%s...\n", f); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate ASSERT((up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) || 9317c478bd9Sstevel@tonic-gate (up->sbc_cm.sbdev_state == DR_STATE_UNCONFIGURED)); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate ASSERT(dr_cpu_unit_is_sane(up->sbc_cm.sbdev_bp, up)); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate if (up->sbc_cm.sbdev_state == DR_STATE_CONNECTED) { 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Cpus were never brought in and so are still 9387c478bd9Sstevel@tonic-gate * effectively disconnected, so nothing to do here. 9397c478bd9Sstevel@tonic-gate */ 940e98fafb9Sjl139090 PR_CPU("%s: cpu %d never brought in\n", f, up->sbc_cpu_id); 9417c478bd9Sstevel@tonic-gate return (0); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate err = drmach_cpu_disconnect(up->sbc_cm.sbdev_id); 9457c478bd9Sstevel@tonic-gate if (err == NULL) 9467c478bd9Sstevel@tonic-gate return (0); 9477c478bd9Sstevel@tonic-gate else { 9487c478bd9Sstevel@tonic-gate DRERR_SET_C(&up->sbc_cm.sbdev_error, &err); 9497c478bd9Sstevel@tonic-gate return (-1); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 9527c478bd9Sstevel@tonic-gate } 953