|
@@ -123,11 +123,13 @@ static int sve_default_vl = -1;
|
|
int __ro_after_init sve_max_vl = -1;
|
|
int __ro_after_init sve_max_vl = -1;
|
|
/* Set of available vector lengths, as vq_to_bit(vq): */
|
|
/* Set of available vector lengths, as vq_to_bit(vq): */
|
|
static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
|
|
static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
|
|
|
|
+static void __percpu *efi_sve_state;
|
|
|
|
|
|
#else /* ! CONFIG_ARM64_SVE */
|
|
#else /* ! CONFIG_ARM64_SVE */
|
|
|
|
|
|
/* Dummy declaration for code that will be optimised out: */
|
|
/* Dummy declaration for code that will be optimised out: */
|
|
extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
|
|
extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
|
|
|
|
+extern void __percpu *efi_sve_state;
|
|
|
|
|
|
#endif /* ! CONFIG_ARM64_SVE */
|
|
#endif /* ! CONFIG_ARM64_SVE */
|
|
|
|
|
|
@@ -552,6 +554,30 @@ int sve_verify_vq_map(void)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void __init sve_efi_setup(void)
|
|
|
|
+{
|
|
|
|
+ if (!IS_ENABLED(CONFIG_EFI))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * alloc_percpu() warns and prints a backtrace if this goes wrong.
|
|
|
|
+ * This is evidence of a crippled system and we are returning void,
|
|
|
|
+ * so no attempt is made to handle this situation here.
|
|
|
|
+ */
|
|
|
|
+ if (!sve_vl_valid(sve_max_vl))
|
|
|
|
+ goto fail;
|
|
|
|
+
|
|
|
|
+ efi_sve_state = __alloc_percpu(
|
|
|
|
+ SVE_SIG_REGS_SIZE(sve_vq_from_vl(sve_max_vl)), SVE_VQ_BYTES);
|
|
|
|
+ if (!efi_sve_state)
|
|
|
|
+ goto fail;
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+fail:
|
|
|
|
+ panic("Cannot allocate percpu memory for EFI SVE save/restore");
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Enable SVE for EL1.
|
|
* Enable SVE for EL1.
|
|
* Intended for use by the cpufeatures code during CPU boot.
|
|
* Intended for use by the cpufeatures code during CPU boot.
|
|
@@ -599,6 +625,8 @@ void __init sve_setup(void)
|
|
sve_max_vl);
|
|
sve_max_vl);
|
|
pr_info("SVE: default vector length %u bytes per vector\n",
|
|
pr_info("SVE: default vector length %u bytes per vector\n",
|
|
sve_default_vl);
|
|
sve_default_vl);
|
|
|
|
+
|
|
|
|
+ sve_efi_setup();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -927,6 +955,7 @@ EXPORT_SYMBOL(kernel_neon_end);
|
|
|
|
|
|
static DEFINE_PER_CPU(struct fpsimd_state, efi_fpsimd_state);
|
|
static DEFINE_PER_CPU(struct fpsimd_state, efi_fpsimd_state);
|
|
static DEFINE_PER_CPU(bool, efi_fpsimd_state_used);
|
|
static DEFINE_PER_CPU(bool, efi_fpsimd_state_used);
|
|
|
|
+static DEFINE_PER_CPU(bool, efi_sve_state_used);
|
|
|
|
|
|
/*
|
|
/*
|
|
* EFI runtime services support functions
|
|
* EFI runtime services support functions
|
|
@@ -952,10 +981,24 @@ void __efi_fpsimd_begin(void)
|
|
|
|
|
|
WARN_ON(preemptible());
|
|
WARN_ON(preemptible());
|
|
|
|
|
|
- if (may_use_simd())
|
|
|
|
|
|
+ if (may_use_simd()) {
|
|
kernel_neon_begin();
|
|
kernel_neon_begin();
|
|
- else {
|
|
|
|
- fpsimd_save_state(this_cpu_ptr(&efi_fpsimd_state));
|
|
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * If !efi_sve_state, SVE can't be in use yet and doesn't need
|
|
|
|
+ * preserving:
|
|
|
|
+ */
|
|
|
|
+ if (system_supports_sve() && likely(efi_sve_state)) {
|
|
|
|
+ char *sve_state = this_cpu_ptr(efi_sve_state);
|
|
|
|
+
|
|
|
|
+ __this_cpu_write(efi_sve_state_used, true);
|
|
|
|
+
|
|
|
|
+ sve_save_state(sve_state + sve_ffr_offset(sve_max_vl),
|
|
|
|
+ &this_cpu_ptr(&efi_fpsimd_state)->fpsr);
|
|
|
|
+ } else {
|
|
|
|
+ fpsimd_save_state(this_cpu_ptr(&efi_fpsimd_state));
|
|
|
|
+ }
|
|
|
|
+
|
|
__this_cpu_write(efi_fpsimd_state_used, true);
|
|
__this_cpu_write(efi_fpsimd_state_used, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -968,10 +1011,22 @@ void __efi_fpsimd_end(void)
|
|
if (!system_supports_fpsimd())
|
|
if (!system_supports_fpsimd())
|
|
return;
|
|
return;
|
|
|
|
|
|
- if (__this_cpu_xchg(efi_fpsimd_state_used, false))
|
|
|
|
- fpsimd_load_state(this_cpu_ptr(&efi_fpsimd_state));
|
|
|
|
- else
|
|
|
|
|
|
+ if (!__this_cpu_xchg(efi_fpsimd_state_used, false)) {
|
|
kernel_neon_end();
|
|
kernel_neon_end();
|
|
|
|
+ } else {
|
|
|
|
+ if (system_supports_sve() &&
|
|
|
|
+ likely(__this_cpu_read(efi_sve_state_used))) {
|
|
|
|
+ char const *sve_state = this_cpu_ptr(efi_sve_state);
|
|
|
|
+
|
|
|
|
+ sve_load_state(sve_state + sve_ffr_offset(sve_max_vl),
|
|
|
|
+ &this_cpu_ptr(&efi_fpsimd_state)->fpsr,
|
|
|
|
+ sve_vq_from_vl(sve_get_vl()) - 1);
|
|
|
|
+
|
|
|
|
+ __this_cpu_write(efi_sve_state_used, false);
|
|
|
|
+ } else {
|
|
|
|
+ fpsimd_load_state(this_cpu_ptr(&efi_fpsimd_state));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_EFI */
|
|
#endif /* CONFIG_EFI */
|