diff options
author | James Morse <james.morse@arm.com> | 2016-03-30 18:33:04 +0100 |
---|---|---|
committer | Alex Shi <alex.shi@linaro.org> | 2016-05-24 22:39:32 +0800 |
commit | d6c1376ab351962a53fa73542abdaef73172eace (patch) | |
tree | b557ea6b2950a845ea68391d8e94853c8a0db9ff /arch | |
parent | 5aa75c8a63ce9b417ffa9c050203cf769af0f018 (diff) |
arm64: KVM: Register CPU notifiers when the kernel runs at HYP
When the kernel is running at EL2, it doesn't need init_hyp_mode() to
configure page tables for HYP. This function also registers the CPU
hotplug and lower power notifiers that cause HYP to be re-initialised
after the CPU has been reset.
To avoid losing the register state that controls stage2 translation, move
the registering of these notifiers into init_subsystems(), and add a
is_kernel_in_hyp_mode() path to each callback.
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
Fixes: 1e947bad0b6 ("arm64: KVM: Skip HYP setup when already running in HYP")
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
(cherry picked from commit 5f5560b1c5f3a80e91c6babb2da34a51943bbdec)
Signed-off-by: Alex Shi <alex.shi@linaro.org>
Conflicts:
skip vimd in arch/arm/kvm/arm.c
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kvm/arm.c | 52 |
1 files changed, 33 insertions, 19 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 17749163feb1..d10c75ba44e8 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -938,15 +938,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; @@ -961,9 +973,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; } @@ -1005,6 +1016,22 @@ static int init_subsystems(void) int err; /* + * Register CPU Hotplug notifier + */ + cpu_notifier_register_begin(); + err = __register_cpu_notifier(&hyp_init_cpu_nb); + cpu_notifier_register_done(); + 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 */ err = kvm_vgic_hyp_init(); @@ -1145,19 +1172,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(); - kvm_info("Hyp mode initialized successfully\n"); return 0; |