Merge tag 'for-linus-4.8-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen updates from David Vrabel: "Features and fixes for 4.8-rc0: - ACPI support for guests on ARM platforms. - Generic steal time support for arm and x86. - Support cases where kernel cpu is not Xen VCPU number (e.g., if in-guest kexec is used). - Use the system workqueue instead of a custom workqueue in various places" * tag 'for-linus-4.8-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (47 commits) xen: add static initialization of steal_clock op to xen_time_ops xen/pvhvm: run xen_vcpu_setup() for the boot CPU xen/evtchn: use xen_vcpu_id mapping xen/events: fifo: use xen_vcpu_id mapping xen/events: use xen_vcpu_id mapping in events_base x86/xen: use xen_vcpu_id mapping when pointing vcpu_info to shared_info x86/xen: use xen_vcpu_id mapping for HYPERVISOR_vcpu_op xen: introduce xen_vcpu_id mapping x86/acpi: store ACPI ids from MADT for future usage x86/xen: update cpuid.h from Xen-4.7 xen/evtchn: add IOCTL_EVTCHN_RESTRICT xen-blkback: really don't leak mode property xen-blkback: constify instance of "struct attribute_group" xen-blkfront: prefer xenbus_scanf() over xenbus_gather() xen-blkback: prefer xenbus_scanf() over xenbus_gather() xen: support runqueue steal time on xen arm/xen: add support for vm_assist hypercall xen: update xen headers xen-pciback: drop superfluous variables xen-pciback: short-circuit read path used for merging write values ...
This commit is contained in:
@@ -20,10 +20,121 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
#include <xen/xen-ops.h>
|
||||
#include <xen/interface/platform.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
|
||||
static efi_char16_t vendor[100] __initdata;
|
||||
|
||||
static efi_system_table_t efi_systab_xen __initdata = {
|
||||
.hdr = {
|
||||
.signature = EFI_SYSTEM_TABLE_SIGNATURE,
|
||||
.revision = 0, /* Initialized later. */
|
||||
.headersize = 0, /* Ignored by Linux Kernel. */
|
||||
.crc32 = 0, /* Ignored by Linux Kernel. */
|
||||
.reserved = 0
|
||||
},
|
||||
.fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */
|
||||
.fw_revision = 0, /* Initialized later. */
|
||||
.con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_out = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.stderr = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.runtime = (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR,
|
||||
/* Not used under Xen. */
|
||||
.boottime = (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR,
|
||||
/* Not used under Xen. */
|
||||
.nr_tables = 0, /* Initialized later. */
|
||||
.tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */
|
||||
};
|
||||
|
||||
static const struct efi efi_xen __initconst = {
|
||||
.systab = NULL, /* Initialized later. */
|
||||
.runtime_version = 0, /* Initialized later. */
|
||||
.mps = EFI_INVALID_TABLE_ADDR,
|
||||
.acpi = EFI_INVALID_TABLE_ADDR,
|
||||
.acpi20 = EFI_INVALID_TABLE_ADDR,
|
||||
.smbios = EFI_INVALID_TABLE_ADDR,
|
||||
.smbios3 = EFI_INVALID_TABLE_ADDR,
|
||||
.sal_systab = EFI_INVALID_TABLE_ADDR,
|
||||
.boot_info = EFI_INVALID_TABLE_ADDR,
|
||||
.hcdp = EFI_INVALID_TABLE_ADDR,
|
||||
.uga = EFI_INVALID_TABLE_ADDR,
|
||||
.uv_systab = EFI_INVALID_TABLE_ADDR,
|
||||
.fw_vendor = EFI_INVALID_TABLE_ADDR,
|
||||
.runtime = EFI_INVALID_TABLE_ADDR,
|
||||
.config_table = EFI_INVALID_TABLE_ADDR,
|
||||
.get_time = xen_efi_get_time,
|
||||
.set_time = xen_efi_set_time,
|
||||
.get_wakeup_time = xen_efi_get_wakeup_time,
|
||||
.set_wakeup_time = xen_efi_set_wakeup_time,
|
||||
.get_variable = xen_efi_get_variable,
|
||||
.get_next_variable = xen_efi_get_next_variable,
|
||||
.set_variable = xen_efi_set_variable,
|
||||
.query_variable_info = xen_efi_query_variable_info,
|
||||
.update_capsule = xen_efi_update_capsule,
|
||||
.query_capsule_caps = xen_efi_query_capsule_caps,
|
||||
.get_next_high_mono_count = xen_efi_get_next_high_mono_count,
|
||||
.reset_system = NULL, /* Functionality provided by Xen. */
|
||||
.set_virtual_address_map = NULL, /* Not used under Xen. */
|
||||
.flags = 0 /* Initialized later. */
|
||||
};
|
||||
|
||||
static efi_system_table_t __init *xen_efi_probe(void)
|
||||
{
|
||||
struct xen_platform_op op = {
|
||||
.cmd = XENPF_firmware_info,
|
||||
.u.firmware_info = {
|
||||
.type = XEN_FW_EFI_INFO,
|
||||
.index = XEN_FW_EFI_CONFIG_TABLE
|
||||
}
|
||||
};
|
||||
union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
|
||||
|
||||
if (!xen_initial_domain() || HYPERVISOR_platform_op(&op) < 0)
|
||||
return NULL;
|
||||
|
||||
/* Here we know that Xen runs on EFI platform. */
|
||||
|
||||
efi = efi_xen;
|
||||
|
||||
efi_systab_xen.tables = info->cfg.addr;
|
||||
efi_systab_xen.nr_tables = info->cfg.nent;
|
||||
|
||||
op.cmd = XENPF_firmware_info;
|
||||
op.u.firmware_info.type = XEN_FW_EFI_INFO;
|
||||
op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
|
||||
info->vendor.bufsz = sizeof(vendor);
|
||||
set_xen_guest_handle(info->vendor.name, vendor);
|
||||
|
||||
if (HYPERVISOR_platform_op(&op) == 0) {
|
||||
efi_systab_xen.fw_vendor = __pa_symbol(vendor);
|
||||
efi_systab_xen.fw_revision = info->vendor.revision;
|
||||
} else
|
||||
efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN");
|
||||
|
||||
op.cmd = XENPF_firmware_info;
|
||||
op.u.firmware_info.type = XEN_FW_EFI_INFO;
|
||||
op.u.firmware_info.index = XEN_FW_EFI_VERSION;
|
||||
|
||||
if (HYPERVISOR_platform_op(&op) == 0)
|
||||
efi_systab_xen.hdr.revision = info->version;
|
||||
|
||||
op.cmd = XENPF_firmware_info;
|
||||
op.u.firmware_info.type = XEN_FW_EFI_INFO;
|
||||
op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
|
||||
|
||||
if (HYPERVISOR_platform_op(&op) == 0)
|
||||
efi.runtime_version = info->version;
|
||||
|
||||
return &efi_systab_xen;
|
||||
}
|
||||
|
||||
void __init xen_efi_init(void)
|
||||
{
|
||||
|
@@ -59,6 +59,7 @@
|
||||
#include <asm/xen/pci.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
#include <asm/xen/cpuid.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/proto.h>
|
||||
@@ -118,6 +119,10 @@ DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
|
||||
*/
|
||||
DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
|
||||
|
||||
/* Linux <-> Xen vCPU id mapping */
|
||||
DEFINE_PER_CPU(int, xen_vcpu_id) = -1;
|
||||
EXPORT_PER_CPU_SYMBOL(xen_vcpu_id);
|
||||
|
||||
enum xen_domain_type xen_domain_type = XEN_NATIVE;
|
||||
EXPORT_SYMBOL_GPL(xen_domain_type);
|
||||
|
||||
@@ -179,7 +184,7 @@ static void clamp_max_cpus(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void xen_vcpu_setup(int cpu)
|
||||
void xen_vcpu_setup(int cpu)
|
||||
{
|
||||
struct vcpu_register_vcpu_info info;
|
||||
int err;
|
||||
@@ -202,8 +207,9 @@ static void xen_vcpu_setup(int cpu)
|
||||
if (per_cpu(xen_vcpu, cpu) == &per_cpu(xen_vcpu_info, cpu))
|
||||
return;
|
||||
}
|
||||
if (cpu < MAX_VIRT_CPUS)
|
||||
per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
|
||||
if (xen_vcpu_nr(cpu) < MAX_VIRT_CPUS)
|
||||
per_cpu(xen_vcpu, cpu) =
|
||||
&HYPERVISOR_shared_info->vcpu_info[xen_vcpu_nr(cpu)];
|
||||
|
||||
if (!have_vcpu_info_placement) {
|
||||
if (cpu >= MAX_VIRT_CPUS)
|
||||
@@ -223,7 +229,8 @@ static void xen_vcpu_setup(int cpu)
|
||||
hypervisor has no unregister variant and this hypercall does not
|
||||
allow to over-write info.mfn and info.offset.
|
||||
*/
|
||||
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
|
||||
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu),
|
||||
&info);
|
||||
|
||||
if (err) {
|
||||
printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
|
||||
@@ -247,10 +254,11 @@ void xen_vcpu_restore(void)
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
bool other_cpu = (cpu != smp_processor_id());
|
||||
bool is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL);
|
||||
bool is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, xen_vcpu_nr(cpu),
|
||||
NULL);
|
||||
|
||||
if (other_cpu && is_up &&
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(cpu), NULL))
|
||||
BUG();
|
||||
|
||||
xen_setup_runstate_info(cpu);
|
||||
@@ -259,7 +267,7 @@ void xen_vcpu_restore(void)
|
||||
xen_vcpu_setup(cpu);
|
||||
|
||||
if (other_cpu && is_up &&
|
||||
HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
|
||||
HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL))
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
@@ -588,7 +596,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
|
||||
{
|
||||
unsigned long va = dtr->address;
|
||||
unsigned int size = dtr->size + 1;
|
||||
unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
unsigned pages = DIV_ROUND_UP(size, PAGE_SIZE);
|
||||
unsigned long frames[pages];
|
||||
int f;
|
||||
|
||||
@@ -637,7 +645,7 @@ static void __init xen_load_gdt_boot(const struct desc_ptr *dtr)
|
||||
{
|
||||
unsigned long va = dtr->address;
|
||||
unsigned int size = dtr->size + 1;
|
||||
unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
unsigned pages = DIV_ROUND_UP(size, PAGE_SIZE);
|
||||
unsigned long frames[pages];
|
||||
int f;
|
||||
|
||||
@@ -1135,8 +1143,11 @@ void xen_setup_vcpu_info_placement(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
for_each_possible_cpu(cpu) {
|
||||
/* Set up direct vCPU id mapping for PV guests. */
|
||||
per_cpu(xen_vcpu_id, cpu) = cpu;
|
||||
xen_vcpu_setup(cpu);
|
||||
}
|
||||
|
||||
/* xen_vcpu_setup managed to place the vcpu_info within the
|
||||
* percpu area for all cpus, so make use of it. Note that for
|
||||
@@ -1727,6 +1738,9 @@ asmlinkage __visible void __init xen_start_kernel(void)
|
||||
#endif
|
||||
xen_raw_console_write("about to get started...\n");
|
||||
|
||||
/* Let's presume PV guests always boot on vCPU with id 0. */
|
||||
per_cpu(xen_vcpu_id, 0) = 0;
|
||||
|
||||
xen_setup_runstate_info(0);
|
||||
|
||||
xen_efi_init();
|
||||
@@ -1768,9 +1782,10 @@ void __ref xen_hvm_init_shared_info(void)
|
||||
* in that case multiple vcpus might be online. */
|
||||
for_each_online_cpu(cpu) {
|
||||
/* Leave it to be NULL. */
|
||||
if (cpu >= MAX_VIRT_CPUS)
|
||||
if (xen_vcpu_nr(cpu) >= MAX_VIRT_CPUS)
|
||||
continue;
|
||||
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
|
||||
per_cpu(xen_vcpu, cpu) =
|
||||
&HYPERVISOR_shared_info->vcpu_info[xen_vcpu_nr(cpu)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1795,6 +1810,12 @@ static void __init init_hvm_pv_info(void)
|
||||
|
||||
xen_setup_features();
|
||||
|
||||
cpuid(base + 4, &eax, &ebx, &ecx, &edx);
|
||||
if (eax & XEN_HVM_CPUID_VCPU_ID_PRESENT)
|
||||
this_cpu_write(xen_vcpu_id, ebx);
|
||||
else
|
||||
this_cpu_write(xen_vcpu_id, smp_processor_id());
|
||||
|
||||
pv_info.name = "Xen HVM";
|
||||
|
||||
xen_domain_type = XEN_HVM_DOMAIN;
|
||||
@@ -1806,6 +1827,10 @@ static int xen_hvm_cpu_notify(struct notifier_block *self, unsigned long action,
|
||||
int cpu = (long)hcpu;
|
||||
switch (action) {
|
||||
case CPU_UP_PREPARE:
|
||||
if (cpu_acpi_id(cpu) != U32_MAX)
|
||||
per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
|
||||
else
|
||||
per_cpu(xen_vcpu_id, cpu) = cpu;
|
||||
xen_vcpu_setup(cpu);
|
||||
if (xen_have_vector_callback) {
|
||||
if (xen_feature(XENFEAT_hvm_safe_pvclock))
|
||||
|
@@ -111,63 +111,18 @@ int arch_gnttab_init(unsigned long nr_shared)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_PVH
|
||||
#include <xen/balloon.h>
|
||||
#include <xen/events.h>
|
||||
#include <linux/slab.h>
|
||||
static int __init xlated_setup_gnttab_pages(void)
|
||||
{
|
||||
struct page **pages;
|
||||
xen_pfn_t *pfns;
|
||||
void *vaddr;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
unsigned long nr_grant_frames = gnttab_max_grant_frames();
|
||||
|
||||
BUG_ON(nr_grant_frames == 0);
|
||||
pages = kcalloc(nr_grant_frames, sizeof(pages[0]), GFP_KERNEL);
|
||||
if (!pages)
|
||||
return -ENOMEM;
|
||||
|
||||
pfns = kcalloc(nr_grant_frames, sizeof(pfns[0]), GFP_KERNEL);
|
||||
if (!pfns) {
|
||||
kfree(pages);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rc = alloc_xenballooned_pages(nr_grant_frames, pages);
|
||||
if (rc) {
|
||||
pr_warn("%s Couldn't balloon alloc %ld pfns rc:%d\n", __func__,
|
||||
nr_grant_frames, rc);
|
||||
kfree(pages);
|
||||
kfree(pfns);
|
||||
return rc;
|
||||
}
|
||||
for (i = 0; i < nr_grant_frames; i++)
|
||||
pfns[i] = page_to_pfn(pages[i]);
|
||||
|
||||
vaddr = vmap(pages, nr_grant_frames, 0, PAGE_KERNEL);
|
||||
if (!vaddr) {
|
||||
pr_warn("%s Couldn't map %ld pfns rc:%d\n", __func__,
|
||||
nr_grant_frames, rc);
|
||||
free_xenballooned_pages(nr_grant_frames, pages);
|
||||
kfree(pages);
|
||||
kfree(pfns);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kfree(pages);
|
||||
|
||||
xen_auto_xlat_grant_frames.pfn = pfns;
|
||||
xen_auto_xlat_grant_frames.count = nr_grant_frames;
|
||||
xen_auto_xlat_grant_frames.vaddr = vaddr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <xen/xen-ops.h>
|
||||
static int __init xen_pvh_gnttab_setup(void)
|
||||
{
|
||||
if (!xen_pvh_domain())
|
||||
return -ENODEV;
|
||||
|
||||
return xlated_setup_gnttab_pages();
|
||||
xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames();
|
||||
|
||||
return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn,
|
||||
&xen_auto_xlat_grant_frames.vaddr,
|
||||
xen_auto_xlat_grant_frames.count);
|
||||
}
|
||||
/* Call it _before_ __gnttab_init as we need to initialize the
|
||||
* xen_auto_xlat_grant_frames first. */
|
||||
|
@@ -109,7 +109,8 @@ static void xen_safe_halt(void)
|
||||
static void xen_halt(void)
|
||||
{
|
||||
if (irqs_disabled())
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down,
|
||||
xen_vcpu_nr(smp_processor_id()), NULL);
|
||||
else
|
||||
xen_safe_halt();
|
||||
}
|
||||
|
@@ -547,7 +547,7 @@ void xen_pmu_init(int cpu)
|
||||
return;
|
||||
|
||||
fail:
|
||||
pr_warn_once("Could not initialize VPMU for cpu %d, error %d\n",
|
||||
pr_info_once("Could not initialize VPMU for cpu %d, error %d\n",
|
||||
cpu, err);
|
||||
free_pages((unsigned long)xenpmu_data, 0);
|
||||
}
|
||||
|
@@ -322,6 +322,13 @@ static void __init xen_smp_prepare_boot_cpu(void)
|
||||
xen_filter_cpu_maps();
|
||||
xen_setup_vcpu_info_placement();
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup vcpu_info for boot CPU.
|
||||
*/
|
||||
if (xen_hvm_domain())
|
||||
xen_vcpu_setup(0);
|
||||
|
||||
/*
|
||||
* The alternative logic (which patches the unlock/lock) runs before
|
||||
* the smp bootup up code is activated. Hence we need to set this up
|
||||
@@ -454,7 +461,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
|
||||
#endif
|
||||
ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
|
||||
ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(swapper_pg_dir));
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_initialise, xen_vcpu_nr(cpu), ctxt))
|
||||
BUG();
|
||||
|
||||
kfree(ctxt);
|
||||
@@ -492,7 +499,7 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
|
||||
rc = HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL);
|
||||
BUG_ON(rc);
|
||||
|
||||
while (cpu_report_state(cpu) != CPU_ONLINE)
|
||||
@@ -520,7 +527,8 @@ static int xen_cpu_disable(void)
|
||||
|
||||
static void xen_cpu_die(unsigned int cpu)
|
||||
{
|
||||
while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
|
||||
while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up,
|
||||
xen_vcpu_nr(cpu), NULL)) {
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(HZ/10);
|
||||
}
|
||||
@@ -536,7 +544,7 @@ static void xen_cpu_die(unsigned int cpu)
|
||||
static void xen_play_dead(void) /* used only with HOTPLUG_CPU */
|
||||
{
|
||||
play_dead_common();
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(smp_processor_id()), NULL);
|
||||
cpu_bringup();
|
||||
/*
|
||||
* commit 4b0c0f294 (tick: Cleanup NOHZ per cpu data on cpu down)
|
||||
@@ -576,7 +584,7 @@ static void stop_self(void *v)
|
||||
|
||||
set_cpu_online(cpu, false);
|
||||
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
|
||||
HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(cpu), NULL);
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
@@ -11,8 +11,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pvclock_gtod.h>
|
||||
@@ -31,44 +29,6 @@
|
||||
|
||||
/* Xen may fire a timer up to this many ns early */
|
||||
#define TIMER_SLOP 100000
|
||||
#define NS_PER_TICK (1000000000LL / HZ)
|
||||
|
||||
/* snapshots of runstate info */
|
||||
static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
|
||||
|
||||
/* unused ns of stolen time */
|
||||
static DEFINE_PER_CPU(u64, xen_residual_stolen);
|
||||
|
||||
static void do_stolen_accounting(void)
|
||||
{
|
||||
struct vcpu_runstate_info state;
|
||||
struct vcpu_runstate_info *snap;
|
||||
s64 runnable, offline, stolen;
|
||||
cputime_t ticks;
|
||||
|
||||
xen_get_runstate_snapshot(&state);
|
||||
|
||||
WARN_ON(state.state != RUNSTATE_running);
|
||||
|
||||
snap = this_cpu_ptr(&xen_runstate_snapshot);
|
||||
|
||||
/* work out how much time the VCPU has not been runn*ing* */
|
||||
runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
|
||||
offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
|
||||
|
||||
*snap = state;
|
||||
|
||||
/* Add the appropriate number of ticks of stolen time,
|
||||
including any left-overs from last time. */
|
||||
stolen = runnable + offline + __this_cpu_read(xen_residual_stolen);
|
||||
|
||||
if (stolen < 0)
|
||||
stolen = 0;
|
||||
|
||||
ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
|
||||
__this_cpu_write(xen_residual_stolen, stolen);
|
||||
account_steal_ticks(ticks);
|
||||
}
|
||||
|
||||
/* Get the TSC speed from Xen */
|
||||
static unsigned long xen_tsc_khz(void)
|
||||
@@ -263,8 +223,10 @@ static int xen_vcpuop_shutdown(struct clock_event_device *evt)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
|
||||
HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, xen_vcpu_nr(cpu),
|
||||
NULL) ||
|
||||
HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, xen_vcpu_nr(cpu),
|
||||
NULL))
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
@@ -274,7 +236,8 @@ static int xen_vcpuop_set_oneshot(struct clock_event_device *evt)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, xen_vcpu_nr(cpu),
|
||||
NULL))
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
@@ -293,7 +256,8 @@ static int xen_vcpuop_set_next_event(unsigned long delta,
|
||||
/* Get an event anyway, even if the timeout is already expired */
|
||||
single.flags = 0;
|
||||
|
||||
ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
|
||||
ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, xen_vcpu_nr(cpu),
|
||||
&single);
|
||||
BUG_ON(ret != 0);
|
||||
|
||||
return ret;
|
||||
@@ -335,8 +299,6 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
do_stolen_accounting();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -394,13 +356,15 @@ void xen_timer_resume(void)
|
||||
return;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer,
|
||||
xen_vcpu_nr(cpu), NULL))
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pv_time_ops xen_time_ops __initconst = {
|
||||
.sched_clock = xen_clocksource_read,
|
||||
.steal_clock = xen_steal_clock,
|
||||
};
|
||||
|
||||
static void __init xen_time_init(void)
|
||||
@@ -414,7 +378,8 @@ static void __init xen_time_init(void)
|
||||
|
||||
clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
|
||||
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
|
||||
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, xen_vcpu_nr(cpu),
|
||||
NULL) == 0) {
|
||||
/* Successfully turned off 100Hz tick, so we have the
|
||||
vcpuop-based timer interface */
|
||||
printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
|
||||
@@ -431,6 +396,8 @@ static void __init xen_time_init(void)
|
||||
xen_setup_timer(cpu);
|
||||
xen_setup_cpu_clockevents();
|
||||
|
||||
xen_time_setup_guest();
|
||||
|
||||
if (xen_initial_domain())
|
||||
pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
|
||||
}
|
||||
|
@@ -76,6 +76,7 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
|
||||
|
||||
bool xen_vcpu_stolen(int vcpu);
|
||||
|
||||
void xen_vcpu_setup(int cpu);
|
||||
void xen_setup_vcpu_info_placement(void);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
Reference in New Issue
Block a user