Unverified Commit 5e4e06e4 authored by Andrzej Hajda's avatar Andrzej Hajda
Browse files

drm/i915: Track gt pm wakerefs



Track every intel_gt_pm_get() until its corresponding release in
intel_gt_pm_put() by returning a cookie to the caller for acquire that
must be passed by on released. When there is an imbalance, we can see who
either tried to free a stale wakeref, or who forgot to free theirs.

v2: track recently added calls in gen8_ggtt_bind_get_ce and
    destroyed_worker_func

Signed-off-by: default avatarAndrzej Hajda <andrzej.hajda@intel.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231030-ref_tracker_i915-v1-2-006fe6b96421@intel.com
parent b49e894c
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ config DRM_I915_DEBUG
	select DRM_I915_DEBUG_GEM_ONCE
	select DRM_I915_DEBUG_MMIO
	select DRM_I915_DEBUG_RUNTIME_PM
	select DRM_I915_DEBUG_WAKEREF
	select DRM_I915_SW_FENCE_DEBUG_OBJECTS
	select DRM_I915_SELFTEST
	default n
@@ -244,3 +245,16 @@ config DRM_I915_DEBUG_RUNTIME_PM
	  Recommended for driver developers only.

	  If in doubt, say "N"

config DRM_I915_DEBUG_WAKEREF
	bool "Enable extra tracking for wakerefs"
	depends on DRM_I915
	select REF_TRACKER
	select STACKDEPOT
	select STACKTRACE
	help
	  Choose this option to turn on extra state checking and usage
	  tracking for the wakerefPM functionality. This may introduce
	  overhead during driver runtime.

	  If in doubt, say "N"
+8 −6
Original line number Diff line number Diff line
@@ -253,6 +253,8 @@ struct i915_execbuffer {
	struct intel_gt *gt; /* gt for the execbuf */
	struct intel_context *context; /* logical state for the request */
	struct i915_gem_context *gem_context; /** caller's context */
	intel_wakeref_t wakeref;
	intel_wakeref_t wakeref_gt0;

	/** our requests to build */
	struct i915_request *requests[MAX_ENGINE_INSTANCE + 1];
@@ -2719,13 +2721,13 @@ eb_select_engine(struct i915_execbuffer *eb)

	for_each_child(ce, child)
		intel_context_get(child);
	intel_gt_pm_get(gt);
	eb->wakeref = intel_gt_pm_get(ce->engine->gt);
	/*
	 * Keep GT0 active on MTL so that i915_vma_parked() doesn't
	 * free VMAs while execbuf ioctl is validating VMAs.
	 */
	if (gt->info.id)
		intel_gt_pm_get(to_gt(gt->i915));
		eb->wakeref_gt0 = intel_gt_pm_get(to_gt(gt->i915));

	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
		err = intel_context_alloc_state(ce);
@@ -2765,9 +2767,9 @@ eb_select_engine(struct i915_execbuffer *eb)

err:
	if (gt->info.id)
		intel_gt_pm_put(to_gt(gt->i915));
		intel_gt_pm_put(to_gt(gt->i915), eb->wakeref_gt0);

	intel_gt_pm_put(gt);
	intel_gt_pm_put(ce->engine->gt, eb->wakeref);
	for_each_child(ce, child)
		intel_context_put(child);
	intel_context_put(ce);
@@ -2785,8 +2787,8 @@ eb_put_engine(struct i915_execbuffer *eb)
	 * i915_vma_parked() from interfering while execbuf validates vmas.
	 */
	if (eb->gt->info.id)
		intel_gt_pm_put(to_gt(eb->gt->i915));
	intel_gt_pm_put(eb->gt);
		intel_gt_pm_put(to_gt(eb->gt->i915), eb->wakeref_gt0);
	intel_gt_pm_put(eb->context->engine->gt, eb->wakeref);
	for_each_child(eb->context, child)
		intel_context_put(child);
	intel_context_put(eb->context);
+6 −4
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ static int cpu_get(struct context *ctx, unsigned long offset, u32 *v)

static int gtt_set(struct context *ctx, unsigned long offset, u32 v)
{
	intel_wakeref_t wakeref;
	struct i915_vma *vma;
	u32 __iomem *map;
	int err = 0;
@@ -99,7 +100,7 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v)
	if (IS_ERR(vma))
		return PTR_ERR(vma);

	intel_gt_pm_get(vma->vm->gt);
	wakeref = intel_gt_pm_get(vma->vm->gt);

	map = i915_vma_pin_iomap(vma);
	i915_vma_unpin(vma);
@@ -112,12 +113,13 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v)
	i915_vma_unpin_iomap(vma);

out_rpm:
	intel_gt_pm_put(vma->vm->gt);
	intel_gt_pm_put(vma->vm->gt, wakeref);
	return err;
}

static int gtt_get(struct context *ctx, unsigned long offset, u32 *v)
{
	intel_wakeref_t wakeref;
	struct i915_vma *vma;
	u32 __iomem *map;
	int err = 0;
@@ -132,7 +134,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v)
	if (IS_ERR(vma))
		return PTR_ERR(vma);

	intel_gt_pm_get(vma->vm->gt);
	wakeref = intel_gt_pm_get(vma->vm->gt);

	map = i915_vma_pin_iomap(vma);
	i915_vma_unpin(vma);
@@ -145,7 +147,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v)
	i915_vma_unpin_iomap(vma);

out_rpm:
	intel_gt_pm_put(vma->vm->gt);
	intel_gt_pm_put(vma->vm->gt, wakeref);
	return err;
}

+8 −6
Original line number Diff line number Diff line
@@ -630,14 +630,14 @@ static bool assert_mmap_offset(struct drm_i915_private *i915,
static void disable_retire_worker(struct drm_i915_private *i915)
{
	i915_gem_driver_unregister__shrinker(i915);
	intel_gt_pm_get(to_gt(i915));
	intel_gt_pm_get_untracked(to_gt(i915));
	cancel_delayed_work_sync(&to_gt(i915)->requests.retire_work);
}

static void restore_retire_worker(struct drm_i915_private *i915)
{
	igt_flush_test(i915);
	intel_gt_pm_put(to_gt(i915));
	intel_gt_pm_put_untracked(to_gt(i915));
	i915_gem_driver_register__shrinker(i915);
}

@@ -778,6 +778,7 @@ static int igt_mmap_offset_exhaustion(void *arg)

static int gtt_set(struct drm_i915_gem_object *obj)
{
	intel_wakeref_t wakeref;
	struct i915_vma *vma;
	void __iomem *map;
	int err = 0;
@@ -786,7 +787,7 @@ static int gtt_set(struct drm_i915_gem_object *obj)
	if (IS_ERR(vma))
		return PTR_ERR(vma);

	intel_gt_pm_get(vma->vm->gt);
	wakeref = intel_gt_pm_get(vma->vm->gt);
	map = i915_vma_pin_iomap(vma);
	i915_vma_unpin(vma);
	if (IS_ERR(map)) {
@@ -798,12 +799,13 @@ static int gtt_set(struct drm_i915_gem_object *obj)
	i915_vma_unpin_iomap(vma);

out:
	intel_gt_pm_put(vma->vm->gt);
	intel_gt_pm_put(vma->vm->gt, wakeref);
	return err;
}

static int gtt_check(struct drm_i915_gem_object *obj)
{
	intel_wakeref_t wakeref;
	struct i915_vma *vma;
	void __iomem *map;
	int err = 0;
@@ -812,7 +814,7 @@ static int gtt_check(struct drm_i915_gem_object *obj)
	if (IS_ERR(vma))
		return PTR_ERR(vma);

	intel_gt_pm_get(vma->vm->gt);
	wakeref = intel_gt_pm_get(vma->vm->gt);
	map = i915_vma_pin_iomap(vma);
	i915_vma_unpin(vma);
	if (IS_ERR(map)) {
@@ -828,7 +830,7 @@ static int gtt_check(struct drm_i915_gem_object *obj)
	i915_vma_unpin_iomap(vma);

out:
	intel_gt_pm_put(vma->vm->gt);
	intel_gt_pm_put(vma->vm->gt, wakeref);
	return err;
}

+9 −4
Original line number Diff line number Diff line
@@ -28,11 +28,14 @@ static void irq_disable(struct intel_breadcrumbs *b)

static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b)
{
	intel_wakeref_t wakeref;

	/*
	 * Since we are waiting on a request, the GPU should be busy
	 * and should have its own rpm reference.
	 */
	if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt)))
	wakeref = intel_gt_pm_get_if_awake(b->irq_engine->gt);
	if (GEM_WARN_ON(!wakeref))
		return;

	/*
@@ -41,7 +44,7 @@ static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b)
	 * which we can add a new waiter and avoid the cost of re-enabling
	 * the irq.
	 */
	WRITE_ONCE(b->irq_armed, true);
	WRITE_ONCE(b->irq_armed, wakeref);

	/* Requests may have completed before we could enable the interrupt. */
	if (!b->irq_enabled++ && b->irq_enable(b))
@@ -61,12 +64,14 @@ static void intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b)

static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
{
	intel_wakeref_t wakeref = b->irq_armed;

	GEM_BUG_ON(!b->irq_enabled);
	if (!--b->irq_enabled)
		b->irq_disable(b);

	WRITE_ONCE(b->irq_armed, false);
	intel_gt_pm_put_async(b->irq_engine->gt);
	WRITE_ONCE(b->irq_armed, 0);
	intel_gt_pm_put_async(b->irq_engine->gt, wakeref);
}

static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
Loading