162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/types.h>
362306a36Sopenharmony_ci#include <linux/tick.h>
462306a36Sopenharmony_ci#include <linux/percpu-defs.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <xen/xen.h>
762306a36Sopenharmony_ci#include <xen/interface/xen.h>
862306a36Sopenharmony_ci#include <xen/grant_table.h>
962306a36Sopenharmony_ci#include <xen/events.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/cpufeatures.h>
1262306a36Sopenharmony_ci#include <asm/msr-index.h>
1362306a36Sopenharmony_ci#include <asm/xen/hypercall.h>
1462306a36Sopenharmony_ci#include <asm/xen/page.h>
1562306a36Sopenharmony_ci#include <asm/fixmap.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "xen-ops.h"
1862306a36Sopenharmony_ci#include "mmu.h"
1962306a36Sopenharmony_ci#include "pmu.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic DEFINE_PER_CPU(u64, spec_ctrl);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid xen_arch_pre_suspend(void)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	xen_save_time_memory_area();
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (xen_pv_domain())
2862306a36Sopenharmony_ci		xen_pv_pre_suspend();
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_civoid xen_arch_post_suspend(int cancelled)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	if (xen_pv_domain())
3462306a36Sopenharmony_ci		xen_pv_post_suspend(cancelled);
3562306a36Sopenharmony_ci	else
3662306a36Sopenharmony_ci		xen_hvm_post_suspend(cancelled);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	xen_restore_time_memory_area();
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void xen_vcpu_notify_restore(void *data)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL))
4462306a36Sopenharmony_ci		wrmsrl(MSR_IA32_SPEC_CTRL, this_cpu_read(spec_ctrl));
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* Boot processor notified via generic timekeeping_resume() */
4762306a36Sopenharmony_ci	if (smp_processor_id() == 0)
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	tick_resume_local();
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void xen_vcpu_notify_suspend(void *data)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	u64 tmp;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	tick_suspend_local();
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) {
6062306a36Sopenharmony_ci		rdmsrl(MSR_IA32_SPEC_CTRL, tmp);
6162306a36Sopenharmony_ci		this_cpu_write(spec_ctrl, tmp);
6262306a36Sopenharmony_ci		wrmsrl(MSR_IA32_SPEC_CTRL, 0);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_civoid xen_arch_resume(void)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	int cpu;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	on_each_cpu(xen_vcpu_notify_restore, NULL, 1);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	for_each_online_cpu(cpu)
7362306a36Sopenharmony_ci		xen_pmu_init(cpu);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid xen_arch_suspend(void)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	int cpu;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for_each_online_cpu(cpu)
8162306a36Sopenharmony_ci		xen_pmu_finish(cpu);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
8462306a36Sopenharmony_ci}
85