9696#include <asm/cpu_device_id.h>
9797#include <asm/intel-family.h>
9898#include "../perf_event.h"
99+ #include "../probe.h"
99100
100101MODULE_LICENSE ("GPL" );
101102
@@ -144,25 +145,42 @@ enum perf_cstate_core_events {
144145 PERF_CSTATE_CORE_EVENT_MAX ,
145146};
146147
147- PMU_EVENT_ATTR_STRING (c1 - residency , evattr_cstate_core_c1 , "event=0x00" );
148- PMU_EVENT_ATTR_STRING (c3 - residency , evattr_cstate_core_c3 , "event=0x01" );
149- PMU_EVENT_ATTR_STRING (c6 - residency , evattr_cstate_core_c6 , "event=0x02" );
150- PMU_EVENT_ATTR_STRING (c7 - residency , evattr_cstate_core_c7 , "event=0x03" );
148+ PMU_EVENT_ATTR_STRING (c1 - residency , attr_cstate_core_c1 , "event=0x00" );
149+ PMU_EVENT_ATTR_STRING (c3 - residency , attr_cstate_core_c3 , "event=0x01" );
150+ PMU_EVENT_ATTR_STRING (c6 - residency , attr_cstate_core_c6 , "event=0x02" );
151+ PMU_EVENT_ATTR_STRING (c7 - residency , attr_cstate_core_c7 , "event=0x03" );
151152
152- static struct perf_cstate_msr core_msr [] = {
153- [PERF_CSTATE_CORE_C1_RES ] = { MSR_CORE_C1_RES , & evattr_cstate_core_c1 },
154- [PERF_CSTATE_CORE_C3_RES ] = { MSR_CORE_C3_RESIDENCY , & evattr_cstate_core_c3 },
155- [PERF_CSTATE_CORE_C6_RES ] = { MSR_CORE_C6_RESIDENCY , & evattr_cstate_core_c6 },
156- [PERF_CSTATE_CORE_C7_RES ] = { MSR_CORE_C7_RESIDENCY , & evattr_cstate_core_c7 },
153+ static unsigned long core_msr_mask ;
154+
155+ PMU_EVENT_GROUP (events , cstate_core_c1 );
156+ PMU_EVENT_GROUP (events , cstate_core_c3 );
157+ PMU_EVENT_GROUP (events , cstate_core_c6 );
158+ PMU_EVENT_GROUP (events , cstate_core_c7 );
159+
160+ static bool test_msr (int idx , void * data )
161+ {
162+ return test_bit (idx , (unsigned long * ) data );
163+ }
164+
165+ static struct perf_msr core_msr [] = {
166+ [PERF_CSTATE_CORE_C1_RES ] = { MSR_CORE_C1_RES , & group_cstate_core_c1 , test_msr },
167+ [PERF_CSTATE_CORE_C3_RES ] = { MSR_CORE_C3_RESIDENCY , & group_cstate_core_c3 , test_msr },
168+ [PERF_CSTATE_CORE_C6_RES ] = { MSR_CORE_C6_RESIDENCY , & group_cstate_core_c6 , test_msr },
169+ [PERF_CSTATE_CORE_C7_RES ] = { MSR_CORE_C7_RESIDENCY , & group_cstate_core_c7 , test_msr },
157170};
158171
159- static struct attribute * core_events_attrs [ PERF_CSTATE_CORE_EVENT_MAX + 1 ] = {
172+ static struct attribute * attrs_empty [ ] = {
160173 NULL ,
161174};
162175
176+ /*
177+ * There are no default events, but we need to create
178+ * "events" group (with empty attrs) before updating
179+ * it with detected events.
180+ */
163181static struct attribute_group core_events_attr_group = {
164182 .name = "events" ,
165- .attrs = core_events_attrs ,
183+ .attrs = attrs_empty ,
166184};
167185
168186DEFINE_CSTATE_FORMAT_ATTR (core_event , event , "config:0-63" );
@@ -211,31 +229,37 @@ enum perf_cstate_pkg_events {
211229 PERF_CSTATE_PKG_EVENT_MAX ,
212230};
213231
214- PMU_EVENT_ATTR_STRING (c2 - residency , evattr_cstate_pkg_c2 , "event=0x00" );
215- PMU_EVENT_ATTR_STRING (c3 - residency , evattr_cstate_pkg_c3 , "event=0x01" );
216- PMU_EVENT_ATTR_STRING (c6 - residency , evattr_cstate_pkg_c6 , "event=0x02" );
217- PMU_EVENT_ATTR_STRING (c7 - residency , evattr_cstate_pkg_c7 , "event=0x03" );
218- PMU_EVENT_ATTR_STRING (c8 - residency , evattr_cstate_pkg_c8 , "event=0x04" );
219- PMU_EVENT_ATTR_STRING (c9 - residency , evattr_cstate_pkg_c9 , "event=0x05" );
220- PMU_EVENT_ATTR_STRING (c10 - residency , evattr_cstate_pkg_c10 , "event=0x06" );
221-
222- static struct perf_cstate_msr pkg_msr [] = {
223- [PERF_CSTATE_PKG_C2_RES ] = { MSR_PKG_C2_RESIDENCY , & evattr_cstate_pkg_c2 },
224- [PERF_CSTATE_PKG_C3_RES ] = { MSR_PKG_C3_RESIDENCY , & evattr_cstate_pkg_c3 },
225- [PERF_CSTATE_PKG_C6_RES ] = { MSR_PKG_C6_RESIDENCY , & evattr_cstate_pkg_c6 },
226- [PERF_CSTATE_PKG_C7_RES ] = { MSR_PKG_C7_RESIDENCY , & evattr_cstate_pkg_c7 },
227- [PERF_CSTATE_PKG_C8_RES ] = { MSR_PKG_C8_RESIDENCY , & evattr_cstate_pkg_c8 },
228- [PERF_CSTATE_PKG_C9_RES ] = { MSR_PKG_C9_RESIDENCY , & evattr_cstate_pkg_c9 },
229- [PERF_CSTATE_PKG_C10_RES ] = { MSR_PKG_C10_RESIDENCY , & evattr_cstate_pkg_c10 },
230- };
231-
232- static struct attribute * pkg_events_attrs [PERF_CSTATE_PKG_EVENT_MAX + 1 ] = {
233- NULL ,
232+ PMU_EVENT_ATTR_STRING (c2 - residency , attr_cstate_pkg_c2 , "event=0x00" );
233+ PMU_EVENT_ATTR_STRING (c3 - residency , attr_cstate_pkg_c3 , "event=0x01" );
234+ PMU_EVENT_ATTR_STRING (c6 - residency , attr_cstate_pkg_c6 , "event=0x02" );
235+ PMU_EVENT_ATTR_STRING (c7 - residency , attr_cstate_pkg_c7 , "event=0x03" );
236+ PMU_EVENT_ATTR_STRING (c8 - residency , attr_cstate_pkg_c8 , "event=0x04" );
237+ PMU_EVENT_ATTR_STRING (c9 - residency , attr_cstate_pkg_c9 , "event=0x05" );
238+ PMU_EVENT_ATTR_STRING (c10 - residency , attr_cstate_pkg_c10 , "event=0x06" );
239+
240+ static unsigned long pkg_msr_mask ;
241+
242+ PMU_EVENT_GROUP (events , cstate_pkg_c2 );
243+ PMU_EVENT_GROUP (events , cstate_pkg_c3 );
244+ PMU_EVENT_GROUP (events , cstate_pkg_c6 );
245+ PMU_EVENT_GROUP (events , cstate_pkg_c7 );
246+ PMU_EVENT_GROUP (events , cstate_pkg_c8 );
247+ PMU_EVENT_GROUP (events , cstate_pkg_c9 );
248+ PMU_EVENT_GROUP (events , cstate_pkg_c10 );
249+
250+ static struct perf_msr pkg_msr [] = {
251+ [PERF_CSTATE_PKG_C2_RES ] = { MSR_PKG_C2_RESIDENCY , & group_cstate_pkg_c2 , test_msr },
252+ [PERF_CSTATE_PKG_C3_RES ] = { MSR_PKG_C3_RESIDENCY , & group_cstate_pkg_c3 , test_msr },
253+ [PERF_CSTATE_PKG_C6_RES ] = { MSR_PKG_C6_RESIDENCY , & group_cstate_pkg_c6 , test_msr },
254+ [PERF_CSTATE_PKG_C7_RES ] = { MSR_PKG_C7_RESIDENCY , & group_cstate_pkg_c7 , test_msr },
255+ [PERF_CSTATE_PKG_C8_RES ] = { MSR_PKG_C8_RESIDENCY , & group_cstate_pkg_c8 , test_msr },
256+ [PERF_CSTATE_PKG_C9_RES ] = { MSR_PKG_C9_RESIDENCY , & group_cstate_pkg_c9 , test_msr },
257+ [PERF_CSTATE_PKG_C10_RES ] = { MSR_PKG_C10_RESIDENCY , & group_cstate_pkg_c10 , test_msr },
234258};
235259
236260static struct attribute_group pkg_events_attr_group = {
237261 .name = "events" ,
238- .attrs = pkg_events_attrs ,
262+ .attrs = attrs_empty ,
239263};
240264
241265DEFINE_CSTATE_FORMAT_ATTR (pkg_event , event , "config:0-63" );
@@ -289,7 +313,8 @@ static int cstate_pmu_event_init(struct perf_event *event)
289313 if (event -> pmu == & cstate_core_pmu ) {
290314 if (cfg >= PERF_CSTATE_CORE_EVENT_MAX )
291315 return - EINVAL ;
292- if (!core_msr [cfg ].attr )
316+ cfg = array_index_nospec ((unsigned long )cfg , PERF_CSTATE_CORE_EVENT_MAX );
317+ if (!(core_msr_mask & (1 << cfg )))
293318 return - EINVAL ;
294319 event -> hw .event_base = core_msr [cfg ].msr ;
295320 cpu = cpumask_any_and (& cstate_core_cpu_mask ,
@@ -298,7 +323,7 @@ static int cstate_pmu_event_init(struct perf_event *event)
298323 if (cfg >= PERF_CSTATE_PKG_EVENT_MAX )
299324 return - EINVAL ;
300325 cfg = array_index_nospec ((unsigned long )cfg , PERF_CSTATE_PKG_EVENT_MAX );
301- if (!pkg_msr [ cfg ]. attr )
326+ if (!( pkg_msr_mask & ( 1 << cfg )) )
302327 return - EINVAL ;
303328 event -> hw .event_base = pkg_msr [cfg ].msr ;
304329 cpu = cpumask_any_and (& cstate_pkg_cpu_mask ,
@@ -421,8 +446,28 @@ static int cstate_cpu_init(unsigned int cpu)
421446 return 0 ;
422447}
423448
449+ const struct attribute_group * core_attr_update [] = {
450+ & group_cstate_core_c1 ,
451+ & group_cstate_core_c3 ,
452+ & group_cstate_core_c6 ,
453+ & group_cstate_core_c7 ,
454+ NULL ,
455+ };
456+
457+ const struct attribute_group * pkg_attr_update [] = {
458+ & group_cstate_pkg_c2 ,
459+ & group_cstate_pkg_c3 ,
460+ & group_cstate_pkg_c6 ,
461+ & group_cstate_pkg_c7 ,
462+ & group_cstate_pkg_c8 ,
463+ & group_cstate_pkg_c9 ,
464+ & group_cstate_pkg_c10 ,
465+ NULL ,
466+ };
467+
424468static struct pmu cstate_core_pmu = {
425469 .attr_groups = core_attr_groups ,
470+ .attr_update = core_attr_update ,
426471 .name = "cstate_core" ,
427472 .task_ctx_nr = perf_invalid_context ,
428473 .event_init = cstate_pmu_event_init ,
@@ -437,6 +482,7 @@ static struct pmu cstate_core_pmu = {
437482
438483static struct pmu cstate_pkg_pmu = {
439484 .attr_groups = pkg_attr_groups ,
485+ .attr_update = pkg_attr_update ,
440486 .name = "cstate_pkg" ,
441487 .task_ctx_nr = perf_invalid_context ,
442488 .event_init = cstate_pmu_event_init ,
@@ -585,31 +631,6 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
585631};
586632MODULE_DEVICE_TABLE (x86cpu , intel_cstates_match );
587633
588- /*
589- * Probe the cstate events and insert the available one into sysfs attrs
590- * Return false if there are no available events.
591- */
592- static bool __init cstate_probe_msr (const unsigned long evmsk , int max ,
593- struct perf_cstate_msr * msr ,
594- struct attribute * * attrs )
595- {
596- bool found = false;
597- unsigned int bit ;
598- u64 val ;
599-
600- for (bit = 0 ; bit < max ; bit ++ ) {
601- if (test_bit (bit , & evmsk ) && !rdmsrl_safe (msr [bit ].msr , & val )) {
602- * attrs ++ = & msr [bit ].attr -> attr .attr ;
603- found = true;
604- } else {
605- msr [bit ].attr = NULL ;
606- }
607- }
608- * attrs = NULL ;
609-
610- return found ;
611- }
612-
613634static int __init cstate_probe (const struct cstate_model * cm )
614635{
615636 /* SLM has different MSR for PKG C6 */
@@ -621,13 +642,14 @@ static int __init cstate_probe(const struct cstate_model *cm)
621642 pkg_msr [PERF_CSTATE_CORE_C6_RES ].msr = MSR_KNL_CORE_C6_RESIDENCY ;
622643
623644
624- has_cstate_core = cstate_probe_msr (cm -> core_events ,
625- PERF_CSTATE_CORE_EVENT_MAX ,
626- core_msr , core_events_attrs );
645+ core_msr_mask = perf_msr_probe (core_msr , PERF_CSTATE_CORE_EVENT_MAX ,
646+ true, (void * ) & cm -> core_events );
647+
648+ pkg_msr_mask = perf_msr_probe (pkg_msr , PERF_CSTATE_PKG_EVENT_MAX ,
649+ true, (void * ) & cm -> pkg_events );
627650
628- has_cstate_pkg = cstate_probe_msr (cm -> pkg_events ,
629- PERF_CSTATE_PKG_EVENT_MAX ,
630- pkg_msr , pkg_events_attrs );
651+ has_cstate_core = !!core_msr_mask ;
652+ has_cstate_pkg = !!pkg_msr_mask ;
631653
632654 return (has_cstate_core || has_cstate_pkg ) ? 0 : - ENODEV ;
633655}
0 commit comments