@@ -4598,6 +4598,16 @@ static void intel_pmu_check_num_counters(int *num_counters,
4598
4598
int * num_counters_fixed ,
4599
4599
u64 * intel_ctrl , u64 fixed_mask );
4600
4600
4601
+ static inline bool intel_pmu_broken_perf_cap (void )
4602
+ {
4603
+ /* The Perf Metric (Bit 15) is always cleared */
4604
+ if ((boot_cpu_data .x86_model == INTEL_FAM6_METEORLAKE ) ||
4605
+ (boot_cpu_data .x86_model == INTEL_FAM6_METEORLAKE_L ))
4606
+ return true;
4607
+
4608
+ return false;
4609
+ }
4610
+
4601
4611
static void update_pmu_cap (struct x86_hybrid_pmu * pmu )
4602
4612
{
4603
4613
unsigned int sub_bitmaps = cpuid_eax (ARCH_PERFMON_EXT_LEAF );
@@ -4610,7 +4620,27 @@ static void update_pmu_cap(struct x86_hybrid_pmu *pmu)
4610
4620
pmu -> num_counters_fixed = fls (ebx );
4611
4621
intel_pmu_check_num_counters (& pmu -> num_counters , & pmu -> num_counters_fixed ,
4612
4622
& pmu -> intel_ctrl , ebx );
4623
+ pmu -> max_pebs_events = min_t (unsigned , MAX_PEBS_EVENTS , pmu -> num_counters );
4624
+ pmu -> unconstrained = (struct event_constraint )
4625
+ __EVENT_CONSTRAINT (0 , (1ULL << pmu -> num_counters ) - 1 ,
4626
+ 0 , pmu -> num_counters , 0 , 0 );
4613
4627
}
4628
+
4629
+
4630
+ if (!intel_pmu_broken_perf_cap ()) {
4631
+ /* Perf Metric (Bit 15) and PEBS via PT (Bit 16) are hybrid enumeration */
4632
+ rdmsrl (MSR_IA32_PERF_CAPABILITIES , pmu -> intel_cap .capabilities );
4633
+ }
4634
+
4635
+ if (pmu -> intel_cap .perf_metrics )
4636
+ pmu -> intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS ;
4637
+ else
4638
+ pmu -> intel_ctrl &= ~(1ULL << GLOBAL_CTRL_EN_PERF_METRICS );
4639
+
4640
+ if (pmu -> intel_cap .pebs_output_pt_available )
4641
+ pmu -> pmu .capabilities |= PERF_PMU_CAP_AUX_OUTPUT ;
4642
+ else
4643
+ pmu -> pmu .capabilities |= ~PERF_PMU_CAP_AUX_OUTPUT ;
4614
4644
}
4615
4645
4616
4646
static struct x86_hybrid_pmu * find_hybrid_pmu_for_cpu (void )
@@ -5915,10 +5945,52 @@ static void intel_pmu_check_hybrid_pmus(u64 fixed_mask)
5915
5945
}
5916
5946
}
5917
5947
5918
- static __always_inline bool is_mtl (u8 x86_model )
5948
+ static const struct { enum hybrid_pmu_type id ; char * name ; } intel_hybrid_pmu_type_map [] __initconst = {
5949
+ { hybrid_small , "cpu_atom" },
5950
+ { hybrid_big , "cpu_core" },
5951
+ };
5952
+
5953
+ static __always_inline int intel_pmu_init_hybrid (enum hybrid_pmu_type pmus )
5919
5954
{
5920
- return (x86_model == INTEL_FAM6_METEORLAKE ) ||
5921
- (x86_model == INTEL_FAM6_METEORLAKE_L );
5955
+ unsigned long pmus_mask = pmus ;
5956
+ struct x86_hybrid_pmu * pmu ;
5957
+ int idx = 0 , bit ;
5958
+
5959
+ x86_pmu .num_hybrid_pmus = hweight_long (pmus_mask );
5960
+ x86_pmu .hybrid_pmu = kcalloc (x86_pmu .num_hybrid_pmus ,
5961
+ sizeof (struct x86_hybrid_pmu ),
5962
+ GFP_KERNEL );
5963
+ if (!x86_pmu .hybrid_pmu )
5964
+ return - ENOMEM ;
5965
+
5966
+ static_branch_enable (& perf_is_hybrid );
5967
+ x86_pmu .filter = intel_pmu_filter ;
5968
+
5969
+ for_each_set_bit (bit , & pmus_mask , ARRAY_SIZE (intel_hybrid_pmu_type_map )) {
5970
+ pmu = & x86_pmu .hybrid_pmu [idx ++ ];
5971
+ pmu -> pmu_type = intel_hybrid_pmu_type_map [bit ].id ;
5972
+ pmu -> name = intel_hybrid_pmu_type_map [bit ].name ;
5973
+
5974
+ pmu -> num_counters = x86_pmu .num_counters ;
5975
+ pmu -> num_counters_fixed = x86_pmu .num_counters_fixed ;
5976
+ pmu -> max_pebs_events = min_t (unsigned , MAX_PEBS_EVENTS , pmu -> num_counters );
5977
+ pmu -> unconstrained = (struct event_constraint )
5978
+ __EVENT_CONSTRAINT (0 , (1ULL << pmu -> num_counters ) - 1 ,
5979
+ 0 , pmu -> num_counters , 0 , 0 );
5980
+
5981
+ pmu -> intel_cap .capabilities = x86_pmu .intel_cap .capabilities ;
5982
+ if (pmu -> pmu_type & hybrid_small ) {
5983
+ pmu -> intel_cap .perf_metrics = 0 ;
5984
+ pmu -> intel_cap .pebs_output_pt_available = 1 ;
5985
+ pmu -> mid_ack = true;
5986
+ } else if (pmu -> pmu_type & hybrid_big ) {
5987
+ pmu -> intel_cap .perf_metrics = 1 ;
5988
+ pmu -> intel_cap .pebs_output_pt_available = 0 ;
5989
+ pmu -> late_ack = true;
5990
+ }
5991
+ }
5992
+
5993
+ return 0 ;
5922
5994
}
5923
5995
5924
5996
static __always_inline void intel_pmu_init_glc (struct pmu * pmu )
@@ -6602,23 +6674,14 @@ __init int intel_pmu_init(void)
6602
6674
case INTEL_FAM6_RAPTORLAKE :
6603
6675
case INTEL_FAM6_RAPTORLAKE_P :
6604
6676
case INTEL_FAM6_RAPTORLAKE_S :
6605
- case INTEL_FAM6_METEORLAKE :
6606
- case INTEL_FAM6_METEORLAKE_L :
6607
6677
/*
6608
6678
* Alder Lake has 2 types of CPU, core and atom.
6609
6679
*
6610
6680
* Initialize the common PerfMon capabilities here.
6611
6681
*/
6612
- x86_pmu .hybrid_pmu = kcalloc (X86_HYBRID_NUM_PMUS ,
6613
- sizeof (struct x86_hybrid_pmu ),
6614
- GFP_KERNEL );
6615
- if (!x86_pmu .hybrid_pmu )
6616
- return - ENOMEM ;
6617
- static_branch_enable (& perf_is_hybrid );
6618
- x86_pmu .num_hybrid_pmus = X86_HYBRID_NUM_PMUS ;
6682
+ intel_pmu_init_hybrid (hybrid_big_small );
6619
6683
6620
6684
x86_pmu .pebs_latency_data = adl_latency_data_small ;
6621
- x86_pmu .filter = intel_pmu_filter ;
6622
6685
x86_pmu .get_event_constraints = adl_get_event_constraints ;
6623
6686
x86_pmu .hw_config = adl_hw_config ;
6624
6687
x86_pmu .get_hybrid_cpu_type = adl_get_hybrid_cpu_type ;
@@ -6631,10 +6694,7 @@ __init int intel_pmu_init(void)
6631
6694
6632
6695
/* Initialize big core specific PerfMon capabilities.*/
6633
6696
pmu = & x86_pmu .hybrid_pmu [X86_HYBRID_PMU_CORE_IDX ];
6634
- pmu -> name = "cpu_core" ;
6635
- pmu -> pmu_type = hybrid_big ;
6636
6697
intel_pmu_init_glc (& pmu -> pmu );
6637
- pmu -> late_ack = true;
6638
6698
if (cpu_feature_enabled (X86_FEATURE_HYBRID_CPU )) {
6639
6699
pmu -> num_counters = x86_pmu .num_counters + 2 ;
6640
6700
pmu -> num_counters_fixed = x86_pmu .num_counters_fixed + 1 ;
@@ -6659,45 +6719,45 @@ __init int intel_pmu_init(void)
6659
6719
pmu -> unconstrained = (struct event_constraint )
6660
6720
__EVENT_CONSTRAINT (0 , (1ULL << pmu -> num_counters ) - 1 ,
6661
6721
0 , pmu -> num_counters , 0 , 0 );
6662
- pmu -> intel_cap .capabilities = x86_pmu .intel_cap .capabilities ;
6663
- pmu -> intel_cap .perf_metrics = 1 ;
6664
- pmu -> intel_cap .pebs_output_pt_available = 0 ;
6665
-
6666
6722
pmu -> extra_regs = intel_glc_extra_regs ;
6667
6723
6668
6724
/* Initialize Atom core specific PerfMon capabilities.*/
6669
6725
pmu = & x86_pmu .hybrid_pmu [X86_HYBRID_PMU_ATOM_IDX ];
6670
- pmu -> name = "cpu_atom" ;
6671
- pmu -> pmu_type = hybrid_small ;
6672
6726
intel_pmu_init_grt (& pmu -> pmu );
6673
- pmu -> mid_ack = true;
6674
- pmu -> num_counters = x86_pmu .num_counters ;
6675
- pmu -> num_counters_fixed = x86_pmu .num_counters_fixed ;
6676
- pmu -> max_pebs_events = x86_pmu .max_pebs_events ;
6677
- pmu -> unconstrained = (struct event_constraint )
6678
- __EVENT_CONSTRAINT (0 , (1ULL << pmu -> num_counters ) - 1 ,
6679
- 0 , pmu -> num_counters , 0 , 0 );
6680
- pmu -> intel_cap .capabilities = x86_pmu .intel_cap .capabilities ;
6681
- pmu -> intel_cap .perf_metrics = 0 ;
6682
- pmu -> intel_cap .pebs_output_pt_available = 1 ;
6683
-
6684
- if (is_mtl (boot_cpu_data .x86_model )) {
6685
- x86_pmu .hybrid_pmu [X86_HYBRID_PMU_CORE_IDX ].extra_regs = intel_rwc_extra_regs ;
6686
- x86_pmu .pebs_latency_data = mtl_latency_data_small ;
6687
- extra_attr = boot_cpu_has (X86_FEATURE_RTM ) ?
6688
- mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr ;
6689
- mem_attr = mtl_hybrid_mem_attrs ;
6690
- intel_pmu_pebs_data_source_mtl ();
6691
- x86_pmu .get_event_constraints = mtl_get_event_constraints ;
6692
- pmu -> extra_regs = intel_cmt_extra_regs ;
6693
- pr_cont ("Meteorlake Hybrid events, " );
6694
- name = "meteorlake_hybrid" ;
6695
- } else {
6696
- x86_pmu .flags |= PMU_FL_MEM_LOADS_AUX ;
6697
- intel_pmu_pebs_data_source_adl ();
6698
- pr_cont ("Alderlake Hybrid events, " );
6699
- name = "alderlake_hybrid" ;
6700
- }
6727
+
6728
+ x86_pmu .flags |= PMU_FL_MEM_LOADS_AUX ;
6729
+ intel_pmu_pebs_data_source_adl ();
6730
+ pr_cont ("Alderlake Hybrid events, " );
6731
+ name = "alderlake_hybrid" ;
6732
+ break ;
6733
+
6734
+ case INTEL_FAM6_METEORLAKE :
6735
+ case INTEL_FAM6_METEORLAKE_L :
6736
+ intel_pmu_init_hybrid (hybrid_big_small );
6737
+
6738
+ x86_pmu .pebs_latency_data = mtl_latency_data_small ;
6739
+ x86_pmu .get_event_constraints = mtl_get_event_constraints ;
6740
+ x86_pmu .hw_config = adl_hw_config ;
6741
+
6742
+ td_attr = adl_hybrid_events_attrs ;
6743
+ mem_attr = mtl_hybrid_mem_attrs ;
6744
+ tsx_attr = adl_hybrid_tsx_attrs ;
6745
+ extra_attr = boot_cpu_has (X86_FEATURE_RTM ) ?
6746
+ mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr ;
6747
+
6748
+ /* Initialize big core specific PerfMon capabilities.*/
6749
+ pmu = & x86_pmu .hybrid_pmu [X86_HYBRID_PMU_CORE_IDX ];
6750
+ intel_pmu_init_glc (& pmu -> pmu );
6751
+ pmu -> extra_regs = intel_rwc_extra_regs ;
6752
+
6753
+ /* Initialize Atom core specific PerfMon capabilities.*/
6754
+ pmu = & x86_pmu .hybrid_pmu [X86_HYBRID_PMU_ATOM_IDX ];
6755
+ intel_pmu_init_grt (& pmu -> pmu );
6756
+ pmu -> extra_regs = intel_cmt_extra_regs ;
6757
+
6758
+ intel_pmu_pebs_data_source_mtl ();
6759
+ pr_cont ("Meteorlake Hybrid events, " );
6760
+ name = "meteorlake_hybrid" ;
6701
6761
break ;
6702
6762
6703
6763
default :
@@ -6809,7 +6869,7 @@ __init int intel_pmu_init(void)
6809
6869
if (!is_hybrid () && x86_pmu .intel_cap .perf_metrics )
6810
6870
x86_pmu .intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS ;
6811
6871
6812
- if (is_hybrid ())
6872
+ if (is_hybrid () && ! boot_cpu_has ( X86_FEATURE_ARCH_PERFMON_EXT ) )
6813
6873
intel_pmu_check_hybrid_pmus ((u64 )fixed_mask );
6814
6874
6815
6875
if (x86_pmu .intel_cap .pebs_timing_info )
0 commit comments