Unverified Commit 38f5bd23 authored by Zong Li's avatar Zong Li Committed by Palmer Dabbelt
Browse files

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: default avatarZong Li <zong.li@sifive.com>
Reviewed-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
Reviewed-by: default avatarPekka Enberg <penberg@kernel.org>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent b5fca7c5
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2020 SiFive
 */

#ifndef _ASM_RISCV_CACHEINFO_H
#define _ASM_RISCV_CACHEINFO_H
@@ -11,5 +14,7 @@ struct riscv_cacheinfo_ops {
};

void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops);
uintptr_t get_cache_size(u32 level, enum cache_type type);
uintptr_t get_cache_geometry(u32 level, enum cache_type type);

#endif /* _ASM_RISCV_CACHEINFO_H */
+13 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <uapi/asm/elf.h>
#include <asm/auxvec.h>
#include <asm/byteorder.h>
#include <asm/cacheinfo.h>

/*
 * These are used to set parameters in the core dumps.
@@ -61,6 +62,18 @@ extern unsigned long elf_hwcap;
do {								\
	NEW_AUX_ENT(AT_SYSINFO_EHDR,				\
		(elf_addr_t)current->mm->context.vdso);		\
	NEW_AUX_ENT(AT_L1I_CACHESIZE,				\
		get_cache_size(1, CACHE_TYPE_INST));		\
	NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY,			\
		get_cache_geometry(1, CACHE_TYPE_INST));	\
	NEW_AUX_ENT(AT_L1D_CACHESIZE,				\
		get_cache_size(1, CACHE_TYPE_DATA));		\
	NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY,			\
		get_cache_geometry(1, CACHE_TYPE_DATA));	\
	NEW_AUX_ENT(AT_L2_CACHESIZE,				\
		get_cache_size(2, CACHE_TYPE_UNIFIED));		\
	NEW_AUX_ENT(AT_L2_CACHEGEOMETRY,			\
		get_cache_geometry(2, CACHE_TYPE_UNIFIED));	\
} while (0)
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
struct linux_binprm;
+22 −1
Original line number Diff line number Diff line
@@ -10,7 +10,28 @@
/* vDSO location */
#define AT_SYSINFO_EHDR 33

/*
 * The set of entries below represent more extensive information
 * about the caches, in the form of two entry per cache type,
 * one entry containing the cache size in bytes, and the other
 * containing the cache line size in bytes in the bottom 16 bits
 * and the cache associativity in the next 16 bits.
 *
 * The associativity is such that if N is the 16-bit value, the
 * cache is N way set associative. A value if 0xffff means fully
 * associative, a value of 1 means directly mapped.
 *
 * For all these fields, a value of 0 means that the information
 * is not known.
 */
#define AT_L1I_CACHESIZE	40
#define AT_L1I_CACHEGEOMETRY	41
#define AT_L1D_CACHESIZE	42
#define AT_L1D_CACHEGEOMETRY	43
#define AT_L2_CACHESIZE		44
#define AT_L2_CACHEGEOMETRY	45

/* entries in ARCH_DLINFO */
#define AT_VECTOR_SIZE_ARCH	1
#define AT_VECTOR_SIZE_ARCH	7

#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
+31 −1
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@
 * Copyright (C) 2017 SiFive
 */

#include <linux/cacheinfo.h>
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -25,6 +24,37 @@ cache_get_priv_group(struct cacheinfo *this_leaf)
	return NULL;
}

static struct cacheinfo *get_cacheinfo(u32 level, enum cache_type type)
{
	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(smp_processor_id());
	struct cacheinfo *this_leaf;
	int index;

	for (index = 0; index < this_cpu_ci->num_leaves; index++) {
		this_leaf = this_cpu_ci->info_list + index;
		if (this_leaf->level == level && this_leaf->type == type)
			return this_leaf;
	}

	return NULL;
}

uintptr_t get_cache_size(u32 level, enum cache_type type)
{
	struct cacheinfo *this_leaf = get_cacheinfo(level, type);

	return this_leaf ? this_leaf->size : 0;
}

uintptr_t get_cache_geometry(u32 level, enum cache_type type)
{
	struct cacheinfo *this_leaf = get_cacheinfo(level, type);

	return this_leaf ? (this_leaf->ways_of_associativity << 16 |
			    this_leaf->coherency_line_size) :
			   0;
}

static void ci_leaf_init(struct cacheinfo *this_leaf, enum cache_type type,
			 unsigned int level, unsigned int size,
			 unsigned int sets, unsigned int line_size)