Commit cac642c1 authored by Marc Zyngier's avatar Marc Zyngier Committed by Catalin Marinas
Browse files

arm64: cpufeature: Allow early filtering of feature override



Some CPUs are broken enough that some overrides need to be rejected
at the earliest opportunity. In some cases, that's right at cpu
feature override time.

Provide the necessary infrastructure to filter out overrides,
and to report such filtered out overrides to the core cpufeature code.

Acked-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210408131010.1109027-2-maz@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 1e28eed1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -63,6 +63,23 @@ struct arm64_ftr_bits {
	s64		safe_val; /* safe value for FTR_EXACT features */
};

/*
 * Describe the early feature override to the core override code:
 *
 * @val			Values that are to be merged into the final
 *			sanitised value of the register. Only the bitfields
 *			set to 1 in @mask are valid
 * @mask		Mask of the features that are overridden by @val
 *
 * A @mask field set to full-1 indicates that the corresponding field
 * in @val is a valid override.
 *
 * A @mask field set to full-0 with the corresponding @val field set
 * to full-0 denotes that this field has no override
 *
 * A @mask field set to full-0 with the corresponding @val field set
 * to full-1 denotes thath this field has an invalid override.
 */
struct arm64_ftr_override {
	u64		val;
	u64		mask;
+6 −0
Original line number Diff line number Diff line
@@ -809,6 +809,12 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
					reg->name,
					ftrp->shift + ftrp->width - 1,
					ftrp->shift, str, tmp);
		} else if ((ftr_mask & reg->override->val) == ftr_mask) {
			reg->override->val &= ~ftr_mask;
			pr_warn("%s[%d:%d]: impossible override, ignored\n",
				reg->name,
				ftrp->shift + ftrp->width - 1,
				ftrp->shift);
		}

		val = arm64_ftr_set_value(ftrp, val, ftr_new);
+13 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ struct ftr_set_desc {
	struct {
		char			name[FTR_DESC_FIELD_LEN];
		u8			shift;
		bool			(*filter)(u64 val);
	} 				fields[];
};

@@ -124,6 +125,18 @@ static void __init match_options(const char *cmdline)
			if (find_field(cmdline, regs[i], f, &v))
				continue;

			/*
			 * If an override gets filtered out, advertise
			 * it by setting the value to 0xf, but
			 * clearing the mask... Yes, this is fragile.
			 */
			if (regs[i]->fields[f].filter &&
			    !regs[i]->fields[f].filter(v)) {
				regs[i]->override->val  |= mask;
				regs[i]->override->mask &= ~mask;
				continue;
			}

			regs[i]->override->val  &= ~mask;
			regs[i]->override->val  |= (v << shift) & mask;
			regs[i]->override->mask |= mask;