Add a helper to check the MIDR of the running CPU against a given
MODEL and a range of revision and variants (just like we do in
is_affected_midr_range()). This will be useful for early checks
for MIDR to detect CPU errata.

Cc: Mark Rutland <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Marc Zyngier <[email protected]>
Signed-off-by: Suzuki K Poulose <[email protected]>
---
 arch/arm64/include/asm/assembler.h | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm64/include/asm/assembler.h 
b/arch/arm64/include/asm/assembler.h
index 5dc4856f3bb9..596b693edb2c 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -25,6 +25,7 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/cpufeature.h>
+#include <asm/cputype.h>
 #include <asm/debug-monitors.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
@@ -516,4 +517,43 @@ alternative_endif
 #endif
        .endm
 
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ *     model:          MIDR_CPU_MODEL of CPU
+ *     rv_min:         Minimum of MIDR_CPU_VAR_REV()
+ *     rv_max:         Maximum of MIDR_CPU_VAR_REV()
+ *     res:            Result register.
+ *     tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns:  0, if the CPU id doesn't match. Non-zero otherwise
+ */
+       .macro  cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+       mrs             \res, midr_el1
+       mov_q           \tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+       mov_q           \tmp2, MIDR_CPU_MODEL_MASK
+       and             \tmp3, \res, \tmp2      // Extract model
+       and             \tmp1, \res, \tmp1      // rev & variant
+       mov_q           \tmp2, \model
+       cmp             \tmp3, \tmp2
+       cset            \res, eq
+       cbz             \res, .Ldone\@          // Model matches ?
+
+       .if (\rv_min != 0)                      // Skip min check if rv_min == 0
+       mov_q           \tmp3, \rv_min
+       cmp             \tmp1, \tmp3
+       cset            \res, ge
+       .endif                                  // \rv_min != 0
+       /* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+       .if ((\rv_min != \rv_max) || \rv_min == 0)
+       mov_q           \tmp2, \rv_max
+       cmp             \tmp1, \tmp2
+       cset            \tmp2, le
+       and             \res, \res, \tmp2
+       .endif
+.Ldone\@:
+       .endm
+
 #endif /* __ASM_ASSEMBLER_H */
-- 
2.13.6

Reply via email to