xref: /titanic_41/usr/src/uts/sun4v/os/suspend.c (revision cbdcbd056f15c9c9fd82d5543b3a502677c4d391)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/mutex.h>
27 #include <sys/cpuvar.h>
28 #include <sys/cyclic.h>
29 #include <sys/disp.h>
30 #include <sys/ddi.h>
31 #include <sys/wdt.h>
32 #include <sys/callb.h>
33 #include <sys/cmn_err.h>
34 #include <sys/hypervisor_api.h>
35 #include <sys/membar.h>
36 #include <sys/x_call.h>
37 #include <sys/promif.h>
38 #include <sys/systm.h>
39 #include <sys/mach_descrip.h>
40 #include <sys/cpu_module.h>
41 #include <sys/pg.h>
42 #include <sys/lgrp.h>
43 #include <sys/sysmacros.h>
44 #include <sys/sunddi.h>
45 #include <sys/cpupart.h>
46 #include <sys/hsvc.h>
47 
48 /*
49  * Sun4v OS Suspend
50  *
51  * Provides a means to suspend a sun4v guest domain by pausing CPUs and then
52  * calling into the HV to initiate a suspension. Suspension is sequenced
53  * externally by calling suspend_pre, suspend_start, and suspend_post.
54  * suspend_pre and suspend_post are meant to perform any special operations
55  * that should be done before or after a suspend/resume operation. e.g.,
56  * callbacks to cluster software to disable heartbeat monitoring before the
57  * system is suspended. suspend_start prepares kernel services to be suspended
58  * and then suspends the domain by calling hv_guest_suspend.
59  *
60  * Special Handling for %tick and %stick Registers
61  *
62  * After a suspend/resume operation, the %tick and %stick registers may have
63  * jumped forwards or backwards. The delta is assumed to be consistent across
64  * all CPUs, within the negligible level of %tick and %stick variation
65  * acceptable on a cold boot. In order to maintain increasing %tick and %stick
66  * counter values without exposing large positive or negative jumps to kernel
67  * or user code, a %tick and %stick offset is used. Kernel reads of these
68  * counters return the sum of the hardware register counter and offset
69  * variable. After a suspend/resume operation, user reads of %tick or %stick
70  * are emulated. Suspend code enables emulation by setting the
71  * %{tick,stick}.NPT fields which trigger a privileged instruction access
72  * trap whenever the registers are read from user mode. If emulation has been
73  * enabled, the trap handler emulates the instruction. Emulation is only
74  * enabled during a successful suspend/resume operation. When emulation is
75  * enabled, CPUs that are DR'd into the system will have their
76  * %{tick,stick}.NPT bits set to 1 as well.
77  */
78 
79 extern u_longlong_t gettick(void);	/* returns %stick */
80 extern uint64_t gettick_counter(void);	/* returns %tick */
81 extern uint64_t gettick_npt(void);
82 extern uint64_t getstick_npt(void);
83 extern int mach_descrip_update(void);
84 extern cpuset_t cpu_ready_set;
85 extern uint64_t native_tick_offset;
86 extern uint64_t native_stick_offset;
87 
88 /*
89  * Global Sun Cluster pre/post callbacks.
90  */
91 const char *(*cl_suspend_error_decode)(int);
92 int (*cl_suspend_pre_callback)(void);
93 int (*cl_suspend_post_callback)(void);
94 #define	SC_PRE_FAIL_STR_FMT	"Sun Cluster pre-suspend failure: %d"
95 #define	SC_POST_FAIL_STR_FMT	"Sun Cluster post-suspend failure: %d"
96 #define	SC_FAIL_STR_MAX		256
97 
98 /*
99  * The minimum major and minor version of the HSVC_GROUP_CORE API group
100  * required in order to use OS suspend.
101  */
102 #define	SUSPEND_CORE_MAJOR	1
103 #define	SUSPEND_CORE_MINOR	2
104 
105 /*
106  * By default, sun4v OS suspend is supported if the required HV version
107  * is present. suspend_disabled should be set on platforms that do not
108  * allow OS suspend regardless of whether or not the HV supports it.
109  * It can also be set in /etc/system.
110  */
111 static int suspend_disabled = 0;
112 
113 /*
114  * Controls whether or not user-land tick and stick register emulation
115  * will be enabled following a successful suspend operation.
116  */
117 static int enable_user_tick_stick_emulation = 1;
118 
119 /*
120  * Indicates whether or not tick and stick emulation is currently active.
121  * After a successful suspend operation, if emulation is enabled, this
122  * variable is set to B_TRUE. Global scope to allow emulation code to
123  * check if emulation is active.
124  */
125 boolean_t tick_stick_emulation_active = B_FALSE;
126 
127 /*
128  * Controls whether or not MD information is refreshed after a
129  * successful suspend and resume. When non-zero, after a successful
130  * suspend and resume, the MD will be downloaded, cpunodes updated,
131  * and processor grouping information recalculated.
132  */
133 static int suspend_update_cpu_mappings = 1;
134 
135 /*
136  * DBG and DBG_PROM() macro.
137  */
138 #ifdef	DEBUG
139 
140 static int suspend_debug_flag = 0;
141 
142 #define	DBG_PROM		\
143 if (suspend_debug_flag)		\
144 	prom_printf
145 
146 #define	DBG			\
147 if (suspend_debug_flag)		\
148 	suspend_debug
149 
150 static void
151 suspend_debug(const char *fmt, ...)
152 {
153 	char	buf[512];
154 	va_list	ap;
155 
156 	va_start(ap, fmt);
157 	(void) vsprintf(buf, fmt, ap);
158 	va_end(ap);
159 
160 	cmn_err(CE_NOTE, "%s", buf);
161 }
162 
163 #else /* DEBUG */
164 
165 #define	DBG_PROM
166 #define	DBG
167 
168 #endif /* DEBUG */
169 
170 /*
171  * Return true if the HV supports OS suspend and if suspend has not been
172  * disabled on this platform.
173  */
174 boolean_t
175 suspend_supported(void)
176 {
177 	uint64_t major, minor;
178 
179 	if (suspend_disabled)
180 		return (B_FALSE);
181 
182 	if (hsvc_version(HSVC_GROUP_CORE, &major, &minor) != 0)
183 		return (B_FALSE);
184 
185 	return ((major == SUSPEND_CORE_MAJOR && minor >= SUSPEND_CORE_MINOR) ||
186 	    (major > SUSPEND_CORE_MAJOR));
187 }
188 
189 /*
190  * Given a source tick and stick value, set the tick and stick offsets such
191  * that the (current physical register value + offset == source value).
192  */
193 static void
194 set_tick_offsets(uint64_t source_tick, uint64_t source_stick)
195 {
196 	uint64_t target_tick;
197 	uint64_t target_stick;
198 
199 	native_tick_offset = 0;
200 	native_stick_offset = 0;
201 
202 	target_tick = gettick_counter();	/* returns %tick */
203 	target_stick = gettick();		/* returns %stick */
204 
205 	native_tick_offset = source_tick - target_tick;
206 	native_stick_offset = source_stick - target_stick;
207 }
208 
209 /*
210  * Set the {tick,stick}.NPT field to 1 on this CPU.
211  */
212 static void
213 enable_tick_stick_npt(void)
214 {
215 	(void) hv_stick_set_npt(1);
216 	(void) hv_tick_set_npt(1);
217 }
218 
219 /*
220  * Synchronize a CPU's {tick,stick}.NPT fields with the current state
221  * of the system. This is used when a CPU is DR'd into the system.
222  */
223 void
224 suspend_sync_tick_stick_npt(void)
225 {
226 	if (tick_stick_emulation_active) {
227 		DBG("enabling {%%tick/%%stick}.NPT on CPU 0x%x", CPU->cpu_id);
228 		(void) hv_stick_set_npt(1);
229 		(void) hv_tick_set_npt(1);
230 	} else {
231 		ASSERT(gettick_npt() == 0);
232 		ASSERT(getstick_npt() == 0);
233 	}
234 }
235 
236 /*
237  * Obtain an updated MD from the hypervisor and update cpunodes, CPU HW
238  * sharing data structures, and processor groups.
239  */
240 static void
241 update_cpu_mappings(void)
242 {
243 	md_t		*mdp;
244 	processorid_t	id;
245 	cpu_t		*cp;
246 	int		rv;
247 	cpu_pg_t	*pgps[NCPU];
248 
249 	/* Download the latest MD */
250 	if ((rv = mach_descrip_update()) != 0) {
251 		DBG("suspend: mach_descrip_update error: %d", rv);
252 		return;
253 	}
254 
255 	if ((mdp = md_get_handle()) == NULL) {
256 		DBG("suspend: md_get_handle failed");
257 		return;
258 	}
259 
260 	DBG("suspend: updating CPU mappings");
261 
262 	mutex_enter(&cpu_lock);
263 
264 	setup_chip_mappings(mdp);
265 	setup_exec_unit_mappings(mdp);
266 	for (id = 0; id < NCPU; id++) {
267 		if ((cp = cpu_get(id)) == NULL)
268 			continue;
269 		cpu_map_exec_units(cp);
270 	}
271 
272 	/*
273 	 * Re-calculate processor groups.
274 	 *
275 	 * First tear down all PG information before adding any new PG
276 	 * information derived from the MD we just downloaded. We must
277 	 * call pg_cpu_inactive and pg_cpu_active with CPUs paused and
278 	 * we want to minimize the number of times pause_cpus is called.
279 	 * Inactivating all CPUs would leave PGs without any active CPUs,
280 	 * so while CPUs are paused, call pg_cpu_inactive and swap in the
281 	 * bootstrap PG structure saving the original PG structure to be
282 	 * fini'd afterwards. This prevents the dispatcher from encountering
283 	 * PGs in which all CPUs are inactive.
284 	 */
285 	pause_cpus(NULL);
286 	for (id = 0; id < NCPU; id++) {
287 		if ((cp = cpu_get(id)) == NULL)
288 			continue;
289 		pg_cpu_inactive(cp);
290 		pgps[id] = cp->cpu_pg;
291 		pg_cpu_bootstrap(cp);
292 	}
293 	start_cpus();
294 
295 	/*
296 	 * pg_cpu_fini* and pg_cpu_init* must be called while CPUs are
297 	 * not paused. Use two separate loops here so that we do not
298 	 * initialize PG data for CPUs until all the old PG data structures
299 	 * are torn down.
300 	 */
301 	for (id = 0; id < NCPU; id++) {
302 		if ((cp = cpu_get(id)) == NULL)
303 			continue;
304 		pg_cpu_fini(cp, pgps[id]);
305 	}
306 
307 	/*
308 	 * Initialize PG data for each CPU, but leave the bootstrapped
309 	 * PG structure in place to avoid running with any PGs containing
310 	 * nothing but inactive CPUs.
311 	 */
312 	for (id = 0; id < NCPU; id++) {
313 		if ((cp = cpu_get(id)) == NULL)
314 			continue;
315 		pgps[id] = pg_cpu_init(cp, B_TRUE);
316 	}
317 
318 	/*
319 	 * Now that PG data has been initialized for all CPUs in the
320 	 * system, replace the bootstrapped PG structure with the
321 	 * initialized PG structure and call pg_cpu_active for each CPU.
322 	 */
323 	pause_cpus(NULL);
324 	for (id = 0; id < NCPU; id++) {
325 		if ((cp = cpu_get(id)) == NULL)
326 			continue;
327 		cp->cpu_pg = pgps[id];
328 		pg_cpu_active(cp);
329 	}
330 	start_cpus();
331 
332 	mutex_exit(&cpu_lock);
333 
334 	(void) md_fini_handle(mdp);
335 }
336 
337 /*
338  * Wrapper for the Sun Cluster error decoding function.
339  */
340 static int
341 cluster_error_decode(int error, char *error_reason, size_t max_reason_len)
342 {
343 	const char	*decoded;
344 	size_t		decoded_len;
345 
346 	ASSERT(error_reason != NULL);
347 	ASSERT(max_reason_len > 0);
348 
349 	max_reason_len = MIN(max_reason_len, SC_FAIL_STR_MAX);
350 
351 	if (cl_suspend_error_decode == NULL)
352 		return (-1);
353 
354 	if ((decoded = (*cl_suspend_error_decode)(error)) == NULL)
355 		return (-1);
356 
357 	/* Get number of non-NULL bytes */
358 	if ((decoded_len = strnlen(decoded, max_reason_len - 1)) == 0)
359 		return (-1);
360 
361 	bcopy(decoded, error_reason, decoded_len);
362 
363 	/*
364 	 * The error string returned from cl_suspend_error_decode
365 	 * should be NULL-terminated, but set the terminator here
366 	 * because we only copied non-NULL bytes. If the decoded
367 	 * string was not NULL-terminated, this guarantees that
368 	 * error_reason will be.
369 	 */
370 	error_reason[decoded_len] = '\0';
371 
372 	return (0);
373 }
374 
375 /*
376  * Wrapper for the Sun Cluster pre-suspend callback.
377  */
378 static int
379 cluster_pre_wrapper(char *error_reason, size_t max_reason_len)
380 {
381 	int rv = 0;
382 
383 	if (cl_suspend_pre_callback != NULL) {
384 		rv = (*cl_suspend_pre_callback)();
385 		DBG("suspend: cl_suspend_pre_callback returned %d", rv);
386 		if (rv != 0 && error_reason != NULL && max_reason_len > 0) {
387 			if (cluster_error_decode(rv, error_reason,
388 			    max_reason_len)) {
389 				(void) snprintf(error_reason, max_reason_len,
390 				    SC_PRE_FAIL_STR_FMT, rv);
391 			}
392 		}
393 	}
394 
395 	return (rv);
396 }
397 
398 /*
399  * Wrapper for the Sun Cluster post-suspend callback.
400  */
401 static int
402 cluster_post_wrapper(char *error_reason, size_t max_reason_len)
403 {
404 	int rv = 0;
405 
406 	if (cl_suspend_post_callback != NULL) {
407 		rv = (*cl_suspend_post_callback)();
408 		DBG("suspend: cl_suspend_post_callback returned %d", rv);
409 		if (rv != 0 && error_reason != NULL && max_reason_len > 0) {
410 			if (cluster_error_decode(rv, error_reason,
411 			    max_reason_len)) {
412 				(void) snprintf(error_reason,
413 				    max_reason_len, SC_POST_FAIL_STR_FMT, rv);
414 			}
415 		}
416 	}
417 
418 	return (rv);
419 }
420 
421 /*
422  * Execute pre-suspend callbacks preparing the system for a suspend operation.
423  * Returns zero on success, non-zero on failure. Sets the recovered argument
424  * to indicate whether or not callbacks could be undone in the event of a
425  * failure--if callbacks were successfully undone, *recovered is set to B_TRUE,
426  * otherwise *recovered is set to B_FALSE. Must be called successfully before
427  * suspend_start can be called. Callers should first call suspend_support to
428  * determine if OS suspend is supported.
429  */
430 int
431 suspend_pre(char *error_reason, size_t max_reason_len, boolean_t *recovered)
432 {
433 	int rv;
434 
435 	ASSERT(recovered != NULL);
436 
437 	/*
438 	 * Return an error if suspend_pre is erreoneously called
439 	 * when OS suspend is not supported.
440 	 */
441 	ASSERT(suspend_supported());
442 	if (!suspend_supported()) {
443 		DBG("suspend: suspend_pre called without suspend support");
444 		*recovered = B_TRUE;
445 		return (ENOTSUP);
446 	}
447 	DBG("suspend: %s", __func__);
448 
449 	rv = cluster_pre_wrapper(error_reason, max_reason_len);
450 
451 	/*
452 	 * At present, only one pre-suspend operation exists.
453 	 * If it fails, no recovery needs to be done.
454 	 */
455 	if (rv != 0 && recovered != NULL)
456 		*recovered = B_TRUE;
457 
458 	return (rv);
459 }
460 
461 /*
462  * Execute post-suspend callbacks. Returns zero on success, non-zero on
463  * failure. Must be called after suspend_start is called, regardless of
464  * whether or not suspend_start is successful.
465  */
466 int
467 suspend_post(char *error_reason, size_t max_reason_len)
468 {
469 	ASSERT(suspend_supported());
470 	DBG("suspend: %s", __func__);
471 	return (cluster_post_wrapper(error_reason, max_reason_len));
472 }
473 
474 /*
475  * Suspends the OS by pausing CPUs and calling into the HV to initiate
476  * the suspend. When the HV routine hv_guest_suspend returns, the system
477  * will be resumed. Must be called after a successful call to suspend_pre.
478  * suspend_post must be called after suspend_start, whether or not
479  * suspend_start returns an error.
480  */
481 /*ARGSUSED*/
482 int
483 suspend_start(char *error_reason, size_t max_reason_len)
484 {
485 	uint64_t	source_tick;
486 	uint64_t	source_stick;
487 	uint64_t	rv;
488 	timestruc_t	source_tod;
489 	int		spl;
490 
491 	ASSERT(suspend_supported());
492 	DBG("suspend: %s", __func__);
493 
494 	mutex_enter(&cpu_lock);
495 
496 	/* Suspend the watchdog */
497 	watchdog_suspend();
498 
499 	/* Record the TOD */
500 	mutex_enter(&tod_lock);
501 	source_tod = tod_get();
502 	mutex_exit(&tod_lock);
503 
504 	/* Pause all other CPUs */
505 	pause_cpus(NULL);
506 	DBG_PROM("suspend: CPUs paused\n");
507 
508 	/* Suspend cyclics and disable interrupts */
509 	cyclic_suspend();
510 	DBG_PROM("suspend: cyclics suspended\n");
511 	spl = spl8();
512 
513 	source_tick = gettick_counter();
514 	source_stick = gettick();
515 	DBG_PROM("suspend: source_tick: 0x%lx\n", source_tick);
516 	DBG_PROM("suspend: source_stick: 0x%lx\n", source_stick);
517 
518 	/*
519 	 * Call into the HV to initiate the suspend.
520 	 * hv_guest_suspend() returns after the guest has been
521 	 * resumed or if the suspend operation failed or was
522 	 * cancelled. After a successful suspend, the %tick and
523 	 * %stick registers may have changed by an amount that is
524 	 * not proportional to the amount of time that has passed.
525 	 * They may have jumped forwards or backwards. This jump
526 	 * must be uniform across all CPUs and we operate under
527 	 * the assumption that it is (maintaining two global offset
528 	 * variables--one for %tick and one for %stick.)
529 	 */
530 	DBG_PROM("suspend: suspending... \n");
531 	rv = hv_guest_suspend();
532 	if (rv != 0) {
533 		splx(spl);
534 		cyclic_resume();
535 		start_cpus();
536 		watchdog_resume();
537 		mutex_exit(&cpu_lock);
538 		DBG("suspend: failed, rv: %ld\n", rv);
539 		return (rv);
540 	}
541 
542 	/* Update the global tick and stick offsets */
543 	set_tick_offsets(source_tick, source_stick);
544 
545 	/* Ensure new offsets are globally visible before resuming CPUs */
546 	membar_sync();
547 
548 	/* Enable interrupts */
549 	splx(spl);
550 
551 	/* Set the {%tick,%stick}.NPT bits on all CPUs */
552 	if (enable_user_tick_stick_emulation) {
553 		xc_all((xcfunc_t *)enable_tick_stick_npt, NULL, NULL);
554 		xt_sync(cpu_ready_set);
555 		ASSERT(gettick_npt() != 0);
556 		ASSERT(getstick_npt() != 0);
557 	}
558 
559 	/* If emulation is enabled, but not currently active, enable it */
560 	if (enable_user_tick_stick_emulation && !tick_stick_emulation_active) {
561 		tick_stick_emulation_active = B_TRUE;
562 	}
563 
564 	/* Resume cyclics, unpause CPUs */
565 	cyclic_resume();
566 	start_cpus();
567 
568 	/* Set the TOD */
569 	mutex_enter(&tod_lock);
570 	tod_set(source_tod);
571 	mutex_exit(&tod_lock);
572 
573 	/* Re-enable the watchdog */
574 	watchdog_resume();
575 
576 	mutex_exit(&cpu_lock);
577 
578 	/* Get new MD, update CPU mappings/relationships */
579 	if (suspend_update_cpu_mappings)
580 		update_cpu_mappings();
581 
582 	DBG("suspend: target tick: 0x%lx", gettick_counter());
583 	DBG("suspend: target stick: 0x%llx", gettick());
584 	DBG("suspend: user %%tick/%%stick emulation is %d",
585 	    tick_stick_emulation_active);
586 	DBG("suspend: finished");
587 
588 	return (0);
589 }
590