1023e71deSHaik Aftandilian /*
2023e71deSHaik Aftandilian * CDDL HEADER START
3023e71deSHaik Aftandilian *
4023e71deSHaik Aftandilian * The contents of this file are subject to the terms of the
5023e71deSHaik Aftandilian * Common Development and Distribution License (the "License").
6023e71deSHaik Aftandilian * You may not use this file except in compliance with the License.
7023e71deSHaik Aftandilian *
8023e71deSHaik Aftandilian * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9023e71deSHaik Aftandilian * or http://www.opensolaris.org/os/licensing.
10023e71deSHaik Aftandilian * See the License for the specific language governing permissions
11023e71deSHaik Aftandilian * and limitations under the License.
12023e71deSHaik Aftandilian *
13023e71deSHaik Aftandilian * When distributing Covered Code, include this CDDL HEADER in each
14023e71deSHaik Aftandilian * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15023e71deSHaik Aftandilian * If applicable, add the following below this CDDL HEADER, with the
16023e71deSHaik Aftandilian * fields enclosed by brackets "[]" replaced with your own identifying
17023e71deSHaik Aftandilian * information: Portions Copyright [yyyy] [name of copyright owner]
18023e71deSHaik Aftandilian *
19023e71deSHaik Aftandilian * CDDL HEADER END
20023e71deSHaik Aftandilian */
21023e71deSHaik Aftandilian /*
2202b4e56cSHaik Aftandilian * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23023e71deSHaik Aftandilian */
24023e71deSHaik Aftandilian
25023e71deSHaik Aftandilian #include <sys/mutex.h>
26023e71deSHaik Aftandilian #include <sys/cpuvar.h>
27023e71deSHaik Aftandilian #include <sys/cyclic.h>
28023e71deSHaik Aftandilian #include <sys/disp.h>
29023e71deSHaik Aftandilian #include <sys/ddi.h>
30023e71deSHaik Aftandilian #include <sys/wdt.h>
31023e71deSHaik Aftandilian #include <sys/callb.h>
32023e71deSHaik Aftandilian #include <sys/cmn_err.h>
33023e71deSHaik Aftandilian #include <sys/hypervisor_api.h>
34023e71deSHaik Aftandilian #include <sys/membar.h>
35023e71deSHaik Aftandilian #include <sys/x_call.h>
36023e71deSHaik Aftandilian #include <sys/promif.h>
37023e71deSHaik Aftandilian #include <sys/systm.h>
38023e71deSHaik Aftandilian #include <sys/mach_descrip.h>
39023e71deSHaik Aftandilian #include <sys/cpu_module.h>
40023e71deSHaik Aftandilian #include <sys/pg.h>
41023e71deSHaik Aftandilian #include <sys/lgrp.h>
42023e71deSHaik Aftandilian #include <sys/sysmacros.h>
43023e71deSHaik Aftandilian #include <sys/sunddi.h>
44023e71deSHaik Aftandilian #include <sys/cpupart.h>
45023e71deSHaik Aftandilian #include <sys/hsvc.h>
46183ef8a1SHaik Aftandilian #include <sys/mpo.h>
47d2365b01SPavel Tatashin #include <vm/hat_sfmmu.h>
4800a57bdfSHaik Aftandilian #include <sys/time.h>
4900a57bdfSHaik Aftandilian #include <sys/clock.h>
50023e71deSHaik Aftandilian
51023e71deSHaik Aftandilian /*
52023e71deSHaik Aftandilian * Sun4v OS Suspend
53023e71deSHaik Aftandilian *
54023e71deSHaik Aftandilian * Provides a means to suspend a sun4v guest domain by pausing CPUs and then
55023e71deSHaik Aftandilian * calling into the HV to initiate a suspension. Suspension is sequenced
56023e71deSHaik Aftandilian * externally by calling suspend_pre, suspend_start, and suspend_post.
57023e71deSHaik Aftandilian * suspend_pre and suspend_post are meant to perform any special operations
58023e71deSHaik Aftandilian * that should be done before or after a suspend/resume operation. e.g.,
59023e71deSHaik Aftandilian * callbacks to cluster software to disable heartbeat monitoring before the
60023e71deSHaik Aftandilian * system is suspended. suspend_start prepares kernel services to be suspended
61023e71deSHaik Aftandilian * and then suspends the domain by calling hv_guest_suspend.
62023e71deSHaik Aftandilian *
63023e71deSHaik Aftandilian * Special Handling for %tick and %stick Registers
64023e71deSHaik Aftandilian *
65023e71deSHaik Aftandilian * After a suspend/resume operation, the %tick and %stick registers may have
66023e71deSHaik Aftandilian * jumped forwards or backwards. The delta is assumed to be consistent across
67023e71deSHaik Aftandilian * all CPUs, within the negligible level of %tick and %stick variation
68023e71deSHaik Aftandilian * acceptable on a cold boot. In order to maintain increasing %tick and %stick
69023e71deSHaik Aftandilian * counter values without exposing large positive or negative jumps to kernel
70023e71deSHaik Aftandilian * or user code, a %tick and %stick offset is used. Kernel reads of these
71023e71deSHaik Aftandilian * counters return the sum of the hardware register counter and offset
72023e71deSHaik Aftandilian * variable. After a suspend/resume operation, user reads of %tick or %stick
73023e71deSHaik Aftandilian * are emulated. Suspend code enables emulation by setting the
74023e71deSHaik Aftandilian * %{tick,stick}.NPT fields which trigger a privileged instruction access
75023e71deSHaik Aftandilian * trap whenever the registers are read from user mode. If emulation has been
76023e71deSHaik Aftandilian * enabled, the trap handler emulates the instruction. Emulation is only
77023e71deSHaik Aftandilian * enabled during a successful suspend/resume operation. When emulation is
78023e71deSHaik Aftandilian * enabled, CPUs that are DR'd into the system will have their
79023e71deSHaik Aftandilian * %{tick,stick}.NPT bits set to 1 as well.
80023e71deSHaik Aftandilian */
81023e71deSHaik Aftandilian
82023e71deSHaik Aftandilian extern u_longlong_t gettick(void); /* returns %stick */
83023e71deSHaik Aftandilian extern uint64_t gettick_counter(void); /* returns %tick */
84023e71deSHaik Aftandilian extern uint64_t gettick_npt(void);
85023e71deSHaik Aftandilian extern uint64_t getstick_npt(void);
86023e71deSHaik Aftandilian extern int mach_descrip_update(void);
87023e71deSHaik Aftandilian extern cpuset_t cpu_ready_set;
88023e71deSHaik Aftandilian extern uint64_t native_tick_offset;
89023e71deSHaik Aftandilian extern uint64_t native_stick_offset;
9000a57bdfSHaik Aftandilian extern uint64_t sys_tick_freq;
91023e71deSHaik Aftandilian
92023e71deSHaik Aftandilian /*
93023e71deSHaik Aftandilian * Global Sun Cluster pre/post callbacks.
94023e71deSHaik Aftandilian */
95023e71deSHaik Aftandilian const char *(*cl_suspend_error_decode)(int);
96023e71deSHaik Aftandilian int (*cl_suspend_pre_callback)(void);
97023e71deSHaik Aftandilian int (*cl_suspend_post_callback)(void);
98023e71deSHaik Aftandilian #define SC_PRE_FAIL_STR_FMT "Sun Cluster pre-suspend failure: %d"
99023e71deSHaik Aftandilian #define SC_POST_FAIL_STR_FMT "Sun Cluster post-suspend failure: %d"
100023e71deSHaik Aftandilian #define SC_FAIL_STR_MAX 256
101023e71deSHaik Aftandilian
102023e71deSHaik Aftandilian /*
103023e71deSHaik Aftandilian * The minimum major and minor version of the HSVC_GROUP_CORE API group
104023e71deSHaik Aftandilian * required in order to use OS suspend.
105023e71deSHaik Aftandilian */
106023e71deSHaik Aftandilian #define SUSPEND_CORE_MAJOR 1
107023e71deSHaik Aftandilian #define SUSPEND_CORE_MINOR 2
108023e71deSHaik Aftandilian
109023e71deSHaik Aftandilian /*
110023e71deSHaik Aftandilian * By default, sun4v OS suspend is supported if the required HV version
111023e71deSHaik Aftandilian * is present. suspend_disabled should be set on platforms that do not
112023e71deSHaik Aftandilian * allow OS suspend regardless of whether or not the HV supports it.
113023e71deSHaik Aftandilian * It can also be set in /etc/system.
114023e71deSHaik Aftandilian */
115023e71deSHaik Aftandilian static int suspend_disabled = 0;
116023e71deSHaik Aftandilian
117023e71deSHaik Aftandilian /*
118023e71deSHaik Aftandilian * Controls whether or not user-land tick and stick register emulation
119023e71deSHaik Aftandilian * will be enabled following a successful suspend operation.
120023e71deSHaik Aftandilian */
121023e71deSHaik Aftandilian static int enable_user_tick_stick_emulation = 1;
122023e71deSHaik Aftandilian
123023e71deSHaik Aftandilian /*
124023e71deSHaik Aftandilian * Indicates whether or not tick and stick emulation is currently active.
125023e71deSHaik Aftandilian * After a successful suspend operation, if emulation is enabled, this
126023e71deSHaik Aftandilian * variable is set to B_TRUE. Global scope to allow emulation code to
127023e71deSHaik Aftandilian * check if emulation is active.
128023e71deSHaik Aftandilian */
129023e71deSHaik Aftandilian boolean_t tick_stick_emulation_active = B_FALSE;
130023e71deSHaik Aftandilian
131023e71deSHaik Aftandilian /*
132d2365b01SPavel Tatashin * When non-zero, after a successful suspend and resume, cpunodes, CPU HW
133d2365b01SPavel Tatashin * sharing data structures, and processor groups will be updated using
134d2365b01SPavel Tatashin * information from the updated MD.
135023e71deSHaik Aftandilian */
136023e71deSHaik Aftandilian static int suspend_update_cpu_mappings = 1;
137023e71deSHaik Aftandilian
138023e71deSHaik Aftandilian /*
13900a57bdfSHaik Aftandilian * The maximum number of microseconds by which the %tick or %stick register
14000a57bdfSHaik Aftandilian * can vary between any two CPUs in the system. To calculate the
14100a57bdfSHaik Aftandilian * native_stick_offset and native_tick_offset, we measure the change in these
14200a57bdfSHaik Aftandilian * registers on one CPU over a suspend/resume. Other CPUs may experience
14300a57bdfSHaik Aftandilian * slightly larger or smaller changes. %tick and %stick should be synchronized
14400a57bdfSHaik Aftandilian * between CPUs, but there may be some variation. So we add an additional value
14500a57bdfSHaik Aftandilian * derived from this variable to ensure that these registers always increase
14600a57bdfSHaik Aftandilian * over a suspend/resume operation, assuming all %tick and %stick registers
14700a57bdfSHaik Aftandilian * are synchronized (within a certain limit) across CPUs in the system. The
14800a57bdfSHaik Aftandilian * delta between %sticks on different CPUs should be a small number of cycles,
14900a57bdfSHaik Aftandilian * not perceptible to readers of %stick that migrate between CPUs. We set this
15000a57bdfSHaik Aftandilian * value to 1 millisecond which means that over a suspend/resume operation,
15100a57bdfSHaik Aftandilian * all CPU's %tick and %stick will advance forwards as long as, across all
15200a57bdfSHaik Aftandilian * CPUs, the %tick and %stick are synchronized to within 1 ms. This applies to
15300a57bdfSHaik Aftandilian * CPUs before the suspend and CPUs after the resume. 1 ms is conservative,
15400a57bdfSHaik Aftandilian * but small enough to not trigger TOD faults.
15500a57bdfSHaik Aftandilian */
15600a57bdfSHaik Aftandilian static uint64_t suspend_tick_stick_max_delta = 1000; /* microseconds */
15700a57bdfSHaik Aftandilian
15800a57bdfSHaik Aftandilian /*
15902b4e56cSHaik Aftandilian * The number of times the system has been suspended and resumed.
16002b4e56cSHaik Aftandilian */
16102b4e56cSHaik Aftandilian static uint64_t suspend_count = 0;
16202b4e56cSHaik Aftandilian
16302b4e56cSHaik Aftandilian /*
164023e71deSHaik Aftandilian * DBG and DBG_PROM() macro.
165023e71deSHaik Aftandilian */
166023e71deSHaik Aftandilian #ifdef DEBUG
167023e71deSHaik Aftandilian
168023e71deSHaik Aftandilian static int suspend_debug_flag = 0;
169023e71deSHaik Aftandilian
170023e71deSHaik Aftandilian #define DBG_PROM \
171023e71deSHaik Aftandilian if (suspend_debug_flag) \
172023e71deSHaik Aftandilian prom_printf
173023e71deSHaik Aftandilian
174023e71deSHaik Aftandilian #define DBG \
175023e71deSHaik Aftandilian if (suspend_debug_flag) \
176023e71deSHaik Aftandilian suspend_debug
177023e71deSHaik Aftandilian
178023e71deSHaik Aftandilian static void
suspend_debug(const char * fmt,...)179023e71deSHaik Aftandilian suspend_debug(const char *fmt, ...)
180023e71deSHaik Aftandilian {
181023e71deSHaik Aftandilian char buf[512];
182023e71deSHaik Aftandilian va_list ap;
183023e71deSHaik Aftandilian
184023e71deSHaik Aftandilian va_start(ap, fmt);
185023e71deSHaik Aftandilian (void) vsprintf(buf, fmt, ap);
186023e71deSHaik Aftandilian va_end(ap);
187023e71deSHaik Aftandilian
188023e71deSHaik Aftandilian cmn_err(CE_NOTE, "%s", buf);
189023e71deSHaik Aftandilian }
190023e71deSHaik Aftandilian
191023e71deSHaik Aftandilian #else /* DEBUG */
192023e71deSHaik Aftandilian
193023e71deSHaik Aftandilian #define DBG_PROM
194023e71deSHaik Aftandilian #define DBG
195023e71deSHaik Aftandilian
196023e71deSHaik Aftandilian #endif /* DEBUG */
197023e71deSHaik Aftandilian
198023e71deSHaik Aftandilian /*
199023e71deSHaik Aftandilian * Return true if the HV supports OS suspend and if suspend has not been
200023e71deSHaik Aftandilian * disabled on this platform.
201023e71deSHaik Aftandilian */
202023e71deSHaik Aftandilian boolean_t
suspend_supported(void)203023e71deSHaik Aftandilian suspend_supported(void)
204023e71deSHaik Aftandilian {
205023e71deSHaik Aftandilian uint64_t major, minor;
206023e71deSHaik Aftandilian
207023e71deSHaik Aftandilian if (suspend_disabled)
208023e71deSHaik Aftandilian return (B_FALSE);
209023e71deSHaik Aftandilian
210023e71deSHaik Aftandilian if (hsvc_version(HSVC_GROUP_CORE, &major, &minor) != 0)
211023e71deSHaik Aftandilian return (B_FALSE);
212023e71deSHaik Aftandilian
213023e71deSHaik Aftandilian return ((major == SUSPEND_CORE_MAJOR && minor >= SUSPEND_CORE_MINOR) ||
214023e71deSHaik Aftandilian (major > SUSPEND_CORE_MAJOR));
215023e71deSHaik Aftandilian }
216023e71deSHaik Aftandilian
217023e71deSHaik Aftandilian /*
21802b4e56cSHaik Aftandilian * Memory DR is not permitted if the system has been suspended and resumed.
21902b4e56cSHaik Aftandilian * It is the responsibility of the caller of suspend_start and the DR
22002b4e56cSHaik Aftandilian * subsystem to serialize DR operations and suspend_memdr_allowed() checks.
22102b4e56cSHaik Aftandilian */
22202b4e56cSHaik Aftandilian boolean_t
suspend_memdr_allowed(void)22302b4e56cSHaik Aftandilian suspend_memdr_allowed(void)
22402b4e56cSHaik Aftandilian {
22502b4e56cSHaik Aftandilian return (suspend_count == 0);
22602b4e56cSHaik Aftandilian }
22702b4e56cSHaik Aftandilian
22802b4e56cSHaik Aftandilian /*
22900a57bdfSHaik Aftandilian * Given a source tick, stick, and tod value, set the tick and stick offsets
23000a57bdfSHaik Aftandilian * such that the (current physical register value) + offset == (source value)
23100a57bdfSHaik Aftandilian * and in addition account for some variation between the %tick/%stick on
23200a57bdfSHaik Aftandilian * different CPUs. We account for this variation by adding in double the value
23300a57bdfSHaik Aftandilian * of suspend_tick_stick_max_delta. The following is an explanation of why
23400a57bdfSHaik Aftandilian * suspend_tick_stick_max_delta must be multplied by two and added to
23500a57bdfSHaik Aftandilian * native_stick_offset.
23600a57bdfSHaik Aftandilian *
23700a57bdfSHaik Aftandilian * Consider a guest instance that is yet to be suspended with CPUs p0 and p1
23800a57bdfSHaik Aftandilian * with physical "source" %stick values s0 and s1 respectively. When the guest
23900a57bdfSHaik Aftandilian * is first resumed, the physical "target" %stick values are t0 and t1
24000a57bdfSHaik Aftandilian * respectively. The virtual %stick values after the resume are v0 and v1
24100a57bdfSHaik Aftandilian * respectively. Let x be the maximum difference between any two CPU's %stick
24200a57bdfSHaik Aftandilian * register at a given point in time and let the %stick values be assigned
24300a57bdfSHaik Aftandilian * such that
24400a57bdfSHaik Aftandilian *
24500a57bdfSHaik Aftandilian * s1 = s0 + x and
24600a57bdfSHaik Aftandilian * t1 = t0 - x
24700a57bdfSHaik Aftandilian *
24800a57bdfSHaik Aftandilian * Let us assume that p0 is driving the suspend and resume. Then, we will
24900a57bdfSHaik Aftandilian * calculate the stick offset f and the virtual %stick on p0 after the
25000a57bdfSHaik Aftandilian * resume as follows.
25100a57bdfSHaik Aftandilian *
25200a57bdfSHaik Aftandilian * f = s0 - t0 and
25300a57bdfSHaik Aftandilian * v0 = t0 + f
25400a57bdfSHaik Aftandilian *
25500a57bdfSHaik Aftandilian * We calculate the virtual %stick v1 on p1 after the resume as
25600a57bdfSHaik Aftandilian *
25700a57bdfSHaik Aftandilian * v1 = t1 + f
25800a57bdfSHaik Aftandilian *
25900a57bdfSHaik Aftandilian * Substitution yields
26000a57bdfSHaik Aftandilian *
26100a57bdfSHaik Aftandilian * v1 = t1 + (s0 - t0)
26200a57bdfSHaik Aftandilian * v1 = (t0 - x) + (s0 - t0)
26300a57bdfSHaik Aftandilian * v1 = -x + s0
26400a57bdfSHaik Aftandilian * v1 = s0 - x
26500a57bdfSHaik Aftandilian * v1 = (s1 - x) - x
26600a57bdfSHaik Aftandilian * v1 = s1 - 2x
26700a57bdfSHaik Aftandilian *
26800a57bdfSHaik Aftandilian * Therefore, in this scenario, without accounting for %stick variation in
26900a57bdfSHaik Aftandilian * the calculation of the native_stick_offset f, the virtual %stick on p1
27000a57bdfSHaik Aftandilian * is less than the value of the %stick on p1 before the suspend which is
27100a57bdfSHaik Aftandilian * unacceptable. By adding 2x to v1, we guarantee it will be equal to s1
27200a57bdfSHaik Aftandilian * which means the %stick on p1 after the resume will always be greater
27300a57bdfSHaik Aftandilian * than or equal to the %stick on p1 before the suspend. Since v1 = t1 + f
27400a57bdfSHaik Aftandilian * at any point in time, we can accomplish this by adding 2x to f. This
27500a57bdfSHaik Aftandilian * guarantees any processes bound to CPU P0 or P1 will not see a %stick
27600a57bdfSHaik Aftandilian * decrease across a suspend/resume. Hence, in the code below, we multiply
27700a57bdfSHaik Aftandilian * suspend_tick_stick_max_delta by two in the calculation for
27800a57bdfSHaik Aftandilian * native_stick_offset, native_tick_offset, and target_hrtime.
279023e71deSHaik Aftandilian */
280023e71deSHaik Aftandilian static void
set_tick_offsets(uint64_t source_tick,uint64_t source_stick,timestruc_t * tsp)28100a57bdfSHaik Aftandilian set_tick_offsets(uint64_t source_tick, uint64_t source_stick, timestruc_t *tsp)
282023e71deSHaik Aftandilian {
283023e71deSHaik Aftandilian uint64_t target_tick;
284023e71deSHaik Aftandilian uint64_t target_stick;
28500a57bdfSHaik Aftandilian hrtime_t source_hrtime;
28600a57bdfSHaik Aftandilian hrtime_t target_hrtime;
287023e71deSHaik Aftandilian
28800a57bdfSHaik Aftandilian /*
28900a57bdfSHaik Aftandilian * Temporarily set the offsets to zero so that the following reads
29000a57bdfSHaik Aftandilian * of the registers will yield physical unadjusted counter values.
29100a57bdfSHaik Aftandilian */
292023e71deSHaik Aftandilian native_tick_offset = 0;
293023e71deSHaik Aftandilian native_stick_offset = 0;
294023e71deSHaik Aftandilian
295023e71deSHaik Aftandilian target_tick = gettick_counter(); /* returns %tick */
296023e71deSHaik Aftandilian target_stick = gettick(); /* returns %stick */
297023e71deSHaik Aftandilian
29800a57bdfSHaik Aftandilian /*
29900a57bdfSHaik Aftandilian * Calculate the new offsets. In addition to the delta observed on
30000a57bdfSHaik Aftandilian * this CPU, add an additional value. Multiply the %tick/%stick
30100a57bdfSHaik Aftandilian * frequency by suspend_tick_stick_max_delta (us). Then, multiply by 2
30200a57bdfSHaik Aftandilian * to account for a delta between CPUs before the suspend and a
30300a57bdfSHaik Aftandilian * delta between CPUs after the resume.
30400a57bdfSHaik Aftandilian */
30500a57bdfSHaik Aftandilian native_tick_offset = (source_tick - target_tick) +
30600a57bdfSHaik Aftandilian (CPU->cpu_curr_clock * suspend_tick_stick_max_delta * 2 / MICROSEC);
30700a57bdfSHaik Aftandilian native_stick_offset = (source_stick - target_stick) +
30800a57bdfSHaik Aftandilian (sys_tick_freq * suspend_tick_stick_max_delta * 2 / MICROSEC);
30900a57bdfSHaik Aftandilian
31000a57bdfSHaik Aftandilian /*
31100a57bdfSHaik Aftandilian * We've effectively increased %stick and %tick by twice the value
31200a57bdfSHaik Aftandilian * of suspend_tick_stick_max_delta to account for variation across
31300a57bdfSHaik Aftandilian * CPUs. Now adjust the preserved TOD by the same amount.
31400a57bdfSHaik Aftandilian */
31500a57bdfSHaik Aftandilian source_hrtime = ts2hrt(tsp);
31600a57bdfSHaik Aftandilian target_hrtime = source_hrtime +
31700a57bdfSHaik Aftandilian (suspend_tick_stick_max_delta * 2 * (NANOSEC/MICROSEC));
31800a57bdfSHaik Aftandilian hrt2ts(target_hrtime, tsp);
319023e71deSHaik Aftandilian }
320023e71deSHaik Aftandilian
321023e71deSHaik Aftandilian /*
322023e71deSHaik Aftandilian * Set the {tick,stick}.NPT field to 1 on this CPU.
323023e71deSHaik Aftandilian */
324023e71deSHaik Aftandilian static void
enable_tick_stick_npt(void)325023e71deSHaik Aftandilian enable_tick_stick_npt(void)
326023e71deSHaik Aftandilian {
327c1374a13SSurya Prakki (void) hv_stick_set_npt(1);
328c1374a13SSurya Prakki (void) hv_tick_set_npt(1);
329023e71deSHaik Aftandilian }
330023e71deSHaik Aftandilian
331023e71deSHaik Aftandilian /*
332023e71deSHaik Aftandilian * Synchronize a CPU's {tick,stick}.NPT fields with the current state
333023e71deSHaik Aftandilian * of the system. This is used when a CPU is DR'd into the system.
334023e71deSHaik Aftandilian */
335023e71deSHaik Aftandilian void
suspend_sync_tick_stick_npt(void)336023e71deSHaik Aftandilian suspend_sync_tick_stick_npt(void)
337023e71deSHaik Aftandilian {
338023e71deSHaik Aftandilian if (tick_stick_emulation_active) {
339023e71deSHaik Aftandilian DBG("enabling {%%tick/%%stick}.NPT on CPU 0x%x", CPU->cpu_id);
340c1374a13SSurya Prakki (void) hv_stick_set_npt(1);
341c1374a13SSurya Prakki (void) hv_tick_set_npt(1);
342023e71deSHaik Aftandilian } else {
343023e71deSHaik Aftandilian ASSERT(gettick_npt() == 0);
344023e71deSHaik Aftandilian ASSERT(getstick_npt() == 0);
345023e71deSHaik Aftandilian }
346023e71deSHaik Aftandilian }
347023e71deSHaik Aftandilian
348023e71deSHaik Aftandilian /*
349023e71deSHaik Aftandilian * Obtain an updated MD from the hypervisor and update cpunodes, CPU HW
350023e71deSHaik Aftandilian * sharing data structures, and processor groups.
351023e71deSHaik Aftandilian */
352023e71deSHaik Aftandilian static void
update_cpu_mappings(void)353023e71deSHaik Aftandilian update_cpu_mappings(void)
354023e71deSHaik Aftandilian {
355023e71deSHaik Aftandilian md_t *mdp;
356023e71deSHaik Aftandilian processorid_t id;
357023e71deSHaik Aftandilian cpu_t *cp;
358023e71deSHaik Aftandilian cpu_pg_t *pgps[NCPU];
359023e71deSHaik Aftandilian
360023e71deSHaik Aftandilian if ((mdp = md_get_handle()) == NULL) {
361023e71deSHaik Aftandilian DBG("suspend: md_get_handle failed");
362023e71deSHaik Aftandilian return;
363023e71deSHaik Aftandilian }
364023e71deSHaik Aftandilian
365023e71deSHaik Aftandilian DBG("suspend: updating CPU mappings");
366023e71deSHaik Aftandilian
367023e71deSHaik Aftandilian mutex_enter(&cpu_lock);
368023e71deSHaik Aftandilian
369023e71deSHaik Aftandilian setup_chip_mappings(mdp);
370023e71deSHaik Aftandilian setup_exec_unit_mappings(mdp);
371023e71deSHaik Aftandilian for (id = 0; id < NCPU; id++) {
372023e71deSHaik Aftandilian if ((cp = cpu_get(id)) == NULL)
373023e71deSHaik Aftandilian continue;
374023e71deSHaik Aftandilian cpu_map_exec_units(cp);
375023e71deSHaik Aftandilian }
376023e71deSHaik Aftandilian
377023e71deSHaik Aftandilian /*
378023e71deSHaik Aftandilian * Re-calculate processor groups.
379023e71deSHaik Aftandilian *
380023e71deSHaik Aftandilian * First tear down all PG information before adding any new PG
381023e71deSHaik Aftandilian * information derived from the MD we just downloaded. We must
382023e71deSHaik Aftandilian * call pg_cpu_inactive and pg_cpu_active with CPUs paused and
383023e71deSHaik Aftandilian * we want to minimize the number of times pause_cpus is called.
384023e71deSHaik Aftandilian * Inactivating all CPUs would leave PGs without any active CPUs,
385023e71deSHaik Aftandilian * so while CPUs are paused, call pg_cpu_inactive and swap in the
386023e71deSHaik Aftandilian * bootstrap PG structure saving the original PG structure to be
387023e71deSHaik Aftandilian * fini'd afterwards. This prevents the dispatcher from encountering
38898b45ebeSHaik Aftandilian * PGs in which all CPUs are inactive. Offline CPUs are already
38998b45ebeSHaik Aftandilian * inactive in their PGs and shouldn't be reactivated, so we must
39098b45ebeSHaik Aftandilian * not call pg_cpu_inactive or pg_cpu_active for those CPUs.
391023e71deSHaik Aftandilian */
392*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
393023e71deSHaik Aftandilian for (id = 0; id < NCPU; id++) {
394023e71deSHaik Aftandilian if ((cp = cpu_get(id)) == NULL)
395023e71deSHaik Aftandilian continue;
39698b45ebeSHaik Aftandilian if ((cp->cpu_flags & CPU_OFFLINE) == 0)
397023e71deSHaik Aftandilian pg_cpu_inactive(cp);
398023e71deSHaik Aftandilian pgps[id] = cp->cpu_pg;
399023e71deSHaik Aftandilian pg_cpu_bootstrap(cp);
400023e71deSHaik Aftandilian }
401023e71deSHaik Aftandilian start_cpus();
402023e71deSHaik Aftandilian
403023e71deSHaik Aftandilian /*
404023e71deSHaik Aftandilian * pg_cpu_fini* and pg_cpu_init* must be called while CPUs are
405023e71deSHaik Aftandilian * not paused. Use two separate loops here so that we do not
406023e71deSHaik Aftandilian * initialize PG data for CPUs until all the old PG data structures
407023e71deSHaik Aftandilian * are torn down.
408023e71deSHaik Aftandilian */
409023e71deSHaik Aftandilian for (id = 0; id < NCPU; id++) {
410023e71deSHaik Aftandilian if ((cp = cpu_get(id)) == NULL)
411023e71deSHaik Aftandilian continue;
412023e71deSHaik Aftandilian pg_cpu_fini(cp, pgps[id]);
413183ef8a1SHaik Aftandilian mpo_cpu_remove(id);
414023e71deSHaik Aftandilian }
415023e71deSHaik Aftandilian
416023e71deSHaik Aftandilian /*
417023e71deSHaik Aftandilian * Initialize PG data for each CPU, but leave the bootstrapped
418023e71deSHaik Aftandilian * PG structure in place to avoid running with any PGs containing
419023e71deSHaik Aftandilian * nothing but inactive CPUs.
420023e71deSHaik Aftandilian */
421023e71deSHaik Aftandilian for (id = 0; id < NCPU; id++) {
422023e71deSHaik Aftandilian if ((cp = cpu_get(id)) == NULL)
423023e71deSHaik Aftandilian continue;
424183ef8a1SHaik Aftandilian mpo_cpu_add(mdp, id);
425023e71deSHaik Aftandilian pgps[id] = pg_cpu_init(cp, B_TRUE);
426023e71deSHaik Aftandilian }
427023e71deSHaik Aftandilian
428023e71deSHaik Aftandilian /*
429023e71deSHaik Aftandilian * Now that PG data has been initialized for all CPUs in the
430023e71deSHaik Aftandilian * system, replace the bootstrapped PG structure with the
431023e71deSHaik Aftandilian * initialized PG structure and call pg_cpu_active for each CPU.
432023e71deSHaik Aftandilian */
433*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
434023e71deSHaik Aftandilian for (id = 0; id < NCPU; id++) {
435023e71deSHaik Aftandilian if ((cp = cpu_get(id)) == NULL)
436023e71deSHaik Aftandilian continue;
437023e71deSHaik Aftandilian cp->cpu_pg = pgps[id];
43898b45ebeSHaik Aftandilian if ((cp->cpu_flags & CPU_OFFLINE) == 0)
439023e71deSHaik Aftandilian pg_cpu_active(cp);
440023e71deSHaik Aftandilian }
441023e71deSHaik Aftandilian start_cpus();
442023e71deSHaik Aftandilian
443023e71deSHaik Aftandilian mutex_exit(&cpu_lock);
444023e71deSHaik Aftandilian
445023e71deSHaik Aftandilian (void) md_fini_handle(mdp);
446023e71deSHaik Aftandilian }
447023e71deSHaik Aftandilian
448023e71deSHaik Aftandilian /*
449023e71deSHaik Aftandilian * Wrapper for the Sun Cluster error decoding function.
450023e71deSHaik Aftandilian */
451023e71deSHaik Aftandilian static int
cluster_error_decode(int error,char * error_reason,size_t max_reason_len)452023e71deSHaik Aftandilian cluster_error_decode(int error, char *error_reason, size_t max_reason_len)
453023e71deSHaik Aftandilian {
454023e71deSHaik Aftandilian const char *decoded;
455023e71deSHaik Aftandilian size_t decoded_len;
456023e71deSHaik Aftandilian
457023e71deSHaik Aftandilian ASSERT(error_reason != NULL);
458023e71deSHaik Aftandilian ASSERT(max_reason_len > 0);
459023e71deSHaik Aftandilian
460023e71deSHaik Aftandilian max_reason_len = MIN(max_reason_len, SC_FAIL_STR_MAX);
461023e71deSHaik Aftandilian
462023e71deSHaik Aftandilian if (cl_suspend_error_decode == NULL)
463023e71deSHaik Aftandilian return (-1);
464023e71deSHaik Aftandilian
465023e71deSHaik Aftandilian if ((decoded = (*cl_suspend_error_decode)(error)) == NULL)
466023e71deSHaik Aftandilian return (-1);
467023e71deSHaik Aftandilian
468023e71deSHaik Aftandilian /* Get number of non-NULL bytes */
469023e71deSHaik Aftandilian if ((decoded_len = strnlen(decoded, max_reason_len - 1)) == 0)
470023e71deSHaik Aftandilian return (-1);
471023e71deSHaik Aftandilian
472023e71deSHaik Aftandilian bcopy(decoded, error_reason, decoded_len);
473023e71deSHaik Aftandilian
474023e71deSHaik Aftandilian /*
475023e71deSHaik Aftandilian * The error string returned from cl_suspend_error_decode
476023e71deSHaik Aftandilian * should be NULL-terminated, but set the terminator here
477023e71deSHaik Aftandilian * because we only copied non-NULL bytes. If the decoded
478023e71deSHaik Aftandilian * string was not NULL-terminated, this guarantees that
479023e71deSHaik Aftandilian * error_reason will be.
480023e71deSHaik Aftandilian */
481023e71deSHaik Aftandilian error_reason[decoded_len] = '\0';
482023e71deSHaik Aftandilian
483023e71deSHaik Aftandilian return (0);
484023e71deSHaik Aftandilian }
485023e71deSHaik Aftandilian
486023e71deSHaik Aftandilian /*
487023e71deSHaik Aftandilian * Wrapper for the Sun Cluster pre-suspend callback.
488023e71deSHaik Aftandilian */
489023e71deSHaik Aftandilian static int
cluster_pre_wrapper(char * error_reason,size_t max_reason_len)490023e71deSHaik Aftandilian cluster_pre_wrapper(char *error_reason, size_t max_reason_len)
491023e71deSHaik Aftandilian {
492023e71deSHaik Aftandilian int rv = 0;
493023e71deSHaik Aftandilian
494023e71deSHaik Aftandilian if (cl_suspend_pre_callback != NULL) {
495023e71deSHaik Aftandilian rv = (*cl_suspend_pre_callback)();
496023e71deSHaik Aftandilian DBG("suspend: cl_suspend_pre_callback returned %d", rv);
497023e71deSHaik Aftandilian if (rv != 0 && error_reason != NULL && max_reason_len > 0) {
498023e71deSHaik Aftandilian if (cluster_error_decode(rv, error_reason,
499023e71deSHaik Aftandilian max_reason_len)) {
500023e71deSHaik Aftandilian (void) snprintf(error_reason, max_reason_len,
501023e71deSHaik Aftandilian SC_PRE_FAIL_STR_FMT, rv);
502023e71deSHaik Aftandilian }
503023e71deSHaik Aftandilian }
504023e71deSHaik Aftandilian }
505023e71deSHaik Aftandilian
506023e71deSHaik Aftandilian return (rv);
507023e71deSHaik Aftandilian }
508023e71deSHaik Aftandilian
509023e71deSHaik Aftandilian /*
510023e71deSHaik Aftandilian * Wrapper for the Sun Cluster post-suspend callback.
511023e71deSHaik Aftandilian */
512023e71deSHaik Aftandilian static int
cluster_post_wrapper(char * error_reason,size_t max_reason_len)513023e71deSHaik Aftandilian cluster_post_wrapper(char *error_reason, size_t max_reason_len)
514023e71deSHaik Aftandilian {
515023e71deSHaik Aftandilian int rv = 0;
516023e71deSHaik Aftandilian
517023e71deSHaik Aftandilian if (cl_suspend_post_callback != NULL) {
518023e71deSHaik Aftandilian rv = (*cl_suspend_post_callback)();
519023e71deSHaik Aftandilian DBG("suspend: cl_suspend_post_callback returned %d", rv);
520023e71deSHaik Aftandilian if (rv != 0 && error_reason != NULL && max_reason_len > 0) {
521023e71deSHaik Aftandilian if (cluster_error_decode(rv, error_reason,
522023e71deSHaik Aftandilian max_reason_len)) {
523023e71deSHaik Aftandilian (void) snprintf(error_reason,
524023e71deSHaik Aftandilian max_reason_len, SC_POST_FAIL_STR_FMT, rv);
525023e71deSHaik Aftandilian }
526023e71deSHaik Aftandilian }
527023e71deSHaik Aftandilian }
528023e71deSHaik Aftandilian
529023e71deSHaik Aftandilian return (rv);
530023e71deSHaik Aftandilian }
531023e71deSHaik Aftandilian
532023e71deSHaik Aftandilian /*
533023e71deSHaik Aftandilian * Execute pre-suspend callbacks preparing the system for a suspend operation.
534023e71deSHaik Aftandilian * Returns zero on success, non-zero on failure. Sets the recovered argument
535023e71deSHaik Aftandilian * to indicate whether or not callbacks could be undone in the event of a
536023e71deSHaik Aftandilian * failure--if callbacks were successfully undone, *recovered is set to B_TRUE,
537023e71deSHaik Aftandilian * otherwise *recovered is set to B_FALSE. Must be called successfully before
538023e71deSHaik Aftandilian * suspend_start can be called. Callers should first call suspend_support to
539023e71deSHaik Aftandilian * determine if OS suspend is supported.
540023e71deSHaik Aftandilian */
541023e71deSHaik Aftandilian int
suspend_pre(char * error_reason,size_t max_reason_len,boolean_t * recovered)542023e71deSHaik Aftandilian suspend_pre(char *error_reason, size_t max_reason_len, boolean_t *recovered)
543023e71deSHaik Aftandilian {
544023e71deSHaik Aftandilian int rv;
545023e71deSHaik Aftandilian
546023e71deSHaik Aftandilian ASSERT(recovered != NULL);
547023e71deSHaik Aftandilian
548023e71deSHaik Aftandilian /*
549023e71deSHaik Aftandilian * Return an error if suspend_pre is erreoneously called
550023e71deSHaik Aftandilian * when OS suspend is not supported.
551023e71deSHaik Aftandilian */
552023e71deSHaik Aftandilian ASSERT(suspend_supported());
553023e71deSHaik Aftandilian if (!suspend_supported()) {
554023e71deSHaik Aftandilian DBG("suspend: suspend_pre called without suspend support");
555023e71deSHaik Aftandilian *recovered = B_TRUE;
556023e71deSHaik Aftandilian return (ENOTSUP);
557023e71deSHaik Aftandilian }
558023e71deSHaik Aftandilian DBG("suspend: %s", __func__);
559023e71deSHaik Aftandilian
560023e71deSHaik Aftandilian rv = cluster_pre_wrapper(error_reason, max_reason_len);
561023e71deSHaik Aftandilian
562023e71deSHaik Aftandilian /*
563023e71deSHaik Aftandilian * At present, only one pre-suspend operation exists.
564023e71deSHaik Aftandilian * If it fails, no recovery needs to be done.
565023e71deSHaik Aftandilian */
566023e71deSHaik Aftandilian if (rv != 0 && recovered != NULL)
567023e71deSHaik Aftandilian *recovered = B_TRUE;
568023e71deSHaik Aftandilian
569023e71deSHaik Aftandilian return (rv);
570023e71deSHaik Aftandilian }
571023e71deSHaik Aftandilian
572023e71deSHaik Aftandilian /*
573023e71deSHaik Aftandilian * Execute post-suspend callbacks. Returns zero on success, non-zero on
574023e71deSHaik Aftandilian * failure. Must be called after suspend_start is called, regardless of
575023e71deSHaik Aftandilian * whether or not suspend_start is successful.
576023e71deSHaik Aftandilian */
577023e71deSHaik Aftandilian int
suspend_post(char * error_reason,size_t max_reason_len)578023e71deSHaik Aftandilian suspend_post(char *error_reason, size_t max_reason_len)
579023e71deSHaik Aftandilian {
580023e71deSHaik Aftandilian ASSERT(suspend_supported());
581023e71deSHaik Aftandilian DBG("suspend: %s", __func__);
582023e71deSHaik Aftandilian return (cluster_post_wrapper(error_reason, max_reason_len));
583023e71deSHaik Aftandilian }
584023e71deSHaik Aftandilian
585023e71deSHaik Aftandilian /*
586023e71deSHaik Aftandilian * Suspends the OS by pausing CPUs and calling into the HV to initiate
587023e71deSHaik Aftandilian * the suspend. When the HV routine hv_guest_suspend returns, the system
588023e71deSHaik Aftandilian * will be resumed. Must be called after a successful call to suspend_pre.
589023e71deSHaik Aftandilian * suspend_post must be called after suspend_start, whether or not
590023e71deSHaik Aftandilian * suspend_start returns an error.
591023e71deSHaik Aftandilian */
592023e71deSHaik Aftandilian /*ARGSUSED*/
593023e71deSHaik Aftandilian int
suspend_start(char * error_reason,size_t max_reason_len)594023e71deSHaik Aftandilian suspend_start(char *error_reason, size_t max_reason_len)
595023e71deSHaik Aftandilian {
596023e71deSHaik Aftandilian uint64_t source_tick;
597023e71deSHaik Aftandilian uint64_t source_stick;
598023e71deSHaik Aftandilian uint64_t rv;
599023e71deSHaik Aftandilian timestruc_t source_tod;
600023e71deSHaik Aftandilian int spl;
601023e71deSHaik Aftandilian
602023e71deSHaik Aftandilian ASSERT(suspend_supported());
603023e71deSHaik Aftandilian DBG("suspend: %s", __func__);
604023e71deSHaik Aftandilian
605d2365b01SPavel Tatashin sfmmu_ctxdoms_lock();
606d2365b01SPavel Tatashin
607023e71deSHaik Aftandilian mutex_enter(&cpu_lock);
608023e71deSHaik Aftandilian
609023e71deSHaik Aftandilian /* Suspend the watchdog */
610023e71deSHaik Aftandilian watchdog_suspend();
611023e71deSHaik Aftandilian
612023e71deSHaik Aftandilian /* Record the TOD */
613023e71deSHaik Aftandilian mutex_enter(&tod_lock);
614023e71deSHaik Aftandilian source_tod = tod_get();
615023e71deSHaik Aftandilian mutex_exit(&tod_lock);
616023e71deSHaik Aftandilian
617023e71deSHaik Aftandilian /* Pause all other CPUs */
618*0ed5c46eSJosef 'Jeff' Sipek pause_cpus(NULL, NULL);
619023e71deSHaik Aftandilian DBG_PROM("suspend: CPUs paused\n");
620023e71deSHaik Aftandilian
62100a57bdfSHaik Aftandilian /* Suspend cyclics */
622023e71deSHaik Aftandilian cyclic_suspend();
623023e71deSHaik Aftandilian DBG_PROM("suspend: cyclics suspended\n");
62400a57bdfSHaik Aftandilian
62500a57bdfSHaik Aftandilian /* Disable interrupts */
626023e71deSHaik Aftandilian spl = spl8();
62700a57bdfSHaik Aftandilian DBG_PROM("suspend: spl8()\n");
628023e71deSHaik Aftandilian
629023e71deSHaik Aftandilian source_tick = gettick_counter();
630023e71deSHaik Aftandilian source_stick = gettick();
631023e71deSHaik Aftandilian DBG_PROM("suspend: source_tick: 0x%lx\n", source_tick);
632023e71deSHaik Aftandilian DBG_PROM("suspend: source_stick: 0x%lx\n", source_stick);
633023e71deSHaik Aftandilian
634023e71deSHaik Aftandilian /*
63500a57bdfSHaik Aftandilian * Call into the HV to initiate the suspend. hv_guest_suspend()
63600a57bdfSHaik Aftandilian * returns after the guest has been resumed or if the suspend
63700a57bdfSHaik Aftandilian * operation failed or was cancelled. After a successful suspend,
63800a57bdfSHaik Aftandilian * the %tick and %stick registers may have changed by an amount
63900a57bdfSHaik Aftandilian * that is not proportional to the amount of time that has passed.
64000a57bdfSHaik Aftandilian * They may have jumped forwards or backwards. Some variation is
64100a57bdfSHaik Aftandilian * allowed and accounted for using suspend_tick_stick_max_delta,
64200a57bdfSHaik Aftandilian * but otherwise this jump must be uniform across all CPUs and we
64300a57bdfSHaik Aftandilian * operate under the assumption that it is (maintaining two global
64400a57bdfSHaik Aftandilian * offset variables--one for %tick and one for %stick.)
645023e71deSHaik Aftandilian */
646023e71deSHaik Aftandilian DBG_PROM("suspend: suspending... \n");
647023e71deSHaik Aftandilian rv = hv_guest_suspend();
648023e71deSHaik Aftandilian if (rv != 0) {
649023e71deSHaik Aftandilian splx(spl);
650023e71deSHaik Aftandilian cyclic_resume();
651023e71deSHaik Aftandilian start_cpus();
652023e71deSHaik Aftandilian watchdog_resume();
653023e71deSHaik Aftandilian mutex_exit(&cpu_lock);
654d2365b01SPavel Tatashin sfmmu_ctxdoms_unlock();
655023e71deSHaik Aftandilian DBG("suspend: failed, rv: %ld\n", rv);
656023e71deSHaik Aftandilian return (rv);
657023e71deSHaik Aftandilian }
658023e71deSHaik Aftandilian
65902b4e56cSHaik Aftandilian suspend_count++;
66002b4e56cSHaik Aftandilian
66100a57bdfSHaik Aftandilian /* Update the global tick and stick offsets and the preserved TOD */
66200a57bdfSHaik Aftandilian set_tick_offsets(source_tick, source_stick, &source_tod);
663023e71deSHaik Aftandilian
664023e71deSHaik Aftandilian /* Ensure new offsets are globally visible before resuming CPUs */
665023e71deSHaik Aftandilian membar_sync();
666023e71deSHaik Aftandilian
667023e71deSHaik Aftandilian /* Enable interrupts */
668023e71deSHaik Aftandilian splx(spl);
669023e71deSHaik Aftandilian
670023e71deSHaik Aftandilian /* Set the {%tick,%stick}.NPT bits on all CPUs */
671023e71deSHaik Aftandilian if (enable_user_tick_stick_emulation) {
672023e71deSHaik Aftandilian xc_all((xcfunc_t *)enable_tick_stick_npt, NULL, NULL);
673023e71deSHaik Aftandilian xt_sync(cpu_ready_set);
674023e71deSHaik Aftandilian ASSERT(gettick_npt() != 0);
675023e71deSHaik Aftandilian ASSERT(getstick_npt() != 0);
676023e71deSHaik Aftandilian }
677023e71deSHaik Aftandilian
678023e71deSHaik Aftandilian /* If emulation is enabled, but not currently active, enable it */
679023e71deSHaik Aftandilian if (enable_user_tick_stick_emulation && !tick_stick_emulation_active) {
680023e71deSHaik Aftandilian tick_stick_emulation_active = B_TRUE;
681023e71deSHaik Aftandilian }
682023e71deSHaik Aftandilian
683d2365b01SPavel Tatashin sfmmu_ctxdoms_remove();
684d2365b01SPavel Tatashin
685023e71deSHaik Aftandilian /* Resume cyclics, unpause CPUs */
686023e71deSHaik Aftandilian cyclic_resume();
687023e71deSHaik Aftandilian start_cpus();
688023e71deSHaik Aftandilian
689023e71deSHaik Aftandilian /* Set the TOD */
690023e71deSHaik Aftandilian mutex_enter(&tod_lock);
691023e71deSHaik Aftandilian tod_set(source_tod);
692023e71deSHaik Aftandilian mutex_exit(&tod_lock);
693023e71deSHaik Aftandilian
694023e71deSHaik Aftandilian /* Re-enable the watchdog */
695023e71deSHaik Aftandilian watchdog_resume();
696023e71deSHaik Aftandilian
697023e71deSHaik Aftandilian mutex_exit(&cpu_lock);
698023e71deSHaik Aftandilian
699d2365b01SPavel Tatashin /* Download the latest MD */
700d2365b01SPavel Tatashin if ((rv = mach_descrip_update()) != 0)
701d2365b01SPavel Tatashin cmn_err(CE_PANIC, "suspend: mach_descrip_update failed: %ld",
702d2365b01SPavel Tatashin rv);
703d2365b01SPavel Tatashin
704d2365b01SPavel Tatashin sfmmu_ctxdoms_update();
705d2365b01SPavel Tatashin sfmmu_ctxdoms_unlock();
706d2365b01SPavel Tatashin
707023e71deSHaik Aftandilian /* Get new MD, update CPU mappings/relationships */
708023e71deSHaik Aftandilian if (suspend_update_cpu_mappings)
709023e71deSHaik Aftandilian update_cpu_mappings();
710023e71deSHaik Aftandilian
711023e71deSHaik Aftandilian DBG("suspend: target tick: 0x%lx", gettick_counter());
712023e71deSHaik Aftandilian DBG("suspend: target stick: 0x%llx", gettick());
713023e71deSHaik Aftandilian DBG("suspend: user %%tick/%%stick emulation is %d",
714023e71deSHaik Aftandilian tick_stick_emulation_active);
715023e71deSHaik Aftandilian DBG("suspend: finished");
716023e71deSHaik Aftandilian
717023e71deSHaik Aftandilian return (0);
718023e71deSHaik Aftandilian }
719