Re: [PATCH v10 04/30] arm64/fpsimd: Determine maximum virtualisable SME vector length

From: Jean-Philippe Brucker

Date: Wed Mar 18 2026 - 13:29:35 EST


On Fri, Mar 06, 2026 at 05:00:56PM +0000, Mark Brown wrote:
> As with SVE we can only virtualise SME vector lengths that are supported by
> all CPUs in the system, implement similar checks to those for SVE. Since
> unlike SVE there are no specific vector lengths that are architecturally
> required the handling is subtly different, we report a system where this
> happens with a maximum vector length of SME_VQ_INVALID.
>
> Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
> ---
> arch/arm64/include/asm/fpsimd.h | 2 ++
> arch/arm64/kernel/fpsimd.c | 21 ++++++++++++++++++++-
> 2 files changed, 22 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index e97729aa3b2f..0cd8a866e844 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -69,6 +69,8 @@ static inline void cpacr_restore(unsigned long cpacr)
> #define ARCH_SVE_VQ_MAX ((ZCR_ELx_LEN_MASK >> ZCR_ELx_LEN_SHIFT) + 1)
> #define SME_VQ_MAX ((SMCR_ELx_LEN_MASK >> SMCR_ELx_LEN_SHIFT) + 1)
>
> +#define SME_VQ_INVALID (SME_VQ_MAX + 1)
> +
> struct task_struct;
>
> extern void fpsimd_save_state(struct user_fpsimd_state *state);
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 2af0e0c5b9f4..49c050ef6db9 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -1218,7 +1218,8 @@ void cpu_enable_sme(const struct arm64_cpu_capabilities *__always_unused p)
> void __init sme_setup(void)
> {
> struct vl_info *info = &vl_info[ARM64_VEC_SME];
> - int min_bit, max_bit;
> + DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> + int min_bit, max_bit, b;
>
> if (!system_supports_sme())
> return;
> @@ -1249,12 +1250,30 @@ void __init sme_setup(void)
> */
> set_sme_default_vl(find_supported_vector_length(ARM64_VEC_SME, 32));
>
> + bitmap_andnot(tmp_map, info->vq_partial_map, info->vq_map,
> + SVE_VQ_MAX);
> +
> + b = find_last_bit(tmp_map, SVE_VQ_MAX);
> + if (b >= SVE_VQ_MAX)
> + /* All VLs virtualisable */
> + info->max_virtualisable_vl = sve_vl_from_vq(ARCH_SVE_VQ_MAX);
> + else if (b == SVE_VQ_MAX - 1)
> + /* No virtualisable VLs */
> + info->max_virtualisable_vl = sve_vl_from_vq(SME_VQ_INVALID);
> + else
> + info->max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));

nit: "b + 1"

Reviewed-by: Jean-Philippe Brucker <jpb@xxxxxxxxxx>

> +
> pr_info("SME: minimum available vector length %u bytes per vector\n",
> info->min_vl);
> pr_info("SME: maximum available vector length %u bytes per vector\n",
> info->max_vl);
> pr_info("SME: default vector length %u bytes per vector\n",
> get_sme_default_vl());
> +
> + /* KVM decides whether to support mismatched systems. Just warn here: */
> + if (info->max_virtualisable_vl < info->max_vl ||
> + info->max_virtualisable_vl == sve_vl_from_vq(SME_VQ_INVALID))
> + pr_warn("SME: unvirtualisable vector lengths present\n");
> }
>
> void sme_suspend_exit(void)
>
> --
> 2.47.3
>
>