summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/gt/intel_engine_pm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-12-06 10:28:09 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-12-06 10:28:09 -0800
commit7ada90eb9c7ae4a8eb066f8e9b4d80122f0363db (patch)
treefbc06c7dacd988b6bed69b509ceef7cd41d743ac /drivers/gpu/drm/i915/gt/intel_engine_pm.c
parent9feb1af97e7366b512ecb9e4dd61d3252074cda3 (diff)
parent9c1867d730a6e1dc23dd633392d102860578c047 (diff)
Merge tag 'drm-next-2019-12-06' of git://anongit.freedesktop.org/drm/drm
Pull more drm updates from Dave Airlie: "Rob pointed out I missed his pull request for msm-next, it's been in next for a while outside of my tree so shouldn't cause any unexpected issues, it has some OCMEM support in drivers/soc that is acked by other maintainers as it's outside my tree. Otherwise it's a usual fixes pull, i915, amdgpu, the main ones, with some tegra, omap, mgag200 and one core fix. Summary: msm-next: - OCMEM support for a3xx and a4xx GPUs. - a510 support + display support core: - mst payload deletion fix i915: - uapi alignment fix - fix for power usage regression due to security fixes - change default preemption timeout to 640ms from 100ms - EHL voltage level display fixes - TGL DGL PHY fix - gvt - MI_ATOMIC cmd parser fix, CFL non-priv warning - CI spotted deadlock fix - EHL port D programming fix amdgpu: - VRAM lost fixes on BACO for CI/VI - navi14 DC fixes - misc SR-IOV, gfx10 fixes - XGMI fixes for arcturus - SRIOV fixes amdkfd: - KFD on ppc64le enabled - page table optimisations radeon: - fix for r1xx/2xx register checker. tegra: - displayport regression fixes - DMA API regression fixes mgag200: - fix devices that can't scanout except at 0 addr omap: - fix dma_addr refcounting" * tag 'drm-next-2019-12-06' of git://anongit.freedesktop.org/drm/drm: (100 commits) drm/dp_mst: Correct the bug in drm_dp_update_payload_part1() drm/omap: fix dma_addr refcounting drm/tegra: Run hub cleanup on ->remove() drm/tegra: sor: Make the +5V HDMI supply optional drm/tegra: Silence expected errors on IOMMU attach drm/tegra: vic: Export module device table drm/tegra: sor: Implement system suspend/resume drm/tegra: Use proper IOVA address for cursor image drm/tegra: gem: Remove premature import restrictions drm/tegra: gem: Properly pin imported buffers drm/tegra: hub: Remove bogus connection mutex check ia64: agp: Replace empty define with do while agp: Add bridge parameter documentation agp: remove unused variable num_segments agp: move AGPGART_MINOR to include/linux/miscdevice.h agp: remove unused variable size in agp_generic_create_gatt_table drm/dp_mst: Fix build on systems with STACKTRACE_SUPPORT=n drm/radeon: fix r1xx/r2xx register checker for POT textures drm/amdgpu: fix GFX10 missing CSIB set(v3) drm/amdgpu: should stop GFX ring in hw_fini ...
Diffstat (limited to 'drivers/gpu/drm/i915/gt/intel_engine_pm.c')
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_pm.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
index 874d82677179..c1dd0cd3efc7 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
@@ -73,8 +73,42 @@ static inline void __timeline_mark_unlock(struct intel_context *ce,
#endif /* !IS_ENABLED(CONFIG_LOCKDEP) */
+static void
+__queue_and_release_pm(struct i915_request *rq,
+ struct intel_timeline *tl,
+ struct intel_engine_cs *engine)
+{
+ struct intel_gt_timelines *timelines = &engine->gt->timelines;
+
+ GEM_TRACE("%s\n", engine->name);
+
+ /*
+ * We have to serialise all potential retirement paths with our
+ * submission, as we don't want to underflow either the
+ * engine->wakeref.counter or our timeline->active_count.
+ *
+ * Equally, we cannot allow a new submission to start until
+ * after we finish queueing, nor could we allow that submitter
+ * to retire us before we are ready!
+ */
+ spin_lock(&timelines->lock);
+
+ /* Let intel_gt_retire_requests() retire us (acquired under lock) */
+ if (!atomic_fetch_inc(&tl->active_count))
+ list_add_tail(&tl->link, &timelines->active_list);
+
+ /* Hand the request over to HW and so engine_retire() */
+ __i915_request_queue(rq, NULL);
+
+ /* Let new submissions commence (and maybe retire this timeline) */
+ __intel_wakeref_defer_park(&engine->wakeref);
+
+ spin_unlock(&timelines->lock);
+}
+
static bool switch_to_kernel_context(struct intel_engine_cs *engine)
{
+ struct intel_context *ce = engine->kernel_context;
struct i915_request *rq;
unsigned long flags;
bool result = true;
@@ -98,16 +132,31 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine)
* This should hold true as we can only park the engine after
* retiring the last request, thus all rings should be empty and
* all timelines idle.
+ *
+ * For unlocking, there are 2 other parties and the GPU who have a
+ * stake here.
+ *
+ * A new gpu user will be waiting on the engine-pm to start their
+ * engine_unpark. New waiters are predicated on engine->wakeref.count
+ * and so intel_wakeref_defer_park() acts like a mutex_unlock of the
+ * engine->wakeref.
+ *
+ * The other party is intel_gt_retire_requests(), which is walking the
+ * list of active timelines looking for completions. Meanwhile as soon
+ * as we call __i915_request_queue(), the GPU may complete our request.
+ * Ergo, if we put ourselves on the timelines.active_list
+ * (se intel_timeline_enter()) before we increment the
+ * engine->wakeref.count, we may see the request completion and retire
+ * it causing an undeflow of the engine->wakeref.
*/
- flags = __timeline_mark_lock(engine->kernel_context);
+ flags = __timeline_mark_lock(ce);
+ GEM_BUG_ON(atomic_read(&ce->timeline->active_count) < 0);
- rq = __i915_request_create(engine->kernel_context, GFP_NOWAIT);
+ rq = __i915_request_create(ce, GFP_NOWAIT);
if (IS_ERR(rq))
/* Context switch failed, hope for the best! Maybe reset? */
goto out_unlock;
- intel_timeline_enter(i915_request_timeline(rq));
-
/* Check again on the next retirement. */
engine->wakeref_serial = engine->serial + 1;
i915_request_add_active_barriers(rq);
@@ -116,13 +165,12 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine)
rq->sched.attr.priority = I915_PRIORITY_BARRIER;
__i915_request_commit(rq);
- /* Release our exclusive hold on the engine */
- __intel_wakeref_defer_park(&engine->wakeref);
- __i915_request_queue(rq, NULL);
+ /* Expose ourselves to the world */
+ __queue_and_release_pm(rq, ce->timeline, engine);
result = false;
out_unlock:
- __timeline_mark_unlock(engine->kernel_context, flags);
+ __timeline_mark_unlock(ce, flags);
return result;
}
@@ -177,7 +225,8 @@ static int __engine_park(struct intel_wakeref *wf)
engine->execlists.no_priolist = false;
- intel_gt_pm_put(engine->gt);
+ /* While gt calls i915_vma_parked(), we have to break the lock cycle */
+ intel_gt_pm_put_async(engine->gt);
return 0;
}