Commit e9ab7a2e authored by Julien Thierry's avatar Julien Thierry Committed by Catalin Marinas

arm64: alternative: Allow alternative status checking per cpufeature

In preparation for the application of alternatives at different points
during the boot process, provide the possibility to check whether
alternatives for a feature of interest was already applied instead of
having a global boolean for all alternatives.

Make VHE enablement code check for the VHE feature instead of considering
all alternatives.
Signed-off-by: default avatarJulien Thierry <julien.thierry@arm.com>
Acked-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Marc Zyngier <Marc.Zyngier@arm.com>
Cc: Christoffer Dall <Christoffer.Dall@arm.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 8cb7eff3
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/stringify.h> #include <linux/stringify.h>
extern int alternatives_applied;
struct alt_instr { struct alt_instr {
s32 orig_offset; /* offset to original instruction */ s32 orig_offset; /* offset to original instruction */
s32 alt_offset; /* offset to replacement instruction */ s32 alt_offset; /* offset to replacement instruction */
...@@ -28,6 +26,7 @@ typedef void (*alternative_cb_t)(struct alt_instr *alt, ...@@ -28,6 +26,7 @@ typedef void (*alternative_cb_t)(struct alt_instr *alt,
__le32 *origptr, __le32 *updptr, int nr_inst); __le32 *origptr, __le32 *updptr, int nr_inst);
void __init apply_alternatives_all(void); void __init apply_alternatives_all(void);
bool alternative_is_applied(u16 cpufeature);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
void apply_alternatives_module(void *start, size_t length); void apply_alternatives_module(void *start, size_t length);
......
...@@ -32,13 +32,23 @@ ...@@ -32,13 +32,23 @@
#define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset) #define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset)
#define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset) #define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset)
int alternatives_applied; static int all_alternatives_applied;
static DECLARE_BITMAP(applied_alternatives, ARM64_NCAPS);
struct alt_region { struct alt_region {
struct alt_instr *begin; struct alt_instr *begin;
struct alt_instr *end; struct alt_instr *end;
}; };
bool alternative_is_applied(u16 cpufeature)
{
if (WARN_ON(cpufeature >= ARM64_NCAPS))
return false;
return test_bit(cpufeature, applied_alternatives);
}
/* /*
* Check if the target PC is within an alternative block. * Check if the target PC is within an alternative block.
*/ */
...@@ -192,6 +202,9 @@ static void __apply_alternatives(void *alt_region, bool is_module) ...@@ -192,6 +202,9 @@ static void __apply_alternatives(void *alt_region, bool is_module)
dsb(ish); dsb(ish);
__flush_icache_all(); __flush_icache_all();
isb(); isb();
/* We applied all that was available */
bitmap_copy(applied_alternatives, cpu_hwcaps, ARM64_NCAPS);
} }
} }
...@@ -208,14 +221,14 @@ static int __apply_alternatives_multi_stop(void *unused) ...@@ -208,14 +221,14 @@ static int __apply_alternatives_multi_stop(void *unused)
/* We always have a CPU 0 at this point (__init) */ /* We always have a CPU 0 at this point (__init) */
if (smp_processor_id()) { if (smp_processor_id()) {
while (!READ_ONCE(alternatives_applied)) while (!READ_ONCE(all_alternatives_applied))
cpu_relax(); cpu_relax();
isb(); isb();
} else { } else {
BUG_ON(alternatives_applied); BUG_ON(all_alternatives_applied);
__apply_alternatives(&region, false); __apply_alternatives(&region, false);
/* Barriers provided by the cache flushing */ /* Barriers provided by the cache flushing */
WRITE_ONCE(alternatives_applied, 1); WRITE_ONCE(all_alternatives_applied, 1);
} }
return 0; return 0;
......
...@@ -1118,7 +1118,7 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) ...@@ -1118,7 +1118,7 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
* that, freshly-onlined CPUs will set tpidr_el2, so we don't need to * that, freshly-onlined CPUs will set tpidr_el2, so we don't need to
* do anything here. * do anything here.
*/ */
if (!alternatives_applied) if (!alternative_is_applied(ARM64_HAS_VIRT_HOST_EXTN))
write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment