arm64.nomte     [ARM64] Unconditionally disable Memory Tagging Extension
                        support
 
+       arm64.nosme     [ARM64] Unconditionally disable Scalable Matrix
+                       Extension support
+
        ataflop=        [HW,M68k]
 
        atarimouse=     [HW,MOUSE] Atari Mouse
 
 
 extern struct arm64_ftr_override id_aa64mmfr1_override;
 extern struct arm64_ftr_override id_aa64pfr1_override;
+extern struct arm64_ftr_override id_aa64smfr0_override;
 extern struct arm64_ftr_override id_aa64isar1_override;
 extern struct arm64_ftr_override id_aa64isar2_override;
 
 
 .Lskip_sve_\@:
 .endm
 
-/* SME register access and priority mapping */
-.macro __init_el2_nvhe_sme
-       mrs     x1, id_aa64pfr1_el1
-       ubfx    x1, x1, #ID_AA64PFR1_SME_SHIFT, #4
-       cbz     x1, .Lskip_sme_\@
-
-       bic     x0, x0, #CPTR_EL2_TSM           // Also disable SME traps
-       msr     cptr_el2, x0                    // Disable copro. traps to EL2
-       isb
-
-       mrs     x1, sctlr_el2
-       orr     x1, x1, #SCTLR_ELx_ENTP2        // Disable TPIDR2 traps
-       msr     sctlr_el2, x1
-       isb
-
-       mov     x1, #0                          // SMCR controls
-
-       mrs_s   x2, SYS_ID_AA64SMFR0_EL1
-       ubfx    x2, x2, #ID_AA64SMFR0_FA64_SHIFT, #1 // Full FP in SM?
-       cbz     x2, .Lskip_sme_fa64_\@
-
-       orr     x1, x1, SMCR_ELx_FA64_MASK
-.Lskip_sme_fa64_\@:
-
-       orr     x1, x1, #SMCR_ELx_LEN_MASK      // Enable full SME vector
-       msr_s   SYS_SMCR_EL2, x1                // length for EL1.
-
-       mrs_s   x1, SYS_SMIDR_EL1               // Priority mapping supported?
-       ubfx    x1, x1, #SMIDR_EL1_SMPS_SHIFT, #1
-       cbz     x1, .Lskip_sme_\@
-
-       msr_s   SYS_SMPRIMAP_EL2, xzr           // Make all priorities equal
-
-       mrs     x1, id_aa64mmfr1_el1            // HCRX_EL2 present?
-       ubfx    x1, x1, #ID_AA64MMFR1_HCX_SHIFT, #4
-       cbz     x1, .Lskip_sme_\@
-
-       mrs_s   x1, SYS_HCRX_EL2
-       orr     x1, x1, #HCRX_EL2_SMPME_MASK    // Enable priority mapping
-       msr_s   SYS_HCRX_EL2, x1
-
-.Lskip_sme_\@:
-.endm
-
 /* Disable any fine grained traps */
 .macro __init_el2_fgt
        mrs     x1, id_aa64mmfr0_el1
        __init_el2_nvhe_idregs
        __init_el2_nvhe_cptr
        __init_el2_nvhe_sve
-       __init_el2_nvhe_sme
        __init_el2_fgt
        __init_el2_nvhe_prepare_eret
 .endm
 
 
 struct arm64_ftr_override __ro_after_init id_aa64mmfr1_override;
 struct arm64_ftr_override __ro_after_init id_aa64pfr1_override;
+struct arm64_ftr_override __ro_after_init id_aa64smfr0_override;
 struct arm64_ftr_override __ro_after_init id_aa64isar1_override;
 struct arm64_ftr_override __ro_after_init id_aa64isar2_override;
 
        ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1,
                               &id_aa64pfr1_override),
        ARM64_FTR_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0),
-       ARM64_FTR_REG(SYS_ID_AA64SMFR0_EL1, ftr_id_aa64smfr0),
+       ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64SMFR0_EL1, ftr_id_aa64smfr0,
+                              &id_aa64smfr0_override),
 
        /* Op1 = 0, CRn = 0, CRm = 5 */
        ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0),
 
 SYM_CODE_END(elx_sync)
 
 SYM_CODE_START_LOCAL(__finalise_el2)
+       check_override id_aa64pfr1 ID_AA64PFR1_SME_SHIFT .Linit_sme .Lskip_sme
+
+.Linit_sme:    /* SME register access and priority mapping */
+       mrs     x0, cptr_el2                    // Disable SME traps
+       bic     x0, x0, #CPTR_EL2_TSM
+       msr     cptr_el2, x0
+       isb
+
+       mrs     x1, sctlr_el2
+       orr     x1, x1, #SCTLR_ELx_ENTP2        // Disable TPIDR2 traps
+       msr     sctlr_el2, x1
+       isb
+
+       mov     x1, #0                          // SMCR controls
+
+       mrs_s   x2, SYS_ID_AA64SMFR0_EL1
+       ubfx    x2, x2, #ID_AA64SMFR0_FA64_SHIFT, #1 // Full FP in SM?
+       cbz     x2, .Lskip_sme_fa64
+
+       orr     x1, x1, SMCR_ELx_FA64_MASK
+.Lskip_sme_fa64:
+
+       orr     x1, x1, #SMCR_ELx_LEN_MASK      // Enable full SME vector
+       msr_s   SYS_SMCR_EL2, x1                // length for EL1.
+
+       mrs_s   x1, SYS_SMIDR_EL1               // Priority mapping supported?
+       ubfx    x1, x1, #SMIDR_EL1_SMPS_SHIFT, #1
+       cbz     x1, .Lskip_sme
+
+       msr_s   SYS_SMPRIMAP_EL2, xzr           // Make all priorities equal
+
+       mrs     x1, id_aa64mmfr1_el1            // HCRX_EL2 present?
+       ubfx    x1, x1, #ID_AA64MMFR1_HCX_SHIFT, #4
+       cbz     x1, .Lskip_sme
+
+       mrs_s   x1, SYS_HCRX_EL2
+       orr     x1, x1, #HCRX_EL2_SMPME_MASK    // Enable priority mapping
+       msr_s   SYS_HCRX_EL2, x1
+
+.Lskip_sme:
+
        // nVHE? No way! Give me the real thing!
        // Sanity check: MMU *must* be off
        mrs     x1, sctlr_el2
 
        },
 };
 
+static bool __init pfr1_sme_filter(u64 val)
+{
+       /*
+        * Similarly to SVE, disabling SME also means disabling all
+        * the features that are associated with it. Just set
+        * id_aa64smfr0_el1 to 0 and don't look back.
+        */
+       if (!val) {
+               id_aa64smfr0_override.val = 0;
+               id_aa64smfr0_override.mask = GENMASK(63, 0);
+       }
+
+       return true;
+}
+
 static const struct ftr_set_desc pfr1 __initconst = {
        .name           = "id_aa64pfr1",
        .override       = &id_aa64pfr1_override,
        .fields         = {
                FIELD("bt", ID_AA64PFR1_BT_SHIFT, NULL),
                FIELD("mte", ID_AA64PFR1_MTE_SHIFT, NULL),
+               FIELD("sme", ID_AA64PFR1_SME_SHIFT, pfr1_sme_filter),
                {}
        },
 };
 } aliases[] __initconst = {
        { "kvm-arm.mode=nvhe",          "id_aa64mmfr1.vh=0" },
        { "kvm-arm.mode=protected",     "id_aa64mmfr1.vh=0" },
+       { "arm64.nosme",                "id_aa64pfr1.sme=0" },
        { "arm64.nobti",                "id_aa64pfr1.bt=0" },
        { "arm64.nopauth",
          "id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 "