forked from Minki/linux
65d0cf0be7
Map shared data structure that will hold CPU registers, VPMU context, V/PCPU IDs of the CPU interrupted by PMU interrupt. Hypervisor fills this information in its handler and passes it to the guest for further processing. Set up PMU VIRQ. Now that perf infrastructure will assume that PMU is available on a PV guest we need to be careful and make sure that accesses via RDPMC instruction don't cause fatal traps by the hypervisor. Provide a nop RDPMC handler. For the same reason avoid issuing a warning on a write to APIC's LVTPC. Both of these will be made functional in later patches. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Reviewed-by: David Vrabel <david.vrabel@citrix.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
116 lines
2.2 KiB
C
116 lines
2.2 KiB
C
#include <linux/types.h>
|
|
#include <linux/tick.h>
|
|
|
|
#include <xen/interface/xen.h>
|
|
#include <xen/grant_table.h>
|
|
#include <xen/events.h>
|
|
|
|
#include <asm/xen/hypercall.h>
|
|
#include <asm/xen/page.h>
|
|
#include <asm/fixmap.h>
|
|
|
|
#include "xen-ops.h"
|
|
#include "mmu.h"
|
|
#include "pmu.h"
|
|
|
|
static void xen_pv_pre_suspend(void)
|
|
{
|
|
xen_mm_pin_all();
|
|
|
|
xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
|
|
xen_start_info->console.domU.mfn =
|
|
mfn_to_pfn(xen_start_info->console.domU.mfn);
|
|
|
|
BUG_ON(!irqs_disabled());
|
|
|
|
HYPERVISOR_shared_info = &xen_dummy_shared_info;
|
|
if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
|
|
__pte_ma(0), 0))
|
|
BUG();
|
|
}
|
|
|
|
static void xen_hvm_post_suspend(int suspend_cancelled)
|
|
{
|
|
#ifdef CONFIG_XEN_PVHVM
|
|
int cpu;
|
|
xen_hvm_init_shared_info();
|
|
xen_callback_vector();
|
|
xen_unplug_emulated_devices();
|
|
if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
|
|
for_each_online_cpu(cpu) {
|
|
xen_setup_runstate_info(cpu);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void xen_pv_post_suspend(int suspend_cancelled)
|
|
{
|
|
xen_build_mfn_list_list();
|
|
|
|
xen_setup_shared_info();
|
|
|
|
if (suspend_cancelled) {
|
|
xen_start_info->store_mfn =
|
|
pfn_to_mfn(xen_start_info->store_mfn);
|
|
xen_start_info->console.domU.mfn =
|
|
pfn_to_mfn(xen_start_info->console.domU.mfn);
|
|
} else {
|
|
#ifdef CONFIG_SMP
|
|
BUG_ON(xen_cpu_initialized_map == NULL);
|
|
cpumask_copy(xen_cpu_initialized_map, cpu_online_mask);
|
|
#endif
|
|
xen_vcpu_restore();
|
|
}
|
|
|
|
xen_mm_unpin_all();
|
|
}
|
|
|
|
void xen_arch_pre_suspend(void)
|
|
{
|
|
int cpu;
|
|
|
|
for_each_online_cpu(cpu)
|
|
xen_pmu_finish(cpu);
|
|
|
|
if (xen_pv_domain())
|
|
xen_pv_pre_suspend();
|
|
}
|
|
|
|
void xen_arch_post_suspend(int cancelled)
|
|
{
|
|
int cpu;
|
|
|
|
if (xen_pv_domain())
|
|
xen_pv_post_suspend(cancelled);
|
|
else
|
|
xen_hvm_post_suspend(cancelled);
|
|
|
|
for_each_online_cpu(cpu)
|
|
xen_pmu_init(cpu);
|
|
}
|
|
|
|
static void xen_vcpu_notify_restore(void *data)
|
|
{
|
|
/* Boot processor notified via generic timekeeping_resume() */
|
|
if (smp_processor_id() == 0)
|
|
return;
|
|
|
|
tick_resume_local();
|
|
}
|
|
|
|
static void xen_vcpu_notify_suspend(void *data)
|
|
{
|
|
tick_suspend_local();
|
|
}
|
|
|
|
void xen_arch_resume(void)
|
|
{
|
|
on_each_cpu(xen_vcpu_notify_restore, NULL, 1);
|
|
}
|
|
|
|
void xen_arch_suspend(void)
|
|
{
|
|
on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
|
|
}
|