2 * Extract CPU cache information and expose them via sysfs.
4 * Copyright IBM Corp. 2012
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
8 #include <linux/seq_file.h>
10 #include <linux/cacheinfo.h>
11 #include <asm/facility.h>
14 CACHE_SCOPE_NOTEXISTS
,
31 EXTRACT_ASSOCIATIVITY
,
42 unsigned char scope
: 2;
43 unsigned char type
: 2;
46 #define CACHE_MAX_LEVEL 8
47 union cache_topology
{
48 struct cache_info ci
[CACHE_MAX_LEVEL
];
49 unsigned long long raw
;
52 static const char * const cache_type_string
[] = {
60 static const enum cache_type cache_type_map
[] = {
61 [CTYPE_SEPARATE
] = CACHE_TYPE_SEPARATE
,
62 [CTYPE_DATA
] = CACHE_TYPE_DATA
,
63 [CTYPE_INSTRUCTION
] = CACHE_TYPE_INST
,
64 [CTYPE_UNIFIED
] = CACHE_TYPE_UNIFIED
,
67 void show_cacheinfo(struct seq_file
*m
)
69 struct cpu_cacheinfo
*this_cpu_ci
;
70 struct cacheinfo
*cache
;
74 this_cpu_ci
= get_cpu_cacheinfo(cpumask_any(cpu_online_mask
));
75 for (idx
= 0; idx
< this_cpu_ci
->num_leaves
; idx
++) {
76 cache
= this_cpu_ci
->info_list
+ idx
;
77 seq_printf(m
, "cache%-11d: ", idx
);
78 seq_printf(m
, "level=%d ", cache
->level
);
79 seq_printf(m
, "type=%s ", cache_type_string
[cache
->type
]);
80 seq_printf(m
, "scope=%s ",
81 cache
->disable_sysfs
? "Shared" : "Private");
82 seq_printf(m
, "size=%dK ", cache
->size
>> 10);
83 seq_printf(m
, "line_size=%u ", cache
->coherency_line_size
);
84 seq_printf(m
, "associativity=%d", cache
->ways_of_associativity
);
90 static inline enum cache_type
get_cache_type(struct cache_info
*ci
, int level
)
92 if (level
>= CACHE_MAX_LEVEL
)
93 return CACHE_TYPE_NOCACHE
;
97 if (ci
->scope
!= CACHE_SCOPE_SHARED
&& ci
->scope
!= CACHE_SCOPE_PRIVATE
)
98 return CACHE_TYPE_NOCACHE
;
100 return cache_type_map
[ci
->type
];
103 static inline unsigned long ecag(int ai
, int li
, int ti
)
105 unsigned long cmd
, val
;
107 cmd
= ai
<< 4 | li
<< 1 | ti
;
108 asm volatile(".insn rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */
109 : "=d" (val
) : "a" (cmd
));
113 static void ci_leaf_init(struct cacheinfo
*this_leaf
, int private,
114 enum cache_type type
, unsigned int level
, int cpu
)
118 if (type
== CACHE_TYPE_INST
)
119 ti
= CACHE_TI_INSTRUCTION
;
121 ti
= CACHE_TI_UNIFIED
;
123 this_leaf
->level
= level
+ 1;
124 this_leaf
->type
= type
;
125 this_leaf
->coherency_line_size
= ecag(EXTRACT_LINE_SIZE
, level
, ti
);
126 this_leaf
->ways_of_associativity
= ecag(EXTRACT_ASSOCIATIVITY
,
128 this_leaf
->size
= ecag(EXTRACT_SIZE
, level
, ti
);
130 num_sets
= this_leaf
->size
/ this_leaf
->coherency_line_size
;
131 num_sets
/= this_leaf
->ways_of_associativity
;
132 this_leaf
->number_of_sets
= num_sets
;
133 cpumask_set_cpu(cpu
, &this_leaf
->shared_cpu_map
);
135 this_leaf
->disable_sysfs
= true;
138 int init_cache_level(unsigned int cpu
)
140 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
141 unsigned int level
= 0, leaves
= 0;
142 union cache_topology ct
;
143 enum cache_type ctype
;
148 ct
.raw
= ecag(EXTRACT_TOPOLOGY
, 0, 0);
150 ctype
= get_cache_type(&ct
.ci
[0], level
);
151 if (ctype
== CACHE_TYPE_NOCACHE
)
153 /* Separate instruction and data caches */
154 leaves
+= (ctype
== CACHE_TYPE_SEPARATE
) ? 2 : 1;
155 } while (++level
< CACHE_MAX_LEVEL
);
157 this_cpu_ci
->num_levels
= level
;
158 this_cpu_ci
->num_leaves
= leaves
;
163 int populate_cache_leaves(unsigned int cpu
)
165 unsigned int level
, idx
, pvt
;
166 union cache_topology ct
;
167 enum cache_type ctype
;
168 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
169 struct cacheinfo
*this_leaf
= this_cpu_ci
->info_list
;
171 ct
.raw
= ecag(EXTRACT_TOPOLOGY
, 0, 0);
172 for (idx
= 0, level
= 0; level
< this_cpu_ci
->num_levels
&&
173 idx
< this_cpu_ci
->num_leaves
; idx
++, level
++) {
177 pvt
= (ct
.ci
[level
].scope
== CACHE_SCOPE_PRIVATE
) ? 1 : 0;
178 ctype
= get_cache_type(&ct
.ci
[0], level
);
179 if (ctype
== CACHE_TYPE_SEPARATE
) {
180 ci_leaf_init(this_leaf
++, pvt
, CACHE_TYPE_DATA
, level
, cpu
);
181 ci_leaf_init(this_leaf
++, pvt
, CACHE_TYPE_INST
, level
, cpu
);
183 ci_leaf_init(this_leaf
++, pvt
, ctype
, level
, cpu
);