Abstract pmu code better by hiding struct i915_pmu and its internals in
i915_pmu.c. Allocate struct i915_pmu dynamically.

Signed-off-by: Jani Nikula <[email protected]>
---
 drivers/gpu/drm/i915/i915_drv.h |   5 +-
 drivers/gpu/drm/i915/i915_pmu.c | 185 +++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/i915_pmu.h | 133 -----------------------
 3 files changed, 175 insertions(+), 148 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 259884b10d9a..29834432e7b7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -65,8 +65,9 @@
 #include "intel_uncore.h"
 
 struct drm_i915_clock_gating_funcs;
-struct vlv_s0ix_state;
+struct i915_pmu;
 struct intel_pxp;
+struct vlv_s0ix_state;
 
 #define GEM_QUIRK_PIN_SWIZZLED_PAGES   BIT(0)
 
@@ -363,7 +364,7 @@ struct drm_i915_private {
 
        bool irq_enabled;
 
-       struct i915_pmu pmu;
+       struct i915_pmu *pmu;
 
        /* The TTM device structure. */
        struct ttm_device bdev;
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 3c6191b7fc82..d26e3c421663 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -4,7 +4,10 @@
  * Copyright © 2017-2018 Intel Corporation
  */
 
+#include <linux/hrtimer.h>
+#include <linux/perf_event.h>
 #include <linux/pm_runtime.h>
+#include <linux/spinlock_types.h>
 
 #include "gt/intel_engine.h"
 #include "gt/intel_engine_pm.h"
@@ -19,6 +22,143 @@
 #include "i915_drv.h"
 #include "i915_pmu.h"
 
+/*
+ * Non-engine events that we need to track enabled-disabled transition and
+ * current state.
+ */
+enum i915_pmu_tracked_events {
+       __I915_PMU_ACTUAL_FREQUENCY_ENABLED = 0,
+       __I915_PMU_REQUESTED_FREQUENCY_ENABLED,
+       __I915_PMU_RC6_RESIDENCY_ENABLED,
+       __I915_PMU_TRACKED_EVENT_COUNT, /* count marker */
+};
+
+/*
+ * Slots used from the sampling timer (non-engine events) with some extras for
+ * convenience.
+ */
+enum {
+       __I915_SAMPLE_FREQ_ACT = 0,
+       __I915_SAMPLE_FREQ_REQ,
+       __I915_SAMPLE_RC6,
+       __I915_SAMPLE_RC6_LAST_REPORTED,
+       __I915_NUM_PMU_SAMPLERS
+};
+
+#define I915_PMU_MAX_GT 2
+
+/*
+ * How many different events we track in the global PMU mask.
+ *
+ * It is also used to know to needed number of event reference counters.
+ */
+#define I915_PMU_MASK_BITS \
+       (I915_ENGINE_SAMPLE_COUNT + \
+        I915_PMU_MAX_GT * __I915_PMU_TRACKED_EVENT_COUNT)
+
+struct i915_pmu {
+       /**
+        * @i915: i915 device backpointer.
+        */
+       struct drm_i915_private *i915;
+       /**
+        * @cpuhp: Struct used for CPU hotplug handling.
+        */
+       struct {
+               struct hlist_node node;
+               unsigned int cpu;
+       } cpuhp;
+       /**
+        * @base: PMU base.
+        */
+       struct pmu base;
+       /**
+        * @closed: i915 is unregistering.
+        */
+       bool closed;
+       /**
+        * @name: Name as registered with perf core.
+        */
+       const char *name;
+       /**
+        * @lock: Lock protecting enable mask and ref count handling.
+        */
+       spinlock_t lock;
+       /**
+        * @unparked: GT unparked mask.
+        */
+       unsigned int unparked;
+       /**
+        * @timer: Timer for internal i915 PMU sampling.
+        */
+       struct hrtimer timer;
+       /**
+        * @enable: Bitmask of specific enabled events.
+        *
+        * For some events we need to track their state and do some internal
+        * house keeping.
+        *
+        * Each engine event sampler type and event listed in enum
+        * i915_pmu_tracked_events gets a bit in this field.
+        *
+        * Low bits are engine samplers and other events continue from there.
+        */
+       u32 enable;
+
+       /**
+        * @timer_last:
+        *
+        * Timestmap of the previous timer invocation.
+        */
+       ktime_t timer_last;
+
+       /**
+        * @enable_count: Reference counts for the enabled events.
+        *
+        * Array indices are mapped in the same way as bits in the @enable field
+        * and they are used to control sampling on/off when multiple clients
+        * are using the PMU API.
+        */
+       unsigned int enable_count[I915_PMU_MASK_BITS];
+       /**
+        * @timer_enabled: Should the internal sampling timer be running.
+        */
+       bool timer_enabled;
+       /**
+        * @sample: Current and previous (raw) counters for sampling events.
+        *
+        * These counters are updated from the i915 PMU sampling timer.
+        *
+        * Only global counters are held here, while the per-engine ones are in
+        * struct intel_engine_cs.
+        */
+       struct i915_pmu_sample sample[I915_PMU_MAX_GT][__I915_NUM_PMU_SAMPLERS];
+       /**
+        * @sleep_last: Last time GT parked for RC6 estimation.
+        */
+       ktime_t sleep_last[I915_PMU_MAX_GT];
+       /**
+        * @irq_count: Number of interrupts
+        *
+        * Intentionally unsigned long to avoid atomics or heuristics on 32bit.
+        * 4e9 interrupts are a lot and postprocessing can really deal with an
+        * occasional wraparound easily. It's 32bit after all.
+        */
+       unsigned long irq_count;
+       /**
+        * @events_attr_group: Device events attribute group.
+        */
+       struct attribute_group events_attr_group;
+       /**
+        * @i915_attr: Memory block holding device attributes.
+        */
+       void *i915_attr;
+       /**
+        * @pmu_attr: Memory block holding device attributes.
+        */
+       void *pmu_attr;
+};
+
 /* Frequency for the sampling timer for events which need it. */
 #define FREQUENCY 200
 #define PERIOD max_t(u64, 10000, NSEC_PER_SEC / FREQUENCY)
@@ -38,7 +178,7 @@ static struct i915_pmu *event_to_pmu(struct perf_event 
*event)
 
 static struct drm_i915_private *pmu_to_i915(struct i915_pmu *pmu)
 {
-       return container_of(pmu, struct drm_i915_private, pmu);
+       return pmu->i915;
 }
 
 static u8 engine_config_sample(u64 config)
@@ -222,7 +362,7 @@ static u64 get_rc6(struct intel_gt *gt)
 {
        struct drm_i915_private *i915 = gt->i915;
        const unsigned int gt_id = gt->info.id;
-       struct i915_pmu *pmu = &i915->pmu;
+       struct i915_pmu *pmu = i915->pmu;
        unsigned long flags;
        bool awake = false;
        u64 val;
@@ -281,7 +421,7 @@ static void init_rc6(struct i915_pmu *pmu)
 
 static void park_rc6(struct intel_gt *gt)
 {
-       struct i915_pmu *pmu = &gt->i915->pmu;
+       struct i915_pmu *pmu = gt->i915->pmu;
 
        store_sample(pmu, gt->info.id, __I915_SAMPLE_RC6, __get_rc6(gt));
        pmu->sleep_last[gt->info.id] = ktime_get_raw();
@@ -300,9 +440,9 @@ static void __i915_pmu_maybe_start_timer(struct i915_pmu 
*pmu)
 
 void i915_pmu_gt_parked(struct intel_gt *gt)
 {
-       struct i915_pmu *pmu = &gt->i915->pmu;
+       struct i915_pmu *pmu = gt->i915->pmu;
 
-       if (!pmu->base.event_init)
+       if (!pmu || !pmu->base.event_init)
                return;
 
        spin_lock_irq(&pmu->lock);
@@ -322,9 +462,9 @@ void i915_pmu_gt_parked(struct intel_gt *gt)
 
 void i915_pmu_gt_unparked(struct intel_gt *gt)
 {
-       struct i915_pmu *pmu = &gt->i915->pmu;
+       struct i915_pmu *pmu = gt->i915->pmu;
 
-       if (!pmu->base.event_init)
+       if (!pmu || !pmu->base.event_init)
                return;
 
        spin_lock_irq(&pmu->lock);
@@ -399,7 +539,7 @@ engines_sample(struct intel_gt *gt, unsigned int period_ns)
        enum intel_engine_id id;
        unsigned long flags;
 
-       if ((i915->pmu.enable & ENGINE_SAMPLE_MASK) == 0)
+       if ((i915->pmu->enable & ENGINE_SAMPLE_MASK) == 0)
                return;
 
        if (!intel_gt_pm_is_awake(gt))
@@ -437,7 +577,7 @@ frequency_sample(struct intel_gt *gt, unsigned int 
period_ns)
 {
        struct drm_i915_private *i915 = gt->i915;
        const unsigned int gt_id = gt->info.id;
-       struct i915_pmu *pmu = &i915->pmu;
+       struct i915_pmu *pmu = i915->pmu;
        struct intel_rps *rps = &gt->rps;
 
        if (!frequency_sampling_enabled(pmu, gt_id))
@@ -1241,7 +1381,7 @@ static bool is_igp(struct drm_i915_private *i915)
 
 void i915_pmu_register(struct drm_i915_private *i915)
 {
-       struct i915_pmu *pmu = &i915->pmu;
+       struct i915_pmu *pmu;
        const struct attribute_group **attr_groups;
        int ret = -ENOMEM;
 
@@ -1250,6 +1390,13 @@ void i915_pmu_register(struct drm_i915_private *i915)
                return;
        }
 
+       pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
+       if (!pmu)
+               return;
+
+       i915->pmu = pmu;
+       pmu->i915 = i915;
+
        spin_lock_init(&pmu->lock);
        hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pmu->timer.function = i915_sample;
@@ -1317,16 +1464,21 @@ void i915_pmu_register(struct drm_i915_private *i915)
        if (!is_igp(i915))
                kfree(pmu->name);
 err:
+       kfree(pmu);
+       i915->pmu = NULL;
        drm_notice(&i915->drm, "Failed to register PMU!\n");
 }
 
 void i915_pmu_unregister(struct drm_i915_private *i915)
 {
-       struct i915_pmu *pmu = &i915->pmu;
+       struct i915_pmu *pmu = i915->pmu;
 
-       if (!pmu->base.event_init)
+       if (!pmu)
                return;
 
+       if (!pmu->base.event_init)
+               goto out;
+
        /*
         * "Disconnect" the PMU callbacks - since all are atomic synchronize_rcu
         * ensures all currently executing ones will have exited before we
@@ -1345,13 +1497,20 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
        if (!is_igp(i915))
                kfree(pmu->name);
        free_event_attributes(pmu);
+
+out:
+       kfree(i915->pmu);
+       i915->pmu = NULL;
 }
 
 void i915_pmu_irq(struct drm_i915_private *i915)
 {
+       if (!i915->pmu)
+               return;
+
        /*
         * A clever compiler translates that into INC. A not so clever one
         * should at least prevent store tearing.
         */
-       WRITE_ONCE(i915->pmu.irq_count, i915->pmu.irq_count + 1);
+       WRITE_ONCE(i915->pmu->irq_count, i915->pmu->irq_count + 1);
 }
diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h
index 26b06132a44f..bd2f9a62413e 100644
--- a/drivers/gpu/drm/i915/i915_pmu.h
+++ b/drivers/gpu/drm/i915/i915_pmu.h
@@ -15,145 +15,12 @@
 struct drm_i915_private;
 struct intel_gt;
 
-/*
- * Non-engine events that we need to track enabled-disabled transition and
- * current state.
- */
-enum i915_pmu_tracked_events {
-       __I915_PMU_ACTUAL_FREQUENCY_ENABLED = 0,
-       __I915_PMU_REQUESTED_FREQUENCY_ENABLED,
-       __I915_PMU_RC6_RESIDENCY_ENABLED,
-       __I915_PMU_TRACKED_EVENT_COUNT, /* count marker */
-};
-
-/*
- * Slots used from the sampling timer (non-engine events) with some extras for
- * convenience.
- */
-enum {
-       __I915_SAMPLE_FREQ_ACT = 0,
-       __I915_SAMPLE_FREQ_REQ,
-       __I915_SAMPLE_RC6,
-       __I915_SAMPLE_RC6_LAST_REPORTED,
-       __I915_NUM_PMU_SAMPLERS
-};
-
-#define I915_PMU_MAX_GT 2
-
-/*
- * How many different events we track in the global PMU mask.
- *
- * It is also used to know to needed number of event reference counters.
- */
-#define I915_PMU_MASK_BITS \
-       (I915_ENGINE_SAMPLE_COUNT + \
-        I915_PMU_MAX_GT * __I915_PMU_TRACKED_EVENT_COUNT)
-
 #define I915_ENGINE_SAMPLE_COUNT (I915_SAMPLE_SEMA + 1)
 
 struct i915_pmu_sample {
        u64 cur;
 };
 
-struct i915_pmu {
-       /**
-        * @cpuhp: Struct used for CPU hotplug handling.
-        */
-       struct {
-               struct hlist_node node;
-               unsigned int cpu;
-       } cpuhp;
-       /**
-        * @base: PMU base.
-        */
-       struct pmu base;
-       /**
-        * @closed: i915 is unregistering.
-        */
-       bool closed;
-       /**
-        * @name: Name as registered with perf core.
-        */
-       const char *name;
-       /**
-        * @lock: Lock protecting enable mask and ref count handling.
-        */
-       spinlock_t lock;
-       /**
-        * @unparked: GT unparked mask.
-        */
-       unsigned int unparked;
-       /**
-        * @timer: Timer for internal i915 PMU sampling.
-        */
-       struct hrtimer timer;
-       /**
-        * @enable: Bitmask of specific enabled events.
-        *
-        * For some events we need to track their state and do some internal
-        * house keeping.
-        *
-        * Each engine event sampler type and event listed in enum
-        * i915_pmu_tracked_events gets a bit in this field.
-        *
-        * Low bits are engine samplers and other events continue from there.
-        */
-       u32 enable;
-
-       /**
-        * @timer_last:
-        *
-        * Timestmap of the previous timer invocation.
-        */
-       ktime_t timer_last;
-
-       /**
-        * @enable_count: Reference counts for the enabled events.
-        *
-        * Array indices are mapped in the same way as bits in the @enable field
-        * and they are used to control sampling on/off when multiple clients
-        * are using the PMU API.
-        */
-       unsigned int enable_count[I915_PMU_MASK_BITS];
-       /**
-        * @timer_enabled: Should the internal sampling timer be running.
-        */
-       bool timer_enabled;
-       /**
-        * @sample: Current and previous (raw) counters for sampling events.
-        *
-        * These counters are updated from the i915 PMU sampling timer.
-        *
-        * Only global counters are held here, while the per-engine ones are in
-        * struct intel_engine_cs.
-        */
-       struct i915_pmu_sample sample[I915_PMU_MAX_GT][__I915_NUM_PMU_SAMPLERS];
-       /**
-        * @sleep_last: Last time GT parked for RC6 estimation.
-        */
-       ktime_t sleep_last[I915_PMU_MAX_GT];
-       /**
-        * @irq_count: Number of interrupts
-        *
-        * Intentionally unsigned long to avoid atomics or heuristics on 32bit.
-        * 4e9 interrupts are a lot and postprocessing can really deal with an
-        * occasional wraparound easily. It's 32bit after all.
-        */
-       unsigned long irq_count;
-       /**
-        * @events_attr_group: Device events attribute group.
-        */
-       struct attribute_group events_attr_group;
-       /**
-        * @i915_attr: Memory block holding device attributes.
-        */
-       void *i915_attr;
-       /**
-        * @pmu_attr: Memory block holding device attributes.
-        */
-       void *pmu_attr;
-};
-
 #ifdef CONFIG_PERF_EVENTS
 int i915_pmu_init(void);
 void i915_pmu_exit(void);
-- 
2.39.2

Reply via email to