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
;
73 if (!test_facility(34))
75 this_cpu_ci
= get_cpu_cacheinfo(cpumask_any(cpu_online_mask
));
76 for (idx
= 0; idx
< this_cpu_ci
->num_leaves
; idx
++) {
77 cache
= this_cpu_ci
->info_list
+ idx
;
78 seq_printf(m
, "cache%-11d: ", idx
);
79 seq_printf(m
, "level=%d ", cache
->level
);
80 seq_printf(m
, "type=%s ", cache_type_string
[cache
->type
]);
81 seq_printf(m
, "scope=%s ",
82 cache
->disable_sysfs
? "Shared" : "Private");
83 seq_printf(m
, "size=%dK ", cache
->size
>> 10);
84 seq_printf(m
, "line_size=%u ", cache
->coherency_line_size
);
85 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
;
95 if (ci
->scope
!= CACHE_SCOPE_SHARED
&& ci
->scope
!= CACHE_SCOPE_PRIVATE
)
96 return CACHE_TYPE_NOCACHE
;
97 return cache_type_map
[ci
->type
];
100 static inline unsigned long ecag(int ai
, int li
, int ti
)
102 return __ecag(ECAG_CACHE_ATTRIBUTE
, ai
<< 4 | li
<< 1 | ti
);
105 static void ci_leaf_init(struct cacheinfo
*this_leaf
, int private,
106 enum cache_type type
, unsigned int level
, int cpu
)
110 if (type
== CACHE_TYPE_INST
)
111 ti
= CACHE_TI_INSTRUCTION
;
113 ti
= CACHE_TI_UNIFIED
;
114 this_leaf
->level
= level
+ 1;
115 this_leaf
->type
= type
;
116 this_leaf
->coherency_line_size
= ecag(EXTRACT_LINE_SIZE
, level
, ti
);
117 this_leaf
->ways_of_associativity
= ecag(EXTRACT_ASSOCIATIVITY
, level
, ti
);
118 this_leaf
->size
= ecag(EXTRACT_SIZE
, level
, ti
);
119 num_sets
= this_leaf
->size
/ this_leaf
->coherency_line_size
;
120 num_sets
/= this_leaf
->ways_of_associativity
;
121 this_leaf
->number_of_sets
= num_sets
;
122 cpumask_set_cpu(cpu
, &this_leaf
->shared_cpu_map
);
124 this_leaf
->disable_sysfs
= true;
127 int init_cache_level(unsigned int cpu
)
129 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
130 unsigned int level
= 0, leaves
= 0;
131 union cache_topology ct
;
132 enum cache_type ctype
;
134 if (!test_facility(34))
138 ct
.raw
= ecag(EXTRACT_TOPOLOGY
, 0, 0);
140 ctype
= get_cache_type(&ct
.ci
[0], level
);
141 if (ctype
== CACHE_TYPE_NOCACHE
)
143 /* Separate instruction and data caches */
144 leaves
+= (ctype
== CACHE_TYPE_SEPARATE
) ? 2 : 1;
145 } while (++level
< CACHE_MAX_LEVEL
);
146 this_cpu_ci
->num_levels
= level
;
147 this_cpu_ci
->num_leaves
= leaves
;
151 int populate_cache_leaves(unsigned int cpu
)
153 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
154 struct cacheinfo
*this_leaf
= this_cpu_ci
->info_list
;
155 unsigned int level
, idx
, pvt
;
156 union cache_topology ct
;
157 enum cache_type ctype
;
159 if (!test_facility(34))
161 ct
.raw
= ecag(EXTRACT_TOPOLOGY
, 0, 0);
162 for (idx
= 0, level
= 0; level
< this_cpu_ci
->num_levels
&&
163 idx
< this_cpu_ci
->num_leaves
; idx
++, level
++) {
166 pvt
= (ct
.ci
[level
].scope
== CACHE_SCOPE_PRIVATE
) ? 1 : 0;
167 ctype
= get_cache_type(&ct
.ci
[0], level
);
168 if (ctype
== CACHE_TYPE_SEPARATE
) {
169 ci_leaf_init(this_leaf
++, pvt
, CACHE_TYPE_DATA
, level
, cpu
);
170 ci_leaf_init(this_leaf
++, pvt
, CACHE_TYPE_INST
, level
, cpu
);
172 ci_leaf_init(this_leaf
++, pvt
, ctype
, level
, cpu
);