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
dr_cpu_unit_is_sane(dr_board_t * bp,dr_cpu_unit_t * cp)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
dr_errno2ecode(int error)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
dr_cpu_set_prop(dr_cpu_unit_t * cp)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
dr_init_cpu_unit(dr_cpu_unit_t * cp)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
dr_pre_attach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)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
dr_attach_cpu(dr_handle_t * hp,dr_common_unit_t * cp)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
dr_post_attach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)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
dr_pre_release_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)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
dr_pre_detach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)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
dr_detach_cpu(dr_handle_t * hp,dr_common_unit_t * cp)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
dr_post_detach_cpu(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)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
dr_fill_cpu_stat(dr_cpu_unit_t * cp,drmach_status_t * pstat,sbd_cpu_stat_t * csp)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
dr_fill_cmp_stat(sbd_cpu_stat_t * csp,int ncores,int impl,sbd_cmp_stat_t * psp)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
dr_cpu_status(dr_handle_t * hp,dr_devset_t devset,sbd_dev_stat_t * dsp)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
dr_cancel_cpu(dr_cpu_unit_t * up)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
dr_disconnect_cpu(dr_cpu_unit_t * up)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