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 580f5ed81SDave Plauger * Common Development and Distribution License (the "License"). 680f5ed81SDave Plauger * 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 */ 217c478bd9Sstevel@tonic-gate /* 2280f5ed81SDave Plauger * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/systm.h> 267c478bd9Sstevel@tonic-gate #include <sys/membar.h> 277c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 287c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 297c478bd9Sstevel@tonic-gate #include <sys/platform_module.h> 307c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 317c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 327c478bd9Sstevel@tonic-gate #include <sys/cmp.h> 3380f5ed81SDave Plauger #include <sys/dumphdr.h> 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate static cpuset_t cpu_idle_set; 387c478bd9Sstevel@tonic-gate static kmutex_t cpu_idle_lock; 397c478bd9Sstevel@tonic-gate typedef const char *fn_t; 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * flags to determine if the PROM routines 437c478bd9Sstevel@tonic-gate * should be used to idle/resume/stop cpus 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate static int kern_idle[NCPU]; /* kernel's idle loop */ 467c478bd9Sstevel@tonic-gate static int cpu_are_paused; 477c478bd9Sstevel@tonic-gate extern void debug_flush_windows(); 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Initialize the idlestop mutex 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate void 537c478bd9Sstevel@tonic-gate idlestop_init(void) 547c478bd9Sstevel@tonic-gate { 557c478bd9Sstevel@tonic-gate mutex_init(&cpu_idle_lock, NULL, MUTEX_SPIN, (void *)ipltospl(PIL_15)); 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate static void 597c478bd9Sstevel@tonic-gate cpu_idle_self(void) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate uint_t s; 627c478bd9Sstevel@tonic-gate label_t save; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate s = spl8(); 657c478bd9Sstevel@tonic-gate debug_flush_windows(); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate CPU->cpu_m.in_prom = 1; 687c478bd9Sstevel@tonic-gate membar_stld(); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate save = curthread->t_pcb; 717c478bd9Sstevel@tonic-gate (void) setjmp(&curthread->t_pcb); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate kern_idle[CPU->cpu_id] = 1; 747c478bd9Sstevel@tonic-gate while (kern_idle[CPU->cpu_id]) 7580f5ed81SDave Plauger dumpsys_helper_nw(); 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate CPU->cpu_m.in_prom = 0; 787c478bd9Sstevel@tonic-gate membar_stld(); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate curthread->t_pcb = save; 817c478bd9Sstevel@tonic-gate splx(s); 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate void 857c478bd9Sstevel@tonic-gate idle_other_cpus(void) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate int i, cpuid, ntries; 887c478bd9Sstevel@tonic-gate int failed = 0; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if (ncpus == 1) 917c478bd9Sstevel@tonic-gate return; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate mutex_enter(&cpu_idle_lock); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate cpuid = CPU->cpu_id; 967c478bd9Sstevel@tonic-gate ASSERT(cpuid < NCPU); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate cpu_idle_set = cpu_ready_set; 997c478bd9Sstevel@tonic-gate CPUSET_DEL(cpu_idle_set, cpuid); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if (CPUSET_ISNULL(cpu_idle_set)) 1027c478bd9Sstevel@tonic-gate return; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate xt_some(cpu_idle_set, (xcfunc_t *)idle_stop_xcall, 1057c478bd9Sstevel@tonic-gate (uint64_t)cpu_idle_self, NULL); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1087c478bd9Sstevel@tonic-gate if (!CPU_IN_SET(cpu_idle_set, i)) 1097c478bd9Sstevel@tonic-gate continue; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate ntries = 0x10000; 1127c478bd9Sstevel@tonic-gate while (!cpu[i]->cpu_m.in_prom && ntries) { 1137c478bd9Sstevel@tonic-gate DELAY(50); 1147c478bd9Sstevel@tonic-gate ntries--; 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * A cpu failing to idle is an error condition, since 1197c478bd9Sstevel@tonic-gate * we can't be sure anymore of its state. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate if (!cpu[i]->cpu_m.in_prom) { 1227c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cpuid 0x%x failed to idle", i); 1237c478bd9Sstevel@tonic-gate failed++; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate if (failed) { 1287c478bd9Sstevel@tonic-gate mutex_exit(&cpu_idle_lock); 1297c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "idle_other_cpus: not all cpus idled"); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate void 1347c478bd9Sstevel@tonic-gate resume_other_cpus(void) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate int i, ntries; 1377c478bd9Sstevel@tonic-gate int cpuid = CPU->cpu_id; 1387c478bd9Sstevel@tonic-gate boolean_t failed = B_FALSE; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate if (ncpus == 1) 1417c478bd9Sstevel@tonic-gate return; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate ASSERT(cpuid < NCPU); 1447c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_idle_lock)); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1477c478bd9Sstevel@tonic-gate if (!CPU_IN_SET(cpu_idle_set, i)) 1487c478bd9Sstevel@tonic-gate continue; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate kern_idle[i] = 0; 1517c478bd9Sstevel@tonic-gate membar_stld(); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) { 1557c478bd9Sstevel@tonic-gate if (!CPU_IN_SET(cpu_idle_set, i)) 1567c478bd9Sstevel@tonic-gate continue; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate ntries = 0x10000; 1597c478bd9Sstevel@tonic-gate while (cpu[i]->cpu_m.in_prom && ntries) { 1607c478bd9Sstevel@tonic-gate DELAY(50); 1617c478bd9Sstevel@tonic-gate ntries--; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * A cpu failing to resume is an error condition, since 1667c478bd9Sstevel@tonic-gate * intrs may have been directed there. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate if (cpu[i]->cpu_m.in_prom) { 1697c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cpuid 0x%x failed to resume", i); 1707c478bd9Sstevel@tonic-gate continue; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate CPUSET_DEL(cpu_idle_set, i); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate failed = !CPUSET_ISNULL(cpu_idle_set); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate mutex_exit(&cpu_idle_lock); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Non-zero if a cpu failed to resume 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate if (failed) 1837c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "resume_other_cpus: not all cpus resumed"); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * Stop all other cpu's before halting or rebooting. We pause the cpu's 1897c478bd9Sstevel@tonic-gate * instead of sending a cross call. 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate void 1927c478bd9Sstevel@tonic-gate stop_other_cpus(void) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 1957c478bd9Sstevel@tonic-gate if (cpu_are_paused) { 1967c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 1977c478bd9Sstevel@tonic-gate return; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate if (ncpus > 1) 2017c478bd9Sstevel@tonic-gate intr_redist_all_cpus_shutdown(); 2027c478bd9Sstevel@tonic-gate 203*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL); 2047c478bd9Sstevel@tonic-gate cpu_are_paused = 1; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate int cpu_quiesce_microsecond_sanity_limit = 60 * 1000000; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate void 2127c478bd9Sstevel@tonic-gate mp_cpu_quiesce(cpu_t *cp0) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate volatile cpu_t *cp = (volatile cpu_t *) cp0; 2167c478bd9Sstevel@tonic-gate int i, sanity_limit = cpu_quiesce_microsecond_sanity_limit; 2177c478bd9Sstevel@tonic-gate int cpuid = cp->cpu_id; 2187c478bd9Sstevel@tonic-gate int found_intr = 1; 2197c478bd9Sstevel@tonic-gate static fn_t f = "mp_cpu_quiesce"; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate ASSERT(CPU->cpu_id != cpuid); 2227c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 2237c478bd9Sstevel@tonic-gate ASSERT(cp->cpu_flags & CPU_QUIESCED); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * Declare CPU as no longer being READY to process interrupts and 2287c478bd9Sstevel@tonic-gate * wait for them to stop. A CPU that is not READY can no longer 2297c478bd9Sstevel@tonic-gate * participate in x-calls or x-traps. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate cp->cpu_flags &= ~CPU_READY; 2327c478bd9Sstevel@tonic-gate CPUSET_DEL(cpu_ready_set, cpuid); 2337c478bd9Sstevel@tonic-gate membar_sync(); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate for (i = 0; i < sanity_limit; i++) { 2367c478bd9Sstevel@tonic-gate if (cp->cpu_intr_actv == 0 && 2379d7041eeSandrei (cp->cpu_thread == cp->cpu_idle_thread || 2389d7041eeSandrei cp->cpu_thread == cp->cpu_startup_thread)) { 2397c478bd9Sstevel@tonic-gate found_intr = 0; 2407c478bd9Sstevel@tonic-gate break; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate DELAY(1); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (found_intr) { 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate if (cp->cpu_intr_actv) { 2487c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "%s: cpu_intr_actv != 0", f); 2499d7041eeSandrei } else if (cp->cpu_thread != cp->cpu_idle_thread && 2509d7041eeSandrei cp->cpu_thread != cp->cpu_startup_thread) { 2519d7041eeSandrei cmn_err(CE_PANIC, "%s: CPU %d is not quiesced", 2529d7041eeSandrei f, cpuid); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * Start CPU on user request. 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2627c478bd9Sstevel@tonic-gate int 2637c478bd9Sstevel@tonic-gate mp_cpu_start(struct cpu *cp) 2647c478bd9Sstevel@tonic-gate { 2657c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * Platforms that use CPU signatures require the signature 2687c478bd9Sstevel@tonic-gate * block update to indicate that this CPU is in the OS now. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, cp->cpu_id); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate cmp_error_resteer(cp->cpu_id); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate return (0); /* nothing special to do on this arch */ 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* 2787c478bd9Sstevel@tonic-gate * Stop CPU on user request. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2817c478bd9Sstevel@tonic-gate int 2827c478bd9Sstevel@tonic-gate mp_cpu_stop(struct cpu *cp) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate cmp_error_resteer(cp->cpu_id); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * Platforms that use CPU signatures require the signature 2907c478bd9Sstevel@tonic-gate * block update to indicate that this CPU is offlined now. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_OFFLINE, SIGSUBST_NULL, cp->cpu_id); 2937c478bd9Sstevel@tonic-gate return (0); /* nothing special to do on this arch */ 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Power on CPU. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate int 3007c478bd9Sstevel@tonic-gate mp_cpu_poweron(struct cpu *cp) 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 3037c478bd9Sstevel@tonic-gate if (&plat_cpu_poweron) 3047c478bd9Sstevel@tonic-gate return (plat_cpu_poweron(cp)); /* platform-dependent hook */ 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate return (ENOTSUP); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Power off CPU. 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate int 3137c478bd9Sstevel@tonic-gate mp_cpu_poweroff(struct cpu *cp) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 3167c478bd9Sstevel@tonic-gate if (&plat_cpu_poweroff) 3177c478bd9Sstevel@tonic-gate return (plat_cpu_poweroff(cp)); /* platform-dependent hook */ 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate return (ENOTSUP); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate void 3237c478bd9Sstevel@tonic-gate mp_cpu_faulted_enter(struct cpu *cp) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate cpu_faulted_enter(cp); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate void 3297c478bd9Sstevel@tonic-gate mp_cpu_faulted_exit(struct cpu *cp) 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate cpu_faulted_exit(cp); 3327c478bd9Sstevel@tonic-gate } 333