diff options
Diffstat (limited to 'arch/arm/xen/enlighten.c')
| -rw-r--r-- | arch/arm/xen/enlighten.c | 74 | 
1 files changed, 67 insertions, 7 deletions
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 8dc0605a9ce..d30042e3997 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -2,6 +2,7 @@  #include <xen/events.h>  #include <xen/grant_table.h>  #include <xen/hvm.h> +#include <xen/interface/vcpu.h>  #include <xen/interface/xen.h>  #include <xen/interface/memory.h>  #include <xen/interface/hvm/params.h> @@ -9,9 +10,11 @@  #include <xen/platform_pci.h>  #include <xen/xenbus.h>  #include <xen/page.h> +#include <xen/interface/sched.h>  #include <xen/xen-ops.h>  #include <asm/xen/hypervisor.h>  #include <asm/xen/hypercall.h> +#include <asm/system_misc.h>  #include <linux/interrupt.h>  #include <linux/irqreturn.h>  #include <linux/module.h> @@ -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);  |