Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv: Add cache information in AUX vector

There are no standard CSR registers to provide cache information, the
way for RISC-V is to get this information from DT. Currently, AT_L1I_X,
AT_L1D_X and AT_L2_X are present in glibc header, and sysconf syscall
could use them to get information of cache through AUX vector.

The result of 'getconf -a' as follows:
LEVEL1_ICACHE_SIZE 32768
LEVEL1_ICACHE_ASSOC 8
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_ASSOC 8
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 2097152
LEVEL2_CACHE_ASSOC 32
LEVEL2_CACHE_LINESIZE 64

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
Reviewed-by: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>

authored by

Zong Li and committed by
Palmer Dabbelt
38f5bd23 b5fca7c5

+71 -2
+5
arch/riscv/include/asm/cacheinfo.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020 SiFive 4 + */ 2 5 3 6 #ifndef _ASM_RISCV_CACHEINFO_H 4 7 #define _ASM_RISCV_CACHEINFO_H ··· 14 11 }; 15 12 16 13 void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops); 14 + uintptr_t get_cache_size(u32 level, enum cache_type type); 15 + uintptr_t get_cache_geometry(u32 level, enum cache_type type); 17 16 18 17 #endif /* _ASM_RISCV_CACHEINFO_H */
+13
arch/riscv/include/asm/elf.h
··· 11 11 #include <uapi/asm/elf.h> 12 12 #include <asm/auxvec.h> 13 13 #include <asm/byteorder.h> 14 + #include <asm/cacheinfo.h> 14 15 15 16 /* 16 17 * These are used to set parameters in the core dumps. ··· 62 61 do { \ 63 62 NEW_AUX_ENT(AT_SYSINFO_EHDR, \ 64 63 (elf_addr_t)current->mm->context.vdso); \ 64 + NEW_AUX_ENT(AT_L1I_CACHESIZE, \ 65 + get_cache_size(1, CACHE_TYPE_INST)); \ 66 + NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY, \ 67 + get_cache_geometry(1, CACHE_TYPE_INST)); \ 68 + NEW_AUX_ENT(AT_L1D_CACHESIZE, \ 69 + get_cache_size(1, CACHE_TYPE_DATA)); \ 70 + NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY, \ 71 + get_cache_geometry(1, CACHE_TYPE_DATA)); \ 72 + NEW_AUX_ENT(AT_L2_CACHESIZE, \ 73 + get_cache_size(2, CACHE_TYPE_UNIFIED)); \ 74 + NEW_AUX_ENT(AT_L2_CACHEGEOMETRY, \ 75 + get_cache_geometry(2, CACHE_TYPE_UNIFIED)); \ 65 76 } while (0) 66 77 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 67 78 struct linux_binprm;
+22 -1
arch/riscv/include/uapi/asm/auxvec.h
··· 10 10 /* vDSO location */ 11 11 #define AT_SYSINFO_EHDR 33 12 12 13 + /* 14 + * The set of entries below represent more extensive information 15 + * about the caches, in the form of two entry per cache type, 16 + * one entry containing the cache size in bytes, and the other 17 + * containing the cache line size in bytes in the bottom 16 bits 18 + * and the cache associativity in the next 16 bits. 19 + * 20 + * The associativity is such that if N is the 16-bit value, the 21 + * cache is N way set associative. A value if 0xffff means fully 22 + * associative, a value of 1 means directly mapped. 23 + * 24 + * For all these fields, a value of 0 means that the information 25 + * is not known. 26 + */ 27 + #define AT_L1I_CACHESIZE 40 28 + #define AT_L1I_CACHEGEOMETRY 41 29 + #define AT_L1D_CACHESIZE 42 30 + #define AT_L1D_CACHEGEOMETRY 43 31 + #define AT_L2_CACHESIZE 44 32 + #define AT_L2_CACHEGEOMETRY 45 33 + 13 34 /* entries in ARCH_DLINFO */ 14 - #define AT_VECTOR_SIZE_ARCH 1 35 + #define AT_VECTOR_SIZE_ARCH 7 15 36 16 37 #endif /* _UAPI_ASM_RISCV_AUXVEC_H */
+31 -1
arch/riscv/kernel/cacheinfo.c
··· 3 3 * Copyright (C) 2017 SiFive 4 4 */ 5 5 6 - #include <linux/cacheinfo.h> 7 6 #include <linux/cpu.h> 8 7 #include <linux/of.h> 9 8 #include <linux/of_device.h> ··· 22 23 if (rv_cache_ops && rv_cache_ops->get_priv_group) 23 24 return rv_cache_ops->get_priv_group(this_leaf); 24 25 return NULL; 26 + } 27 + 28 + static struct cacheinfo *get_cacheinfo(u32 level, enum cache_type type) 29 + { 30 + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(smp_processor_id()); 31 + struct cacheinfo *this_leaf; 32 + int index; 33 + 34 + for (index = 0; index < this_cpu_ci->num_leaves; index++) { 35 + this_leaf = this_cpu_ci->info_list + index; 36 + if (this_leaf->level == level && this_leaf->type == type) 37 + return this_leaf; 38 + } 39 + 40 + return NULL; 41 + } 42 + 43 + uintptr_t get_cache_size(u32 level, enum cache_type type) 44 + { 45 + struct cacheinfo *this_leaf = get_cacheinfo(level, type); 46 + 47 + return this_leaf ? this_leaf->size : 0; 48 + } 49 + 50 + uintptr_t get_cache_geometry(u32 level, enum cache_type type) 51 + { 52 + struct cacheinfo *this_leaf = get_cacheinfo(level, type); 53 + 54 + return this_leaf ? (this_leaf->ways_of_associativity << 16 | 55 + this_leaf->coherency_line_size) : 56 + 0; 25 57 } 26 58 27 59 static void ci_leaf_init(struct cacheinfo *this_leaf, enum cache_type type,