kvm-arm: Cleanup stage2 pgd handling
[cascardo/linux.git] / arch / arm / kvm / arm.c
index 3e0fb66..be4b639 100644 (file)
@@ -373,7 +373,9 @@ static void exit_vm_noop(void *info)
 
 void force_vm_exit(const cpumask_t *mask)
 {
+       preempt_disable();
        smp_call_function_many(mask, exit_vm_noop, NULL, true);
+       preempt_enable();
 }
 
 /**
@@ -446,7 +448,7 @@ static void update_vttbr(struct kvm *kvm)
        kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
 
        /* update vttbr to be used with the new vmid */
-       pgd_phys = virt_to_phys(kvm_get_hwpgd(kvm));
+       pgd_phys = virt_to_phys(kvm->arch.pgd);
        BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK);
        vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
        kvm->arch.vttbr = pgd_phys | vmid;
@@ -1059,15 +1061,27 @@ static void cpu_init_hyp_mode(void *dummy)
        kvm_arm_init_debug();
 }
 
+static void cpu_hyp_reinit(void)
+{
+       if (is_kernel_in_hyp_mode()) {
+               /*
+                * cpu_init_stage2() is safe to call even if the PM
+                * event was cancelled before the CPU was reset.
+                */
+               cpu_init_stage2(NULL);
+       } else {
+               if (__hyp_get_vectors() == hyp_default_vectors)
+                       cpu_init_hyp_mode(NULL);
+       }
+}
+
 static int hyp_init_cpu_notify(struct notifier_block *self,
                               unsigned long action, void *cpu)
 {
        switch (action) {
        case CPU_STARTING:
        case CPU_STARTING_FROZEN:
-               if (__hyp_get_vectors() == hyp_default_vectors)
-                       cpu_init_hyp_mode(NULL);
-               break;
+               cpu_hyp_reinit();
        }
 
        return NOTIFY_OK;
@@ -1082,9 +1096,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
                                    unsigned long cmd,
                                    void *v)
 {
-       if (cmd == CPU_PM_EXIT &&
-           __hyp_get_vectors() == hyp_default_vectors) {
-               cpu_init_hyp_mode(NULL);
+       if (cmd == CPU_PM_EXIT) {
+               cpu_hyp_reinit();
                return NOTIFY_OK;
        }
 
@@ -1099,10 +1112,17 @@ static void __init hyp_cpu_pm_init(void)
 {
        cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
 }
+static void __init hyp_cpu_pm_exit(void)
+{
+       cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
+}
 #else
 static inline void hyp_cpu_pm_init(void)
 {
 }
+static inline void hyp_cpu_pm_exit(void)
+{
+}
 #endif
 
 static void teardown_common_resources(void)
@@ -1125,6 +1145,20 @@ static int init_subsystems(void)
 {
        int err;
 
+       /*
+        * Register CPU Hotplug notifier
+        */
+       err = register_cpu_notifier(&hyp_init_cpu_nb);
+       if (err) {
+               kvm_err("Cannot register KVM init CPU notifier (%d)\n", err);
+               return err;
+       }
+
+       /*
+        * Register CPU lower-power notifier
+        */
+       hyp_cpu_pm_init();
+
        /*
         * Init HYP view of VGIC
         */
@@ -1164,6 +1198,8 @@ static void teardown_hyp_mode(void)
        free_hyp_pgds();
        for_each_possible_cpu(cpu)
                free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
+       unregister_cpu_notifier(&hyp_init_cpu_nb);
+       hyp_cpu_pm_exit();
 }
 
 static int init_vhe_mode(void)
@@ -1268,19 +1304,6 @@ static int init_hyp_mode(void)
        free_boot_hyp_pgd();
 #endif
 
-       cpu_notifier_register_begin();
-
-       err = __register_cpu_notifier(&hyp_init_cpu_nb);
-
-       cpu_notifier_register_done();
-
-       if (err) {
-               kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
-               goto out_err;
-       }
-
-       hyp_cpu_pm_init();
-
        /* set size of VMID supported by CPU */
        kvm_vmid_bits = kvm_get_vmid_bits();
        kvm_info("%d-bit VMID\n", kvm_vmid_bits);