perf/x86/amd/brs: Move feature-specific functions
authorSandipan Das <sandipan.das@amd.com>
Thu, 11 Aug 2022 12:29:49 +0000 (17:59 +0530)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 26 Aug 2022 22:05:41 +0000 (00:05 +0200)
Move some of the Branch Sampling (BRS) specific functions out of the Core
events sources and into the BRS sources in preparation for adding other
mechanisms to record branches.

Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/b60283b57179475d18ee242d117c335c16733693.1660211399.git.sandipan.das@amd.com
arch/x86/events/amd/brs.c
arch/x86/events/amd/core.c
arch/x86/events/perf_event.h

index bee8765a1e9b631febe5c05e2e53f3ed9e1ddc7b..f1bff153d94578a549e59416a9754b559ad6f0b4 100644 (file)
@@ -81,7 +81,7 @@ static bool __init amd_brs_detect(void)
  * a br_sel_map. Software filtering is not supported because it would not correlate well
  * with a sampling period.
  */
-int amd_brs_setup_filter(struct perf_event *event)
+static int amd_brs_setup_filter(struct perf_event *event)
 {
        u64 type = event->attr.branch_sample_type;
 
@@ -96,6 +96,73 @@ int amd_brs_setup_filter(struct perf_event *event)
        return 0;
 }
 
+static inline int amd_is_brs_event(struct perf_event *e)
+{
+       return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;
+}
+
+int amd_brs_hw_config(struct perf_event *event)
+{
+       int ret = 0;
+
+       /*
+        * Due to interrupt holding, BRS is not recommended in
+        * counting mode.
+        */
+       if (!is_sampling_event(event))
+               return -EINVAL;
+
+       /*
+        * Due to the way BRS operates by holding the interrupt until
+        * lbr_nr entries have been captured, it does not make sense
+        * to allow sampling on BRS with an event that does not match
+        * what BRS is capturing, i.e., retired taken branches.
+        * Otherwise the correlation with the event's period is even
+        * more loose:
+        *
+        * With retired taken branch:
+        *   Effective P = P + 16 + X
+        * With any other event:
+        *   Effective P = P + Y + X
+        *
+        * Where X is the number of taken branches due to interrupt
+        * skid. Skid is large.
+        *
+        * Where Y is the occurences of the event while BRS is
+        * capturing the lbr_nr entries.
+        *
+        * By using retired taken branches, we limit the impact on the
+        * Y variable. We know it cannot be more than the depth of
+        * BRS.
+        */
+       if (!amd_is_brs_event(event))
+               return -EINVAL;
+
+       /*
+        * BRS implementation does not work with frequency mode
+        * reprogramming of the period.
+        */
+       if (event->attr.freq)
+               return -EINVAL;
+       /*
+        * The kernel subtracts BRS depth from period, so it must
+        * be big enough.
+        */
+       if (event->attr.sample_period <= x86_pmu.lbr_nr)
+               return -EINVAL;
+
+       /*
+        * Check if we can allow PERF_SAMPLE_BRANCH_STACK
+        */
+       ret = amd_brs_setup_filter(event);
+
+       /* only set in case of success */
+       if (!ret)
+               event->hw.flags |= PERF_X86_EVENT_AMD_BRS;
+
+       return ret;
+}
+
 /* tos = top of stack, i.e., last valid entry written */
 static inline int amd_brs_get_tos(union amd_debug_extn_cfg *cfg)
 {
index 9ac3718410ce4bf4173ee566f6bce208938ea08e..e32a27899e1159a43b34ff357ee096cc4647f343 100644 (file)
@@ -330,16 +330,8 @@ static inline bool amd_is_pair_event_code(struct hw_perf_event *hwc)
        }
 }
 
-#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */
-static inline int amd_is_brs_event(struct perf_event *e)
-{
-       return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;
-}
-
 static int amd_core_hw_config(struct perf_event *event)
 {
-       int ret = 0;
-
        if (event->attr.exclude_host && event->attr.exclude_guest)
                /*
                 * When HO == GO == 1 the hardware treats that as GO == HO == 0
@@ -356,66 +348,10 @@ static int amd_core_hw_config(struct perf_event *event)
        if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw))
                event->hw.flags |= PERF_X86_EVENT_PAIR;
 
-       /*
-        * if branch stack is requested
-        */
-       if (has_branch_stack(event)) {
-               /*
-                * Due to interrupt holding, BRS is not recommended in
-                * counting mode.
-                */
-               if (!is_sampling_event(event))
-                       return -EINVAL;
-
-               /*
-                * Due to the way BRS operates by holding the interrupt until
-                * lbr_nr entries have been captured, it does not make sense
-                * to allow sampling on BRS with an event that does not match
-                * what BRS is capturing, i.e., retired taken branches.
-                * Otherwise the correlation with the event's period is even
-                * more loose:
-                *
-                * With retired taken branch:
-                *   Effective P = P + 16 + X
-                * With any other event:
-                *   Effective P = P + Y + X
-                *
-                * Where X is the number of taken branches due to interrupt
-                * skid. Skid is large.
-                *
-                * Where Y is the occurences of the event while BRS is
-                * capturing the lbr_nr entries.
-                *
-                * By using retired taken branches, we limit the impact on the
-                * Y variable. We know it cannot be more than the depth of
-                * BRS.
-                */
-               if (!amd_is_brs_event(event))
-                       return -EINVAL;
+       if (has_branch_stack(event))
+               return amd_brs_hw_config(event);
 
-               /*
-                * BRS implementation does not work with frequency mode
-                * reprogramming of the period.
-                */
-               if (event->attr.freq)
-                       return -EINVAL;
-               /*
-                * The kernel subtracts BRS depth from period, so it must
-                * be big enough.
-                */
-               if (event->attr.sample_period <= x86_pmu.lbr_nr)
-                       return -EINVAL;
-
-               /*
-                * Check if we can allow PERF_SAMPLE_BRANCH_STACK
-                */
-               ret = amd_brs_setup_filter(event);
-
-               /* only set in case of success */
-               if (!ret)
-                       event->hw.flags |= PERF_X86_EVENT_AMD_BRS;
-       }
-       return ret;
+       return 0;
 }
 
 static inline int amd_is_nb_event(struct hw_perf_event *hwc)
index ba3d24a6a4ec282369db8842cfe85e2e6166f815..5deb34e42bbd448ecbdb60286b000e9672178295 100644 (file)
@@ -1233,6 +1233,9 @@ static inline bool fixed_counter_disabled(int i, struct pmu *pmu)
 int amd_pmu_init(void);
 
 #ifdef CONFIG_PERF_EVENTS_AMD_BRS
+
+#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */
+
 int amd_brs_init(void);
 void amd_brs_disable(void);
 void amd_brs_enable(void);
@@ -1241,7 +1244,7 @@ void amd_brs_disable_all(void);
 void amd_brs_drain(void);
 void amd_brs_lopwr_init(void);
 void amd_brs_disable_all(void);
-int amd_brs_setup_filter(struct perf_event *event);
+int amd_brs_hw_config(struct perf_event *event);
 void amd_brs_reset(void);
 
 static inline void amd_pmu_brs_add(struct perf_event *event)
@@ -1277,7 +1280,7 @@ static inline void amd_brs_enable(void) {}
 static inline void amd_brs_drain(void) {}
 static inline void amd_brs_lopwr_init(void) {}
 static inline void amd_brs_disable_all(void) {}
-static inline int amd_brs_setup_filter(struct perf_event *event)
+static inline int amd_brs_hw_config(struct perf_event *event)
 {
        return 0;
 }