[RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework

Suzuki K Poulose Suzuki.Poulose at arm.com
Thu Mar 23 07:11:50 PDT 2017


On 22/03/17 14:51, Dave Martin wrote:
> For robust feature detection and appropriate handling of feature
> mismatches between CPUs, this patch adds knowledge of the new
> feature fields and new registers ZCR_EL1 and ID_AA64ZFR0_EL1 to the
> cpufeature framework.

...

>
> The SVE field in AA64PFR0 is made visible visible to userspace MRS
> emulation.  This should make sense for future architecture
> extensions.

Please could you also update the following documentation :

  Documentation/arm64/cpu-feature-registers.txt

> +#ifdef CONFIG_ARM64_SVE
> +	{
> +		.desc = "Scalable Vector Extension",
> +		.capability = ARM64_SVE,
> +		.def_scope = SCOPE_SYSTEM,
> +		.sys_reg = SYS_ID_AA64PFR0_EL1,
> +		.sign = FTR_UNSIGNED,
> +		.field_pos = ID_AA64PFR0_SVE_SHIFT,
> +		.min_field_value = ID_AA64PFR0_SVE,
> +		.matches = has_cpuid_feature,
> +	},
> +#endif /* CONFIG_ARM64_SVE */
>  	{},
>  };
>
> @@ -889,7 +923,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
>  	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
>  	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
>  #ifdef CONFIG_ARM64_SVE
> -	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SVE),
> +	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),

>  #endif
>  	{},
>  };
> @@ -1120,6 +1154,8 @@ void __init setup_cpu_features(void)
>  	if (system_supports_32bit_el0())
>  		setup_elf_hwcaps(compat_elf_hwcaps);
>
> +	sve_setup();
> +
>  	/* Advertise that we have computed the system capabilities */
>  	set_sys_caps_initialised();
>
> diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
> index 8dd410e..cb3b0dd 100644
> --- a/arch/arm64/kernel/cpuinfo.c
> +++ b/arch/arm64/kernel/cpuinfo.c
> @@ -19,6 +19,7 @@
>  #include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/cpufeature.h>
> +#include <asm/fpsimd.h>
>
>  #include <linux/bitops.h>
>  #include <linux/bug.h>
> @@ -325,6 +326,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
>  	info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
>  	info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
>  	info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
> +	info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
>
>  	/* Update the 32bit ID registers only if AArch32 is implemented */
>  	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
> @@ -347,6 +349,17 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
>  		info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
>  	}
>
> +	if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
> +		u64 zcr;
> +
> +		write_sysreg_s(ZCR_EL1_LEN_MASK, SYS_ZCR_EL1);
> +		zcr = read_sysreg_s(SYS_ZCR_EL1);
> +		zcr &= ~(u64)ZCR_EL1_LEN_MASK;
> +		zcr |= sve_get_vl() / 16 - 1;
> +
> +		info->reg_zcr = zcr;
> +	}
> +
>  	cpuinfo_detect_icache_policy(info);
>  }
>
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index ddb651a..34ec75e 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -340,6 +340,26 @@ int sve_get_task_vl(struct task_struct *task)
>  	return sve_prctl_status(task);
>  }
>
> +void __init sve_setup(void)
> +{
> +	u64 zcr;
> +
> +	if (!system_supports_sve())
> +		return;
> +
> +	zcr = read_system_reg(SYS_ZCR_EL1);
> +
> +	BUG_ON(((zcr & ZCR_EL1_LEN_MASK) + 1) * 16 > sve_max_vl);
> +
> +	sve_max_vl = ((zcr & ZCR_EL1_LEN_MASK) + 1) * 16;
> +	sve_default_vl = sve_max_vl > 64 ? 64 : sve_max_vl;
> +
> +	pr_info("SVE: maximum available vector length %u bytes per vector\n",
> +		sve_max_vl);
> +	pr_info("SVE: default vector length %u bytes per vector\n",
> +		sve_default_vl);

I think we may need an extra check in verify_local_cpu_capabilities() to make sure the new CPU,
which comes up late can support the SVE vector length that could possibly used, i.e, sve_max_vl.

Rest looks good to me.

Suzuki

> +}
> +
>  #ifdef CONFIG_PROC_FS
>
>  struct default_vl_write_state {
> @@ -898,9 +918,6 @@ static int __init fpsimd_init(void)
>  	if (!(elf_hwcap & HWCAP_ASIMD))
>  		pr_notice("Advanced SIMD is not implemented\n");
>
> -	if (!(elf_hwcap & HWCAP_SVE))
> -		pr_info("Scalable Vector Extension available\n");
> -
>  	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))

nit: You may use system_supports_sve() here, instead of the elf_hwcap check. Since this
is not a performance critical path it doesn't really matter, how we check it.

>  		return sve_procfs_init();
>
>




More information about the linux-arm-kernel mailing list