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 <[email protected]>
---
 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));
+
        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


Reply via email to