18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Suspend support specific for i386/x86-64.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
68c2ecf20Sopenharmony_ci * Copyright (c) 2002 Pavel Machek <pavel@ucw.cz>
78c2ecf20Sopenharmony_ci * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/suspend.h>
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/smp.h>
138c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
148c2ecf20Sopenharmony_ci#include <linux/tboot.h>
158c2ecf20Sopenharmony_ci#include <linux/dmi.h>
168c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/proto.h>
198c2ecf20Sopenharmony_ci#include <asm/mtrr.h>
208c2ecf20Sopenharmony_ci#include <asm/page.h>
218c2ecf20Sopenharmony_ci#include <asm/mce.h>
228c2ecf20Sopenharmony_ci#include <asm/suspend.h>
238c2ecf20Sopenharmony_ci#include <asm/fpu/internal.h>
248c2ecf20Sopenharmony_ci#include <asm/debugreg.h>
258c2ecf20Sopenharmony_ci#include <asm/cpu.h>
268c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
278c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
288c2ecf20Sopenharmony_ci#include <asm/microcode.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
318c2ecf20Sopenharmony_ci__visible unsigned long saved_context_ebx;
328c2ecf20Sopenharmony_ci__visible unsigned long saved_context_esp, saved_context_ebp;
338c2ecf20Sopenharmony_ci__visible unsigned long saved_context_esi, saved_context_edi;
348c2ecf20Sopenharmony_ci__visible unsigned long saved_context_eflags;
358c2ecf20Sopenharmony_ci#endif
368c2ecf20Sopenharmony_cistruct saved_context saved_context;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void msr_save_context(struct saved_context *ctxt)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct saved_msr *msr = ctxt->saved_msrs.array;
418c2ecf20Sopenharmony_ci	struct saved_msr *end = msr + ctxt->saved_msrs.num;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	while (msr < end) {
448c2ecf20Sopenharmony_ci		if (msr->valid)
458c2ecf20Sopenharmony_ci			rdmsrl(msr->info.msr_no, msr->info.reg.q);
468c2ecf20Sopenharmony_ci		msr++;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic void msr_restore_context(struct saved_context *ctxt)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct saved_msr *msr = ctxt->saved_msrs.array;
538c2ecf20Sopenharmony_ci	struct saved_msr *end = msr + ctxt->saved_msrs.num;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	while (msr < end) {
568c2ecf20Sopenharmony_ci		if (msr->valid)
578c2ecf20Sopenharmony_ci			wrmsrl(msr->info.msr_no, msr->info.reg.q);
588c2ecf20Sopenharmony_ci		msr++;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/**
638c2ecf20Sopenharmony_ci *	__save_processor_state - save CPU registers before creating a
648c2ecf20Sopenharmony_ci *		hibernation image and before restoring the memory state from it
658c2ecf20Sopenharmony_ci *	@ctxt - structure to store the registers contents in
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci *	NOTE: If there is a CPU register the modification of which by the
688c2ecf20Sopenharmony_ci *	boot kernel (ie. the kernel used for loading the hibernation image)
698c2ecf20Sopenharmony_ci *	might affect the operations of the restored target kernel (ie. the one
708c2ecf20Sopenharmony_ci *	saved in the hibernation image), then its contents must be saved by this
718c2ecf20Sopenharmony_ci *	function.  In other words, if kernel A is hibernated and different
728c2ecf20Sopenharmony_ci *	kernel B is used for loading the hibernation image into memory, the
738c2ecf20Sopenharmony_ci *	kernel A's __save_processor_state() function must save all registers
748c2ecf20Sopenharmony_ci *	needed by kernel A, so that it can operate correctly after the resume
758c2ecf20Sopenharmony_ci *	regardless of what kernel B does in the meantime.
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_cistatic void __save_processor_state(struct saved_context *ctxt)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
808c2ecf20Sopenharmony_ci	mtrr_save_fixed_ranges(NULL);
818c2ecf20Sopenharmony_ci#endif
828c2ecf20Sopenharmony_ci	kernel_fpu_begin();
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/*
858c2ecf20Sopenharmony_ci	 * descriptor tables
868c2ecf20Sopenharmony_ci	 */
878c2ecf20Sopenharmony_ci	store_idt(&ctxt->idt);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/*
908c2ecf20Sopenharmony_ci	 * We save it here, but restore it only in the hibernate case.
918c2ecf20Sopenharmony_ci	 * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
928c2ecf20Sopenharmony_ci	 * mode in "secondary_startup_64". In 32-bit mode it is done via
938c2ecf20Sopenharmony_ci	 * 'pmode_gdt' in wakeup_start.
948c2ecf20Sopenharmony_ci	 */
958c2ecf20Sopenharmony_ci	ctxt->gdt_desc.size = GDT_SIZE - 1;
968c2ecf20Sopenharmony_ci	ctxt->gdt_desc.address = (unsigned long)get_cpu_gdt_rw(smp_processor_id());
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	store_tr(ctxt->tr);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
1018c2ecf20Sopenharmony_ci	/*
1028c2ecf20Sopenharmony_ci	 * segment registers
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32_LAZY_GS
1058c2ecf20Sopenharmony_ci	savesegment(gs, ctxt->gs);
1068c2ecf20Sopenharmony_ci#endif
1078c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
1088c2ecf20Sopenharmony_ci	savesegment(gs, ctxt->gs);
1098c2ecf20Sopenharmony_ci	savesegment(fs, ctxt->fs);
1108c2ecf20Sopenharmony_ci	savesegment(ds, ctxt->ds);
1118c2ecf20Sopenharmony_ci	savesegment(es, ctxt->es);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	rdmsrl(MSR_FS_BASE, ctxt->fs_base);
1148c2ecf20Sopenharmony_ci	rdmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
1158c2ecf20Sopenharmony_ci	rdmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
1168c2ecf20Sopenharmony_ci	mtrr_save_fixed_ranges(NULL);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	rdmsrl(MSR_EFER, ctxt->efer);
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 * control registers
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	ctxt->cr0 = read_cr0();
1258c2ecf20Sopenharmony_ci	ctxt->cr2 = read_cr2();
1268c2ecf20Sopenharmony_ci	ctxt->cr3 = __read_cr3();
1278c2ecf20Sopenharmony_ci	ctxt->cr4 = __read_cr4();
1288c2ecf20Sopenharmony_ci	ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE,
1298c2ecf20Sopenharmony_ci					       &ctxt->misc_enable);
1308c2ecf20Sopenharmony_ci	msr_save_context(ctxt);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* Needed by apm.c */
1348c2ecf20Sopenharmony_civoid save_processor_state(void)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	__save_processor_state(&saved_context);
1378c2ecf20Sopenharmony_ci	x86_platform.save_sched_clock_state();
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
1408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(save_processor_state);
1418c2ecf20Sopenharmony_ci#endif
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void do_fpu_end(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	/*
1468c2ecf20Sopenharmony_ci	 * Restore FPU regs if necessary.
1478c2ecf20Sopenharmony_ci	 */
1488c2ecf20Sopenharmony_ci	kernel_fpu_end();
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void fix_processor_context(void)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	int cpu = smp_processor_id();
1548c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
1558c2ecf20Sopenharmony_ci	struct desc_struct *desc = get_cpu_gdt_rw(cpu);
1568c2ecf20Sopenharmony_ci	tss_desc tss;
1578c2ecf20Sopenharmony_ci#endif
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/*
1608c2ecf20Sopenharmony_ci	 * We need to reload TR, which requires that we change the
1618c2ecf20Sopenharmony_ci	 * GDT entry to indicate "available" first.
1628c2ecf20Sopenharmony_ci	 *
1638c2ecf20Sopenharmony_ci	 * XXX: This could probably all be replaced by a call to
1648c2ecf20Sopenharmony_ci	 * force_reload_TR().
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci	set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
1698c2ecf20Sopenharmony_ci	memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
1708c2ecf20Sopenharmony_ci	tss.type = 0x9; /* The available 64-bit TSS (see AMD vol 2, pg 91 */
1718c2ecf20Sopenharmony_ci	write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	syscall_init();				/* This sets MSR_*STAR and related */
1748c2ecf20Sopenharmony_ci#else
1758c2ecf20Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_SEP))
1768c2ecf20Sopenharmony_ci		enable_sep_cpu();
1778c2ecf20Sopenharmony_ci#endif
1788c2ecf20Sopenharmony_ci	load_TR_desc();				/* This does ltr */
1798c2ecf20Sopenharmony_ci	load_mm_ldt(current->active_mm);	/* This does lldt */
1808c2ecf20Sopenharmony_ci	initialize_tlbstate_and_flush();
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	fpu__resume_cpu();
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* The processor is back on the direct GDT, load back the fixmap */
1858c2ecf20Sopenharmony_ci	load_fixmap_gdt(cpu);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci * __restore_processor_state - restore the contents of CPU registers saved
1908c2ecf20Sopenharmony_ci *                             by __save_processor_state()
1918c2ecf20Sopenharmony_ci * @ctxt - structure to load the registers contents from
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * The asm code that gets us here will have restored a usable GDT, although
1948c2ecf20Sopenharmony_ci * it will be pointing to the wrong alias.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistatic void notrace __restore_processor_state(struct saved_context *ctxt)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct cpuinfo_x86 *c;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (ctxt->misc_enable_saved)
2018c2ecf20Sopenharmony_ci		wrmsrl(MSR_IA32_MISC_ENABLE, ctxt->misc_enable);
2028c2ecf20Sopenharmony_ci	/*
2038c2ecf20Sopenharmony_ci	 * control registers
2048c2ecf20Sopenharmony_ci	 */
2058c2ecf20Sopenharmony_ci	/* cr4 was introduced in the Pentium CPU */
2068c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
2078c2ecf20Sopenharmony_ci	if (ctxt->cr4)
2088c2ecf20Sopenharmony_ci		__write_cr4(ctxt->cr4);
2098c2ecf20Sopenharmony_ci#else
2108c2ecf20Sopenharmony_ci/* CONFIG X86_64 */
2118c2ecf20Sopenharmony_ci	wrmsrl(MSR_EFER, ctxt->efer);
2128c2ecf20Sopenharmony_ci	__write_cr4(ctxt->cr4);
2138c2ecf20Sopenharmony_ci#endif
2148c2ecf20Sopenharmony_ci	write_cr3(ctxt->cr3);
2158c2ecf20Sopenharmony_ci	write_cr2(ctxt->cr2);
2168c2ecf20Sopenharmony_ci	write_cr0(ctxt->cr0);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Restore the IDT. */
2198c2ecf20Sopenharmony_ci	load_idt(&ctxt->idt);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * Just in case the asm code got us here with the SS, DS, or ES
2238c2ecf20Sopenharmony_ci	 * out of sync with the GDT, update them.
2248c2ecf20Sopenharmony_ci	 */
2258c2ecf20Sopenharmony_ci	loadsegment(ss, __KERNEL_DS);
2268c2ecf20Sopenharmony_ci	loadsegment(ds, __USER_DS);
2278c2ecf20Sopenharmony_ci	loadsegment(es, __USER_DS);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/*
2308c2ecf20Sopenharmony_ci	 * Restore percpu access.  Percpu access can happen in exception
2318c2ecf20Sopenharmony_ci	 * handlers or in complicated helpers like load_gs_index().
2328c2ecf20Sopenharmony_ci	 */
2338c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
2348c2ecf20Sopenharmony_ci	wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
2358c2ecf20Sopenharmony_ci#else
2368c2ecf20Sopenharmony_ci	loadsegment(fs, __KERNEL_PERCPU);
2378c2ecf20Sopenharmony_ci	loadsegment(gs, __KERNEL_STACK_CANARY);
2388c2ecf20Sopenharmony_ci#endif
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Restore the TSS, RO GDT, LDT, and usermode-relevant MSRs. */
2418c2ecf20Sopenharmony_ci	fix_processor_context();
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/*
2448c2ecf20Sopenharmony_ci	 * Now that we have descriptor tables fully restored and working
2458c2ecf20Sopenharmony_ci	 * exception handling, restore the usermode segments.
2468c2ecf20Sopenharmony_ci	 */
2478c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
2488c2ecf20Sopenharmony_ci	loadsegment(ds, ctxt->es);
2498c2ecf20Sopenharmony_ci	loadsegment(es, ctxt->es);
2508c2ecf20Sopenharmony_ci	loadsegment(fs, ctxt->fs);
2518c2ecf20Sopenharmony_ci	load_gs_index(ctxt->gs);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/*
2548c2ecf20Sopenharmony_ci	 * Restore FSBASE and GSBASE after restoring the selectors, since
2558c2ecf20Sopenharmony_ci	 * restoring the selectors clobbers the bases.  Keep in mind
2568c2ecf20Sopenharmony_ci	 * that MSR_KERNEL_GS_BASE is horribly misnamed.
2578c2ecf20Sopenharmony_ci	 */
2588c2ecf20Sopenharmony_ci	wrmsrl(MSR_FS_BASE, ctxt->fs_base);
2598c2ecf20Sopenharmony_ci	wrmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
2608c2ecf20Sopenharmony_ci#elif defined(CONFIG_X86_32_LAZY_GS)
2618c2ecf20Sopenharmony_ci	loadsegment(gs, ctxt->gs);
2628c2ecf20Sopenharmony_ci#endif
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	do_fpu_end();
2658c2ecf20Sopenharmony_ci	tsc_verify_tsc_adjust(true);
2668c2ecf20Sopenharmony_ci	x86_platform.restore_sched_clock_state();
2678c2ecf20Sopenharmony_ci	mtrr_bp_restore();
2688c2ecf20Sopenharmony_ci	perf_restore_debug_store();
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	c = &cpu_data(smp_processor_id());
2718c2ecf20Sopenharmony_ci	if (cpu_has(c, X86_FEATURE_MSR_IA32_FEAT_CTL))
2728c2ecf20Sopenharmony_ci		init_ia32_feat_ctl(c);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	microcode_bsp_resume();
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/*
2778c2ecf20Sopenharmony_ci	 * This needs to happen after the microcode has been updated upon resume
2788c2ecf20Sopenharmony_ci	 * because some of the MSRs are "emulated" in microcode.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	msr_restore_context(ctxt);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* Needed by apm.c */
2848c2ecf20Sopenharmony_civoid notrace restore_processor_state(void)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	__restore_processor_state(&saved_context);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
2898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(restore_processor_state);
2908c2ecf20Sopenharmony_ci#endif
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci#if defined(CONFIG_HIBERNATION) && defined(CONFIG_HOTPLUG_CPU)
2938c2ecf20Sopenharmony_cistatic void resume_play_dead(void)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	play_dead_common();
2968c2ecf20Sopenharmony_ci	tboot_shutdown(TB_SHUTDOWN_WFS);
2978c2ecf20Sopenharmony_ci	hlt_play_dead();
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint hibernate_resume_nonboot_cpu_disable(void)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	void (*play_dead)(void) = smp_ops.play_dead;
3038c2ecf20Sopenharmony_ci	int ret;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	 * Ensure that MONITOR/MWAIT will not be used in the "play dead" loop
3078c2ecf20Sopenharmony_ci	 * during hibernate image restoration, because it is likely that the
3088c2ecf20Sopenharmony_ci	 * monitored address will be actually written to at that time and then
3098c2ecf20Sopenharmony_ci	 * the "dead" CPU will attempt to execute instructions again, but the
3108c2ecf20Sopenharmony_ci	 * address in its instruction pointer may not be possible to resolve
3118c2ecf20Sopenharmony_ci	 * any more at that point (the page tables used by it previously may
3128c2ecf20Sopenharmony_ci	 * have been overwritten by hibernate image data).
3138c2ecf20Sopenharmony_ci	 *
3148c2ecf20Sopenharmony_ci	 * First, make sure that we wake up all the potentially disabled SMT
3158c2ecf20Sopenharmony_ci	 * threads which have been initially brought up and then put into
3168c2ecf20Sopenharmony_ci	 * mwait/cpuidle sleep.
3178c2ecf20Sopenharmony_ci	 * Those will be put to proper (not interfering with hibernation
3188c2ecf20Sopenharmony_ci	 * resume) sleep afterwards, and the resumed kernel will decide itself
3198c2ecf20Sopenharmony_ci	 * what to do with them.
3208c2ecf20Sopenharmony_ci	 */
3218c2ecf20Sopenharmony_ci	ret = cpuhp_smt_enable();
3228c2ecf20Sopenharmony_ci	if (ret)
3238c2ecf20Sopenharmony_ci		return ret;
3248c2ecf20Sopenharmony_ci	smp_ops.play_dead = resume_play_dead;
3258c2ecf20Sopenharmony_ci	ret = freeze_secondary_cpus(0);
3268c2ecf20Sopenharmony_ci	smp_ops.play_dead = play_dead;
3278c2ecf20Sopenharmony_ci	return ret;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci#endif
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/*
3328c2ecf20Sopenharmony_ci * When bsp_check() is called in hibernate and suspend, cpu hotplug
3338c2ecf20Sopenharmony_ci * is disabled already. So it's unnessary to handle race condition between
3348c2ecf20Sopenharmony_ci * cpumask query and cpu hotplug.
3358c2ecf20Sopenharmony_ci */
3368c2ecf20Sopenharmony_cistatic int bsp_check(void)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	if (cpumask_first(cpu_online_mask) != 0) {
3398c2ecf20Sopenharmony_ci		pr_warn("CPU0 is offline.\n");
3408c2ecf20Sopenharmony_ci		return -ENODEV;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return 0;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int bsp_pm_callback(struct notifier_block *nb, unsigned long action,
3478c2ecf20Sopenharmony_ci			   void *ptr)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	int ret = 0;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	switch (action) {
3528c2ecf20Sopenharmony_ci	case PM_SUSPEND_PREPARE:
3538c2ecf20Sopenharmony_ci	case PM_HIBERNATION_PREPARE:
3548c2ecf20Sopenharmony_ci		ret = bsp_check();
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_HOTPLUG_CPU0
3578c2ecf20Sopenharmony_ci	case PM_RESTORE_PREPARE:
3588c2ecf20Sopenharmony_ci		/*
3598c2ecf20Sopenharmony_ci		 * When system resumes from hibernation, online CPU0 because
3608c2ecf20Sopenharmony_ci		 * 1. it's required for resume and
3618c2ecf20Sopenharmony_ci		 * 2. the CPU was online before hibernation
3628c2ecf20Sopenharmony_ci		 */
3638c2ecf20Sopenharmony_ci		if (!cpu_online(0))
3648c2ecf20Sopenharmony_ci			_debug_hotplug_cpu(0, 1);
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case PM_POST_RESTORE:
3678c2ecf20Sopenharmony_ci		/*
3688c2ecf20Sopenharmony_ci		 * When a resume really happens, this code won't be called.
3698c2ecf20Sopenharmony_ci		 *
3708c2ecf20Sopenharmony_ci		 * This code is called only when user space hibernation software
3718c2ecf20Sopenharmony_ci		 * prepares for snapshot device during boot time. So we just
3728c2ecf20Sopenharmony_ci		 * call _debug_hotplug_cpu() to restore to CPU0's state prior to
3738c2ecf20Sopenharmony_ci		 * preparing the snapshot device.
3748c2ecf20Sopenharmony_ci		 *
3758c2ecf20Sopenharmony_ci		 * This works for normal boot case in our CPU0 hotplug debug
3768c2ecf20Sopenharmony_ci		 * mode, i.e. CPU0 is offline and user mode hibernation
3778c2ecf20Sopenharmony_ci		 * software initializes during boot time.
3788c2ecf20Sopenharmony_ci		 *
3798c2ecf20Sopenharmony_ci		 * If CPU0 is online and user application accesses snapshot
3808c2ecf20Sopenharmony_ci		 * device after boot time, this will offline CPU0 and user may
3818c2ecf20Sopenharmony_ci		 * see different CPU0 state before and after accessing
3828c2ecf20Sopenharmony_ci		 * the snapshot device. But hopefully this is not a case when
3838c2ecf20Sopenharmony_ci		 * user debugging CPU0 hotplug. Even if users hit this case,
3848c2ecf20Sopenharmony_ci		 * they can easily online CPU0 back.
3858c2ecf20Sopenharmony_ci		 *
3868c2ecf20Sopenharmony_ci		 * To simplify this debug code, we only consider normal boot
3878c2ecf20Sopenharmony_ci		 * case. Otherwise we need to remember CPU0's state and restore
3888c2ecf20Sopenharmony_ci		 * to that state and resolve racy conditions etc.
3898c2ecf20Sopenharmony_ci		 */
3908c2ecf20Sopenharmony_ci		_debug_hotplug_cpu(0, 0);
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci#endif
3938c2ecf20Sopenharmony_ci	default:
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci	return notifier_from_errno(ret);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int __init bsp_pm_check_init(void)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	/*
4028c2ecf20Sopenharmony_ci	 * Set this bsp_pm_callback as lower priority than
4038c2ecf20Sopenharmony_ci	 * cpu_hotplug_pm_callback. So cpu_hotplug_pm_callback will be called
4048c2ecf20Sopenharmony_ci	 * earlier to disable cpu hotplug before bsp online check.
4058c2ecf20Sopenharmony_ci	 */
4068c2ecf20Sopenharmony_ci	pm_notifier(bsp_pm_callback, -INT_MAX);
4078c2ecf20Sopenharmony_ci	return 0;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cicore_initcall(bsp_pm_check_init);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int msr_build_context(const u32 *msr_id, const int num)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
4158c2ecf20Sopenharmony_ci	struct saved_msr *msr_array;
4168c2ecf20Sopenharmony_ci	int total_num;
4178c2ecf20Sopenharmony_ci	int i, j;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	total_num = saved_msrs->num + num;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
4228c2ecf20Sopenharmony_ci	if (!msr_array) {
4238c2ecf20Sopenharmony_ci		pr_err("x86/pm: Can not allocate memory to save/restore MSRs during suspend.\n");
4248c2ecf20Sopenharmony_ci		return -ENOMEM;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (saved_msrs->array) {
4288c2ecf20Sopenharmony_ci		/*
4298c2ecf20Sopenharmony_ci		 * Multiple callbacks can invoke this function, so copy any
4308c2ecf20Sopenharmony_ci		 * MSR save requests from previous invocations.
4318c2ecf20Sopenharmony_ci		 */
4328c2ecf20Sopenharmony_ci		memcpy(msr_array, saved_msrs->array,
4338c2ecf20Sopenharmony_ci		       sizeof(struct saved_msr) * saved_msrs->num);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		kfree(saved_msrs->array);
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
4398c2ecf20Sopenharmony_ci		u64 dummy;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		msr_array[i].info.msr_no	= msr_id[j];
4428c2ecf20Sopenharmony_ci		msr_array[i].valid		= !rdmsrl_safe(msr_id[j], &dummy);
4438c2ecf20Sopenharmony_ci		msr_array[i].info.reg.q		= 0;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	saved_msrs->num   = total_num;
4468c2ecf20Sopenharmony_ci	saved_msrs->array = msr_array;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	return 0;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci/*
4528c2ecf20Sopenharmony_ci * The following sections are a quirk framework for problematic BIOSen:
4538c2ecf20Sopenharmony_ci * Sometimes MSRs are modified by the BIOSen after suspended to
4548c2ecf20Sopenharmony_ci * RAM, this might cause unexpected behavior after wakeup.
4558c2ecf20Sopenharmony_ci * Thus we save/restore these specified MSRs across suspend/resume
4568c2ecf20Sopenharmony_ci * in order to work around it.
4578c2ecf20Sopenharmony_ci *
4588c2ecf20Sopenharmony_ci * For any further problematic BIOSen/platforms,
4598c2ecf20Sopenharmony_ci * please add your own function similar to msr_initialize_bdw.
4608c2ecf20Sopenharmony_ci */
4618c2ecf20Sopenharmony_cistatic int msr_initialize_bdw(const struct dmi_system_id *d)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	/* Add any extra MSR ids into this array. */
4648c2ecf20Sopenharmony_ci	u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
4678c2ecf20Sopenharmony_ci	return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic const struct dmi_system_id msr_save_dmi_table[] = {
4718c2ecf20Sopenharmony_ci	{
4728c2ecf20Sopenharmony_ci	 .callback = msr_initialize_bdw,
4738c2ecf20Sopenharmony_ci	 .ident = "BROADWELL BDX_EP",
4748c2ecf20Sopenharmony_ci	 .matches = {
4758c2ecf20Sopenharmony_ci		DMI_MATCH(DMI_PRODUCT_NAME, "GRANTLEY"),
4768c2ecf20Sopenharmony_ci		DMI_MATCH(DMI_PRODUCT_VERSION, "E63448-400"),
4778c2ecf20Sopenharmony_ci		},
4788c2ecf20Sopenharmony_ci	},
4798c2ecf20Sopenharmony_ci	{}
4808c2ecf20Sopenharmony_ci};
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic int msr_save_cpuid_features(const struct x86_cpu_id *c)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	u32 cpuid_msr_id[] = {
4858c2ecf20Sopenharmony_ci		MSR_AMD64_CPUID_FN_1,
4868c2ecf20Sopenharmony_ci	};
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
4898c2ecf20Sopenharmony_ci		c->family);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic const struct x86_cpu_id msr_save_cpu_table[] = {
4958c2ecf20Sopenharmony_ci	X86_MATCH_VENDOR_FAM(AMD, 0x15, &msr_save_cpuid_features),
4968c2ecf20Sopenharmony_ci	X86_MATCH_VENDOR_FAM(AMD, 0x16, &msr_save_cpuid_features),
4978c2ecf20Sopenharmony_ci	{}
4988c2ecf20Sopenharmony_ci};
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_citypedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);
5018c2ecf20Sopenharmony_cistatic int pm_cpu_check(const struct x86_cpu_id *c)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	const struct x86_cpu_id *m;
5048c2ecf20Sopenharmony_ci	int ret = 0;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	m = x86_match_cpu(msr_save_cpu_table);
5078c2ecf20Sopenharmony_ci	if (m) {
5088c2ecf20Sopenharmony_ci		pm_cpu_match_t fn;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		fn = (pm_cpu_match_t)m->driver_data;
5118c2ecf20Sopenharmony_ci		ret = fn(m);
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return ret;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic void pm_save_spec_msr(void)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct msr_enumeration {
5208c2ecf20Sopenharmony_ci		u32 msr_no;
5218c2ecf20Sopenharmony_ci		u32 feature;
5228c2ecf20Sopenharmony_ci	} msr_enum[] = {
5238c2ecf20Sopenharmony_ci		{ MSR_IA32_SPEC_CTRL,	 X86_FEATURE_MSR_SPEC_CTRL },
5248c2ecf20Sopenharmony_ci		{ MSR_IA32_TSX_CTRL,	 X86_FEATURE_MSR_TSX_CTRL },
5258c2ecf20Sopenharmony_ci		{ MSR_TSX_FORCE_ABORT,	 X86_FEATURE_TSX_FORCE_ABORT },
5268c2ecf20Sopenharmony_ci		{ MSR_IA32_MCU_OPT_CTRL, X86_FEATURE_SRBDS_CTRL },
5278c2ecf20Sopenharmony_ci		{ MSR_AMD64_LS_CFG,	 X86_FEATURE_LS_CFG_SSBD },
5288c2ecf20Sopenharmony_ci		{ MSR_AMD64_DE_CFG,	 X86_FEATURE_LFENCE_RDTSC },
5298c2ecf20Sopenharmony_ci	};
5308c2ecf20Sopenharmony_ci	int i;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(msr_enum); i++) {
5338c2ecf20Sopenharmony_ci		if (boot_cpu_has(msr_enum[i].feature))
5348c2ecf20Sopenharmony_ci			msr_build_context(&msr_enum[i].msr_no, 1);
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic int pm_check_save_msr(void)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	dmi_check_system(msr_save_dmi_table);
5418c2ecf20Sopenharmony_ci	pm_cpu_check(msr_save_cpu_table);
5428c2ecf20Sopenharmony_ci	pm_save_spec_msr();
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	return 0;
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cidevice_initcall(pm_check_save_msr);
548