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: Julien Thierry <julien.thierry@arm.com> Acked-by: Marc 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: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
committed by
Catalin Marinas
parent
8cb7eff32c
commit
e9ab7a2e33
@@ -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,
|
|||||||
__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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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(®ion, false);
|
__apply_alternatives(®ion, 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)
|
|||||||
* 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
|
||||||
|
|||||||
Reference in New Issue
Block a user