summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/jump_label.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2018-08-16 11:45:50 +0100
committerWill Deacon <will.deacon@arm.com>2018-08-17 10:26:44 +0100
commitf6cc0c50164994afd538911603b4a8f8029aeba7 (patch)
tree07366db3fe04e6545f8d792697d7a7bd3ca3626d /arch/arm64/kernel/jump_label.c
parent3c4d9137eefecf273a520d392071ffc9df0a9a7a (diff)
downloadlinux-f6cc0c50164994afd538911603b4a8f8029aeba7.tar.bz2
arm64: Avoid calling stop_machine() when patching jump labels
Patching a jump label involves patching a single instruction at a time, swizzling between a branch and a NOP. The architecture treats these instructions specially, so a concurrently executing CPU is guaranteed to see either the NOP or the branch, rather than an amalgamation of the two instruction encodings. However, in order to guarantee that the new instruction is visible, it is necessary to send an IPI to the concurrently executing CPU so that it discards any previously fetched instructions from its pipeline. This operation therefore cannot be completed from a context with IRQs disabled, but this is exactly what happens on the jump label path where the hotplug lock is held and irqs are subsequently disabled by stop_machine_cpuslocked(). This results in a deadlock during boot on Hikey-960. Due to the architectural guarantees around patching NOPs and branches, we don't actually need to stop_machine() at all on the jump label path, so we can avoid the deadlock by using the "nosync" variant of our instruction patching routine. Fixes: 693350a79980 ("arm64: insn: Don't fallback on nosync path for general insn patching") Reported-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi> Reported-by: John Stultz <john.stultz@linaro.org> Tested-by: Valentin Schneider <valentin.schneider@arm.com> Tested-by: Tuomas Tynkkynen <tuomas@tuxera.com> Tested-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/jump_label.c')
-rw-r--r--arch/arm64/kernel/jump_label.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c
index c2dd1ad3e648..e0756416e567 100644
--- a/arch/arm64/kernel/jump_label.c
+++ b/arch/arm64/kernel/jump_label.c
@@ -36,7 +36,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
insn = aarch64_insn_gen_nop();
}
- aarch64_insn_patch_text(&addr, &insn, 1);
+ aarch64_insn_patch_text_nosync(addr, insn);
}
void arch_jump_label_transform_static(struct jump_entry *entry,