Merge tag 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford...
[cascardo/linux.git] / arch / x86 / xen / enlighten.c
index 0f87db2..8ffb089 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/sched.h>
 #include <linux/kprobes.h>
 #include <linux/bootmem.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/page-flags.h>
 #include <linux/highmem.h>
@@ -34,9 +34,7 @@
 #include <linux/edd.h>
 #include <linux/frame.h>
 
-#ifdef CONFIG_KEXEC_CORE
 #include <linux/kexec.h>
-#endif
 
 #include <xen/xen.h>
 #include <xen/events.h>
@@ -59,6 +57,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 +117,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 +182,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 +205,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 +227,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 +252,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 +265,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 +594,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 +643,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 +1141,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
@@ -1323,7 +1332,8 @@ static void xen_crash_shutdown(struct pt_regs *regs)
 static int
 xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
-       xen_reboot(SHUTDOWN_crash);
+       if (!kexec_crash_loaded())
+               xen_reboot(SHUTDOWN_crash);
        return NOTIFY_DONE;
 }
 
@@ -1727,6 +1737,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 +1781,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 +1809,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 +1826,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))