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 <jani.nikula@xxxxxxxxx> --- 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 = >->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 = >->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 = >->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 = >->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