mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-14 06:24:53 +08:00
arm64: cpufeature: Add global feature override facility
Add a facility to globally override a feature, no matter what the HW says. Yes, this sounds dangerous, but we do respect the "safe" value for a given feature. This doesn't mean the user doesn't need to know what they are doing. Nothing uses this yet, so we are pretty safe. For now. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Acked-by: David Brazdil <dbrazdil@google.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Link: https://lore.kernel.org/r/20210208095732.3267263-11-maz@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
d077cb3cb9
commit
8f266a5d87
@ -63,6 +63,11 @@ struct arm64_ftr_bits {
|
||||
s64 safe_val; /* safe value for FTR_EXACT features */
|
||||
};
|
||||
|
||||
struct arm64_ftr_override {
|
||||
u64 val;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* @arm64_ftr_reg - Feature register
|
||||
* @strict_mask Bits which should match across all CPUs for sanity.
|
||||
@ -74,6 +79,7 @@ struct arm64_ftr_reg {
|
||||
u64 user_mask;
|
||||
u64 sys_val;
|
||||
u64 user_val;
|
||||
struct arm64_ftr_override *override;
|
||||
const struct arm64_ftr_bits *ftr_bits;
|
||||
};
|
||||
|
||||
|
@ -352,9 +352,12 @@ static const struct arm64_ftr_bits ftr_ctr[] = {
|
||||
ARM64_FTR_END,
|
||||
};
|
||||
|
||||
static struct arm64_ftr_override __ro_after_init no_override = { };
|
||||
|
||||
struct arm64_ftr_reg arm64_ftr_reg_ctrel0 = {
|
||||
.name = "SYS_CTR_EL0",
|
||||
.ftr_bits = ftr_ctr
|
||||
.ftr_bits = ftr_ctr,
|
||||
.override = &no_override,
|
||||
};
|
||||
|
||||
static const struct arm64_ftr_bits ftr_id_mmfr0[] = {
|
||||
@ -544,13 +547,16 @@ static const struct arm64_ftr_bits ftr_raz[] = {
|
||||
ARM64_FTR_END,
|
||||
};
|
||||
|
||||
#define ARM64_FTR_REG(id, table) { \
|
||||
.sys_id = id, \
|
||||
.reg = &(struct arm64_ftr_reg){ \
|
||||
.name = #id, \
|
||||
.ftr_bits = &((table)[0]), \
|
||||
#define ARM64_FTR_REG_OVERRIDE(id, table, ovr) { \
|
||||
.sys_id = id, \
|
||||
.reg = &(struct arm64_ftr_reg){ \
|
||||
.name = #id, \
|
||||
.override = (ovr), \
|
||||
.ftr_bits = &((table)[0]), \
|
||||
}}
|
||||
|
||||
#define ARM64_FTR_REG(id, table) ARM64_FTR_REG_OVERRIDE(id, table, &no_override)
|
||||
|
||||
static const struct __ftr_reg_entry {
|
||||
u32 sys_id;
|
||||
struct arm64_ftr_reg *reg;
|
||||
@ -770,6 +776,33 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
|
||||
for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) {
|
||||
u64 ftr_mask = arm64_ftr_mask(ftrp);
|
||||
s64 ftr_new = arm64_ftr_value(ftrp, new);
|
||||
s64 ftr_ovr = arm64_ftr_value(ftrp, reg->override->val);
|
||||
|
||||
if ((ftr_mask & reg->override->mask) == ftr_mask) {
|
||||
s64 tmp = arm64_ftr_safe_value(ftrp, ftr_ovr, ftr_new);
|
||||
char *str = NULL;
|
||||
|
||||
if (ftr_ovr != tmp) {
|
||||
/* Unsafe, remove the override */
|
||||
reg->override->mask &= ~ftr_mask;
|
||||
reg->override->val &= ~ftr_mask;
|
||||
tmp = ftr_ovr;
|
||||
str = "ignoring override";
|
||||
} else if (ftr_new != tmp) {
|
||||
/* Override was valid */
|
||||
ftr_new = tmp;
|
||||
str = "forced";
|
||||
} else if (ftr_ovr == tmp) {
|
||||
/* Override was the safe value */
|
||||
str = "already set";
|
||||
}
|
||||
|
||||
if (str)
|
||||
pr_warn("%s[%d:%d]: %s to %llx\n",
|
||||
reg->name,
|
||||
ftrp->shift + ftrp->width - 1,
|
||||
ftrp->shift, str, tmp);
|
||||
}
|
||||
|
||||
val = arm64_ftr_set_value(ftrp, val, ftr_new);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user