[PATCH v4 10/38] arm64: Explicitly save/restore CPACR when probing SVE and SME
Catalin Marinas
catalin.marinas at arm.com
Mon Oct 16 09:11:15 PDT 2023
On Mon, Oct 16, 2023 at 01:02:13PM +0100, Mark Brown wrote:
> On Mon, Oct 16, 2023 at 11:24:33AM +0100, Mark Rutland wrote:
> > When a CPUs onlined we first probe for supported features and
> > propetites, and then we subsequently enable features that have been
> > detected. This is a little problematic for SVE and SME, as some
> > properties (e.g. vector lengths) cannot be probed while they are
> > disabled. Due to this, the code probing for SVE properties has to enable
>
> Reviewed-by: Mark Brown <broonie at kernel.org>
Thanks Mark for reviewing. Could you please also check my conflict
resolution? Mark R's patches conflict with your patches on
for-next/sve-remove-pseudo-regs (maybe I should have applied them on
top; hopefully git rerere remembers it correctly).
diff --cc arch/arm64/include/asm/fpsimd.h
index 9e5d3a0812b6,c43ae9c013ec..50e5f25d3024
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@@ -123,11 -149,13 +149,12 @@@ extern void sme_save_state(void *state
extern void sme_load_state(void const *state, int zt);
struct arm64_cpu_capabilities;
- extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
- extern void sme_kernel_enable(const struct arm64_cpu_capabilities *__unused);
- extern void sme2_kernel_enable(const struct arm64_cpu_capabilities *__unused);
- extern void fa64_kernel_enable(const struct arm64_cpu_capabilities *__unused);
+ extern void cpu_enable_fpsimd(const struct arm64_cpu_capabilities *__unused);
+ extern void cpu_enable_sve(const struct arm64_cpu_capabilities *__unused);
+ extern void cpu_enable_sme(const struct arm64_cpu_capabilities *__unused);
+ extern void cpu_enable_sme2(const struct arm64_cpu_capabilities *__unused);
+ extern void cpu_enable_fa64(const struct arm64_cpu_capabilities *__unused);
-extern u64 read_zcr_features(void);
extern u64 read_smcr_features(void);
/*
diff --cc arch/arm64/kernel/cpufeature.c
index 55a3bc719d46,ad7ec30d3bd3..397a1bbf4fba
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@@ -1026,21 -1040,30 +1026,26 @@@ void __init init_cpu_features(struct cp
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
id_aa64pfr0_sve(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
- sve_kernel_enable(NULL);
+ unsigned long cpacr = cpacr_save_enable_kernel_sve();
+
- info->reg_zcr = read_zcr_features();
- init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
vec_init_vq_map(ARM64_VEC_SVE);
+
+ cpacr_restore(cpacr);
}
if (IS_ENABLED(CONFIG_ARM64_SME) &&
id_aa64pfr1_sme(read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1))) {
- sme_kernel_enable(NULL);
+ unsigned long cpacr = cpacr_save_enable_kernel_sme();
- info->reg_smcr = read_smcr_features();
/*
* We mask out SMPS since even if the hardware
* supports priorities the kernel does not at present
* and we block access to them.
*/
info->reg_smidr = read_cpuid(SMIDR_EL1) & ~SMIDR_EL1_SMPS;
- init_cpu_ftr_reg(SYS_SMCR_EL1, info->reg_smcr);
vec_init_vq_map(ARM64_VEC_SME);
+
+ cpacr_restore(cpacr);
}
if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
@@@ -1274,29 -1297,40 +1279,35 @@@ void update_cpu_features(int cpu
taint |= check_update_ftr_reg(SYS_ID_AA64SMFR0_EL1, cpu,
info->reg_id_aa64smfr0, boot->reg_id_aa64smfr0);
+ /* Probe vector lengths */
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
id_aa64pfr0_sve(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
- unsigned long cpacr = cpacr_save_enable_kernel_sve();
+ if (!system_capabilities_finalized()) {
- sve_kernel_enable(NULL);
++ unsigned long cpacr = cpacr_save_enable_kernel_sve();
+
- info->reg_zcr = read_zcr_features();
- taint |= check_update_ftr_reg(SYS_ZCR_EL1, cpu,
- info->reg_zcr, boot->reg_zcr);
-
- /* Probe vector lengths */
- if (!system_capabilities_finalized())
vec_update_vq_map(ARM64_VEC_SVE);
+
- cpacr_restore(cpacr);
++ cpacr_restore(cpacr);
+ }
}
if (IS_ENABLED(CONFIG_ARM64_SME) &&
id_aa64pfr1_sme(read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1))) {
- sme_kernel_enable(NULL);
- unsigned long cpacr = cpacr_save_enable_kernel_sme();
--
- info->reg_smcr = read_smcr_features();
/*
* We mask out SMPS since even if the hardware
* supports priorities the kernel does not at present
* and we block access to them.
*/
info->reg_smidr = read_cpuid(SMIDR_EL1) & ~SMIDR_EL1_SMPS;
- taint |= check_update_ftr_reg(SYS_SMCR_EL1, cpu,
- info->reg_smcr, boot->reg_smcr);
/* Probe vector lengths */
-- if (!system_capabilities_finalized())
++ if (!system_capabilities_finalized()) {
++ unsigned long cpacr = cpacr_save_enable_kernel_sme();
++
vec_update_vq_map(ARM64_VEC_SME);
+
- cpacr_restore(cpacr);
++ cpacr_restore(cpacr);
++ }
}
/*
@@@ -3138,7 -3182,15 +3162,9 @@@ static void verify_local_elf_hwcaps(voi
static void verify_sve_features(void)
{
+ unsigned long cpacr = cpacr_save_enable_kernel_sve();
+
- u64 safe_zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
- u64 zcr = read_zcr_features();
-
- unsigned int safe_len = safe_zcr & ZCR_ELx_LEN_MASK;
- unsigned int len = zcr & ZCR_ELx_LEN_MASK;
-
- if (len < safe_len || vec_verify_vq_map(ARM64_VEC_SVE)) {
+ if (vec_verify_vq_map(ARM64_VEC_SVE)) {
pr_crit("CPU%d: SVE: vector length support mismatch\n",
smp_processor_id());
cpu_die_early();
@@@ -3147,7 -3201,15 +3175,9 @@@
static void verify_sme_features(void)
{
+ unsigned long cpacr = cpacr_save_enable_kernel_sme();
+
- u64 safe_smcr = read_sanitised_ftr_reg(SYS_SMCR_EL1);
- u64 smcr = read_smcr_features();
-
- unsigned int safe_len = safe_smcr & SMCR_ELx_LEN_MASK;
- unsigned int len = smcr & SMCR_ELx_LEN_MASK;
-
- if (len < safe_len || vec_verify_vq_map(ARM64_VEC_SME)) {
+ if (vec_verify_vq_map(ARM64_VEC_SME)) {
pr_crit("CPU%d: SME: vector length support mismatch\n",
smp_processor_id());
cpu_die_early();
diff --cc arch/arm64/kernel/fpsimd.c
index 04c801001767,d0d28bc069d2..5ddc246f1482
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@@ -1173,11 -1169,30 +1169,11 @@@ void cpu_enable_sve(const struct arm64_
void __init sve_setup(void)
{
struct vl_info *info = &vl_info[ARM64_VEC_SVE];
- u64 zcr;
DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
unsigned long b;
+ int max_bit;
- if (!system_supports_sve())
+ if (!cpus_have_cap(ARM64_SVE))
return;
/*
@@@ -1307,9 -1329,29 +1301,9 @@@ void cpu_enable_fa64(const struct arm64
void __init sme_setup(void)
{
struct vl_info *info = &vl_info[ARM64_VEC_SME];
- u64 smcr;
- int min_bit;
+ int min_bit, max_bit;
- if (!system_supports_sme())
+ if (!cpus_have_cap(ARM64_SME))
return;
/*
--
Catalin
More information about the linux-arm-kernel
mailing list