nmi_backtrace: do a local dump_stack() instead of a self-NMI
[cascardo/linux.git] / kernel / smp.c
index 3aa642d..bba3b20 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/smp.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
+#include <linux/hypervisor.h>
 
 #include "smpboot.h"
 
@@ -724,3 +725,54 @@ void wake_up_all_idle_cpus(void)
        preempt_enable();
 }
 EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus);
+
+/**
+ * smp_call_on_cpu - Call a function on a specific cpu
+ *
+ * Used to call a function on a specific cpu and wait for it to return.
+ * Optionally make sure the call is done on a specified physical cpu via vcpu
+ * pinning in order to support virtualized environments.
+ */
+struct smp_call_on_cpu_struct {
+       struct work_struct      work;
+       struct completion       done;
+       int                     (*func)(void *);
+       void                    *data;
+       int                     ret;
+       int                     cpu;
+};
+
+static void smp_call_on_cpu_callback(struct work_struct *work)
+{
+       struct smp_call_on_cpu_struct *sscs;
+
+       sscs = container_of(work, struct smp_call_on_cpu_struct, work);
+       if (sscs->cpu >= 0)
+               hypervisor_pin_vcpu(sscs->cpu);
+       sscs->ret = sscs->func(sscs->data);
+       if (sscs->cpu >= 0)
+               hypervisor_pin_vcpu(-1);
+
+       complete(&sscs->done);
+}
+
+int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, bool phys)
+{
+       struct smp_call_on_cpu_struct sscs = {
+               .done = COMPLETION_INITIALIZER_ONSTACK(sscs.done),
+               .func = func,
+               .data = par,
+               .cpu  = phys ? cpu : -1,
+       };
+
+       INIT_WORK_ONSTACK(&sscs.work, smp_call_on_cpu_callback);
+
+       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+               return -ENXIO;
+
+       queue_work_on(cpu, system_wq, &sscs.work);
+       wait_for_completion(&sscs.done);
+
+       return sscs.ret;
+}
+EXPORT_SYMBOL_GPL(smp_call_on_cpu);