Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Extract CPU cache information and expose them via sysfs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *    Copyright IBM Corp. 2012
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/cacheinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <asm/facility.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 	CACHE_SCOPE_NOTEXISTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 	CACHE_SCOPE_PRIVATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 	CACHE_SCOPE_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 	CACHE_SCOPE_RESERVED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	CTYPE_SEPARATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	CTYPE_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	CTYPE_INSTRUCTION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	CTYPE_UNIFIED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	EXTRACT_TOPOLOGY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	EXTRACT_LINE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	EXTRACT_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	EXTRACT_ASSOCIATIVITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	CACHE_TI_UNIFIED = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	CACHE_TI_DATA = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	CACHE_TI_INSTRUCTION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) struct cache_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	unsigned char	    : 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	unsigned char scope : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	unsigned char type  : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define CACHE_MAX_LEVEL 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) union cache_topology {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	struct cache_info ci[CACHE_MAX_LEVEL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	unsigned long long raw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) static const char * const cache_type_string[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	"",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	"Instruction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	"Data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	"",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	"Unified",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) static const enum cache_type cache_type_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	[CTYPE_SEPARATE] = CACHE_TYPE_SEPARATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	[CTYPE_DATA] = CACHE_TYPE_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	[CTYPE_INSTRUCTION] = CACHE_TYPE_INST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) void show_cacheinfo(struct seq_file *m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct cpu_cacheinfo *this_cpu_ci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct cacheinfo *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	if (!test_facility(34))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	this_cpu_ci = get_cpu_cacheinfo(cpumask_any(cpu_online_mask));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		cache = this_cpu_ci->info_list + idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		seq_printf(m, "cache%-11d: ", idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		seq_printf(m, "level=%d ", cache->level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		seq_printf(m, "scope=%s ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			   cache->disable_sysfs ? "Shared" : "Private");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		seq_printf(m, "size=%dK ", cache->size >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		seq_printf(m, "line_size=%u ", cache->coherency_line_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 		seq_printf(m, "associativity=%d", cache->ways_of_associativity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		seq_puts(m, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) static inline enum cache_type get_cache_type(struct cache_info *ci, int level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	if (level >= CACHE_MAX_LEVEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		return CACHE_TYPE_NOCACHE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	ci += level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		return CACHE_TYPE_NOCACHE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	return cache_type_map[ci->type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static inline unsigned long ecag(int ai, int li, int ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	return __ecag(ECAG_CACHE_ATTRIBUTE, ai << 4 | li << 1 | ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static void ci_leaf_init(struct cacheinfo *this_leaf, int private,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 			 enum cache_type type, unsigned int level, int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	int ti, num_sets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (type == CACHE_TYPE_INST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		ti = CACHE_TI_INSTRUCTION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		ti = CACHE_TI_UNIFIED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	this_leaf->level = level + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	this_leaf->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	this_leaf->size = ecag(EXTRACT_SIZE, level, ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	num_sets = this_leaf->size / this_leaf->coherency_line_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	num_sets /= this_leaf->ways_of_associativity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	this_leaf->number_of_sets = num_sets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	if (!private)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		this_leaf->disable_sysfs = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) int init_cache_level(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	unsigned int level = 0, leaves = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	union cache_topology ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	enum cache_type ctype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	if (!test_facility(34))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	if (!this_cpu_ci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		ctype = get_cache_type(&ct.ci[0], level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		if (ctype == CACHE_TYPE_NOCACHE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		/* Separate instruction and data caches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	} while (++level < CACHE_MAX_LEVEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	this_cpu_ci->num_levels = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	this_cpu_ci->num_leaves = leaves;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int populate_cache_leaves(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	unsigned int level, idx, pvt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	union cache_topology ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	enum cache_type ctype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	if (!test_facility(34))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	for (idx = 0, level = 0; level < this_cpu_ci->num_levels &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	     idx < this_cpu_ci->num_leaves; idx++, level++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		if (!this_leaf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		ctype = get_cache_type(&ct.ci[0], level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		if (ctype == CACHE_TYPE_SEPARATE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			ci_leaf_init(this_leaf++, pvt, ctype, level, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }