1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/cpuvar.h> 30 #include <sys/cpu_module.h> 31 #include <sys/machsystm.h> 32 #include <sys/archsystm.h> 33 #include <sys/prom_plat.h> 34 #include <sys/hypervisor_api.h> 35 #include <sys/hsvc.h> 36 37 extern uint64_t xc_tick_limit; 38 extern uint64_t xc_tick_jump_limit; 39 40 extern void cpu_intrq_unregister_powerdown(uint64_t doneflag_va); 41 42 /* 43 * set_idle_cpu is called from idle() when a CPU becomes idle. 44 */ 45 /*ARGSUSED*/ 46 void 47 set_idle_cpu(int cpun) 48 { 49 } 50 51 /* 52 * unset_idle_cpu is called from idle() when a CPU is no longer idle. 53 */ 54 /*ARGSUSED*/ 55 void 56 unset_idle_cpu(int cpun) 57 { 58 } 59 60 /* 61 * Stop a CPU based on its cpuid, using the cpu_stop hypervisor call. 62 * Since this requires that the hypervisor force a remote CPU to stop, 63 * the assumption is made that this should take roughly the same amount 64 * of time as a executing a cross-call. Consequently, the xcall 65 * timeout is used to determine when to give up waiting for the CPU to 66 * stop. 67 * 68 * Attempts to stop a CPU already in the stopped or error state will 69 * silently succeed. Zero is returned on success and a non-negative 70 * errno value is returned on failure. 71 */ 72 int 73 stopcpu_bycpuid(int cpuid) 74 { 75 uint64_t loop_cnt; 76 uint64_t state; 77 uint64_t rv; 78 uint64_t major = 0; 79 uint64_t minor = 0; 80 uint64_t cpu_stop_time_limit; 81 extern uint64_t xc_func_time_limit; 82 83 ASSERT(MUTEX_HELD(&cpu_lock)); 84 85 /* 86 * Check the state of the CPU up front to see if an 87 * attempt to stop it is even necessary. 88 */ 89 if (hv_cpu_state(cpuid, &state) != H_EOK) 90 return (EINVAL); 91 92 /* treat stopped and error state the same */ 93 if (state != CPU_STATE_RUNNING) { 94 /* nothing to do */ 95 return (0); 96 } 97 98 /* 99 * The HV API to stop a CPU is only supported in 100 * version 1.1 and later of the core group. If an 101 * older version of the HV is in use, return not 102 * supported. 103 */ 104 if (hsvc_version(HSVC_GROUP_CORE, &major, &minor) != 0) 105 return (EINVAL); 106 107 ASSERT(major != 0); 108 109 if ((major == 1) && (minor < 1)) 110 return (ENOTSUP); 111 112 /* use the mondo timeout if it has been initialized */ 113 cpu_stop_time_limit = xc_func_time_limit; 114 115 /* 116 * If called early in boot before the mondo time limit 117 * is set, use a reasonable timeout based on the the 118 * clock frequency of the current CPU. 119 */ 120 if (cpu_stop_time_limit == 0) 121 cpu_stop_time_limit = cpunodes[CPU->cpu_id].clock_freq; 122 123 /* should only fail if called too early in boot */ 124 ASSERT(cpu_stop_time_limit > 0); 125 126 loop_cnt = 0; 127 128 /* 129 * Attempt to stop the CPU, retrying if it is busy. 130 */ 131 while (loop_cnt++ < cpu_stop_time_limit) { 132 133 if ((rv = hv_cpu_stop(cpuid)) != H_EWOULDBLOCK) 134 break; 135 } 136 137 if (loop_cnt == cpu_stop_time_limit) 138 return (ETIMEDOUT); 139 140 if (rv != H_EOK) 141 return (EINVAL); 142 143 /* 144 * Verify that the CPU has reached the stopped state. 145 */ 146 while (loop_cnt++ < cpu_stop_time_limit) { 147 148 if (hv_cpu_state(cpuid, &state) != H_EOK) 149 return (EINVAL); 150 151 /* treat stopped and error state the same */ 152 if (state != CPU_STATE_RUNNING) 153 break; 154 } 155 156 return ((loop_cnt == cpu_stop_time_limit) ? ETIMEDOUT : 0); 157 } 158 159 /* 160 * X-trap to the target to unregister its interrupt and error queues 161 * and put it in a safe place just before the CPU is stopped. After 162 * unregistering its queues, the target CPU must not return from the 163 * trap to priv or user context. Ensure that the interrupt CPU unregister 164 * succeeded. 165 */ 166 void 167 xt_cpu_unreg_powerdown(struct cpu *cpup) 168 { 169 uint8_t volatile not_done; 170 uint64_t starttick, endtick, tick, lasttick; 171 processorid_t cpuid = cpup->cpu_id; 172 173 kpreempt_disable(); 174 175 /* 176 * Sun4v uses a queue for receiving mondos. Successful 177 * transmission of a mondo only indicates that the mondo 178 * has been written into the queue. 179 * 180 * Set the not_done flag to 1 before sending the cross 181 * trap and wait until the other cpu resets it to 0. 182 */ 183 184 not_done = 1; 185 186 xt_one_unchecked(cpuid, (xcfunc_t *)cpu_intrq_unregister_powerdown, 187 (uint64_t)¬_done, 0); 188 189 starttick = lasttick = gettick(); 190 endtick = starttick + xc_tick_limit; 191 192 while (not_done) { 193 194 tick = gettick(); 195 196 /* 197 * If there is a big jump between the current tick 198 * count and lasttick, we have probably hit a break 199 * point. Adjust endtick accordingly to avoid panic. 200 */ 201 if (tick > (lasttick + xc_tick_jump_limit)) { 202 endtick += (tick - lasttick); 203 } 204 205 lasttick = tick; 206 if (tick > endtick) { 207 cmn_err(CE_CONT, "Cross trap timeout at cpu id %x\n", 208 cpuid); 209 cmn_err(CE_WARN, "xt_intrq_unreg_powerdown: timeout"); 210 } 211 } 212 213 kpreempt_enable(); 214 } 215 216 int 217 plat_cpu_poweroff(struct cpu *cp) 218 { 219 int rv = 0; 220 int status; 221 processorid_t cpuid = cp->cpu_id; 222 223 ASSERT(MUTEX_HELD(&cpu_lock)); 224 225 /* 226 * Capture all CPUs (except for detaching proc) to prevent 227 * crosscalls to the detaching proc until it has cleared its 228 * bit in cpu_ready_set. 229 * 230 * The CPU's remain paused and the prom_mutex is known to be free. 231 * This prevents the x-trap victim from blocking when doing prom 232 * IEEE-1275 calls at a high PIL level. 233 */ 234 promsafe_pause_cpus(); 235 236 /* 237 * Quiesce interrupts on the target CPU. We do this by setting 238 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) 239 * to prevent it from receiving cross calls and cross traps. This 240 * prevents the processor from receiving any new soft interrupts. 241 */ 242 mp_cpu_quiesce(cp); 243 244 /* 245 * Send a cross trap to the cpu to unregister its interrupt 246 * error queues. 247 */ 248 xt_cpu_unreg_powerdown(cp); 249 250 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 251 252 /* call into the Hypervisor to stop the CPU */ 253 if ((status = stopcpu_bycpuid(cpuid)) != 0) { 254 rv = -1; 255 } 256 257 start_cpus(); 258 259 if (rv != 0) { 260 cmn_err(CE_WARN, "failed to stop cpu %d (%d)", cpuid, status); 261 /* mark the CPU faulted so that it cannot be onlined */ 262 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_FAULTED; 263 } 264 265 return (rv); 266 } 267 268 int 269 plat_cpu_poweron(struct cpu *cp) 270 { 271 extern void restart_other_cpu(int); 272 273 ASSERT(MUTEX_HELD(&cpu_lock)); 274 275 cp->cpu_flags &= ~CPU_POWEROFF; 276 277 restart_other_cpu(cp->cpu_id); 278 279 return (0); 280 } 281