@@ -120,6 +120,8 @@ enum m1_pmu_events {
120120 */
121121 M1_PMU_CFG_COUNT_USER = BIT (8 ),
122122 M1_PMU_CFG_COUNT_KERNEL = BIT (9 ),
123+ M1_PMU_CFG_COUNT_HOST = BIT (10 ),
124+ M1_PMU_CFG_COUNT_GUEST = BIT (11 ),
123125};
124126
125127/*
@@ -327,11 +329,10 @@ static void m1_pmu_disable_counter_interrupt(unsigned int index)
327329 __m1_pmu_enable_counter_interrupt (index , false);
328330}
329331
330- static void m1_pmu_configure_counter (unsigned int index , u8 event ,
331- bool user , bool kernel )
332+ static void __m1_pmu_configure_event_filter (unsigned int index , bool user ,
333+ bool kernel , bool host )
332334{
333- u64 val , user_bit , kernel_bit ;
334- int shift ;
335+ u64 clear , set , user_bit , kernel_bit ;
335336
336337 switch (index ) {
337338 case 0 ... 7 :
@@ -346,19 +347,27 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
346347 BUG ();
347348 }
348349
349- val = read_sysreg_s (SYS_IMP_APL_PMCR1_EL1 );
350-
350+ clear = set = 0 ;
351351 if (user )
352- val |= user_bit ;
352+ set |= user_bit ;
353353 else
354- val &= ~ user_bit ;
354+ clear |= user_bit ;
355355
356356 if (kernel )
357- val |= kernel_bit ;
357+ set |= kernel_bit ;
358358 else
359- val &= ~ kernel_bit ;
359+ clear |= kernel_bit ;
360360
361- write_sysreg_s (val , SYS_IMP_APL_PMCR1_EL1 );
361+ if (host )
362+ sysreg_clear_set_s (SYS_IMP_APL_PMCR1_EL1 , clear , set );
363+ else if (is_kernel_in_hyp_mode ())
364+ sysreg_clear_set_s (SYS_IMP_APL_PMCR1_EL12 , clear , set );
365+ }
366+
367+ static void __m1_pmu_configure_eventsel (unsigned int index , u8 event )
368+ {
369+ u64 clear = 0 , set = 0 ;
370+ int shift ;
362371
363372 /*
364373 * Counters 0 and 1 have fixed events. For anything else,
@@ -371,21 +380,32 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
371380 break ;
372381 case 2 ... 5 :
373382 shift = (index - 2 ) * 8 ;
374- val = read_sysreg_s (SYS_IMP_APL_PMESR0_EL1 );
375- val &= ~((u64 )0xff << shift );
376- val |= (u64 )event << shift ;
377- write_sysreg_s (val , SYS_IMP_APL_PMESR0_EL1 );
383+ clear |= (u64 )0xff << shift ;
384+ set |= (u64 )event << shift ;
385+ sysreg_clear_set_s (SYS_IMP_APL_PMESR0_EL1 , clear , set );
378386 break ;
379387 case 6 ... 9 :
380388 shift = (index - 6 ) * 8 ;
381- val = read_sysreg_s (SYS_IMP_APL_PMESR1_EL1 );
382- val &= ~((u64 )0xff << shift );
383- val |= (u64 )event << shift ;
384- write_sysreg_s (val , SYS_IMP_APL_PMESR1_EL1 );
389+ clear |= (u64 )0xff << shift ;
390+ set |= (u64 )event << shift ;
391+ sysreg_clear_set_s (SYS_IMP_APL_PMESR1_EL1 , clear , set );
385392 break ;
386393 }
387394}
388395
396+ static void m1_pmu_configure_counter (unsigned int index , unsigned long config_base )
397+ {
398+ bool kernel = config_base & M1_PMU_CFG_COUNT_KERNEL ;
399+ bool guest = config_base & M1_PMU_CFG_COUNT_GUEST ;
400+ bool host = config_base & M1_PMU_CFG_COUNT_HOST ;
401+ bool user = config_base & M1_PMU_CFG_COUNT_USER ;
402+ u8 evt = config_base & M1_PMU_CFG_EVENT ;
403+
404+ __m1_pmu_configure_event_filter (index , user && host , kernel && host , true);
405+ __m1_pmu_configure_event_filter (index , user && guest , kernel && guest , false);
406+ __m1_pmu_configure_eventsel (index , evt );
407+ }
408+
389409/* arm_pmu backend */
390410static void m1_pmu_enable_event (struct perf_event * event )
391411{
@@ -396,7 +416,7 @@ static void m1_pmu_enable_event(struct perf_event *event)
396416 user = event -> hw .config_base & M1_PMU_CFG_COUNT_USER ;
397417 kernel = event -> hw .config_base & M1_PMU_CFG_COUNT_KERNEL ;
398418
399- m1_pmu_configure_counter (event -> hw .idx , evt , user , kernel );
419+ m1_pmu_configure_counter (event -> hw .idx , event -> hw . config_base );
400420 m1_pmu_enable_counter (event -> hw .idx );
401421 m1_pmu_enable_counter_interrupt (event -> hw .idx );
402422 isb ();
@@ -554,14 +574,18 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
554574{
555575 unsigned long config_base = 0 ;
556576
557- if (!attr -> exclude_guest ) {
577+ if (!attr -> exclude_guest && ! is_kernel_in_hyp_mode () ) {
558578 pr_debug ("ARM performance counters do not support mode exclusion\n" );
559579 return - EOPNOTSUPP ;
560580 }
561581 if (!attr -> exclude_kernel )
562582 config_base |= M1_PMU_CFG_COUNT_KERNEL ;
563583 if (!attr -> exclude_user )
564584 config_base |= M1_PMU_CFG_COUNT_USER ;
585+ if (!attr -> exclude_host )
586+ config_base |= M1_PMU_CFG_COUNT_HOST ;
587+ if (!attr -> exclude_guest )
588+ config_base |= M1_PMU_CFG_COUNT_GUEST ;
565589
566590 event -> config_base = config_base ;
567591
0 commit comments