arm64: add helper functions to read I-cache attributes
PATCH v3 1/2 arm64: add helper functions to read I-cache attributes
This adds helper functions and #defines to <asm/cachetype.h> to read the line size and the number of sets from the level 1 instruction cache.
---
v3: add WARN_ON(preemptible()), move icache_get_ccsidr() to cpuinfo.c to
prevent #include header recursion hell
v2: put () around macro args, use 64-bit types for asm() mrs/msr calls
arch/arm64/include/asm/cachetype.h | 20 ++++++++++++++++++++ arch/arm64/kernel/cpuinfo.c | 14 ++++++++++++++ 2 files changed, 34 insertions(+)
arch/arm64/include/asm/cachetype.h +20 -0
@@ -39,6 +39,26 @@extern unsigned long __icache_flags; +#define CCSIDR_EL1_LINESIZE_MASK 0x7 +#define CCSIDR_EL1_LINESIZE (x) ((x) & CCSIDR_EL1_LINESIZE_MASK) + +#define CCSIDR_EL1_NUMSETS_SHIFT 13 +#define CCSIDR_EL1_NUMSETS_MASK (0x7fff << CCSIDR_EL1_NUMSETS_SHIFT) +#define CCSIDR_EL1_NUMSETS (x) \ + (((x) & CCSIDR_EL1_NUMSETS_MASK) >> CCSIDR_EL1_NUMSETS_SHIFT) + +extern u64 __attribute_const__ icache_get_ccsidr(void); + +static inline int icache_get_linesize (void ) +{ +return 16 <<CCSIDR_EL1_LINESIZE (icache_get_ccsidr ()); +} + +static inline int icache_get_numsets (void ) +{ +return 1 +CCSIDR_EL1_NUMSETS (icache_get_ccsidr ()); +} +/* * Whilst the D-side always behaves as PIPT on AArch64, aliasing is * permitted in the I-cache.
arch/arm64/kernel/cpuinfo.c +14 -0
@@ -20,8 +20,10 @@#include <asm/cputype.h> #include <linux/bitops.h> +#include <linux/bug.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/preempt.h> #include <linux/printk.h> #include <linux/smp.h>
@@ -190,3 +192,15 @@ void __init cpuinfo_store_boot_cpu(void) boot_cpu_data = *info; } + +u64 __attribute_const__ icache_get_ccsidr(void) +{ +u64 ccsidr; + +WARN_ON (preemptible ()); + +/* Select L1 I-cache and read its size ID register */ + asm("msr csselr_el1, %1; isb; mrs %0, ccsidr_el1" + :"=r" (ccsidr) :"r" (1L )); +return ccsidr; +}
Signature · 1 line
1.8.3.2
PATCH v3 2/2 arm64: don't flag non-aliasing VIPT I-caches as aliasing
VIPT caches are non-aliasing if the index is derived from address bits that are always equal between VA and PA. Classifying these as aliasing results in unnecessary flushing which may hurt performance.
---
v2, v3: no changes
arch/arm64/kernel/cpuinfo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
arch/arm64/kernel/cpuinfo.c +7 -1
@@ -49,7 +49,13 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)unsigned int cpu =smp_processor_id ();u32 l1ip =CTR_L1IP (info->reg_ctr); -if (l1ip !=ICACHE_POLICY_PIPT ) +/* +* VIPT caches are non-aliasing if the VA always equals the PA in all +* bit positions that are covered by the index, i.e., if num_sets_shift +* is less than or equal to PAGE_SHIFT minus line_size_shift. +*/ +if (l1ip !=ICACHE_POLICY_PIPT && !(l1ip ==ICACHE_POLICY_VIPT && +icache_get_linesize () *icache_get_numsets () <=PAGE_SIZE ))set_bit (ICACHEF_ALIASING , &__icache_flags);if (l1ip ==ICACHE_POLICY_AIVIVT );set_bit (ICACHEF_AIVIVT , &__icache_flags);
Signature · 1 line
1.8.3.2
PATCH v3 2/2 arm64: don't flag non-aliasing VIPT I-caches as aliasing
Quoted 17 lines · Ard Biesheuvel
VIPT caches are non-aliasing if the index is derived from address bits that are always equal between VA and PA. Classifying these as aliasing results in unnecessary flushing which may hurt performance.
Signed-off-by Ard Biesheuvel <[email protected]>---
v2, v3: no changesarch/arm64/kernel/cpuinfo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)arch/arm64/kernel/cpuinfo.c +0
-0@@ -49,7 +49,13 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)unsigned int cpu =smp_processor_id ();
arch/arm64/kernel/cpuinfo.c static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) · line 58
Quoted 10 lines
arch/arm64/kernel/cpuinfo.c +7
-1u32 l1ip =CTR_L1IP (info->reg_ctr); -if (l1ip !=ICACHE_POLICY_PIPT ) +/* +* VIPT caches are non-aliasing if the VA always equals the PA in all +* bit positions that are covered by the index, i.e., if num_sets_shift +* is less than or equal to PAGE_SHIFT minus line_size_shift. +*/ +if (l1ip !=ICACHE_POLICY_PIPT && !(l1ip ==ICACHE_POLICY_VIPT && +icache_get_linesize () *icache_get_numsets () <=PAGE_SIZE ))
Might just be me, but I'd find this a lot easier to understand if you had a local `way_size' variable and set it to linesize * num_sets.
Either way:
Will
PATCH v3 1/2 arm64: add helper functions to read I-cache attributes
In reply to Ard BiesheuvelQuoted 4 lines · Ard Biesheuvel
This adds helper functions and #defines to <
asm/cachetype.h> to read the line size and the number of sets from the level 1 instruction cache.Signed-off-by Ard Biesheuvel <[email protected]>
Quoted 8 lines
---
v3: add WARN_ON(preemptible()), moveicache_get_ccsidr()tocpuinfo.cto
prevent #include header recursion hell
v2: put () around macro args, use 64-bit types forasm()mrs/msr callsarch/arm64/include/asm/cachetype.h | 20 ++++++++++++++++++++ arch/arm64/kernel/cpuinfo.c | 14 ++++++++++++++ 2 files changed, 34 insertions(+)
Will