diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 34ef016626ff401211964897e5c75ec9f012583b..aa71a2321040ab2995acb134d0cf686c3a546345 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1794,6 +1794,7 @@ config XEN depends on ARM && AEABI && OF depends on CPU_V7 && !CPU_V6 depends on !GENERIC_ATOMIC64 + select ARM_PSCI help Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8562af4fe8fd46e4639c275120ce09129efac733..b9f7121e6ecf02c561e5b1b10308659aad23fb28 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -200,8 +200,8 @@ dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ vexpress-v2p-ca9.dtb \ vexpress-v2p-ca15-tc1.dtb \ - vexpress-v2p-ca15_a7.dtb \ - xenvm-4.2.dtb + vexpress-v2p-ca15_a7.dtb +dtb-$(CONFIG_ARCH_VIRT) += xenvm-4.2.dtb dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ wm8505-ref.dtb \ wm8650-mid.dtb \ diff --git a/arch/arm/boot/dts/xenvm-4.2.dts b/arch/arm/boot/dts/xenvm-4.2.dts index ec3f9528e180c75e42b633104fb537ced0762691..336915151398d81a44d8f1521cf844ade6961237 100644 --- a/arch/arm/boot/dts/xenvm-4.2.dts +++ b/arch/arm/boot/dts/xenvm-4.2.dts @@ -29,6 +29,19 @@ compatible = "arm,cortex-a15"; reg = <0>; }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <1>; + }; + }; + + psci { + compatible = "arm,psci"; + method = "hvc"; + cpu_off = <1>; + cpu_on = <2>; }; memory@80000000 { diff --git a/arch/arm/include/asm/xen/hypercall.h b/arch/arm/include/asm/xen/hypercall.h index 8a823253d775d83337bab6e833d30949e553e49d..799f42ecca63309d485090add41c495cc4f4ccea 100644 --- a/arch/arm/include/asm/xen/hypercall.h +++ b/arch/arm/include/asm/xen/hypercall.h @@ -46,6 +46,7 @@ int HYPERVISOR_event_channel_op(int cmd, void *arg); unsigned long HYPERVISOR_hvm_op(int op, void *arg); int HYPERVISOR_memory_op(unsigned int cmd, void *arg); int HYPERVISOR_physdev_op(int cmd, void *arg); +int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args); static inline void MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va, diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index b6083bb1eb8cf4c9092630a25c43b041c163f7f6..8802030df98d0fbac53f4cd1f01df30f598f1773 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -450,7 +450,6 @@ static void __init v2m_dt_init(void) static const char * const v2m_dt_match[] __initconst = { "arm,vexpress", - "xen,xenvm", NULL, }; diff --git a/arch/arm/mach-virt/virt.c b/arch/arm/mach-virt/virt.c index adc0945255aea2dee90e170d2426c7a25fc128e0..061f283f579e891b59f8a0c17c0dcafa7bdc4288 100644 --- a/arch/arm/mach-virt/virt.c +++ b/arch/arm/mach-virt/virt.c @@ -32,6 +32,7 @@ static void __init virt_init(void) static const char *virt_dt_match[] = { "linux,dummy-virt", + "xen,xenvm", NULL }; diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 8dc0605a9ce9e2d3b5df910fafd6eadb008bfb21..d30042e39974f949e6ab3cc81f88f7c6dfc51c4d 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,9 +10,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -32,6 +35,7 @@ struct shared_info xen_dummy_shared_info; struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); +static struct vcpu_info __percpu *xen_vcpu_info; /* These are unused until we support booting "pre-ballooned" */ unsigned long xen_released_pages; @@ -148,6 +152,47 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, } EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); +static int __init xen_secondary_init(unsigned int cpu) +{ + struct vcpu_register_vcpu_info info; + struct vcpu_info *vcpup; + int err; + + pr_info("Xen: initializing cpu%d\n", cpu); + vcpup = per_cpu_ptr(xen_vcpu_info, cpu); + + info.mfn = __pa(vcpup) >> PAGE_SHIFT; + info.offset = offset_in_page(vcpup); + + err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info); + if (err) { + pr_debug("register_vcpu_info failed: err=%d\n", err); + } else { + /* This cpu is using the registered vcpu info, even if + later ones fail to. */ + per_cpu(xen_vcpu, cpu) = vcpup; + } + return 0; +} + +static void xen_restart(char str, const char *cmd) +{ + struct sched_shutdown r = { .reason = SHUTDOWN_reboot }; + int rc; + rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); + if (rc) + BUG(); +} + +static void xen_power_off(void) +{ + struct sched_shutdown r = { .reason = SHUTDOWN_poweroff }; + int rc; + rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); + if (rc) + BUG(); +} + /* * see Documentation/devicetree/bindings/arm/xen.txt for the * documentation of the Xen Device Tree format. @@ -163,6 +208,7 @@ static int __init xen_guest_init(void) const char *version = NULL; const char *xen_prefix = "xen,xen-"; struct resource res; + int i; node = of_find_compatible_node(NULL, NULL, "xen,xen"); if (!node) { @@ -209,18 +255,26 @@ static int __init xen_guest_init(void) /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info * page, we use it in the event channel upcall and in some pvclock - * related functions. We don't need the vcpu_info placement - * optimizations because we don't use any pv_mmu or pv_irq op on - * HVM. + * related functions. * The shared info contains exactly 1 CPU (the boot CPU). The guest * is required to use VCPUOP_register_vcpu_info to place vcpu info - * for secondary CPUs as they are brought up. */ - per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; + * for secondary CPUs as they are brought up. + * For uniformity we use VCPUOP_register_vcpu_info even on cpu0. + */ + xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info), + sizeof(struct vcpu_info)); + if (xen_vcpu_info == NULL) + return -ENOMEM; + for_each_online_cpu(i) + xen_secondary_init(i); gnttab_init(); if (!xen_initial_domain()) xenbus_probe(NULL); + pm_power_off = xen_power_off; + arm_pm_restart = xen_restart; + return 0; } core_initcall(xen_guest_init); @@ -231,6 +285,11 @@ static irqreturn_t xen_arm_callback(int irq, void *arg) return IRQ_HANDLED; } +static __init void xen_percpu_enable_events(void *unused) +{ + enable_percpu_irq(xen_events_irq, 0); +} + static int __init xen_init_events(void) { if (!xen_domain() || xen_events_irq < 0) @@ -239,12 +298,12 @@ static int __init xen_init_events(void) xen_init_IRQ(); if (request_percpu_irq(xen_events_irq, xen_arm_callback, - "events", xen_vcpu)) { + "events", &xen_vcpu)) { pr_err("Error requesting IRQ %d\n", xen_events_irq); return -EINVAL; } - enable_percpu_irq(xen_events_irq, 0); + on_each_cpu(xen_percpu_enable_events, NULL, 0); return 0; } @@ -259,4 +318,5 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_sched_op); EXPORT_SYMBOL_GPL(HYPERVISOR_hvm_op); EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op); EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op); +EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op); EXPORT_SYMBOL_GPL(privcmd_call); diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S index 71f723984cbd94eced133e49bc7fd0db8dbdf92b..199cb2da76637929cd50bf1301f7771faefe8415 100644 --- a/arch/arm/xen/hypercall.S +++ b/arch/arm/xen/hypercall.S @@ -87,6 +87,7 @@ HYPERCALL2(event_channel_op); HYPERCALL2(hvm_op); HYPERCALL2(memory_op); HYPERCALL2(physdev_op); +HYPERCALL3(vcpu_op); ENTRY(privcmd_call) stmdb sp!, {r4}