From d822bb18ce96391245d877d5bada8913b88a15cf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Apr 2017 12:34:25 +0100 Subject: [PATCH 0001/1270] drm/i915: intel_ring.engine is unused Or rather it is used only by intel_ring_pin() to extract the drm_i915_private which we can easily pass in. As this is a relatively rare operation, save the space in the struct, and as such it is even break even in the extra code for passing around the parameter: add/remove: 0/0 grow/shrink: 2/3 up/down: 15/-15 (0) function old new delta intel_init_ring_buffer 906 918 +12 execlists_context_pin 1308 1311 +3 mock_engine 407 403 -4 intel_engine_create_ring 367 363 -4 intel_ring_pin 326 319 -7 Total: Before=1261794, After=1261794, chg +0.00% v2: Reorder intel_init_ring_buffer to keep the ring setup together: add/remove: 0/0 grow/shrink: 2/3 up/down: 9/-15 (-6) function old new delta intel_init_ring_buffer 906 912 +6 execlists_context_pin 1308 1311 +3 mock_engine 407 403 -4 intel_engine_create_ring 367 363 -4 intel_ring_pin 326 319 -7 Total: Before=1261794, After=1261788, chg -0.00% Signed-off-by: Chris Wilson Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170403113426.25707-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 28 +++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 6 ++--- drivers/gpu/drm/i915/selftests/mock_engine.c | 1 - 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c8f7c631fc1f..0dc1cc4ad6e7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -771,7 +771,7 @@ static int execlists_context_pin(struct intel_engine_cs *engine, goto unpin_vma; } - ret = intel_ring_pin(ce->ring, ctx->ggtt_offset_bias); + ret = intel_ring_pin(ce->ring, ctx->i915, ctx->ggtt_offset_bias); if (ret) goto unpin_map; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 66a2b8b83972..5e7634c00cbd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1270,17 +1270,18 @@ static int init_phys_status_page(struct intel_engine_cs *engine) return 0; } -int intel_ring_pin(struct intel_ring *ring, unsigned int offset_bias) +int intel_ring_pin(struct intel_ring *ring, + struct drm_i915_private *i915, + unsigned int offset_bias) { - unsigned int flags; - enum i915_map_type map; + enum i915_map_type map = HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC; struct i915_vma *vma = ring->vma; + unsigned int flags; void *addr; int ret; GEM_BUG_ON(ring->vaddr); - map = HAS_LLC(ring->engine->i915) ? I915_MAP_WB : I915_MAP_WC; flags = PIN_GLOBAL; if (offset_bias) @@ -1369,8 +1370,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size) if (!ring) return ERR_PTR(-ENOMEM); - ring->engine = engine; - INIT_LIST_HEAD(&ring->request_list); ring->size = size; @@ -1481,7 +1480,6 @@ static void intel_ring_context_unpin(struct intel_engine_cs *engine, static int intel_init_ring_buffer(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; struct intel_ring *ring; int ret; @@ -1493,13 +1491,7 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) if (ret) goto error; - ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE); - if (IS_ERR(ring)) { - ret = PTR_ERR(ring); - goto error; - } - - if (HWS_NEEDS_PHYSICAL(dev_priv)) { + if (HWS_NEEDS_PHYSICAL(engine->i915)) { WARN_ON(engine->id != RCS); ret = init_phys_status_page(engine); if (ret) @@ -1510,8 +1502,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) goto error; } + ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE); + if (IS_ERR(ring)) { + ret = PTR_ERR(ring); + goto error; + } + /* Ring wraparound at offset 0 sometimes hangs. No idea why. */ - ret = intel_ring_pin(ring, I915_GTT_PAGE_SIZE); + ret = intel_ring_pin(ring, engine->i915, I915_GTT_PAGE_SIZE); if (ret) { intel_ring_free(ring); goto error; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a82a0807f64d..cbe61d3f31da 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -139,8 +139,6 @@ struct intel_ring { struct i915_vma *vma; void *vaddr; - struct intel_engine_cs *engine; - struct list_head request_list; u32 head; @@ -487,7 +485,9 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value) struct intel_ring * intel_engine_create_ring(struct intel_engine_cs *engine, int size); -int intel_ring_pin(struct intel_ring *ring, unsigned int offset_bias); +int intel_ring_pin(struct intel_ring *ring, + struct drm_i915_private *i915, + unsigned int offset_bias); void intel_ring_unpin(struct intel_ring *ring); void intel_ring_free(struct intel_ring *ring); diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 0ad624a1db90..b89050e0de48 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -112,7 +112,6 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine) if (!ring) return NULL; - ring->engine = engine; ring->size = sz; ring->effective_size = sz; ring->vaddr = (void *)(ring + 1); From 1a5788bf2729c6e98444c7f56f960957694472c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Apr 2017 12:34:26 +0100 Subject: [PATCH 0002/1270] drm/i915: Onion unwind for intel_init_ring_common() Rather than call intel_engine_cleanup() with a partially constructed engine, unwind the error during intel_init_ring_common(). Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170403113426.25707-2-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_ringbuffer.c | 77 ++++++++++++------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5e7634c00cbd..c98acc27279a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1259,6 +1259,8 @@ static int init_phys_status_page(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + GEM_BUG_ON(engine->id != RCS); + dev_priv->status_page_dmah = drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE); if (!dev_priv->status_page_dmah) @@ -1481,76 +1483,69 @@ static void intel_ring_context_unpin(struct intel_engine_cs *engine, static int intel_init_ring_buffer(struct intel_engine_cs *engine) { struct intel_ring *ring; - int ret; - - WARN_ON(engine->buffer); + int err; intel_engine_setup_common(engine); - ret = intel_engine_init_common(engine); - if (ret) - goto error; + err = intel_engine_init_common(engine); + if (err) + goto err; - if (HWS_NEEDS_PHYSICAL(engine->i915)) { - WARN_ON(engine->id != RCS); - ret = init_phys_status_page(engine); - if (ret) - goto error; - } else { - ret = init_status_page(engine); - if (ret) - goto error; - } + if (HWS_NEEDS_PHYSICAL(engine->i915)) + err = init_phys_status_page(engine); + else + err = init_status_page(engine); + if (err) + goto err; ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE); if (IS_ERR(ring)) { - ret = PTR_ERR(ring); - goto error; + err = PTR_ERR(ring); + goto err_hws; } /* Ring wraparound at offset 0 sometimes hangs. No idea why. */ - ret = intel_ring_pin(ring, engine->i915, I915_GTT_PAGE_SIZE); - if (ret) { - intel_ring_free(ring); - goto error; - } + err = intel_ring_pin(ring, engine->i915, I915_GTT_PAGE_SIZE); + if (err) + goto err_ring; + + GEM_BUG_ON(engine->buffer); engine->buffer = ring; return 0; -error: - intel_engine_cleanup(engine); - return ret; +err_ring: + intel_ring_free(ring); +err_hws: + if (HWS_NEEDS_PHYSICAL(engine->i915)) + cleanup_phys_status_page(engine); + else + cleanup_status_page(engine); +err: + intel_engine_cleanup_common(engine); + return err; } void intel_engine_cleanup(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv; + struct drm_i915_private *dev_priv = engine->i915; - dev_priv = engine->i915; + WARN_ON(INTEL_GEN(dev_priv) > 2 && + (I915_READ_MODE(engine) & MODE_IDLE) == 0); - if (engine->buffer) { - WARN_ON(INTEL_GEN(dev_priv) > 2 && - (I915_READ_MODE(engine) & MODE_IDLE) == 0); - - intel_ring_unpin(engine->buffer); - intel_ring_free(engine->buffer); - engine->buffer = NULL; - } + intel_ring_unpin(engine->buffer); + intel_ring_free(engine->buffer); if (engine->cleanup) engine->cleanup(engine); - if (HWS_NEEDS_PHYSICAL(dev_priv)) { - WARN_ON(engine->id != RCS); + if (HWS_NEEDS_PHYSICAL(dev_priv)) cleanup_phys_status_page(engine); - } else { + else cleanup_status_page(engine); - } intel_engine_cleanup_common(engine); - engine->i915 = NULL; dev_priv->engine[engine->id] = NULL; kfree(engine); } From 7a3ee5deb46e1350b2c290d2b1fe0a2bc4087bff Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 30 Mar 2017 17:31:30 +0100 Subject: [PATCH 0003/1270] drm/i915: Remove user-triggerable WARN from i915_gem_object_create Since this can be triggered by simply attempting a huge object, a WARN_ON is not appropriate. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170330163130.24141-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bbc6f1c9f175..4ca88f2539c0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4195,7 +4195,7 @@ i915_gem_object_create(struct drm_i915_private *dev_priv, u64 size) * catch if we ever need to fix it. In the meantime, if you do spot * such a local variable, please consider fixing! */ - if (WARN_ON(size >> PAGE_SHIFT > INT_MAX)) + if (size >> PAGE_SHIFT > INT_MAX) return ERR_PTR(-E2BIG); if (overflows_type(size, obj->base.size)) From b1becb88268beb72df6495e35d3d76c138d215bb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Apr 2017 11:51:24 +0100 Subject: [PATCH 0004/1270] drm/i915: Park the signaler before sleeping If the signal to park arrives before we sleep, then we need to check kthread_should_park() before sleeping to avoid missing the signal. Otherwise, if the signal arrives whilst we are processing completed requests, we will reset the current->state back to TASK_INTERRUPTIBLE and so miss the wakeup. Fixes: fe3288b5da2c ("drm/i915: Park the breadcrumbs signaler across a GPU reset") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170403105124.8969-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index b6ea192ad550..308c56a021ab 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -629,6 +629,9 @@ static int intel_breadcrumbs_signaler(void *arg) } else { DEFINE_WAIT(exec); + if (kthread_should_park()) + kthread_parkme(); + if (kthread_should_stop()) { GEM_BUG_ON(request); break; @@ -641,9 +644,6 @@ static int intel_breadcrumbs_signaler(void *arg) if (request) remove_wait_queue(&request->execute, &exec); - - if (kthread_should_park()) - kthread_parkme(); } i915_gem_request_put(request); } while (1); From a7980a640cbd339aa80f406d1786a275a2c320bc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Apr 2017 13:05:31 +0100 Subject: [PATCH 0005/1270] drm/i915: Apply a cond_resched() to the saturated signaler If the engine is continually completing nops, we can saturate the signaler and keep it working indefinitely. This angers the NMI watchdog! A good example is to disable semaphores on snb and run igt/gem_exec_nop - the parallel, multi-engine workloads are more than sufficient to hog the CPU, preventing the system from even processing ICMP echo replies. v2: Tvrtko dug into cond_resched() on x86 and found that it only depended upon preempt_count and not tif_need_resched() - which means that we would always call schedule() at that point. Fixes: c81d46138da6 ("drm/i915: Convert trace-irq to the breadcrumb waiter") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170404120531.10737-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 308c56a021ab..9ccbf26124c6 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -580,6 +580,8 @@ static int intel_breadcrumbs_signaler(void *arg) signaler_set_rtpriority(); do { + bool do_schedule = true; + set_current_state(TASK_INTERRUPTIBLE); /* We are either woken up by the interrupt bottom-half, @@ -626,7 +628,18 @@ static int intel_breadcrumbs_signaler(void *arg) spin_unlock_irq(&b->rb_lock); i915_gem_request_put(request); - } else { + + /* If the engine is saturated we may be continually + * processing completed requests. This angers the + * NMI watchdog if we never let anything else + * have access to the CPU. Let's pretend to be nice + * and relinquish the CPU if we burn through the + * entire RT timeslice! + */ + do_schedule = need_resched(); + } + + if (unlikely(do_schedule)) { DEFINE_WAIT(exec); if (kthread_should_park()) From 01a9ca0ba87176432f0b91fd9adbfa66e33253ed Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 31 Mar 2017 11:57:09 +0000 Subject: [PATCH 0006/1270] drm/i915/huc: Simplify intel_huc_init_hw() On last guc/huc cleanup series we've simplified guc init hw function but missed the one for the huc. While here, change its signature as we don't care about huc loading status. Signed-off-by: Michal Wajdeczko Cc: Anusha Srivatsa Cc: Arkadiusz Hiler Cc: Tvrtko Ursulin Reviewed-by: Anusha Srivatsa Signed-off-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170331115709.181940-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_huc.c | 48 ++++++-------------------------- drivers/gpu/drm/i915/intel_uc.h | 2 +- 2 files changed, 9 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 9ee819666a4c..385cacb65dbe 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -186,68 +186,36 @@ void intel_huc_select_fw(struct intel_huc *huc) * earlier call to intel_huc_init(), so here we need only check that * is succeeded, and then transfer the image to the h/w. * - * Return: non-zero code on error */ -int intel_huc_init_hw(struct intel_huc *huc) +void intel_huc_init_hw(struct intel_huc *huc) { struct drm_i915_private *dev_priv = huc_to_i915(huc); int err; - if (huc->fw.fetch_status == INTEL_UC_FIRMWARE_NONE) - return 0; - DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n", huc->fw.path, intel_uc_fw_status_repr(huc->fw.fetch_status), intel_uc_fw_status_repr(huc->fw.load_status)); - if (huc->fw.fetch_status == INTEL_UC_FIRMWARE_SUCCESS && - huc->fw.load_status == INTEL_UC_FIRMWARE_FAIL) - return -ENOEXEC; + if (huc->fw.fetch_status != INTEL_UC_FIRMWARE_SUCCESS) + return; huc->fw.load_status = INTEL_UC_FIRMWARE_PENDING; - switch (huc->fw.fetch_status) { - case INTEL_UC_FIRMWARE_FAIL: - /* something went wrong :( */ - err = -EIO; - goto fail; - - case INTEL_UC_FIRMWARE_NONE: - case INTEL_UC_FIRMWARE_PENDING: - default: - /* "can't happen" */ - WARN_ONCE(1, "HuC fw %s invalid fetch_status %s [%d]\n", - huc->fw.path, - intel_uc_fw_status_repr(huc->fw.fetch_status), - huc->fw.fetch_status); - err = -ENXIO; - goto fail; - - case INTEL_UC_FIRMWARE_SUCCESS: - break; - } - err = huc_ucode_xfer(dev_priv); - if (err) - goto fail; - huc->fw.load_status = INTEL_UC_FIRMWARE_SUCCESS; + huc->fw.load_status = err ? + INTEL_UC_FIRMWARE_FAIL : INTEL_UC_FIRMWARE_SUCCESS; DRM_DEBUG_DRIVER("%s fw status: fetch %s, load %s\n", huc->fw.path, intel_uc_fw_status_repr(huc->fw.fetch_status), intel_uc_fw_status_repr(huc->fw.load_status)); - return 0; + if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) + DRM_ERROR("Failed to complete HuC uCode load with ret %d\n", err); -fail: - if (huc->fw.load_status == INTEL_UC_FIRMWARE_PENDING) - huc->fw.load_status = INTEL_UC_FIRMWARE_FAIL; - - DRM_ERROR("Failed to complete HuC uCode load with ret %d\n", err); - - return err; + return; } /** diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 4b7f73aeddac..2f0229da20bb 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -266,7 +266,7 @@ static inline u32 guc_ggtt_offset(struct i915_vma *vma) /* intel_huc.c */ void intel_huc_select_fw(struct intel_huc *huc); -int intel_huc_init_hw(struct intel_huc *huc); +void intel_huc_init_hw(struct intel_huc *huc); void intel_guc_auth_huc(struct drm_i915_private *dev_priv); #endif From 895203044067af64400cedbc055898bcec98d102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 29 Mar 2017 17:21:23 +0300 Subject: [PATCH 0007/1270] drm/i915: Make legacy cursor updates more unsynced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're clearing the legacy_cursor_update flag before calling drm_atomic_helper_setup_commit() which means the helper will wait for the flip to complete before cleaning up the framebuffers. That's not what we want for the legacy cursor, so let's clear the flag after setting up the commit. Also toss in a FIXME about solving these problems in a nicer way using the fabled vblank workers. v2: Also unsync with legacy page flips Cc: Maarten Lankhorst Cc: Daniel Vetter Cc: Uwe Kleine-König Cc: Rafael Ristovski Fixes: a5509abda48e ("drm/i915: Fix legacy cursor vs. watermarks for ILK-BDW") Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170329142123.5923-1-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst --- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fe6bd745c130..26e871a4c30c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13024,17 +13024,6 @@ static int intel_atomic_commit(struct drm_device *dev, struct drm_i915_private *dev_priv = to_i915(dev); int ret = 0; - /* - * The intel_legacy_cursor_update() fast path takes care - * of avoiding the vblank waits for simple cursor - * movement and flips. For cursor on/off and size changes, - * we want to perform the vblank waits so that watermark - * updates happen during the correct frames. Gen9+ have - * double buffered watermarks and so shouldn't need this. - */ - if (INTEL_GEN(dev_priv) < 9) - state->legacy_cursor_update = false; - ret = drm_atomic_helper_setup_commit(state, nonblock); if (ret) return ret; @@ -13050,6 +13039,26 @@ static int intel_atomic_commit(struct drm_device *dev, return ret; } + /* + * The intel_legacy_cursor_update() fast path takes care + * of avoiding the vblank waits for simple cursor + * movement and flips. For cursor on/off and size changes, + * we want to perform the vblank waits so that watermark + * updates happen during the correct frames. Gen9+ have + * double buffered watermarks and so shouldn't need this. + * + * Do this after drm_atomic_helper_setup_commit() and + * intel_atomic_prepare_commit() because we still want + * to skip the flip and fb cleanup waits. Although that + * does risk yanking the mapping from under the display + * engine. + * + * FIXME doing watermarks and fb cleanup from a vblank worker + * (assuming we had any) would solve these problems. + */ + if (INTEL_GEN(dev_priv) < 9) + state->legacy_cursor_update = false; + drm_atomic_helper_swap_state(state, true); dev_priv->wm.distrust_bios_wm = false; intel_shared_dpll_swap_state(state); From b64b7a605d8e6869106e1101e1fefa5dc2790e65 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Tue, 4 Apr 2017 11:16:05 -0700 Subject: [PATCH 0008/1270] drm/i915: Typo fix - 'pipe bpc' to 'pipe bpp' Noticed this while I was looking at some debug output, [drm:intel_hdmi_compute_config [i915]] picking bpc to 12 for HDMI output [drm:intel_hdmi_compute_config [i915]] forcing pipe bpc to 36 for HDMI I believe the second line should be pipe *bpp* Signed-off-by: Dhinakaran Pandiyan Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1491329765-14340-1-git-send-email-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1d623b5e09d6..6efc3cb8c471 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1392,7 +1392,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } if (!pipe_config->bw_constrained) { - DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); + DRM_DEBUG_KMS("forcing pipe bpp to %i for HDMI\n", desired_bpp); pipe_config->pipe_bpp = desired_bpp; } From b53af8bb18b85188b5c8cacaa6a966774b548f17 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 4 Apr 2017 13:38:36 +0000 Subject: [PATCH 0009/1270] drm/i915/guc: Use GUC prefix for CORE_FAMILY definitions Almost all other GuC fw definitions are using GUC|guc prefix. While around, in get_core_family() change explicit WARN into MISSING_CASE as it looks more appropriate, since GuC support capability we are controlling by intel_device_info.has_guc flag. Signed-off-by: Michal Wajdeczko Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170404133836.125736-1-michal.wajdeczko@intel.com Reviewed-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_guc_fwif.h | 4 ++-- drivers/gpu/drm/i915/intel_guc_loader.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index cb36cbf3818f..6156845641a3 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -23,8 +23,8 @@ #ifndef _INTEL_GUC_FWIF_H #define _INTEL_GUC_FWIF_H -#define GFXCORE_FAMILY_GEN9 12 -#define GFXCORE_FAMILY_UNKNOWN 0x7fffffff +#define GUC_CORE_FAMILY_GEN9 12 +#define GUC_CORE_FAMILY_UNKNOWN 0x7fffffff #define GUC_CLIENT_PRIORITY_KMD_HIGH 0 #define GUC_CLIENT_PRIORITY_HIGH 1 diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 8a1a023e48b2..2793c01767b8 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -86,11 +86,11 @@ static u32 get_core_family(struct drm_i915_private *dev_priv) switch (gen) { case 9: - return GFXCORE_FAMILY_GEN9; + return GUC_CORE_FAMILY_GEN9; default: - WARN(1, "GEN%d does not support GuC operation!\n", gen); - return GFXCORE_FAMILY_UNKNOWN; + MISSING_CASE(gen); + return GUC_CORE_FAMILY_UNKNOWN; } } From 709f3fc92c113c88c96c5def37acb92e2eef610a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 3 Mar 2017 17:19:26 +0200 Subject: [PATCH 0010/1270] drm/i915: Check for id==PLANE_CURSOR instead of type==DRM_PLANE_TYPE_CURSOR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VLV/CHV watermark calculation is really interested in the hardware plane type rather than the plane type (which is more of a software concept). Let's check plane->id rather plane->type. No functional changes. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170303151928.23053-3-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 570bd603f401..2807054e49a5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1039,7 +1039,7 @@ static uint16_t vlv_compute_wm_level(const struct intel_crtc_state *crtc_state, if (WARN_ON(htotal == 0)) htotal = 1; - if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + if (plane->id == PLANE_CURSOR) { /* * FIXME the formula gives values that are * too big for the cursor FIFO, and hence we From a07102f1cce6ebf11f8d880665eb6f6353b16177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 3 Mar 2017 17:19:27 +0200 Subject: [PATCH 0011/1270] drm/i915: Use intel_wm_plane_visible() on VLV/CHV as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV/CHV don't have double buffered watermarks so they need to consider the cursor visibility as a special case just like ILK-BDW. Let's use the helper we have for that. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170303151928.23053-4-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2807054e49a5..55e1e88cd361 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1029,7 +1029,7 @@ static uint16_t vlv_compute_wm_level(const struct intel_crtc_state *crtc_state, if (dev_priv->wm.pri_latency[level] == 0) return USHRT_MAX; - if (!plane_state->base.visible) + if (!intel_wm_plane_visible(crtc_state, plane_state)) return 0; cpp = plane_state->base.fb->format->cpp[0]; @@ -1203,7 +1203,7 @@ static bool vlv_plane_wm_compute(struct intel_crtc_state *crtc_state, int level; bool dirty = false; - if (!plane_state->base.visible) { + if (!intel_wm_plane_visible(crtc_state, plane_state)) { dirty |= vlv_raw_plane_wm_set(crtc_state, 0, plane_id, 0); goto out; } From ff4c3b76eefe3c9c52326250c6701149d0985fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 3 Mar 2017 17:19:28 +0200 Subject: [PATCH 0012/1270] drm/i915: Enable atomic on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV/CHV watermarks are now able to handle the radiation, so mark these platforms as ready for atomic. Cc: Maarten Lankhorst Suggested-by: Maarten Lankhorst Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170303151928.23053-5-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst --- drivers/gpu/drm/i915/i915_drv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0b3811673199..0595600fb775 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1213,9 +1213,8 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_i915_private *dev_priv; int ret; - /* Enable nuclear pageflip on ILK+, except vlv/chv */ - if (!i915.nuclear_pageflip && - (match_info->gen < 5 || match_info->has_gmch_display)) + /* Enable nuclear pageflip on ILK+ */ + if (!i915.nuclear_pageflip && match_info->gen < 5) driver.driver_features &= ~DRIVER_ATOMIC; ret = -ENOMEM; From fd08923384385400101c71ac0d21d37d6b23b00d Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 5 Apr 2017 15:51:50 +0530 Subject: [PATCH 0013/1270] drm/i915: Suspend GuC prior to GPU Reset during GEM suspend i915 is currently doing a full GPU reset at the end of i915_gem_suspend() followed by GuC suspend in i915_drm_suspend(). This GPU reset clobbers the GuC, causing the suspend request to then fail, leaving the GuC in an undefined state. We need to tell the GuC to suspend before we do the direct intel_gpu_reset(). v2: Commit message update. (Chris, Daniele) Fixes: 1c777c5d1dcd ("drm/i915/hsw: Fix GPU hang during resume from S3-devices state") Cc: Jeff McGee Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Joonas Lahtinen Cc: Imre Deak Cc: Mika Kuoppala Signed-off-by: Sagar Arun Kamble Link: http://patchwork.freedesktop.org/patch/msgid/1491387710-20553-1-git-send-email-sagar.a.kamble@intel.com Reviewed-by: Daniele Ceraolo Spurio Acked-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 2 -- drivers/gpu/drm/i915/i915_gem.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0595600fb775..94c61aa975d8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1486,8 +1486,6 @@ static int i915_drm_suspend(struct drm_device *dev) goto out; } - intel_guc_suspend(dev_priv); - intel_display_suspend(dev); intel_dp_mst_suspend(dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4ca88f2539c0..28e77d28e276 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4456,6 +4456,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) i915_gem_context_lost(dev_priv); mutex_unlock(&dev->struct_mutex); + intel_guc_suspend(dev_priv); + cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work); cancel_delayed_work_sync(&dev_priv->gt.retire_work); From 3194102439f6acb0b43f36cc909c04adf3ad97e3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Mar 2017 17:59:01 +0300 Subject: [PATCH 0014/1270] drm/i915/dp: use known correct array size in rate_to_index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I can't think of a real world bug this could cause now, but this will be required in follow-up work. While at it, change the parameter order to be slightly more sensible. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/ff5b08f45a72c2247f5326b080027e2f5d8cc4ee.1490712890.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fd96a6cf7326..88c708b07c70 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1538,12 +1538,12 @@ bool intel_dp_read_desc(struct intel_dp *intel_dp) return true; } -static int rate_to_index(int find, const int *rates) +static int rate_to_index(const int *rates, int len, int rate) { - int i = 0; + int i; - for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i) - if (find == rates[i]) + for (i = 0; i < len; i++) + if (rate == rates[i]) break; return i; @@ -1564,7 +1564,8 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp) int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) { - return rate_to_index(rate, intel_dp->sink_rates); + return rate_to_index(intel_dp->sink_rates, intel_dp->num_sink_rates, + rate); } void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, From b5c72b207baaa33184b23a5a69603f981aaef0c1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Mar 2017 17:59:02 +0300 Subject: [PATCH 0015/1270] drm/i915/dp: return errors from rate_to_index() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't silently use the first element if we can't find the rate we're looking for. Make rate_to_index() more generally useful, and fallback to the first element in the caller, with a big warning. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/8a6e83b7bf35da0cbbc703ae157944107ff145be.1490712890.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 88c708b07c70..0e200a37b75b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1544,9 +1544,9 @@ static int rate_to_index(const int *rates, int len, int rate) for (i = 0; i < len; i++) if (rate == rates[i]) - break; + return i; - return i; + return -1; } int @@ -1564,8 +1564,13 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp) int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) { - return rate_to_index(intel_dp->sink_rates, intel_dp->num_sink_rates, - rate); + int i = rate_to_index(intel_dp->sink_rates, intel_dp->num_sink_rates, + rate); + + if (WARN_ON(i < 0)) + i = 0; + + return i; } void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, From 8001b7541aa7a2f0adc4941bdebf44ea969e7ed5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Mar 2017 17:59:03 +0300 Subject: [PATCH 0016/1270] drm/i915/dp: rename rate_to_index() to intel_dp_rate_index() and reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the function, move it at the top, and reuse in intel_dp_link_rate_index(). If there was a reason in the past to use reverse search order here, there isn't now. The names may be slightly confusing now, but intel_dp_link_rate_index() will go away in follow-up patches. v2: Use name intel_dp_rate_index (Dhinakaran) Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/c7b6197aaa12e368a0d024dc142fa574fd0443a7.1490712890.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 34 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0e200a37b75b..9fc066dda4e0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -266,6 +266,18 @@ static int intersect_rates(const int *source_rates, int source_len, return k; } +/* return index of rate in rates array, or -1 if not found */ +static int intel_dp_rate_index(const int *rates, int len, int rate) +{ + int i; + + for (i = 0; i < len; i++) + if (rate == rates[i]) + return i; + + return -1; +} + static int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates) { @@ -284,15 +296,10 @@ static int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates, int link_rate) { int common_len; - int index; common_len = intel_dp_common_rates(intel_dp, common_rates); - for (index = 0; index < common_len; index++) { - if (link_rate == common_rates[common_len - index - 1]) - return common_len - index - 1; - } - return -1; + return intel_dp_rate_index(common_rates, common_len, link_rate); } int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, @@ -1538,17 +1545,6 @@ bool intel_dp_read_desc(struct intel_dp *intel_dp) return true; } -static int rate_to_index(const int *rates, int len, int rate) -{ - int i; - - for (i = 0; i < len; i++) - if (rate == rates[i]) - return i; - - return -1; -} - int intel_dp_max_link_rate(struct intel_dp *intel_dp) { @@ -1564,8 +1560,8 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp) int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) { - int i = rate_to_index(intel_dp->sink_rates, intel_dp->num_sink_rates, - rate); + int i = intel_dp_rate_index(intel_dp->sink_rates, + intel_dp->num_sink_rates, rate); if (WARN_ON(i < 0)) i = 0; From 55cfc580809698e952c1df36140eefb8d97ce222 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Mar 2017 17:59:04 +0300 Subject: [PATCH 0017/1270] drm/i915/dp: cache source rates at init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need the source rates array so often that it makes sense to set it once at init. This reduces function calls when we need the rates, making the code easier to follow. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/aa998882d2b824f671272c60e9d26621ab9d2d17.1490712890.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 35 +++++++++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 3 +++ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9fc066dda4e0..e9bd75ff3904 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -218,21 +218,25 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) return (intel_dp->max_sink_link_bw >> 3) + 1; } -static int -intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates) +static void +intel_dp_set_source_rates(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + const int *source_rates; int size; + /* This should only be done once */ + WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates); + if (IS_GEN9_LP(dev_priv)) { - *source_rates = bxt_rates; + source_rates = bxt_rates; size = ARRAY_SIZE(bxt_rates); } else if (IS_GEN9_BC(dev_priv)) { - *source_rates = skl_rates; + source_rates = skl_rates; size = ARRAY_SIZE(skl_rates); } else { - *source_rates = default_rates; + source_rates = default_rates; size = ARRAY_SIZE(default_rates); } @@ -240,7 +244,8 @@ intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates) if (!intel_dp_source_supports_hbr2(intel_dp)) size--; - return size; + intel_dp->source_rates = source_rates; + intel_dp->num_source_rates = size; } static int intersect_rates(const int *source_rates, int source_len, @@ -281,13 +286,13 @@ static int intel_dp_rate_index(const int *rates, int len, int rate) static int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates) { - const int *source_rates, *sink_rates; - int source_len, sink_len; + const int *sink_rates; + int sink_len; sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); - source_len = intel_dp_source_rates(intel_dp, &source_rates); - return intersect_rates(source_rates, source_len, + return intersect_rates(intel_dp->source_rates, + intel_dp->num_source_rates, sink_rates, sink_len, common_rates); } @@ -1493,16 +1498,16 @@ static void snprintf_int_array(char *str, size_t len, static void intel_dp_print_rates(struct intel_dp *intel_dp) { - const int *source_rates, *sink_rates; - int source_len, sink_len, common_len; + const int *sink_rates; + int sink_len, common_len; int common_rates[DP_MAX_SUPPORTED_RATES]; char str[128]; /* FIXME: too big for stack? */ if ((drm_debug & DRM_UT_KMS) == 0) return; - source_len = intel_dp_source_rates(intel_dp, &source_rates); - snprintf_int_array(str, sizeof(str), source_rates, source_len); + snprintf_int_array(str, sizeof(str), + intel_dp->source_rates, intel_dp->num_source_rates); DRM_DEBUG_KMS("source rates: %s\n", str); sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); @@ -5943,6 +5948,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dig_port->max_lanes, port_name(port))) return false; + intel_dp_set_source_rates(intel_dp); + intel_dp->reset_link_params = true; intel_dp->pps_pipe = INVALID_PIPE; intel_dp->active_pipe = INVALID_PIPE; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 313fad059bfa..c3382eb580b5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -949,6 +949,9 @@ struct intel_dp { uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE]; uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; uint8_t edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; + /* source rates */ + int num_source_rates; + const int *source_rates; /* sink rates as reported by DP_SUPPORTED_LINK_RATES */ uint8_t num_sink_rates; int sink_rates[DP_MAX_SUPPORTED_RATES]; From 68f357cb734738d60a749abb6673e7b63ccf0221 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 Mar 2017 17:59:05 +0300 Subject: [PATCH 0018/1270] drm/i915/dp: generate and cache sink rate array for all DP, not just eDP 1.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is some conflation related to sink rates, making this change more complicated than it would otherwise have to be. There are three changes here that are rather difficult to split up: 1) Use the intel_dp->sink_rates array for all DP, not just eDP 1.4. We initialize it from DPCD on eDP 1.4 like before, but generate it based on DP_MAX_LINK_RATE on others. This reduces code complexity when we need to use the sink rates; they are all always in the sink_rates array. 2) Update the sink rate array whenever we read DPCD, and use the information from there. This increases code readability when we need the sink rates. 3) Disentangle fallback rate limiting from sink rates. In the code, the max rate is a dynamic property of the *link*, not of the *sink*. Do the limiting after intersecting the source and sink rates, which are static properties of the devices. This paves the way for follow-up refactoring that I've refrained from doing here to keep this change as simple as it possibly can. v2: introduce use_rate_select and handle non-confirming eDP (Ville) v3: don't clobber cached eDP rates on short pulse (Ville) Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/071bad76467f8ab2e73f3f61ad52d5a468004c71.1490712890.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 81 +++++++++++++------ drivers/gpu/drm/i915/intel_dp_link_training.c | 3 +- drivers/gpu/drm/i915/intel_drv.h | 5 +- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e9bd75ff3904..b38cba7d5abc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -133,6 +133,34 @@ static void vlv_steal_power_sequencer(struct drm_device *dev, enum pipe pipe); static void intel_dp_unset_edid(struct intel_dp *intel_dp); +static int intel_dp_num_rates(u8 link_bw_code) +{ + switch (link_bw_code) { + default: + WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n", + link_bw_code); + case DP_LINK_BW_1_62: + return 1; + case DP_LINK_BW_2_7: + return 2; + case DP_LINK_BW_5_4: + return 3; + } +} + +/* update sink rates from dpcd */ +static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) +{ + int i, num_rates; + + num_rates = intel_dp_num_rates(intel_dp->dpcd[DP_MAX_LINK_RATE]); + + for (i = 0; i < num_rates; i++) + intel_dp->sink_rates[i] = default_rates[i]; + + intel_dp->num_sink_rates = num_rates; +} + static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { @@ -205,19 +233,6 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp) return max_dotclk; } -static int -intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) -{ - if (intel_dp->num_sink_rates) { - *sink_rates = intel_dp->sink_rates; - return intel_dp->num_sink_rates; - } - - *sink_rates = default_rates; - - return (intel_dp->max_sink_link_bw >> 3) + 1; -} - static void intel_dp_set_source_rates(struct intel_dp *intel_dp) { @@ -286,15 +301,22 @@ static int intel_dp_rate_index(const int *rates, int len, int rate) static int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates) { - const int *sink_rates; - int sink_len; + int max_rate = drm_dp_bw_code_to_link_rate(intel_dp->max_sink_link_bw); + int i, common_len; - sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); + common_len = intersect_rates(intel_dp->source_rates, + intel_dp->num_source_rates, + intel_dp->sink_rates, + intel_dp->num_sink_rates, + common_rates); - return intersect_rates(intel_dp->source_rates, - intel_dp->num_source_rates, - sink_rates, sink_len, - common_rates); + /* Limit results by potentially reduced max rate */ + for (i = 0; i < common_len; i++) { + if (common_rates[common_len - i - 1] <= max_rate) + return common_len - i; + } + + return 0; } static int intel_dp_link_rate_index(struct intel_dp *intel_dp, @@ -1498,8 +1520,7 @@ static void snprintf_int_array(char *str, size_t len, static void intel_dp_print_rates(struct intel_dp *intel_dp) { - const int *sink_rates; - int sink_len, common_len; + int common_len; int common_rates[DP_MAX_SUPPORTED_RATES]; char str[128]; /* FIXME: too big for stack? */ @@ -1510,8 +1531,8 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) intel_dp->source_rates, intel_dp->num_source_rates); DRM_DEBUG_KMS("source rates: %s\n", str); - sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); - snprintf_int_array(str, sizeof(str), sink_rates, sink_len); + snprintf_int_array(str, sizeof(str), + intel_dp->sink_rates, intel_dp->num_sink_rates); DRM_DEBUG_KMS("sink rates: %s\n", str); common_len = intel_dp_common_rates(intel_dp, common_rates); @@ -1577,7 +1598,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, uint8_t *link_bw, uint8_t *rate_select) { - if (intel_dp->num_sink_rates) { + /* eDP 1.4 rate select method. */ + if (intel_dp->use_rate_select) { *link_bw = 0; *rate_select = intel_dp_rate_select(intel_dp, port_clock); @@ -3702,6 +3724,11 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) intel_dp->num_sink_rates = i; } + if (intel_dp->num_sink_rates) + intel_dp->use_rate_select = true; + else + intel_dp_set_sink_rates(intel_dp); + return true; } @@ -3712,6 +3739,10 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) if (!intel_dp_read_dpcd(intel_dp)) return false; + /* Don't clobber cached eDP rates. */ + if (!is_edp(intel_dp)) + intel_dp_set_sink_rates(intel_dp); + if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT, &intel_dp->sink_count, 1) < 0) return false; diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 0048b520baf7..694ad0ffb523 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -146,7 +146,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); - if (intel_dp->num_sink_rates) + /* eDP 1.4 rate select method. */ + if (!link_bw) drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET, &rate_select, 1); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c3382eb580b5..7bc0c25b3396 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -952,9 +952,10 @@ struct intel_dp { /* source rates */ int num_source_rates; const int *source_rates; - /* sink rates as reported by DP_SUPPORTED_LINK_RATES */ - uint8_t num_sink_rates; + /* sink rates as reported by DP_MAX_LINK_RATE/DP_SUPPORTED_LINK_RATES */ + int num_sink_rates; int sink_rates[DP_MAX_SUPPORTED_RATES]; + bool use_rate_select; /* Max lane count for the sink as per DPCD registers */ uint8_t max_sink_lane_count; /* Max link BW for the sink as per DPCD registers */ From 97f55ca5b6625bb4ddeca7b1272b53ca04ab3cf0 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Wed, 5 Apr 2017 09:04:23 -0400 Subject: [PATCH 0019/1270] drm/i915/glk: limit pixel clock to 99% of cdclk workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per BSPEC, valid cdclk values for glk are 79.2, 158.4, 316.8 Mhz. Practically we can achive only 99% of these cdclk values (HW team checking on this). So cdclk should be calculated for the given pixclk as per that otherwise it may lead to screen corruption, explained below: 1. For DSI AUO panel(1920x1200 @60) required pixclk is 157100 KHZ 2. glk_calc_cdclk returns 79200 KHZ for this pixclk, For 2PPC it will be 158400 KHZ 3. Practically 100% of the cdclk can’t be achieved, so 99% of 158400 KHZ = 156816 which is less than the desired pixlclk and causes panel corruption. v2: Rebased to new CDLCK code framework v3: Addressed review comments from Ander/Jani - Add comment in code about 99% usage of CDCLK - Calculate max dot clock as well with 99% limit v4 by Jani: - drop superfluous whitespace change - rewrite code comments to clarify v5: Added details of non-working scenario in commit message Cc: Ander Conselvan de Oliveira Cc: Ville Syrjälä Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Reviewed-by: Ander Conselvan de Oliveira Link: http://patchwork.freedesktop.org/patch/msgid/1491397463-13637-1-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/intel_cdclk.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index dd3ad52b7dfe..763010f8ad89 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1071,9 +1071,15 @@ static int bxt_calc_cdclk(int max_pixclk) static int glk_calc_cdclk(int max_pixclk) { - if (max_pixclk > 2 * 158400) + /* + * FIXME: Avoid using a pixel clock that is more than 99% of the cdclk + * as a temporary workaround. Use a higher cdclk instead. (Note that + * intel_compute_max_dotclk() limits the max pixel clock to 99% of max + * cdclk.) + */ + if (max_pixclk > DIV_ROUND_UP(2 * 158400 * 99, 100)) return 316800; - else if (max_pixclk > 2 * 79200) + else if (max_pixclk > DIV_ROUND_UP(2 * 79200 * 99, 100)) return 158400; else return 79200; @@ -1664,7 +1670,11 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv) int max_cdclk_freq = dev_priv->max_cdclk_freq; if (IS_GEMINILAKE(dev_priv)) - return 2 * max_cdclk_freq; + /* + * FIXME: Limiting to 99% as a temporary workaround. See + * glk_calc_cdclk() for details. + */ + return 2 * max_cdclk_freq * 99 / 100; else if (INTEL_INFO(dev_priv)->gen >= 9 || IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) return max_cdclk_freq; From b268d9fe0f10544f5f7a1b7015e2b97075e6215d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Apr 2017 23:15:14 +0100 Subject: [PATCH 0020/1270] drm/i915: Use the right mapping_gfp_mask for final shmem allocation Many sightings report the greater prevalence of allocation failures. This is all due to the incorrect use of mapping_gfp_constraint(), so remove it in favour of just querying the mapping_gfp_mask() which are the exact gfp_t we wanted in the first place. We still do expect a higher chance of reporting ENOMEM, as that is the intention of using __GFP_NORETRY -- to fail rather than oom after having reclaimed from our bo caches, and having done a direct|kswapd reclaim pass. Reported-by: Jason Ekstrand Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100594 Fixes: 24f8e00a8a2e ("drm/i915: Prefer to report ENOMEM rather than incur the oom for gfx allocations") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170405221514.23251-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 28e77d28e276..391aa69097f1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2340,7 +2340,7 @@ rebuild_st: * defer the oom here by reporting the ENOMEM back * to userspace. */ - reclaim = mapping_gfp_constraint(mapping, 0); + reclaim = mapping_gfp_mask(mapping); reclaim |= __GFP_NORETRY; /* reclaim, but no oom */ page = shmem_read_mapping_page_gfp(mapping, i, reclaim); From 90f192c8241e431d2c3076e4f2cb99ac25bfb1c5 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 30 Mar 2017 13:24:06 -0700 Subject: [PATCH 0021/1270] drm/i915/GuC/GLK: Load GuC on GLK Load GuC 10.56 on GLK. Work on firmware is still in progress. Testing has not been done yet. This patch addresses the initial need to load the GuC firmware for HuC authentication v2: rebased. Cc: Jeff mcgee Cc: Rodrigo Vivi Cc: John Spotswood Signed-off-by: Anusha Srivatsa Reviewed-by: John Spotswood Signed-off-by: Ander Conselvan de Oliveira Link: http://patchwork.freedesktop.org/patch/msgid/1490905447-15815-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/intel_guc_loader.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 2793c01767b8..12f80ece1d05 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -61,6 +61,9 @@ #define KBL_FW_MAJOR 9 #define KBL_FW_MINOR 14 +#define GLK_FW_MAJOR 10 +#define GLK_FW_MINOR 56 + #define GUC_FW_PATH(platform, major, minor) \ "i915/" __stringify(platform) "_guc_ver" __stringify(major) "_" __stringify(minor) ".bin" @@ -73,6 +76,8 @@ MODULE_FIRMWARE(I915_BXT_GUC_UCODE); #define I915_KBL_GUC_UCODE GUC_FW_PATH(kbl, KBL_FW_MAJOR, KBL_FW_MINOR) MODULE_FIRMWARE(I915_KBL_GUC_UCODE); +#define I915_GLK_GUC_UCODE GUC_FW_PATH(glk, GLK_FW_MAJOR, GLK_FW_MINOR) + static u32 get_gttype(struct drm_i915_private *dev_priv) { @@ -405,6 +410,10 @@ int intel_guc_select_fw(struct intel_guc *guc) guc->fw.path = I915_KBL_GUC_UCODE; guc->fw.major_ver_wanted = KBL_FW_MAJOR; guc->fw.minor_ver_wanted = KBL_FW_MINOR; + } else if (IS_GEMINILAKE(dev_priv)) { + guc->fw.path = I915_GLK_GUC_UCODE; + guc->fw.major_ver_wanted = GLK_FW_MAJOR; + guc->fw.minor_ver_wanted = GLK_FW_MINOR; } else { DRM_ERROR("No GuC firmware known for platform with GuC!\n"); return -ENOENT; From db5ba0d8931ee0e470805b972a905c869dc793bb Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 30 Mar 2017 13:24:07 -0700 Subject: [PATCH 0022/1270] drm/i915/GLK/HuC: Load HuC on GLK Load HuC version 1.07.1748 on GLK. v2: rebased. v3: Use name of the right platform(John Spotswood) v4: rebased. Cc: Jeff Mcgee Cc: John Spotswood Cc: Rodrigo Vivi Signed-off-by: Anusha Srivatsa Reviewed-by: John Spotswood Signed-off-by: Ander Conselvan de Oliveira Link: http://patchwork.freedesktop.org/patch/msgid/1490905447-15815-2-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/intel_huc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 385cacb65dbe..7a0bf1593463 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -52,6 +52,10 @@ #define KBL_HUC_FW_MINOR 00 #define KBL_BLD_NUM 1810 +#define GLK_HUC_FW_MAJOR 01 +#define GLK_HUC_FW_MINOR 07 +#define GLK_BLD_NUM 1748 + #define HUC_FW_PATH(platform, major, minor, bld_num) \ "i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \ __stringify(minor) "_" __stringify(bld_num) ".bin" @@ -68,6 +72,9 @@ MODULE_FIRMWARE(I915_BXT_HUC_UCODE); KBL_HUC_FW_MINOR, KBL_BLD_NUM) MODULE_FIRMWARE(I915_KBL_HUC_UCODE); +#define I915_GLK_HUC_UCODE HUC_FW_PATH(glk, GLK_HUC_FW_MAJOR, \ + GLK_HUC_FW_MINOR, GLK_BLD_NUM) + /** * huc_ucode_xfer() - DMA's the firmware * @dev_priv: the drm_i915_private device @@ -169,6 +176,10 @@ void intel_huc_select_fw(struct intel_huc *huc) huc->fw.path = I915_KBL_HUC_UCODE; huc->fw.major_ver_wanted = KBL_HUC_FW_MAJOR; huc->fw.minor_ver_wanted = KBL_HUC_FW_MINOR; + } else if (IS_GEMINILAKE(dev_priv)) { + huc->fw.path = I915_GLK_HUC_UCODE; + huc->fw.major_ver_wanted = GLK_HUC_FW_MAJOR; + huc->fw.minor_ver_wanted = GLK_HUC_FW_MINOR; } else { DRM_ERROR("No HuC firmware known for platform with HuC!\n"); return; From 2ca9faa551c4c97610bb0209e20c7231a93712ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Apr 2017 16:30:54 +0100 Subject: [PATCH 0023/1270] drm/i915: Assert the engine is idle before overwiting the HWS When we update the global seqno (on the engine timeline), we modify HW state (both registers and mapped pages). As we do this, we should be sure that the HW is idle and we are not causing a conflict. The caller is supposed to wait_for_idle before calling us to update the seqno, so let's assert they have and the engine is indeed idle. Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170405153055.28123-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem_request.c | 2 +- drivers/gpu/drm/i915/intel_engine_cs.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 6348353b91ec..2f8c5132b54e 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -214,8 +214,8 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) } /* Finally reset hw state */ - tl->seqno = seqno; intel_engine_init_global_seqno(engine, seqno); + tl->seqno = seqno; list_for_each_entry(timeline, &i915->gt.timelines, link) memset(timeline->engine[id].sync_seqno, 0, diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 854e8e0c836b..92f871cf3265 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -223,6 +223,8 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno) { struct drm_i915_private *dev_priv = engine->i915; + GEM_BUG_ON(!intel_engine_is_idle(engine)); + /* Our semaphore implementation is strictly monotonic (i.e. we proceed * so long as the semaphore value in the register/page is greater * than the sync value), so whenever we reset the seqno, @@ -260,6 +262,8 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno) * there are any waiters for that seqno. */ intel_engine_wakeup(engine); + + GEM_BUG_ON(intel_engine_get_seqno(engine) != seqno); } static void intel_engine_init_timeline(struct intel_engine_cs *engine) From cbb60b4b987c8a57533dca0f66887ed14a9498e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Apr 2017 18:00:28 +0100 Subject: [PATCH 0024/1270] drm/i915: Advance ring->head fully when idle When we retire the last request on the ring, before we ever access that ring again we know it will be completely idle and so we can advance the ring->head fully to the end (i.e. ring->tail) and not just to the start of the breadcrumb. This allows us to skip re-emitting the breadcrumb after resetting the GPU if the ring was entirely idle. This prevents us from overwriting a seqno wraparound by re-executing a stale breadcrumb, i.e. submit_request(1) intel_engine_init_global_seqno(0) i915_reset() would then leave 1 in the HWS, but the next request to execute would also be with seqno 1. The sanity checks upon submission detect this as a timewarp and explode. By setting the ring as empty, upon reset the HWS is left as 0, leaving it consistent with the timeline. v2: Fix check for deleting last element of list. We know that this request is always the first element of the ring, so only if next points back to the start will this be the only request in flight. v3: Remove opencoding of list_is_last() v4: Move the block to its own function for some clarity. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100144 Testcase: igt/gem_exec_whisper/hang-* Signed-off-by: Chris Wilson Cc: Mika Kuoppala Link: http://patchwork.freedesktop.org/patch/msgid/20170406170028.26871-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem_request.c | 32 +++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 2f8c5132b54e..313cdff7c6dd 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -271,6 +271,27 @@ void i915_gem_retire_noop(struct i915_gem_active *active, /* Space left intentionally blank */ } +static void advance_ring(struct drm_i915_gem_request *request) +{ + unsigned int tail; + + /* We know the GPU must have read the request to have + * sent us the seqno + interrupt, so use the position + * of tail of the request to update the last known position + * of the GPU head. + * + * Note this requires that we are always called in request + * completion order. + */ + if (list_is_last(&request->ring_link, &request->ring->request_list)) + tail = request->ring->tail; + else + tail = request->postfix; + list_del(&request->ring_link); + + request->ring->head = tail; +} + static void i915_gem_request_retire(struct drm_i915_gem_request *request) { struct intel_engine_cs *engine = request->engine; @@ -287,16 +308,6 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) list_del_init(&request->link); spin_unlock_irq(&engine->timeline->lock); - /* We know the GPU must have read the request to have - * sent us the seqno + interrupt, so use the position - * of tail of the request to update the last known position - * of the GPU head. - * - * Note this requires that we are always called in request - * completion order. - */ - list_del(&request->ring_link); - request->ring->head = request->postfix; if (!--request->i915->gt.active_requests) { GEM_BUG_ON(!request->i915->gt.awake); mod_delayed_work(request->i915->wq, @@ -304,6 +315,7 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) msecs_to_jiffies(100)); } unreserve_seqno(request->engine); + advance_ring(request); /* Walk through the active list, calling retire on each. This allows * objects to track their GPU activity and mark themselves as idle From 400c19d9f85c58913956eb5ca9705c9bdd4b8fe6 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 7 Apr 2017 01:23:45 +0200 Subject: [PATCH 0025/1270] i915: initialize the free_list of the fencing atomic_helper Just in case the llist model changes and NULL isn't valid initialization. Signed-off-by: Andrea Arcangeli Link: http://patchwork.freedesktop.org/patch/msgid/20170406232347.988-4-aarcange@redhat.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 26e871a4c30c..b60ba164f567 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14992,6 +14992,7 @@ int intel_modeset_init(struct drm_device *dev) dev->mode_config.funcs = &intel_mode_funcs; + init_llist_head(&dev_priv->atomic_helper.free_list); INIT_WORK(&dev_priv->atomic_helper.free_work, intel_atomic_helper_free_state_worker); From d0aa301ae5a60cdfddac12888dc373a68985335b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Apr 2017 11:25:49 +0100 Subject: [PATCH 0026/1270] drm/i915: The shrinker already acquires struct_mutex, so call it unlocked The shrinker is prepared to be called unlocked (and at other times with struct_mutex held for DIRECT_RECLAIM) so we can skip acquiring the struct_mutex prior to calling the shrinker during freeze. This improves our ability to shrink as we can be more aggressive when we know the caller isn't holding struct_mutex. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170407102552.5781-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 391aa69097f1..372183e21c72 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4864,9 +4864,10 @@ void i915_gem_load_cleanup(struct drm_i915_private *dev_priv) int i915_gem_freeze(struct drm_i915_private *dev_priv) { - mutex_lock(&dev_priv->drm.struct_mutex); + /* Discard all purgeable objects, let userspace recover those as + * required after resuming. + */ i915_gem_shrink_all(dev_priv); - mutex_unlock(&dev_priv->drm.struct_mutex); return 0; } @@ -4891,12 +4892,12 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv) * we update that state just before writing out the image. * * To try and reduce the hibernation image, we manually shrink - * the objects as well. + * the objects as well, see i915_gem_freeze() */ - mutex_lock(&dev_priv->drm.struct_mutex); i915_gem_shrink(dev_priv, -1UL, I915_SHRINK_UNBOUND); + mutex_lock(&dev_priv->drm.struct_mutex); for (p = phases; *p; p++) { list_for_each_entry(obj, *p, global_link) { obj->base.read_domains = I915_GEM_DOMAIN_CPU; From 17b93c40e74868c92f23a3e95c905bc3296580e9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Apr 2017 11:25:50 +0100 Subject: [PATCH 0027/1270] drm/i915: Drain any freed objects prior to hibernation As we call into the shrinker during freeze, we may have freed more objects since we idled during i915_gem_suspend. Make sure we flush the i915_gem_free_objects worker prior to saving the unwanted pages into the hibernation image. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170407102552.5781-2-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 372183e21c72..38e4e58a801e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4896,6 +4896,7 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv) */ i915_gem_shrink(dev_priv, -1UL, I915_SHRINK_UNBOUND); + i915_gem_drain_freed_objects(dev_priv); mutex_lock(&dev_priv->drm.struct_mutex); for (p = phases; *p; p++) { From 8f612d055183545070ca1009ac2eb1f2e044cc20 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Fri, 7 Apr 2017 13:49:34 +0300 Subject: [PATCH 0028/1270] drm/i915: Don't call synchronize_rcu_expedited under struct_mutex Only call synchronize_rcu_expedited after unlocking struct_mutex to avoid deadlock because the workqueues depend on struct_mutex. >From original patch by Andrea: synchronize_rcu/synchronize_sched/synchronize_rcu_expedited() will hang until its own workqueues are run. The i915 gem workqueues will wait on the struct_mutex to be released. So we cannot wait for a quiescent state using those rcu primitives while holding the struct_mutex or it creates a circular lock dependency resulting in kernel hangs (which is reproducible but goes undetected by lockdep). kswapd0 D 0 700 2 0x00000000 Call Trace: ? __schedule+0x1a5/0x660 ? schedule+0x36/0x80 ? _synchronize_rcu_expedited.constprop.65+0x2ef/0x300 ? wake_up_bit+0x20/0x20 ? rcu_stall_kick_kthreads.part.54+0xc0/0xc0 ? rcu_exp_wait_wake+0x530/0x530 ? i915_gem_shrink+0x34b/0x4b0 ? i915_gem_shrinker_scan+0x7c/0x90 ? i915_gem_shrinker_scan+0x7c/0x90 ? shrink_slab.part.61.constprop.72+0x1c1/0x3a0 ? shrink_zone+0x154/0x160 ? kswapd+0x40a/0x720 ? kthread+0xf4/0x130 ? try_to_free_pages+0x450/0x450 ? kthread_create_on_node+0x40/0x40 ? ret_from_fork+0x23/0x30 plasmashell D 0 4657 4614 0x00000000 Call Trace: ? __schedule+0x1a5/0x660 ? schedule+0x36/0x80 ? schedule_preempt_disabled+0xe/0x10 ? __mutex_lock.isra.4+0x1c9/0x790 ? i915_gem_close_object+0x26/0xc0 ? i915_gem_close_object+0x26/0xc0 ? drm_gem_object_release_handle+0x48/0x90 ? drm_gem_handle_delete+0x50/0x80 ? drm_ioctl+0x1fa/0x420 ? drm_gem_handle_create+0x40/0x40 ? pipe_write+0x391/0x410 ? __vfs_write+0xc6/0x120 ? do_vfs_ioctl+0x8b/0x5d0 ? SyS_ioctl+0x3b/0x70 ? entry_SYSCALL_64_fastpath+0x13/0x94 kworker/0:0 D 0 29186 2 0x00000000 Workqueue: events __i915_gem_free_work Call Trace: ? __schedule+0x1a5/0x660 ? schedule+0x36/0x80 ? schedule_preempt_disabled+0xe/0x10 ? __mutex_lock.isra.4+0x1c9/0x790 ? del_timer_sync+0x44/0x50 ? update_curr+0x57/0x110 ? __i915_gem_free_objects+0x31/0x300 ? __i915_gem_free_objects+0x31/0x300 ? __i915_gem_free_work+0x2d/0x40 ? process_one_work+0x13a/0x3b0 ? worker_thread+0x4a/0x460 ? kthread+0xf4/0x130 ? process_one_work+0x3b0/0x3b0 ? kthread_create_on_node+0x40/0x40 ? ret_from_fork+0x23/0x30 Fixes: 3d3d18f086cd ("drm/i915: Avoid rcu_barrier() from reclaim paths (shrinker)") Reported-by: Andrea Arcangeli Signed-off-by: Joonas Lahtinen Cc: Andrea Arcangeli Cc: Chris Wilson Cc: Daniel Vetter Cc: Jani Nikula Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_shrinker.c | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 2978acdd995e..129ed303a6c4 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -53,6 +53,17 @@ static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) BUG(); } +static void i915_gem_shrinker_unlock(struct drm_device *dev, bool unlock) +{ + if (!unlock) + return; + + mutex_unlock(&dev->struct_mutex); + + /* expedite the RCU grace period to free some request slabs */ + synchronize_rcu_expedited(); +} + static bool any_vma_pinned(struct drm_i915_gem_object *obj) { struct i915_vma *vma; @@ -232,11 +243,8 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, intel_runtime_pm_put(dev_priv); i915_gem_retire_requests(dev_priv); - if (unlock) - mutex_unlock(&dev_priv->drm.struct_mutex); - /* expedite the RCU grace period to free some request slabs */ - synchronize_rcu_expedited(); + i915_gem_shrinker_unlock(&dev_priv->drm, unlock); return count; } @@ -296,8 +304,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) count += obj->base.size >> PAGE_SHIFT; } - if (unlock) - mutex_unlock(&dev->struct_mutex); + i915_gem_shrinker_unlock(dev, unlock); return count; } @@ -324,8 +331,8 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) sc->nr_to_scan - freed, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); - if (unlock) - mutex_unlock(&dev->struct_mutex); + + i915_gem_shrinker_unlock(dev, unlock); return freed; } @@ -367,8 +374,7 @@ i915_gem_shrinker_unlock_uninterruptible(struct drm_i915_private *dev_priv, struct shrinker_lock_uninterruptible *slu) { dev_priv->mm.interruptible = slu->was_interruptible; - if (slu->unlock) - mutex_unlock(&dev_priv->drm.struct_mutex); + i915_gem_shrinker_unlock(&dev_priv->drm, slu->unlock); } static int From e92075ff7dc54305bd5709a758ffe825aef35e8f Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Fri, 7 Apr 2017 13:49:35 +0300 Subject: [PATCH 0029/1270] drm/i915: Simplify shrinker locking By using the same structure for both interruptible and uninterruptible locking in shrinker code, combined with the information that mm.interruptible is only being written to, the code can be greatly simplified. Also removing the i915_gem_ prefix from the locking functions so that nobody in their wildest dreams considers exporting them. Signed-off-by: Joonas Lahtinen Cc: Chris Wilson Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1491562175-27680-1-git-send-email-joonas.lahtinen@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 6 --- drivers/gpu/drm/i915/i915_gem.c | 2 - drivers/gpu/drm/i915/i915_gem_shrinker.c | 56 ++++++++---------------- drivers/gpu/drm/i915/intel_display.c | 3 -- 4 files changed, 19 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c9b0949f6c1a..f990f0eff95c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1511,12 +1511,6 @@ struct i915_gem_mm { /** LRU list of objects with fence regs on them. */ struct list_head fence_list; - /** - * Are we in a non-interruptible section of code like - * modesetting? - */ - bool interruptible; - /* the indicator for dispatch video commands on two BSD rings */ atomic_t bsd_engine_dispatch_index; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 38e4e58a801e..5cfe63e3cb28 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4822,8 +4822,6 @@ i915_gem_load_init(struct drm_i915_private *dev_priv) init_waitqueue_head(&dev_priv->pending_flip_queue); - dev_priv->mm.interruptible = true; - atomic_set(&dev_priv->mm.bsd_engine_dispatch_index, 0); spin_lock_init(&dev_priv->fb_tracking.lock); diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 129ed303a6c4..0e7352d82ca4 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -35,9 +35,9 @@ #include "i915_drv.h" #include "i915_trace.h" -static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) +static bool shrinker_lock(struct drm_i915_private *dev_priv, bool *unlock) { - switch (mutex_trylock_recursive(&dev->struct_mutex)) { + switch (mutex_trylock_recursive(&dev_priv->drm.struct_mutex)) { case MUTEX_TRYLOCK_FAILED: return false; @@ -53,12 +53,12 @@ static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) BUG(); } -static void i915_gem_shrinker_unlock(struct drm_device *dev, bool unlock) +static void shrinker_unlock(struct drm_i915_private *dev_priv, bool unlock) { if (!unlock) return; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->drm.struct_mutex); /* expedite the RCU grace period to free some request slabs */ synchronize_rcu_expedited(); @@ -156,7 +156,7 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long count = 0; bool unlock; - if (!i915_gem_shrinker_lock(&dev_priv->drm, &unlock)) + if (!shrinker_lock(dev_priv, &unlock)) return 0; trace_i915_gem_shrink(dev_priv, target, flags); @@ -244,7 +244,7 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, i915_gem_retire_requests(dev_priv); - i915_gem_shrinker_unlock(&dev_priv->drm, unlock); + shrinker_unlock(dev_priv, unlock); return count; } @@ -284,12 +284,11 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) { struct drm_i915_private *dev_priv = container_of(shrinker, struct drm_i915_private, mm.shrinker); - struct drm_device *dev = &dev_priv->drm; struct drm_i915_gem_object *obj; unsigned long count; bool unlock; - if (!i915_gem_shrinker_lock(dev, &unlock)) + if (!shrinker_lock(dev_priv, &unlock)) return 0; i915_gem_retire_requests(dev_priv); @@ -304,7 +303,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) count += obj->base.size >> PAGE_SHIFT; } - i915_gem_shrinker_unlock(dev, unlock); + shrinker_unlock(dev_priv, unlock); return count; } @@ -314,11 +313,10 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) { struct drm_i915_private *dev_priv = container_of(shrinker, struct drm_i915_private, mm.shrinker); - struct drm_device *dev = &dev_priv->drm; unsigned long freed; bool unlock; - if (!i915_gem_shrinker_lock(dev, &unlock)) + if (!shrinker_lock(dev_priv, &unlock)) return SHRINK_STOP; freed = i915_gem_shrink(dev_priv, @@ -332,26 +330,20 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); - i915_gem_shrinker_unlock(dev, unlock); + shrinker_unlock(dev_priv, unlock); return freed; } -struct shrinker_lock_uninterruptible { - bool was_interruptible; - bool unlock; -}; - static bool -i915_gem_shrinker_lock_uninterruptible(struct drm_i915_private *dev_priv, - struct shrinker_lock_uninterruptible *slu, - int timeout_ms) +shrinker_lock_uninterruptible(struct drm_i915_private *dev_priv, bool *unlock, + int timeout_ms) { unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms); do { if (i915_gem_wait_for_idle(dev_priv, 0) == 0 && - i915_gem_shrinker_lock(&dev_priv->drm, &slu->unlock)) + shrinker_lock(dev_priv, unlock)) break; schedule_timeout_killable(1); @@ -364,29 +356,19 @@ i915_gem_shrinker_lock_uninterruptible(struct drm_i915_private *dev_priv, } } while (1); - slu->was_interruptible = dev_priv->mm.interruptible; - dev_priv->mm.interruptible = false; return true; } -static void -i915_gem_shrinker_unlock_uninterruptible(struct drm_i915_private *dev_priv, - struct shrinker_lock_uninterruptible *slu) -{ - dev_priv->mm.interruptible = slu->was_interruptible; - i915_gem_shrinker_unlock(&dev_priv->drm, slu->unlock); -} - static int i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) { struct drm_i915_private *dev_priv = container_of(nb, struct drm_i915_private, mm.oom_notifier); - struct shrinker_lock_uninterruptible slu; struct drm_i915_gem_object *obj; unsigned long unevictable, bound, unbound, freed_pages; + bool unlock; - if (!i915_gem_shrinker_lock_uninterruptible(dev_priv, &slu, 5000)) + if (!shrinker_lock_uninterruptible(dev_priv, &unlock, 5000)) return NOTIFY_DONE; freed_pages = i915_gem_shrink_all(dev_priv); @@ -415,7 +397,7 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) bound += obj->base.size >> PAGE_SHIFT; } - i915_gem_shrinker_unlock_uninterruptible(dev_priv, &slu); + shrinker_unlock(dev_priv, unlock); if (freed_pages || unbound || bound) pr_info("Purging GPU memory, %lu pages freed, " @@ -435,12 +417,12 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr { struct drm_i915_private *dev_priv = container_of(nb, struct drm_i915_private, mm.vmap_notifier); - struct shrinker_lock_uninterruptible slu; struct i915_vma *vma, *next; unsigned long freed_pages = 0; + bool unlock; int ret; - if (!i915_gem_shrinker_lock_uninterruptible(dev_priv, &slu, 5000)) + if (!shrinker_lock_uninterruptible(dev_priv, &unlock, 5000)) return NOTIFY_DONE; /* Force everything onto the inactive lists */ @@ -465,7 +447,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr } out: - i915_gem_shrinker_unlock_uninterruptible(dev_priv, &slu); + shrinker_unlock(dev_priv, unlock); *(unsigned long *)ptr += freed_pages; return NOTIFY_DONE; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b60ba164f567..ced8a12d5792 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4872,12 +4872,9 @@ static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc) { if (intel_crtc->overlay) { struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev->struct_mutex); - dev_priv->mm.interruptible = false; (void) intel_overlay_switch_off(intel_crtc->overlay); - dev_priv->mm.interruptible = true; mutex_unlock(&dev->struct_mutex); } From 5ad08be7e34fc6f3c6936ac40063ea839d4ce0d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Apr 2017 11:25:51 +0100 Subject: [PATCH 0030/1270] drm/i915: Break up long runs of freeing objects Before freeing the next batch of objects from the worker, check if the worker's timeslice has expired and if so, defer the next batch to the next invocation of the worker. Suggested-by: Andrea Arcangeli Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170407102552.5781-3-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5cfe63e3cb28..9bc4d8917107 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4349,8 +4349,11 @@ static void __i915_gem_free_work(struct work_struct *work) * unbound now. */ - while ((freed = llist_del_all(&i915->mm.free_list))) + while ((freed = llist_del_all(&i915->mm.free_list))) { __i915_gem_free_objects(i915, freed); + if (need_resched()) + break; + } } static void __i915_gem_free_object_rcu(struct rcu_head *head) From f2be9d68334dbb4ab8a3aa40b1633e3f408c616b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Apr 2017 11:25:52 +0100 Subject: [PATCH 0031/1270] drm/i915: Insert cond_resched() into i915_gem_free_objects As we may have very many objects to free, check to see if the task needs to be rescheduled whilst freeing them. Suggested-by: Andrea Arcangeli Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170407102552.5781-4-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9bc4d8917107..b210acc3d0b4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4302,6 +4302,8 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915, intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); + cond_resched(); + llist_for_each_entry_safe(obj, on, freed, freed) { GEM_BUG_ON(obj->bind_count); GEM_BUG_ON(atomic_read(&obj->frontbuffer_bits)); From d769ab182771df6d7ad6c3ecb0449d94043b7921 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 7 Apr 2017 13:32:10 +0000 Subject: [PATCH 0032/1270] drm/i915: Fix type of timeout_ms parameter in intel_wait_for_register_fw() There is no need to specify timeout as unsigned long since this parameter will be consumed by usecs_to_jiffies() which expects unsigned int only. Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170407133212.174608-1-michal.wajdeczko@intel.com Reviewed-by: Tvrtko Ursulin Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f990f0eff95c..59433df46859 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3092,7 +3092,7 @@ int intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, const u32 mask, const u32 value, - const unsigned long timeout_ms); + const unsigned int timeout_ms); static inline bool intel_gvt_active(struct drm_i915_private *dev_priv) { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 6d1ea26b2493..bcabf54ef854 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1610,7 +1610,7 @@ int intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, const u32 mask, const u32 value, - const unsigned long timeout_ms) + const unsigned int timeout_ms) { #define done ((I915_READ_FW(reg) & mask) == value) int ret = wait_for_us(done, 2); From 1d1a9774e40414148ecebbdb713746bfb6f9a561 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 7 Apr 2017 16:01:44 +0000 Subject: [PATCH 0033/1270] drm/i915: Extend intel_wait_for_register_fw() with fast timeout In some cases we may want to spend more time in atomic wait than hardcoded 2us. Let's add additional fast timeout parameter to allow flexible configuration of atomic timeout before switching into heavy wait. Add also possibility to return registry value to avoid extra read. v2: use explicit fast timeout (Tvrtko/Chris) allow returning register value (Chris) Signed-off-by: Michal Wajdeczko Suggested-by: Tvrtko Ursulin Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170407160145.181328-1-michal.wajdeczko@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 14 +++++++++++- drivers/gpu/drm/i915/intel_uncore.c | 34 +++++++++++++++++++---------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 59433df46859..bb6fc1e08a52 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3088,11 +3088,23 @@ int intel_wait_for_register(struct drm_i915_private *dev_priv, const u32 mask, const u32 value, const unsigned long timeout_ms); +int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, + i915_reg_t reg, + const u32 mask, + const u32 value, + const unsigned int fast_timeout_us, + const unsigned int slow_timeout_ms, + u32 *out_value); +static inline int intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, const u32 mask, const u32 value, - const unsigned int timeout_ms); + const unsigned int timeout_ms) +{ + return __intel_wait_for_register_fw(dev_priv, reg, mask, value, + 2, timeout_ms, NULL); +} static inline bool intel_gvt_active(struct drm_i915_private *dev_priv) { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index bcabf54ef854..ace099381d11 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1585,19 +1585,21 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, } /** - * intel_wait_for_register_fw - wait until register matches expected state + * __intel_wait_for_register_fw - wait until register matches expected state * @dev_priv: the i915 device * @reg: the register to read * @mask: mask to apply to register value * @value: expected value - * @timeout_ms: timeout in millisecond + * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait + * @slow_timeout_ms: slow timeout in millisecond + * @out_value: optional placeholder to hold registry value * * This routine waits until the target register @reg contains the expected * @value after applying the @mask, i.e. it waits until :: * * (I915_READ_FW(reg) & mask) == value * - * Otherwise, the wait will timeout after @timeout_ms milliseconds. + * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds. * * Note that this routine assumes the caller holds forcewake asserted, it is * not suitable for very long waits. See intel_wait_for_register() if you @@ -1606,16 +1608,26 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, * * Returns 0 if the register matches the desired condition, or -ETIMEOUT. */ -int intel_wait_for_register_fw(struct drm_i915_private *dev_priv, - i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned int timeout_ms) +int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, + i915_reg_t reg, + const u32 mask, + const u32 value, + const unsigned int fast_timeout_us, + const unsigned int slow_timeout_ms, + u32 *out_value) { -#define done ((I915_READ_FW(reg) & mask) == value) - int ret = wait_for_us(done, 2); + u32 reg_value; +#define done (((reg_value = I915_READ_FW(reg)) & mask) == value) + int ret; + + if (fast_timeout_us > 10) + ret = _wait_for(done, fast_timeout_us, 10); + else + ret = _wait_for_atomic(done, fast_timeout_us, 0); if (ret) - ret = wait_for(done, timeout_ms); + ret = wait_for(done, slow_timeout_ms); + if (out_value) + *out_value = reg_value; return ret; #undef done } From bea4e4a4f831df1c104be60b3caa7205ba1bb4f9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 7 Apr 2017 16:01:45 +0000 Subject: [PATCH 0034/1270] drm/i915/guc: Use wait_for_register_fw() while waiting for MMIO response Waiting for the response status in scratch register can be done using our generic function. Let's use it. v2: rebased Signed-off-by: Michal Wajdeczko Suggested-by: Tvrtko Ursulin Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170407160145.181328-2-michal.wajdeczko@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_uc.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index c117424f1f50..4364b1a9064e 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -359,19 +359,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv) i915_ggtt_disable_guc(dev_priv); } -/* - * Read GuC command/status register (SOFT_SCRATCH_0) - * Return true if it contains a response rather than a command - */ -static bool guc_recv(struct intel_guc *guc, u32 *status) -{ - struct drm_i915_private *dev_priv = guc_to_i915(guc); - - u32 val = I915_READ(SOFT_SCRATCH(0)); - *status = val; - return INTEL_GUC_RECV_IS_RESPONSE(val); -} - /* * This function implements the MMIO based host to GuC interface. */ @@ -399,13 +386,14 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) I915_WRITE(GUC_SEND_INTERRUPT, GUC_SEND_TRIGGER); /* - * Fast commands should complete in less than 10us, so sample quickly - * up to that length of time, then switch to a slower sleep-wait loop. - * No inte_guc_send command should ever take longer than 10ms. + * No GuC command should ever take longer than 10ms. + * Fast commands should still complete in 10us. */ - ret = wait_for_us(guc_recv(guc, &status), 10); - if (ret) - ret = wait_for(guc_recv(guc, &status), 10); + ret = __intel_wait_for_register_fw(dev_priv, + SOFT_SCRATCH(0), + INTEL_GUC_RECV_MASK, + INTEL_GUC_RECV_MASK, + 10, 10, &status); if (status != INTEL_GUC_STATUS_SUCCESS) { /* * Either the GuC explicitly returned an error (which From c18701c5f2c9fdb2386d521c1a1f7b216c041b4a Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 10 Apr 2017 12:06:41 +0530 Subject: [PATCH 0035/1270] MAINTAINERS: Update maintainers/reviewers for bridge drivers Add Laurent as a reviewer and Andrzej as a maintainer for DRM bridge chip drivers. They actively review and contribute to bridge drivers and the bridge API. Acked-by: Andrzej Hajda Acked-by: Laurent Pinchart Acked-by: Sean Paul Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170410063641.17704-1-architt@codeaurora.org --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4ea82b26cc2e..c36dfaeef26b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4168,6 +4168,8 @@ F: drivers/gpu/drm/ast/ DRM DRIVERS FOR BRIDGE CHIPS M: Archit Taneja +M: Andrzej Hajda +R: Laurent Pinchart S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/bridge/ From bcc36d8a4f1eb91a05655471f0c8cf2b5be07b16 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Apr 2017 20:42:20 +0100 Subject: [PATCH 0036/1270] drm/i915: Use drm_i915_private directly from debugfs The void *data passed to debugfs callbacks is actually the drm_i915_private pointer, so use it thusly and avoid the to_i915(dev) indirection. Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170407194220.821-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_debugfs.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d689e511744e..870c470177b5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2568,8 +2568,7 @@ static int i915_guc_log_dump(struct seq_file *m, void *data) static int i915_guc_log_control_get(void *data, u64 *val) { - struct drm_device *dev = data; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = data; if (!dev_priv->guc.log.vma) return -EINVAL; @@ -2581,14 +2580,13 @@ static int i915_guc_log_control_get(void *data, u64 *val) static int i915_guc_log_control_set(void *data, u64 val) { - struct drm_device *dev = data; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = data; int ret; if (!dev_priv->guc.log.vma) return -EINVAL; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex); if (ret) return ret; @@ -2596,7 +2594,7 @@ static int i915_guc_log_control_set(void *data, u64 val) ret = i915_guc_log_control(dev_priv, val); intel_runtime_pm_put(dev_priv); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->drm.struct_mutex); return ret; } From 3fc7d86b3268af92181b517ca832258809b2d771 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 10 Apr 2017 09:38:17 +0000 Subject: [PATCH 0037/1270] drm/i915: Drop const qualifiers from params in wait_for_register() These params are passed by value, const qualifiers are ignored any way. While around, unify timeout_ms type from long to int. Signed-off-by: Michal Wajdeczko Suggested-by: Joonas Lahtinen Cc: Joonas Lahtinen Cc: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170410093817.151280-1-michal.wajdeczko@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_uncore.c | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bb6fc1e08a52..ed079c244b5d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3085,22 +3085,22 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv); int intel_wait_for_register(struct drm_i915_private *dev_priv, i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned long timeout_ms); + u32 mask, + u32 value, + unsigned int timeout_ms); int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned int fast_timeout_us, - const unsigned int slow_timeout_ms, + u32 mask, + u32 value, + unsigned int fast_timeout_us, + unsigned int slow_timeout_ms, u32 *out_value); static inline int intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned int timeout_ms) + u32 mask, + u32 value, + unsigned int timeout_ms) { return __intel_wait_for_register_fw(dev_priv, reg, mask, value, 2, timeout_ms, NULL); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index ace099381d11..1deb1a4342ba 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1610,10 +1610,10 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, */ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned int fast_timeout_us, - const unsigned int slow_timeout_ms, + u32 mask, + u32 value, + unsigned int fast_timeout_us, + unsigned int slow_timeout_ms, u32 *out_value) { u32 reg_value; @@ -1651,9 +1651,9 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, */ int intel_wait_for_register(struct drm_i915_private *dev_priv, i915_reg_t reg, - const u32 mask, - const u32 value, - const unsigned long timeout_ms) + u32 mask, + u32 value, + unsigned int timeout_ms) { unsigned fw = From 6976e74b5fa12430b36c3b0f8afd7e8e695be0ab Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 10 Apr 2017 12:17:47 +0000 Subject: [PATCH 0038/1270] drm/i915: Don't allow overuse of __intel_wait_for_register_fw() This function should not be called with long timeouts in atomic context. Annotate it as might_sleep if timeout is longer than 10us. v2: fix comment (Michal) Signed-off-by: Michal Wajdeczko Suggested-by: Chris Wilson Cc: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170410121747.209200-1-michal.wajdeczko@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_uncore.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 1deb1a4342ba..eb38392a2435 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1600,6 +1600,8 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, * (I915_READ_FW(reg) & mask) == value * * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds. + * For atomic context @slow_timeout_ms must be zero and @fast_timeout_us + * must be not larger than 10 microseconds. * * Note that this routine assumes the caller holds forcewake asserted, it is * not suitable for very long waits. See intel_wait_for_register() if you @@ -1620,6 +1622,9 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, #define done (((reg_value = I915_READ_FW(reg)) & mask) == value) int ret; + /* Catch any overuse of this function */ + might_sleep_if(fast_timeout_us > 10 || slow_timeout_ms); + if (fast_timeout_us > 10) ret = _wait_for(done, fast_timeout_us, 10); else From 84d84cb7e20d3d2c6413c5f75634e88eb68a3f97 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 12:27:05 +0100 Subject: [PATCH 0039/1270] drm/i915: Stop second guessing the caller for intel_uncore_wait_for_register() Allow the caller to use the fast_timeout_us to specify how long to wait within the atomic section, rather than transparently switching to a sleeping loop for larger values. This is required as some callsites may need a long wait and are in an atomic section. v2: Reinforce kerneldoc fast_timeout_us limit with a GEM_BUG_ON Signed-off-by: Chris Wilson Cc: Michal Wajdeczko Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170411112705.12656-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_uncore.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index eb38392a2435..dded42db880b 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1601,7 +1601,7 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, * * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds. * For atomic context @slow_timeout_ms must be zero and @fast_timeout_us - * must be not larger than 10 microseconds. + * must be not larger than 20,0000 microseconds. * * Note that this routine assumes the caller holds forcewake asserted, it is * not suitable for very long waits. See intel_wait_for_register() if you @@ -1623,16 +1623,18 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, int ret; /* Catch any overuse of this function */ - might_sleep_if(fast_timeout_us > 10 || slow_timeout_ms); + might_sleep_if(slow_timeout_ms); + GEM_BUG_ON(fast_timeout_us > 20000); - if (fast_timeout_us > 10) - ret = _wait_for(done, fast_timeout_us, 10); - else + ret = -ETIMEDOUT; + if (fast_timeout_us && fast_timeout_us <= 20000) ret = _wait_for_atomic(done, fast_timeout_us, 0); if (ret) ret = wait_for(done, slow_timeout_ms); + if (out_value) *out_value = reg_value; + return ret; #undef done } From 02b312d05d1b51008e37f72f5a30c88e11c51ea5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 11:13:37 +0100 Subject: [PATCH 0040/1270] drm/i915: Stop sleeping from inside gen6_bsd_submit_request() submit_request() is called from an atomic context, it's not allowed to sleep. We have to be careful in our parameters to intel_uncore_wait_for_register() to limit ourselves to the atomic wait loop and not incur the wrath of our warnings. Fixes: 6976e74b5fa1 ("drm/i915: Don't allow overuse of __intel_wait_for_register_fw()") Signed-off-by: Chris Wilson Cc: Michal Wajdeczko Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170410143807.22725-1-chris@chris-wilson.co.uk Link: http://patchwork.freedesktop.org/patch/msgid/20170411101340.31994-2-chris@chris-wilson.co.uk Reviewed-by: Michal Wajdeczko Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c98acc27279a..331da59a1eb5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1729,11 +1729,11 @@ static void gen6_bsd_submit_request(struct drm_i915_gem_request *request) I915_WRITE64_FW(GEN6_BSD_RNCID, 0x0); /* Wait for the ring not to be idle, i.e. for it to wake up. */ - if (intel_wait_for_register_fw(dev_priv, - GEN6_BSD_SLEEP_PSMI_CONTROL, - GEN6_BSD_SLEEP_INDICATOR, - 0, - 50)) + if (__intel_wait_for_register_fw(dev_priv, + GEN6_BSD_SLEEP_PSMI_CONTROL, + GEN6_BSD_SLEEP_INDICATOR, + 0, + 1000, 0, NULL)) DRM_ERROR("timed out waiting for the BSD ring to wake up\n"); /* Now that the ring is fully powered up, update the tail */ From 0564654340e2776843ade007c1aaa8e8f30dd147 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 11:13:38 +0100 Subject: [PATCH 0041/1270] drm/i915: Acquire uncore.lock over intel_uncore_wait_for_register() We acquire the forcewake and use I915_READ_FW instead for the atomic wait within intel_uncore_wait_for_register. However, this still leaves us vulnerable to concurrent mmio access to the register, which can cause system hangs on gen7. The protection is to acquire uncore.lock around each register, so lets add it back. v2: Wrap __intel_wait_for_register_fw() to re-use its atomic wait_for loop and spare adding another for ourselves. v3: Add might_sleep() annotation Signed-off-by: Chris Wilson Cc: Michal Wajdeczko Cc: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170411101340.31994-3-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_uncore.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index dded42db880b..fb38c7692fc2 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1662,14 +1662,22 @@ int intel_wait_for_register(struct drm_i915_private *dev_priv, u32 value, unsigned int timeout_ms) { - unsigned fw = intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ); int ret; - intel_uncore_forcewake_get(dev_priv, fw); - ret = wait_for_us((I915_READ_FW(reg) & mask) == value, 2); - intel_uncore_forcewake_put(dev_priv, fw); + might_sleep(); + + spin_lock_irq(&dev_priv->uncore.lock); + intel_uncore_forcewake_get__locked(dev_priv, fw); + + ret = __intel_wait_for_register_fw(dev_priv, + reg, mask, value, + 2, 0, NULL); + + intel_uncore_forcewake_put__locked(dev_priv, fw); + spin_unlock_irq(&dev_priv->uncore.lock); + if (ret) ret = wait_for((I915_READ_NOTRACE(reg) & mask) == value, timeout_ms); From e09a3036412a959689bacf017bf2cbc226c9fea4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 11:13:39 +0100 Subject: [PATCH 0042/1270] drm/i915: Use __intel_uncore_wait_for_register_fw for sandybride_pcode_read Since the sandybridge_pcode_read() may be called from skl_pcode_request() inside an atomic context (with preempt disabled), we should avoid hitting any sleeping paths. Currently is being called with a 500ms timeout, irrespective of being inside an atomic context or not. This is reduced down to 500us to play nice with the atomic context, and that appears to be sufficient to keep BAT happy (we have a DRM_ERROR should it timeout), i.e. we do not see any 500us pcode timeouts for normal use. So leave it as a pure spin without having to introduce new code paths to separate atomic/normal contexts. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170411101340.31994-4-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_pm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 55e1e88cd361..cacb65fa2dd5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -8135,9 +8135,9 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val I915_WRITE_FW(GEN6_PCODE_DATA1, 0); I915_WRITE_FW(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); - if (intel_wait_for_register_fw(dev_priv, - GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - 500)) { + if (__intel_wait_for_register_fw(dev_priv, + GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, + 500, 0, NULL)) { DRM_ERROR("timeout waiting for pcode read (%d) to finish\n", mbox); return -ETIMEDOUT; } @@ -8180,9 +8180,9 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, I915_WRITE_FW(GEN6_PCODE_DATA1, 0); I915_WRITE_FW(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); - if (intel_wait_for_register_fw(dev_priv, - GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - 500)) { + if (__intel_wait_for_register_fw(dev_priv, + GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, + 500, 0, NULL)) { DRM_ERROR("timeout waiting for pcode write (%d) to finish\n", mbox); return -ETIMEDOUT; } From f42bb651d1e796ad6d86fc66d578abdee445696b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 11:13:40 +0100 Subject: [PATCH 0043/1270] drm/i915: Use safer intel_uncore_wait_for_register in ring-init While we do hold the forcewake for legacy ringbuffer initialisation, we don't guard our access with the uncore.lock spinlock. In theory, we only initialise when no others should be accessing the same mmio cachelines, but in practice be safe as this is an infrequently used path and not worth risky micro-optimisations. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170411101340.31994-5-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 331da59a1eb5..97d5fcca8805 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -538,9 +538,9 @@ static int init_ring_common(struct intel_engine_cs *engine) I915_WRITE_CTL(engine, RING_CTL_SIZE(ring->size) | RING_VALID); /* If the head is still not zero, the ring is dead */ - if (intel_wait_for_register_fw(dev_priv, RING_CTL(engine->mmio_base), - RING_VALID, RING_VALID, - 50)) { + if (intel_wait_for_register(dev_priv, RING_CTL(engine->mmio_base), + RING_VALID, RING_VALID, + 50)) { DRM_ERROR("%s initialization failed " "ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n", engine->name, From 0908180b9a1cf8c5410d0c1151894fae710744dc Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Mon, 10 Apr 2017 07:34:29 -0700 Subject: [PATCH 0044/1270] drm/i915: Classify the engines in class + instance In such a way that vcs and vcs2 are just two different instances (0 and 1) of the same engine class (VIDEO_DECODE_CLASS). v2: Align the instance types (Tvrtko) v3: Don't use enums for bspec-defined stuff (Michal) Cc: Paulo Zanoni Cc: Rodrigo Vivi Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Tvrtko Ursulin Reviewed-by: Michal Wajdeczko Signed-off-by: Oscar Mateo Link: http://patchwork.freedesktop.org/patch/msgid/1491834873-9345-2-git-send-email-oscar.mateo@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_engine_cs.c | 14 ++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++++ 3 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 11b12f412492..4c72adae368b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -85,6 +85,14 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define VECS_HW 3 #define VCS2_HW 4 +/* Engine class */ + +#define RENDER_CLASS 0 +#define VIDEO_DECODE_CLASS 1 +#define VIDEO_ENHANCEMENT_CLASS 2 +#define COPY_ENGINE_CLASS 3 +#define OTHER_CLASS 4 + /* PCI config space */ #define MCHBAR_I915 0x44 diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 92f871cf3265..bb229274c30d 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -30,6 +30,8 @@ static const struct engine_info { const char *name; unsigned int exec_id; unsigned int hw_id; + u8 class; + u8 instance; u32 mmio_base; unsigned irq_shift; int (*init_legacy)(struct intel_engine_cs *engine); @@ -39,6 +41,8 @@ static const struct engine_info { .name = "rcs", .hw_id = RCS_HW, .exec_id = I915_EXEC_RENDER, + .class = RENDER_CLASS, + .instance = 0, .mmio_base = RENDER_RING_BASE, .irq_shift = GEN8_RCS_IRQ_SHIFT, .init_execlists = logical_render_ring_init, @@ -48,6 +52,8 @@ static const struct engine_info { .name = "bcs", .hw_id = BCS_HW, .exec_id = I915_EXEC_BLT, + .class = COPY_ENGINE_CLASS, + .instance = 0, .mmio_base = BLT_RING_BASE, .irq_shift = GEN8_BCS_IRQ_SHIFT, .init_execlists = logical_xcs_ring_init, @@ -57,6 +63,8 @@ static const struct engine_info { .name = "vcs", .hw_id = VCS_HW, .exec_id = I915_EXEC_BSD, + .class = VIDEO_DECODE_CLASS, + .instance = 0, .mmio_base = GEN6_BSD_RING_BASE, .irq_shift = GEN8_VCS1_IRQ_SHIFT, .init_execlists = logical_xcs_ring_init, @@ -66,6 +74,8 @@ static const struct engine_info { .name = "vcs2", .hw_id = VCS2_HW, .exec_id = I915_EXEC_BSD, + .class = VIDEO_DECODE_CLASS, + .instance = 1, .mmio_base = GEN8_BSD2_RING_BASE, .irq_shift = GEN8_VCS2_IRQ_SHIFT, .init_execlists = logical_xcs_ring_init, @@ -75,6 +85,8 @@ static const struct engine_info { .name = "vecs", .hw_id = VECS_HW, .exec_id = I915_EXEC_VEBOX, + .class = VIDEO_ENHANCEMENT_CLASS, + .instance = 0, .mmio_base = VEBOX_RING_BASE, .irq_shift = GEN8_VECS_IRQ_SHIFT, .init_execlists = logical_xcs_ring_init, @@ -101,6 +113,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = info->mmio_base; engine->irq_shift = info->irq_shift; + engine->class = info->class; + engine->instance = info->instance; /* Nothing to do here, execute in order of dependencies */ engine->schedule = NULL; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index cbe61d3f31da..f54fe7d063a8 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -193,6 +193,10 @@ struct intel_engine_cs { enum intel_engine_id id; unsigned int exec_id; unsigned int hw_id; + + u8 class; + u8 instance; + unsigned int guc_id; u32 mmio_base; unsigned int irq_shift; From 5ff36d36a36d55c8bd4bc937b6a9450b72853c5f Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Mon, 10 Apr 2017 07:34:30 -0700 Subject: [PATCH 0045/1270] drm/i915: Use the same vfunc for BSD2 ring init If we needed to do something different for the init functions, we could always look at the engine instance to make the distinction. But, in any case, the two functions are virtually identical already (please notice that BSD2_RING is only used from gen8 onwards). With this, the init functions depends excusively on the engine class (a fact that we will use soon). v2: Commit message Cc: Paulo Zanoni Cc: Rodrigo Vivi Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1491834873-9345-3-git-send-email-oscar.mateo@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 14 -------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index bb229274c30d..a7ffa4c66d1c 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -79,7 +79,7 @@ static const struct engine_info { .mmio_base = GEN8_BSD2_RING_BASE, .irq_shift = GEN8_VCS2_IRQ_SHIFT, .init_execlists = logical_xcs_ring_init, - .init_legacy = intel_init_bsd2_ring_buffer, + .init_legacy = intel_init_bsd_ring_buffer, }, [VECS] = { .name = "vecs", diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 97d5fcca8805..833740bf49c9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2175,20 +2175,6 @@ int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine) return intel_init_ring_buffer(engine); } -/** - * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3) - */ -int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - - intel_ring_default_vfuncs(dev_priv, engine); - - engine->emit_flush = gen6_bsd_ring_flush; - - return intel_init_ring_buffer(engine); -} - int intel_init_blt_ring_buffer(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index f54fe7d063a8..8b53ddb190c5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -555,7 +555,6 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine); int intel_init_render_ring_buffer(struct intel_engine_cs *engine); int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine); -int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine); int intel_init_blt_ring_buffer(struct intel_engine_cs *engine); int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine); From 6e516148f35401029ac920e323cce34266c22e6d Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Mon, 10 Apr 2017 07:34:31 -0700 Subject: [PATCH 0046/1270] drm/i915: Generate the engine name based on the instance number Not really needed, but makes the next change a little bit more compact. v2: - Use zero-based numbering for engine names: xcs0, xcs1.. xcsN (Tvrtko, Chris) - Make sure the mock engine name is null-terminated (Tvrtko, Chris) v3: Because I'm stupid (Chris) v4: Verify engine name wasn't truncated (Michal) v5: - Kill the warning in mock engine (Chris) Cc: Paulo Zanoni Cc: Rodrigo Vivi Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Reviewed-by: Tvrtko Ursulin Reviewed-by: Michal Wajdeczko Signed-off-by: Oscar Mateo Link: http://patchwork.freedesktop.org/patch/msgid/1491834873-9345-4-git-send-email-oscar.mateo@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_engine_cs.c | 5 +++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +++- drivers/gpu/drm/i915/selftests/mock_engine.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a7ffa4c66d1c..5e5cda02ee19 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -71,7 +71,7 @@ static const struct engine_info { .init_legacy = intel_init_bsd_ring_buffer, }, [VCS2] = { - .name = "vcs2", + .name = "vcs", .hw_id = VCS2_HW, .exec_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, @@ -108,7 +108,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->id = id; engine->i915 = dev_priv; - engine->name = info->name; + WARN_ON(snprintf(engine->name, sizeof(engine->name), "%s%u", + info->name, info->instance) >= sizeof(engine->name)); engine->exec_id = info->exec_id; engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = info->mmio_base; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8b53ddb190c5..fd8994b5688c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -187,9 +187,11 @@ enum intel_engine_id { VECS }; +#define INTEL_ENGINE_CS_MAX_NAME 8 + struct intel_engine_cs { struct drm_i915_private *i915; - const char *name; + char name[INTEL_ENGINE_CS_MAX_NAME]; enum intel_engine_id id; unsigned int exec_id; unsigned int hw_id; diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index b89050e0de48..b8e53bdc3cc4 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -140,7 +140,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, /* minimal engine setup for requests */ engine->base.i915 = i915; - engine->base.name = name; + snprintf(engine->base.name, sizeof(engine->base.name), "%s", name); engine->base.id = id++; engine->base.status_page.page_addr = (void *)(engine + 1); From b8400f01fcbbacec274d89a1c41340d0409529bb Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Mon, 10 Apr 2017 07:34:32 -0700 Subject: [PATCH 0047/1270] drm/i915: Split the engine info table in two levels, using class + instance There are some properties that logically belong to the engine class, and some that belong to the engine instance. Make it explicit. v2: Commit message (Tvrtko) v3: - Rebased - Exec/uabi id should be per instance (Chris) v4: - Rebased - Avoid re-ordering fields for smaller diff (Tvrtko) - Bug on oob access to the class array (Michal) v5: Bug on the right thing (Michal) v6: Rebased Cc: Tvrtko Ursulin Cc: Paulo Zanoni Cc: Rodrigo Vivi Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Reviewed-by: Michal Wajdeczko Signed-off-by: Oscar Mateo Link: http://patchwork.freedesktop.org/patch/msgid/1491834873-9345-5-git-send-email-oscar.mateo@intel.com Reviewed-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_engine_cs.c | 66 +++++++++++++++++--------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 5e5cda02ee19..058ecc020b28 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -26,71 +26,84 @@ #include "intel_ringbuffer.h" #include "intel_lrc.h" -static const struct engine_info { +struct engine_class_info { const char *name; - unsigned int exec_id; + int (*init_legacy)(struct intel_engine_cs *engine); + int (*init_execlists)(struct intel_engine_cs *engine); +}; + +static const struct engine_class_info intel_engine_classes[] = { + [RENDER_CLASS] = { + .name = "rcs", + .init_execlists = logical_render_ring_init, + .init_legacy = intel_init_render_ring_buffer, + }, + [COPY_ENGINE_CLASS] = { + .name = "bcs", + .init_execlists = logical_xcs_ring_init, + .init_legacy = intel_init_blt_ring_buffer, + }, + [VIDEO_DECODE_CLASS] = { + .name = "vcs", + .init_execlists = logical_xcs_ring_init, + .init_legacy = intel_init_bsd_ring_buffer, + }, + [VIDEO_ENHANCEMENT_CLASS] = { + .name = "vecs", + .init_execlists = logical_xcs_ring_init, + .init_legacy = intel_init_vebox_ring_buffer, + }, +}; + +struct engine_info { unsigned int hw_id; + unsigned int exec_id; u8 class; u8 instance; u32 mmio_base; unsigned irq_shift; - int (*init_legacy)(struct intel_engine_cs *engine); - int (*init_execlists)(struct intel_engine_cs *engine); -} intel_engines[] = { +}; + +static const struct engine_info intel_engines[] = { [RCS] = { - .name = "rcs", .hw_id = RCS_HW, .exec_id = I915_EXEC_RENDER, .class = RENDER_CLASS, .instance = 0, .mmio_base = RENDER_RING_BASE, .irq_shift = GEN8_RCS_IRQ_SHIFT, - .init_execlists = logical_render_ring_init, - .init_legacy = intel_init_render_ring_buffer, }, [BCS] = { - .name = "bcs", .hw_id = BCS_HW, .exec_id = I915_EXEC_BLT, .class = COPY_ENGINE_CLASS, .instance = 0, .mmio_base = BLT_RING_BASE, .irq_shift = GEN8_BCS_IRQ_SHIFT, - .init_execlists = logical_xcs_ring_init, - .init_legacy = intel_init_blt_ring_buffer, }, [VCS] = { - .name = "vcs", .hw_id = VCS_HW, .exec_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 0, .mmio_base = GEN6_BSD_RING_BASE, .irq_shift = GEN8_VCS1_IRQ_SHIFT, - .init_execlists = logical_xcs_ring_init, - .init_legacy = intel_init_bsd_ring_buffer, }, [VCS2] = { - .name = "vcs", .hw_id = VCS2_HW, .exec_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 1, .mmio_base = GEN8_BSD2_RING_BASE, .irq_shift = GEN8_VCS2_IRQ_SHIFT, - .init_execlists = logical_xcs_ring_init, - .init_legacy = intel_init_bsd_ring_buffer, }, [VECS] = { - .name = "vecs", .hw_id = VECS_HW, .exec_id = I915_EXEC_VEBOX, .class = VIDEO_ENHANCEMENT_CLASS, .instance = 0, .mmio_base = VEBOX_RING_BASE, .irq_shift = GEN8_VECS_IRQ_SHIFT, - .init_execlists = logical_xcs_ring_init, - .init_legacy = intel_init_vebox_ring_buffer, }, }; @@ -99,8 +112,12 @@ intel_engine_setup(struct drm_i915_private *dev_priv, enum intel_engine_id id) { const struct engine_info *info = &intel_engines[id]; + const struct engine_class_info *class_info; struct intel_engine_cs *engine; + GEM_BUG_ON(info->class >= ARRAY_SIZE(intel_engine_classes)); + class_info = &intel_engine_classes[info->class]; + GEM_BUG_ON(dev_priv->engine[id]); engine = kzalloc(sizeof(*engine), GFP_KERNEL); if (!engine) @@ -109,7 +126,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->id = id; engine->i915 = dev_priv; WARN_ON(snprintf(engine->name, sizeof(engine->name), "%s%u", - info->name, info->instance) >= sizeof(engine->name)); + class_info->name, info->instance) >= + sizeof(engine->name)); engine->exec_id = info->exec_id; engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = info->mmio_base; @@ -190,12 +208,14 @@ int intel_engines_init(struct drm_i915_private *dev_priv) int err = 0; for_each_engine(engine, dev_priv, id) { + const struct engine_class_info *class_info = + &intel_engine_classes[engine->class]; int (*init)(struct intel_engine_cs *engine); if (i915.enable_execlists) - init = intel_engines[id].init_execlists; + init = class_info->init_execlists; else - init = intel_engines[id].init_legacy; + init = class_info->init_legacy; if (!init) { kfree(engine); dev_priv->engine[id] = NULL; From 1d39f28170cb95e8b9eb9833d1c17528f400f9c4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 13:43:06 +0100 Subject: [PATCH 0048/1270] drm/i915: Rename intel_engine_cs.exec_id to uabi_id We want to refer to the index of the engine consistently throughout the userspace ABI. We already have such an index through the execbuffer engine specifier, that needs to be able to refer to each engine specifically, so rename it the index to uabi_id to reflect its generality beyond execbuf. Signed-off-by: Chris Wilson Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170411124306.15448-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_cmd_parser.c | 8 ++++---- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_engine_cs.c | 14 +++++++------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 7af100f84410..2a1a3347495a 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1166,8 +1166,8 @@ static bool check_cmd(const struct intel_engine_cs *engine, find_reg(engine, is_master, reg_addr); if (!reg) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (exec_id=%d)\n", - reg_addr, *cmd, engine->exec_id); + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (%s)\n", + reg_addr, *cmd, engine->name); return false; } @@ -1222,11 +1222,11 @@ static bool check_cmd(const struct intel_engine_cs *engine, desc->bits[i].mask; if (dword != desc->bits[i].expected) { - DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (exec_id=%d)\n", + DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (%s)\n", *cmd, desc->bits[i].mask, desc->bits[i].expected, - dword, engine->exec_id); + dword, engine->name); return false; } } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b210acc3d0b4..cb8c6a94ba4e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3996,7 +3996,7 @@ __busy_set_if_active(const struct dma_fence *fence, if (i915_gem_request_completed(rq)) return 0; - return flag(rq->engine->exec_id); + return flag(rq->engine->uabi_id); } static __always_inline unsigned int diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 058ecc020b28..71e89a93fe18 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -57,7 +57,7 @@ static const struct engine_class_info intel_engine_classes[] = { struct engine_info { unsigned int hw_id; - unsigned int exec_id; + unsigned int uabi_id; u8 class; u8 instance; u32 mmio_base; @@ -67,7 +67,7 @@ struct engine_info { static const struct engine_info intel_engines[] = { [RCS] = { .hw_id = RCS_HW, - .exec_id = I915_EXEC_RENDER, + .uabi_id = I915_EXEC_RENDER, .class = RENDER_CLASS, .instance = 0, .mmio_base = RENDER_RING_BASE, @@ -75,7 +75,7 @@ static const struct engine_info intel_engines[] = { }, [BCS] = { .hw_id = BCS_HW, - .exec_id = I915_EXEC_BLT, + .uabi_id = I915_EXEC_BLT, .class = COPY_ENGINE_CLASS, .instance = 0, .mmio_base = BLT_RING_BASE, @@ -83,7 +83,7 @@ static const struct engine_info intel_engines[] = { }, [VCS] = { .hw_id = VCS_HW, - .exec_id = I915_EXEC_BSD, + .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 0, .mmio_base = GEN6_BSD_RING_BASE, @@ -91,7 +91,7 @@ static const struct engine_info intel_engines[] = { }, [VCS2] = { .hw_id = VCS2_HW, - .exec_id = I915_EXEC_BSD, + .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 1, .mmio_base = GEN8_BSD2_RING_BASE, @@ -99,7 +99,7 @@ static const struct engine_info intel_engines[] = { }, [VECS] = { .hw_id = VECS_HW, - .exec_id = I915_EXEC_VEBOX, + .uabi_id = I915_EXEC_VEBOX, .class = VIDEO_ENHANCEMENT_CLASS, .instance = 0, .mmio_base = VEBOX_RING_BASE, @@ -128,7 +128,7 @@ intel_engine_setup(struct drm_i915_private *dev_priv, WARN_ON(snprintf(engine->name, sizeof(engine->name), "%s%u", class_info->name, info->instance) >= sizeof(engine->name)); - engine->exec_id = info->exec_id; + engine->uabi_id = info->uabi_id; engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = info->mmio_base; engine->irq_shift = info->irq_shift; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index fd8994b5688c..00d36aa4e26d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -193,7 +193,7 @@ struct intel_engine_cs { struct drm_i915_private *i915; char name[INTEL_ENGINE_CS_MAX_NAME]; enum intel_engine_id id; - unsigned int exec_id; + unsigned int uabi_id; unsigned int hw_id; u8 class; From a079d10812a3ed84a73d152522e658fe9f76526e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:09 +0300 Subject: [PATCH 0049/1270] drm/i915/dp: use the sink rates array for max sink rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looking at DPCD DP_MAX_LINK_RATE may be completely bogus for eDP 1.4 which is allowed to use link rate select method and have 0 in max link rate. With this change, it makes sense to store the max rate as the actual rate rather than as a bw code. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/3e8baadb406d59f414cab36fed9f0b35d207fde5.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 28 +++++++--------------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b38cba7d5abc..e4650f1625cc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -161,23 +161,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) intel_dp->num_sink_rates = num_rates; } -static int -intel_dp_max_link_bw(struct intel_dp *intel_dp) +static int intel_dp_max_sink_rate(struct intel_dp *intel_dp) { - int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; - - switch (max_link_bw) { - case DP_LINK_BW_1_62: - case DP_LINK_BW_2_7: - case DP_LINK_BW_5_4: - break; - default: - WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n", - max_link_bw); - max_link_bw = DP_LINK_BW_1_62; - break; - } - return max_link_bw; + return intel_dp->sink_rates[intel_dp->num_sink_rates - 1]; } static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp) @@ -301,7 +287,7 @@ static int intel_dp_rate_index(const int *rates, int len, int rate) static int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates) { - int max_rate = drm_dp_bw_code_to_link_rate(intel_dp->max_sink_link_bw); + int max_rate = intel_dp->max_sink_link_rate; int i, common_len; common_len = intersect_rates(intel_dp->source_rates, @@ -339,10 +325,10 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, common_rates, link_rate); if (link_rate_index > 0) { - intel_dp->max_sink_link_bw = drm_dp_link_rate_to_bw_code(common_rates[link_rate_index - 1]); + intel_dp->max_sink_link_rate = common_rates[link_rate_index - 1]; intel_dp->max_sink_lane_count = lane_count; } else if (lane_count > 1) { - intel_dp->max_sink_link_bw = intel_dp_max_link_bw(intel_dp); + intel_dp->max_sink_link_rate = intel_dp_max_sink_rate(intel_dp); intel_dp->max_sink_lane_count = lane_count >> 1; } else { DRM_ERROR("Link Training Unsuccessful\n"); @@ -4652,8 +4638,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) /* Set the max lane count for sink */ intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); - /* Set the max link BW for sink */ - intel_dp->max_sink_link_bw = intel_dp_max_link_bw(intel_dp); + /* Set the max link rate for sink */ + intel_dp->max_sink_link_rate = intel_dp_max_sink_rate(intel_dp); intel_dp->reset_link_params = false; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7bc0c25b3396..92e353dc61bf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -959,7 +959,7 @@ struct intel_dp { /* Max lane count for the sink as per DPCD registers */ uint8_t max_sink_lane_count; /* Max link BW for the sink as per DPCD registers */ - int max_sink_link_bw; + int max_sink_link_rate; /* sink or branch descriptor */ struct intel_dp_desc desc; struct drm_dp_aux aux; From 975ee5fca10b713aff92cee87e1789e5e2e6c1da Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:10 +0300 Subject: [PATCH 0050/1270] drm/i915/dp: cache common rates with sink rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that source rates are static and sink rates are updated whenever DPCD is updated, we can do and cache the intersection of them whenever sink rates are updated. This reduces code complexity, as we don't have to keep calling the functions to intersect. We also get rid of several common rates arrays on stack. Limiting the common rates by a max link rate can be done by picking the first N elements of the cached common rates. v2: get rid of the local common_rates variable (Manasi) v3: don't clobber cached eDP rates on short pulse (Ville) Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/e3b287e8cb6559b1f8fd4e80b78a8d22f1802eb7.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 75 ++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 3 ++ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e4650f1625cc..1808af6d635d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -284,17 +284,29 @@ static int intel_dp_rate_index(const int *rates, int len, int rate) return -1; } -static int intel_dp_common_rates(struct intel_dp *intel_dp, - int *common_rates) +static void intel_dp_set_common_rates(struct intel_dp *intel_dp) { - int max_rate = intel_dp->max_sink_link_rate; - int i, common_len; + WARN_ON(!intel_dp->num_source_rates || !intel_dp->num_sink_rates); - common_len = intersect_rates(intel_dp->source_rates, - intel_dp->num_source_rates, - intel_dp->sink_rates, - intel_dp->num_sink_rates, - common_rates); + intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates, + intel_dp->num_source_rates, + intel_dp->sink_rates, + intel_dp->num_sink_rates, + intel_dp->common_rates); + + /* Paranoia, there should always be something in common. */ + if (WARN_ON(intel_dp->num_common_rates == 0)) { + intel_dp->common_rates[0] = default_rates[0]; + intel_dp->num_common_rates = 1; + } +} + +/* get length of common rates potentially limited by max_rate */ +static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp, + int max_rate) +{ + const int *common_rates = intel_dp->common_rates; + int i, common_len = intel_dp->num_common_rates; /* Limit results by potentially reduced max rate */ for (i = 0; i < common_len; i++) { @@ -305,25 +317,23 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp, return 0; } -static int intel_dp_link_rate_index(struct intel_dp *intel_dp, - int *common_rates, int link_rate) +static int intel_dp_link_rate_index(struct intel_dp *intel_dp, int link_rate) { int common_len; - common_len = intel_dp_common_rates(intel_dp, common_rates); + common_len = intel_dp_common_len_rate_limit(intel_dp, + intel_dp->max_sink_link_rate); - return intel_dp_rate_index(common_rates, common_len, link_rate); + return intel_dp_rate_index(intel_dp->common_rates, common_len, link_rate); } int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, int link_rate, uint8_t lane_count) { - int common_rates[DP_MAX_SUPPORTED_RATES]; + const int *common_rates = intel_dp->common_rates; int link_rate_index; - link_rate_index = intel_dp_link_rate_index(intel_dp, - common_rates, - link_rate); + link_rate_index = intel_dp_link_rate_index(intel_dp, link_rate); if (link_rate_index > 0) { intel_dp->max_sink_link_rate = common_rates[link_rate_index - 1]; intel_dp->max_sink_lane_count = lane_count; @@ -1506,8 +1516,6 @@ static void snprintf_int_array(char *str, size_t len, static void intel_dp_print_rates(struct intel_dp *intel_dp) { - int common_len; - int common_rates[DP_MAX_SUPPORTED_RATES]; char str[128]; /* FIXME: too big for stack? */ if ((drm_debug & DRM_UT_KMS) == 0) @@ -1521,8 +1529,8 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) intel_dp->sink_rates, intel_dp->num_sink_rates); DRM_DEBUG_KMS("sink rates: %s\n", str); - common_len = intel_dp_common_rates(intel_dp, common_rates); - snprintf_int_array(str, sizeof(str), common_rates, common_len); + snprintf_int_array(str, sizeof(str), + intel_dp->common_rates, intel_dp->num_common_rates); DRM_DEBUG_KMS("common rates: %s\n", str); } @@ -1560,14 +1568,14 @@ bool intel_dp_read_desc(struct intel_dp *intel_dp) int intel_dp_max_link_rate(struct intel_dp *intel_dp) { - int rates[DP_MAX_SUPPORTED_RATES] = {}; int len; - len = intel_dp_common_rates(intel_dp, rates); + len = intel_dp_common_len_rate_limit(intel_dp, + intel_dp->max_sink_link_rate); if (WARN_ON(len <= 0)) return 162000; - return rates[len - 1]; + return intel_dp->common_rates[len - 1]; } int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) @@ -1636,11 +1644,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, int link_rate_index; int bpp, mode_rate; int link_avail, link_clock; - int common_rates[DP_MAX_SUPPORTED_RATES] = {}; int common_len; uint8_t link_bw, rate_select; - common_len = intel_dp_common_rates(intel_dp, common_rates); + common_len = intel_dp_common_len_rate_limit(intel_dp, + intel_dp->max_sink_link_rate); /* No common link rates between source and sink */ WARN_ON(common_len <= 0); @@ -1678,7 +1686,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Use values requested by Compliance Test Request */ if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { link_rate_index = intel_dp_link_rate_index(intel_dp, - common_rates, intel_dp->compliance.test_link_rate); if (link_rate_index >= 0) min_clock = max_clock = link_rate_index; @@ -1686,7 +1693,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, } DRM_DEBUG_KMS("DP link computation with max lane count %i " "max bw %d pixel clock %iKHz\n", - max_lane_count, common_rates[max_clock], + max_lane_count, intel_dp->common_rates[max_clock], adjusted_mode->crtc_clock); /* Walk through all bpp values. Luckily they're all nicely spaced with 2 @@ -1722,7 +1729,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, lane_count <= max_lane_count; lane_count <<= 1) { - link_clock = common_rates[clock]; + link_clock = intel_dp->common_rates[clock]; link_avail = intel_dp_max_data_rate(link_clock, lane_count); @@ -1754,7 +1761,7 @@ found: pipe_config->lane_count = lane_count; pipe_config->pipe_bpp = bpp; - pipe_config->port_clock = common_rates[clock]; + pipe_config->port_clock = intel_dp->common_rates[clock]; intel_dp_compute_rate(intel_dp, pipe_config->port_clock, &link_bw, &rate_select); @@ -3715,6 +3722,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) else intel_dp_set_sink_rates(intel_dp); + intel_dp_set_common_rates(intel_dp); + return true; } @@ -3726,8 +3735,10 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) return false; /* Don't clobber cached eDP rates. */ - if (!is_edp(intel_dp)) + if (!is_edp(intel_dp)) { intel_dp_set_sink_rates(intel_dp); + intel_dp_set_common_rates(intel_dp); + } if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT, &intel_dp->sink_count, 1) < 0) @@ -3950,7 +3961,6 @@ static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp) { int status = 0; int min_lane_count = 1; - int common_rates[DP_MAX_SUPPORTED_RATES] = {}; int link_rate_index, test_link_rate; uint8_t test_lane_count, test_link_bw; /* (DP CTS 1.2) @@ -3979,7 +3989,6 @@ static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp) /* Validate the requested link rate */ test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw); link_rate_index = intel_dp_link_rate_index(intel_dp, - common_rates, test_link_rate); if (link_rate_index < 0) return DP_TEST_NAK; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 92e353dc61bf..4a4bf9cb0d90 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -956,6 +956,9 @@ struct intel_dp { int num_sink_rates; int sink_rates[DP_MAX_SUPPORTED_RATES]; bool use_rate_select; + /* intersection of source and sink rates */ + int num_common_rates; + int common_rates[DP_MAX_SUPPORTED_RATES]; /* Max lane count for the sink as per DPCD registers */ uint8_t max_sink_lane_count; /* Max link BW for the sink as per DPCD registers */ From b1810a74a0513993e02ba13e60a29c5f01ea3bf0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:11 +0300 Subject: [PATCH 0051/1270] drm/i915/dp: do not limit rate seek when not needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In link training fallback, we're trying to find a rate that we know is in a sorted array of common link rates. We don't need to limit the array using the max rate. For test request, the DP CTS doesn't say we should limit the rate based on earlier fallback. This lets us get rid of intel_dp_link_rate_index() and use intel_dp_rate_index() instead. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/33cab481a3228f31e938b5891a6285d892dcf272.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1808af6d635d..8c061c54d481 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -317,25 +317,16 @@ static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp, return 0; } -static int intel_dp_link_rate_index(struct intel_dp *intel_dp, int link_rate) -{ - int common_len; - - common_len = intel_dp_common_len_rate_limit(intel_dp, - intel_dp->max_sink_link_rate); - - return intel_dp_rate_index(intel_dp->common_rates, common_len, link_rate); -} - int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, int link_rate, uint8_t lane_count) { - const int *common_rates = intel_dp->common_rates; - int link_rate_index; + int index; - link_rate_index = intel_dp_link_rate_index(intel_dp, link_rate); - if (link_rate_index > 0) { - intel_dp->max_sink_link_rate = common_rates[link_rate_index - 1]; + index = intel_dp_rate_index(intel_dp->common_rates, + intel_dp->num_common_rates, + link_rate); + if (index > 0) { + intel_dp->max_sink_link_rate = intel_dp->common_rates[index - 1]; intel_dp->max_sink_lane_count = lane_count; } else if (lane_count > 1) { intel_dp->max_sink_link_rate = intel_dp_max_sink_rate(intel_dp); @@ -1685,8 +1676,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Use values requested by Compliance Test Request */ if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { - link_rate_index = intel_dp_link_rate_index(intel_dp, - intel_dp->compliance.test_link_rate); + link_rate_index = intel_dp_rate_index(intel_dp->common_rates, + intel_dp->num_common_rates, + intel_dp->compliance.test_link_rate); if (link_rate_index >= 0) min_clock = max_clock = link_rate_index; min_lane_count = max_lane_count = intel_dp->compliance.test_lane_count; @@ -3988,8 +3980,9 @@ static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp) } /* Validate the requested link rate */ test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw); - link_rate_index = intel_dp_link_rate_index(intel_dp, - test_link_rate); + link_rate_index = intel_dp_rate_index(intel_dp->common_rates, + intel_dp->num_common_rates, + test_link_rate); if (link_rate_index < 0) return DP_TEST_NAK; From e6c0c64a291e20e34668b8878b34af78389f9da3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:12 +0300 Subject: [PATCH 0052/1270] drm/i915/dp: don't call the link parameters sink parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we modify these on the fly depending on the link conditions, don't pretend they are sink properties. Some link vs. sink confusion still remains, but we'll take care of them in follow-up patches. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/3739b4fac502ebd1c6e075a62c1a195e4094eb16.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 25 ++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 8 ++++---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8c061c54d481..a0082a3784e8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -172,7 +172,7 @@ static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp) u8 source_max, sink_max; source_max = intel_dig_port->max_lanes; - sink_max = intel_dp->max_sink_lane_count; + sink_max = intel_dp->max_link_lane_count; return min(source_max, sink_max); } @@ -326,11 +326,11 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, intel_dp->num_common_rates, link_rate); if (index > 0) { - intel_dp->max_sink_link_rate = intel_dp->common_rates[index - 1]; - intel_dp->max_sink_lane_count = lane_count; + intel_dp->max_link_rate = intel_dp->common_rates[index - 1]; + intel_dp->max_link_lane_count = lane_count; } else if (lane_count > 1) { - intel_dp->max_sink_link_rate = intel_dp_max_sink_rate(intel_dp); - intel_dp->max_sink_lane_count = lane_count >> 1; + intel_dp->max_link_rate = intel_dp_max_sink_rate(intel_dp); + intel_dp->max_link_lane_count = lane_count >> 1; } else { DRM_ERROR("Link Training Unsuccessful\n"); return -1; @@ -1561,8 +1561,7 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp) { int len; - len = intel_dp_common_len_rate_limit(intel_dp, - intel_dp->max_sink_link_rate); + len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate); if (WARN_ON(len <= 0)) return 162000; @@ -1639,7 +1638,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, uint8_t link_bw, rate_select; common_len = intel_dp_common_len_rate_limit(intel_dp, - intel_dp->max_sink_link_rate); + intel_dp->max_link_rate); /* No common link rates between source and sink */ WARN_ON(common_len <= 0); @@ -3969,7 +3968,7 @@ static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp) test_lane_count &= DP_MAX_LANE_COUNT_MASK; /* Validate the requested lane count */ if (test_lane_count < min_lane_count || - test_lane_count > intel_dp->max_sink_lane_count) + test_lane_count > intel_dp->max_link_lane_count) return DP_TEST_NAK; status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE, @@ -4637,11 +4636,11 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) yesno(drm_dp_tps3_supported(intel_dp->dpcd))); if (intel_dp->reset_link_params) { - /* Set the max lane count for sink */ - intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); + /* Set the max lane count for link */ + intel_dp->max_link_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); - /* Set the max link rate for sink */ - intel_dp->max_sink_link_rate = intel_dp_max_sink_rate(intel_dp); + /* Set the max link rate for link */ + intel_dp->max_link_rate = intel_dp_max_sink_rate(intel_dp); intel_dp->reset_link_params = false; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4a4bf9cb0d90..f97603b74a28 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -959,10 +959,10 @@ struct intel_dp { /* intersection of source and sink rates */ int num_common_rates; int common_rates[DP_MAX_SUPPORTED_RATES]; - /* Max lane count for the sink as per DPCD registers */ - uint8_t max_sink_lane_count; - /* Max link BW for the sink as per DPCD registers */ - int max_sink_link_rate; + /* Max lane count for the current link */ + int max_link_lane_count; + /* Max rate for the current link */ + int max_link_rate; /* sink or branch descriptor */ struct intel_dp_desc desc; struct drm_dp_aux aux; From 540b0b7fe915858870be6cfe0fecd1fa85ccb4d6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:13 +0300 Subject: [PATCH 0053/1270] drm/i915/dp: add functions for max common link rate and lane count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are the theoretical maximums common for source and sink. These are the maximums we should start with. They may be degraded in case of link training failures, and the dynamic link values are stored separately. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/5088aca253c47dfa18251e1adb976aca1718f083.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a0082a3784e8..b3df2082eac9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -161,22 +161,27 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) intel_dp->num_sink_rates = num_rates; } -static int intel_dp_max_sink_rate(struct intel_dp *intel_dp) +/* Theoretical max between source and sink */ +static int intel_dp_max_common_rate(struct intel_dp *intel_dp) { - return intel_dp->sink_rates[intel_dp->num_sink_rates - 1]; + return intel_dp->common_rates[intel_dp->num_common_rates - 1]; } -static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp) +/* Theoretical max between source and sink */ +static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - u8 source_max, sink_max; - - source_max = intel_dig_port->max_lanes; - sink_max = intel_dp->max_link_lane_count; + int source_max = intel_dig_port->max_lanes; + int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); return min(source_max, sink_max); } +static int intel_dp_max_lane_count(struct intel_dp *intel_dp) +{ + return intel_dp->max_link_lane_count; +} + int intel_dp_link_required(int pixel_clock, int bpp) { @@ -329,7 +334,7 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, intel_dp->max_link_rate = intel_dp->common_rates[index - 1]; intel_dp->max_link_lane_count = lane_count; } else if (lane_count > 1) { - intel_dp->max_link_rate = intel_dp_max_sink_rate(intel_dp); + intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); intel_dp->max_link_lane_count = lane_count >> 1; } else { DRM_ERROR("Link Training Unsuccessful\n"); @@ -4636,11 +4641,11 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) yesno(drm_dp_tps3_supported(intel_dp->dpcd))); if (intel_dp->reset_link_params) { - /* Set the max lane count for link */ - intel_dp->max_link_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); + /* Initial max link lane count */ + intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp); - /* Set the max link rate for link */ - intel_dp->max_link_rate = intel_dp_max_sink_rate(intel_dp); + /* Initial max link rate */ + intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); intel_dp->reset_link_params = false; } From 3d65a735d8341830ef8ec57e290ed785b01085a1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:14 +0300 Subject: [PATCH 0054/1270] drm/i915/mst: use max link not sink lane count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The source might not support as many lanes as the sink, or the link training might have failed at higher lane counts. Take these into account. Cc: Dhinakaran Pandiyan Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/cf59530acafaf9258fb643d321ad251b44f34e29.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_dp_mst.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b3df2082eac9..95f2278700e3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -177,7 +177,7 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) return min(source_max, sink_max); } -static int intel_dp_max_lane_count(struct intel_dp *intel_dp) +int intel_dp_max_lane_count(struct intel_dp *intel_dp) { return intel_dp->max_link_lane_count; } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 094cbdcbcd6d..40608101cd3a 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -56,7 +56,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, * for MST we always configure max link bw - the spec doesn't * seem to suggest we should do otherwise. */ - lane_count = drm_dp_max_lane_count(intel_dp->dpcd); + lane_count = intel_dp_max_lane_count(intel_dp); pipe_config->lane_count = lane_count; @@ -343,7 +343,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, int max_rate, mode_rate, max_lanes, max_link_clock; max_link_clock = intel_dp_max_link_rate(intel_dp); - max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); + max_lanes = intel_dp_max_lane_count(intel_dp); max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); mode_rate = intel_dp_link_required(mode->clock, bpp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f97603b74a28..5f6e1aad909d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1503,6 +1503,7 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co void intel_dp_mst_suspend(struct drm_device *dev); void intel_dp_mst_resume(struct drm_device *dev); int intel_dp_max_link_rate(struct intel_dp *intel_dp); +int intel_dp_max_lane_count(struct intel_dp *intel_dp); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); void intel_dp_hot_plug(struct intel_encoder *intel_encoder); void intel_power_sequencer_reset(struct drm_i915_private *dev_priv); From ec990e21d7668e08f6f4bd9b73e9d40d04b04198 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:15 +0300 Subject: [PATCH 0055/1270] drm/i915/dp: localize link rate index variable more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Localize link_rate_index to the if block, and rename to just index to reduce indent. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/d348d990c96705427b93c1cac8c3e4447d06eebf.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 95f2278700e3..6f743490855b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1636,7 +1636,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Conveniently, the link BW constants become indices with a shift...*/ int min_clock = 0; int max_clock; - int link_rate_index; int bpp, mode_rate; int link_avail, link_clock; int common_len; @@ -1680,11 +1679,13 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Use values requested by Compliance Test Request */ if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { - link_rate_index = intel_dp_rate_index(intel_dp->common_rates, - intel_dp->num_common_rates, - intel_dp->compliance.test_link_rate); - if (link_rate_index >= 0) - min_clock = max_clock = link_rate_index; + int index; + + index = intel_dp_rate_index(intel_dp->common_rates, + intel_dp->num_common_rates, + intel_dp->compliance.test_link_rate); + if (index >= 0) + min_clock = max_clock = index; min_lane_count = max_lane_count = intel_dp->compliance.test_lane_count; } DRM_DEBUG_KMS("DP link computation with max lane count %i " From 010b9b397b32e1fa2d2bd15ec521350a99ac4dc4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:16 +0300 Subject: [PATCH 0056/1270] drm/i915/dp: use readb and writeb calls for single byte DPCD access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is what we have the readb and writeb variants for. Do some minor return value and variable cleanup while at it. Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/fd8a8f110bcfdc73a8c9241e5f9d61f7dd7c9677.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 37 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6f743490855b..81682fd2804b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3661,9 +3661,9 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) uint8_t frame_sync_cap; dev_priv->psr.sink_support = true; - drm_dp_dpcd_read(&intel_dp->aux, - DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP, - &frame_sync_cap, 1); + drm_dp_dpcd_readb(&intel_dp->aux, + DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP, + &frame_sync_cap); dev_priv->psr.aux_frame_sync = frame_sync_cap ? true : false; /* PSR2 needs frame sync as well */ dev_priv->psr.psr2_support = dev_priv->psr.aux_frame_sync; @@ -3737,8 +3737,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) intel_dp_set_common_rates(intel_dp); } - if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT, - &intel_dp->sink_count, 1) < 0) + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, + &intel_dp->sink_count) <= 0) return false; /* @@ -3775,7 +3775,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) static bool intel_dp_can_mst(struct intel_dp *intel_dp) { - u8 buf[1]; + u8 mstm_cap; if (!i915.enable_dp_mst) return false; @@ -3786,10 +3786,10 @@ intel_dp_can_mst(struct intel_dp *intel_dp) if (intel_dp->dpcd[DP_DPCD_REV] < 0x12) return false; - if (drm_dp_dpcd_read(&intel_dp->aux, DP_MSTM_CAP, buf, 1) != 1) + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_MSTM_CAP, &mstm_cap) != 1) return false; - return buf[0] & DP_MST_CAP; + return mstm_cap & DP_MST_CAP; } static void @@ -3935,9 +3935,8 @@ stop: static bool intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) { - return drm_dp_dpcd_read(&intel_dp->aux, - DP_DEVICE_SERVICE_IRQ_VECTOR, - sink_irq_vector, 1) == 1; + return drm_dp_dpcd_readb(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector) == 1; } static bool @@ -4000,13 +3999,13 @@ static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp) static uint8_t intel_dp_autotest_video_pattern(struct intel_dp *intel_dp) { uint8_t test_pattern; - uint16_t test_misc; + uint8_t test_misc; __be16 h_width, v_height; int status = 0; /* Read the TEST_PATTERN (DP CTS 3.1.5) */ - status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_PATTERN, - &test_pattern, 1); + status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_PATTERN, + &test_pattern); if (status <= 0) { DRM_DEBUG_KMS("Test pattern read failed\n"); return DP_TEST_NAK; @@ -4028,8 +4027,8 @@ static uint8_t intel_dp_autotest_video_pattern(struct intel_dp *intel_dp) return DP_TEST_NAK; } - status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_MISC0, - &test_misc, 1); + status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_MISC0, + &test_misc); if (status <= 0) { DRM_DEBUG_KMS("TEST MISC read failed\n"); return DP_TEST_NAK; @@ -4088,10 +4087,8 @@ static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp) */ block += intel_connector->detect_edid->extensions; - if (!drm_dp_dpcd_write(&intel_dp->aux, - DP_TEST_EDID_CHECKSUM, - &block->checksum, - 1)) + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM, + block->checksum) <= 0) DRM_DEBUG_KMS("Failed to write EDID checksum\n"); test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE; From 27dbefb911f2650f473eb98b5de79e88f6559c64 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 6 Apr 2017 16:44:17 +0300 Subject: [PATCH 0057/1270] drm/i915/dp: read sink count to a temporary variable first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't clobber intel_dp->sink_count with the raw value. Suggested-by: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/37d3222115172922fcd5ab038238359935bd561f.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 81682fd2804b..3c5c80da9ea3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3728,6 +3728,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) static bool intel_dp_get_dpcd(struct intel_dp *intel_dp) { + u8 sink_count; + if (!intel_dp_read_dpcd(intel_dp)) return false; @@ -3737,8 +3739,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) intel_dp_set_common_rates(intel_dp); } - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, - &intel_dp->sink_count) <= 0) + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_COUNT, &sink_count) <= 0) return false; /* @@ -3746,7 +3747,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) * a member variable in intel_dp will track any changes * between short pulse interrupts. */ - intel_dp->sink_count = DP_GET_SINK_COUNT(intel_dp->sink_count); + intel_dp->sink_count = DP_GET_SINK_COUNT(sink_count); /* * SINK_COUNT == 0 and DOWNSTREAM_PORT_PRESENT == 1 implies that From 5f9be05432cb4c323967f6d71ce0ecc024a775c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 17:56:58 +0100 Subject: [PATCH 0058/1270] drm/i915: Bail if we do not setup the RCS engine In places, we assume that RCS exists. This has been true forever, but let us catch this failure during bringup by adding an explicit check that we do have an RCS engine. v2: Make use of HAS_ENGINE (Tvrtko) Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170411165658.23828-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 71e89a93fe18..15970f1b09d2 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -153,10 +153,10 @@ intel_engine_setup(struct drm_i915_private *dev_priv, int intel_engines_init_early(struct drm_i915_private *dev_priv) { struct intel_device_info *device_info = mkwrite_device_info(dev_priv); - unsigned int ring_mask = INTEL_INFO(dev_priv)->ring_mask; - unsigned int mask = 0; + const unsigned int ring_mask = INTEL_INFO(dev_priv)->ring_mask; struct intel_engine_cs *engine; enum intel_engine_id id; + unsigned int mask = 0; unsigned int i; int err; @@ -183,6 +183,12 @@ int intel_engines_init_early(struct drm_i915_private *dev_priv) if (WARN_ON(mask != ring_mask)) device_info->ring_mask = mask; + /* We always presume we have at least RCS available for later probing */ + if (WARN_ON(!HAS_ENGINE(dev_priv, RCS))) { + err = -ENODEV; + goto cleanup; + } + device_info->num_rings = hweight32(mask); return 0; From ddfb570c205446fc6dcfaff1efb5c0e5ca1b30d7 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 11 Apr 2017 03:11:12 -0700 Subject: [PATCH 0059/1270] drm/i915: Use the engine class to get the context size Technically speaking, the context size is per engine class, not per instance. v2: Add MISSING_CASE (Tvrtko) v3: Rebased v4: Restore the interface back to hiding the class lookup (Chris) Cc: Paulo Zanoni Cc: Rodrigo Vivi Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Tvrtko Ursulin Signed-off-by: Oscar Mateo Link: http://patchwork.freedesktop.org/patch/msgid/1491905472-16189-1-git-send-email-oscar.mateo@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lrc.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0dc1cc4ad6e7..711125a7624c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1923,21 +1923,30 @@ populate_lr_context(struct i915_gem_context *ctx, */ uint32_t intel_lr_context_size(struct intel_engine_cs *engine) { - int ret = 0; + struct drm_i915_private *dev_priv = engine->i915; + int ret; - WARN_ON(INTEL_GEN(engine->i915) < 8); + WARN_ON(INTEL_GEN(dev_priv) < 8); - switch (engine->id) { - case RCS: - if (INTEL_GEN(engine->i915) >= 9) + switch (engine->class) { + case RENDER_CLASS: + switch (INTEL_GEN(dev_priv)) { + default: + MISSING_CASE(INTEL_GEN(dev_priv)); + case 9: ret = GEN9_LR_CONTEXT_RENDER_SIZE; - else + break; + case 8: ret = GEN8_LR_CONTEXT_RENDER_SIZE; + break; + } break; - case VCS: - case BCS: - case VECS: - case VCS2: + + default: + MISSING_CASE(engine->class); + case VIDEO_DECODE_CLASS: + case VIDEO_ENHANCEMENT_CLASS: + case COPY_ENGINE_CLASS: ret = GEN8_LR_CONTEXT_OTHER_SIZE; break; } From a8e9a419c337a655e23b4bab422e85e47ee86c92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 20:00:42 +0100 Subject: [PATCH 0060/1270] drm/i915: Lie and treat all engines as idle if wedged Similar to commit 8490ae207f1d ("drm/i915: Suppress busy status for engines if wedged") we also want to report intel_engine_is_idle() as true as well as the main intel_engines_are_idle(), as we now check that the engines are idle when overwriting the HWS page. This is not true whilst we are setting the device as wedged, at least according to our bookkeeping, so we have to lie to ourselves! [ 383.588601] [drm:i915_reset [i915]] *ERROR* Failed to reset chip: -110 [ 383.588685] ------------[ cut here ]------------ [ 383.588755] WARNING: CPU: 0 PID: 12 at drivers/gpu/drm/i915/intel_engine_cs.c:226 intel_engine_init_global_seqno+0x222/0x290 [i915] [ 383.588757] WARN_ON(!intel_engine_is_idle(engine)) [ 383.588759] Modules linked in: ctr ccm snd_hda_codec_hdmi snd_hda_codec_conexant snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core arc4 iwldvm mac80211 snd_pcm snd_hwdep snd_seq_midi snd_seq_midi_event rfcomm bnep snd_rawmidi intel_powerclamp coretemp dm_multipath iwlwifi crct10dif_pclmul snd_seq crc32_pclmul ghash_clmulni_intel btusb aesni_intel btrtl btbcm aes_x86_64 crypto_simd cryptd btintel snd_timer glue_helper bluetooth intel_ips snd_seq_device cfg80211 snd soundcore binfmt_misc mei_me mei dm_mirror dm_region_hash dm_log i915 intel_gtt i2c_algo_bit drm_kms_helper cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea prime_numbers ahci libahci drm e1000e [ 383.588851] CPU: 0 PID: 12 Comm: migration/0 Not tainted 4.11.0-rc5+ #207 [ 383.588853] Hardware name: LENOVO 514328U/514328U, BIOS 6QET44WW (1.14 ) 04/20/2010 [ 383.588855] Call Trace: [ 383.588866] dump_stack+0x63/0x90 [ 383.588871] __warn+0xc7/0xf0 [ 383.588876] warn_slowpath_fmt+0x4a/0x50 [ 383.588883] ? set_next_entity+0x821/0x910 [ 383.588943] intel_engine_init_global_seqno+0x222/0x290 [i915] [ 383.588998] __i915_gem_set_wedged_BKL+0xa4/0x190 [i915] [ 383.589003] ? __switch_to+0x215/0x390 [ 383.589008] multi_cpu_stop+0xbb/0xe0 [ 383.589012] ? cpu_stop_queue_work+0x90/0x90 [ 383.589016] cpu_stopper_thread+0x82/0x110 [ 383.589021] smpboot_thread_fn+0x137/0x190 [ 383.589026] kthread+0xf7/0x130 [ 383.589030] ? sort_range+0x20/0x20 [ 383.589034] ? kthread_park+0x90/0x90 [ 383.589040] ret_from_fork+0x2c/0x40 Fixes: 2ca9faa551c4 ("drm/i915: Assert the engine is idle before overwiting the HWS") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170411190042.25662-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 15970f1b09d2..ee87ca7420de 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1131,6 +1131,10 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + /* More white lies, if wedged, hw state is inconsistent */ + if (i915_terminally_wedged(&dev_priv->gpu_error)) + return true; + /* Any inflight/incomplete requests? */ if (!i915_seqno_passed(intel_engine_get_seqno(engine), intel_engine_last_submit(engine))) From 48921260b7d030ec6a2e11a435eae28ddb88ea56 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Apr 2017 18:58:50 +0100 Subject: [PATCH 0061/1270] drm/i915/execlists: Document runtime pm for intel_lrc_irq_handler() We indirectly hold the runtime-pm for the intel_lrc_irq_handler() by virtue of dev_priv->gt.awake keeping a wakeref whilst the requests are busy. As this is not obvious from the code, add a comment. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170411175850.2470-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_lrc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 711125a7624c..7df278fe492e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -515,6 +515,15 @@ static void intel_lrc_irq_handler(unsigned long data) struct execlist_port *port = engine->execlist_port; struct drm_i915_private *dev_priv = engine->i915; + /* We can skip acquiring intel_runtime_pm_get() here as it was taken + * on our behalf by the request (see i915_gem_mark_busy()) and it will + * not be relinquished until the device is idle (see + * i915_gem_idle_work_handler()). As a precaution, we make sure + * that all ELSP are drained i.e. we have processed the CSB, + * before allowing ourselves to idle and calling intel_runtime_pm_put(). + */ + GEM_BUG_ON(!dev_priv->gt.awake); + intel_uncore_forcewake_get(dev_priv, engine->fw_domains); /* Prefer doing test_and_clear_bit() as a two stage operation to avoid From 735a9876cf7f5ddda1027942344f31d3a1a4488a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 11:07:07 +0200 Subject: [PATCH 0062/1270] drm/i915: Remove unused members from intel_tv.c They have been unused since 2010, after the code for intel_tv_save/restore was removed in the below commit: commit 6443170f6d862a1cc89e61e4bb2410b714b875f4 Author: Eric Anholt Date: Fri Apr 2 15:24:27 2010 -0700 drm/i915: Remove dead KMS encoder save/restore code. This was brought over from UMS, and used for a while until we decided that drm_helper_resume_force_mode was easier and more reliable, since it didn't require duplicating all the code deleted here. We just forgot to delete all that junk for a while. Reviewed-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491815239-10685-2-git-send-email-maarten.lankhorst@linux.intel.com [mlankhorst: Add commit blurb based on danvet's feedback.] --- drivers/gpu/drm/i915/intel_tv.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index e077c2a9e694..3af857a75fab 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -50,39 +50,6 @@ struct intel_tv { int type; const char *tv_format; int margin[4]; - u32 save_TV_H_CTL_1; - u32 save_TV_H_CTL_2; - u32 save_TV_H_CTL_3; - u32 save_TV_V_CTL_1; - u32 save_TV_V_CTL_2; - u32 save_TV_V_CTL_3; - u32 save_TV_V_CTL_4; - u32 save_TV_V_CTL_5; - u32 save_TV_V_CTL_6; - u32 save_TV_V_CTL_7; - u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; - - u32 save_TV_CSC_Y; - u32 save_TV_CSC_Y2; - u32 save_TV_CSC_U; - u32 save_TV_CSC_U2; - u32 save_TV_CSC_V; - u32 save_TV_CSC_V2; - u32 save_TV_CLR_KNOBS; - u32 save_TV_CLR_LEVEL; - u32 save_TV_WIN_POS; - u32 save_TV_WIN_SIZE; - u32 save_TV_FILTER_CTL_1; - u32 save_TV_FILTER_CTL_2; - u32 save_TV_FILTER_CTL_3; - - u32 save_TV_H_LUMA[60]; - u32 save_TV_H_CHROMA[60]; - u32 save_TV_V_LUMA[43]; - u32 save_TV_V_CHROMA[43]; - - u32 save_TV_DAC; - u32 save_TV_CTL; }; struct video_levels { From 0e891b3f447f4d8af3010761fa0c358b057ae2e8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 11:07:08 +0200 Subject: [PATCH 0063/1270] drm/i915: Convert intel_tv connector properties to atomic, v5. intel_tv has properties that are handled in the atomic core, but needs a modeset to update the properties inside the connector. The detect(), get_mode() and mode_valid() probe callbacks also depend on the connector state, which made this a good connector to convert first. It helped find all the issues when converting connectors to atomic. Because of these requirements, connector atomic_check() was added and connection_mutex is held during probing. The diffstat looks more favorable now. :) Changes since v1: - Add intel_encoder->swap_state to allow updating connector state. - Add intel_tv->format for detect_mode and mode_valid, updated on atomic commit. Changes since v2: - Fix typo in tv_choose_preferred modes function name. - Assignment of tv properties is done in core, so intel_tv only needs a atomic_check function. Thanks Ville! Changes since v3: - connection_mutex is now held in mode_valid() and get_modes(), this removes the need for caching parts of the connector_state. Changes since v4: - Use the new atomic connector check function. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491815239-10685-3-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_tv.c | 175 ++++++++++++-------------------- 1 file changed, 63 insertions(+), 112 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 3af857a75fab..784df024e230 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -48,8 +48,6 @@ struct intel_tv { struct intel_encoder base; int type; - const char *tv_format; - int margin[4]; }; struct video_levels { @@ -840,32 +838,18 @@ intel_disable_tv(struct intel_encoder *encoder, I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); } -static const struct tv_mode * -intel_tv_mode_lookup(const char *tv_format) +static const struct tv_mode *intel_tv_mode_find(struct drm_connector_state *conn_state) { - int i; + int format = conn_state->tv.mode; - for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { - const struct tv_mode *tv_mode = &tv_modes[i]; - - if (!strcmp(tv_format, tv_mode->name)) - return tv_mode; - } - return NULL; -} - -static const struct tv_mode * -intel_tv_mode_find(struct intel_tv *intel_tv) -{ - return intel_tv_mode_lookup(intel_tv->tv_format); + return &tv_modes[format]; } static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_tv *intel_tv = intel_attached_tv(connector); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; if (mode->clock > max_dotclk) @@ -892,8 +876,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { - struct intel_tv *intel_tv = enc_to_tv(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state); if (!tv_mode) return false; @@ -999,7 +982,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_tv *intel_tv = enc_to_tv(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state); u32 tv_ctl; u32 scctl1, scctl2, scctl3; int i, j; @@ -1102,12 +1085,12 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder, else ysize = 2*tv_mode->nbr_end + 1; - xpos += intel_tv->margin[TV_MARGIN_LEFT]; - ypos += intel_tv->margin[TV_MARGIN_TOP]; - xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + - intel_tv->margin[TV_MARGIN_RIGHT]); - ysize -= (intel_tv->margin[TV_MARGIN_TOP] + - intel_tv->margin[TV_MARGIN_BOTTOM]); + xpos += conn_state->tv.margins.left; + ypos += conn_state->tv.margins.top; + xsize -= (conn_state->tv.margins.left + + conn_state->tv.margins.right); + ysize -= (conn_state->tv.margins.top + + conn_state->tv.margins.bottom); I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); @@ -1255,7 +1238,7 @@ intel_tv_detect_type(struct intel_tv *intel_tv, static void intel_tv_find_better_format(struct drm_connector *connector) { struct intel_tv *intel_tv = intel_attached_tv(connector); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); int i; if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == @@ -1271,9 +1254,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) break; } - intel_tv->tv_format = tv_mode->name; - drm_object_property_set_value(&connector->base, - connector->dev->mode_config.tv_mode_property, i); + connector->state->tv.mode = i; } /** @@ -1314,16 +1295,15 @@ intel_tv_detect(struct drm_connector *connector, connector_status_connected; } else status = connector_status_unknown; + + if (status == connector_status_connected) { + intel_tv->type = type; + intel_tv_find_better_format(connector); + } + + return status; } else return connector->status; - - if (status != connector_status_connected) - return status; - - intel_tv->type = type; - intel_tv_find_better_format(connector); - - return connector_status_connected; } static const struct input_res { @@ -1343,12 +1323,9 @@ static const struct input_res { * Chose preferred mode according to line number of TV format */ static void -intel_tv_chose_preferred_modes(struct drm_connector *connector, +intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode, struct drm_display_mode *mode_ptr) { - struct intel_tv *intel_tv = intel_attached_tv(connector); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); - if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; else if (tv_mode->nbr_end > 480) { @@ -1371,8 +1348,7 @@ static int intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; - struct intel_tv *intel_tv = intel_attached_tv(connector); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); int j, count = 0; u64 tmp; @@ -1415,7 +1391,7 @@ intel_tv_get_modes(struct drm_connector *connector) mode_ptr->clock = (int) tmp; mode_ptr->type = DRM_MODE_TYPE_DRIVER; - intel_tv_chose_preferred_modes(connector, mode_ptr); + intel_tv_choose_preferred_modes(tv_mode, mode_ptr); drm_mode_probed_add(connector, mode_ptr); count++; } @@ -1430,74 +1406,47 @@ intel_tv_destroy(struct drm_connector *connector) kfree(connector); } - -static int -intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = connector->dev; - struct intel_tv *intel_tv = intel_attached_tv(connector); - struct drm_crtc *crtc = intel_tv->base.base.crtc; - int ret = 0; - bool changed = false; - - ret = drm_object_property_set_value(&connector->base, property, val); - if (ret < 0) - goto out; - - if (property == dev->mode_config.tv_left_margin_property && - intel_tv->margin[TV_MARGIN_LEFT] != val) { - intel_tv->margin[TV_MARGIN_LEFT] = val; - changed = true; - } else if (property == dev->mode_config.tv_right_margin_property && - intel_tv->margin[TV_MARGIN_RIGHT] != val) { - intel_tv->margin[TV_MARGIN_RIGHT] = val; - changed = true; - } else if (property == dev->mode_config.tv_top_margin_property && - intel_tv->margin[TV_MARGIN_TOP] != val) { - intel_tv->margin[TV_MARGIN_TOP] = val; - changed = true; - } else if (property == dev->mode_config.tv_bottom_margin_property && - intel_tv->margin[TV_MARGIN_BOTTOM] != val) { - intel_tv->margin[TV_MARGIN_BOTTOM] = val; - changed = true; - } else if (property == dev->mode_config.tv_mode_property) { - if (val >= ARRAY_SIZE(tv_modes)) { - ret = -EINVAL; - goto out; - } - if (!strcmp(intel_tv->tv_format, tv_modes[val].name)) - goto out; - - intel_tv->tv_format = tv_modes[val].name; - changed = true; - } else { - ret = -EINVAL; - goto out; - } - - if (changed && crtc) - intel_crtc_restore_mode(crtc); -out: - return ret; -} - static const struct drm_connector_funcs intel_tv_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, .destroy = intel_tv_destroy, - .set_property = intel_tv_set_property, - .atomic_get_property = intel_connector_atomic_get_property, + .set_property = drm_atomic_helper_connector_set_property, .fill_modes = drm_helper_probe_single_connector_modes, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, }; +static int intel_tv_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_state) +{ + struct drm_crtc_state *new_crtc_state; + struct drm_connector_state *old_state; + + if (!new_state->crtc) + return 0; + + old_state = drm_atomic_get_old_connector_state(new_state->state, connector); + new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc); + + if (old_state->tv.mode != new_state->tv.mode || + old_state->tv.margins.left != new_state->tv.margins.left || + old_state->tv.margins.right != new_state->tv.margins.right || + old_state->tv.margins.top != new_state->tv.margins.top || + old_state->tv.margins.bottom != new_state->tv.margins.bottom) { + /* Force a modeset. */ + + new_crtc_state->connectors_changed = true; + } + + return 0; +} + static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { .detect_ctx = intel_tv_detect, .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, + .atomic_check = intel_tv_atomic_check, }; static const struct drm_encoder_funcs intel_tv_enc_funcs = { @@ -1515,6 +1464,7 @@ intel_tv_init(struct drm_i915_private *dev_priv) u32 tv_dac_on, tv_dac_off, save_tv_dac; const char *tv_format_names[ARRAY_SIZE(tv_modes)]; int i, initial_mode = 0; + struct drm_connector_state *state; if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) return; @@ -1560,6 +1510,7 @@ intel_tv_init(struct drm_i915_private *dev_priv) intel_encoder = &intel_tv->base; connector = &intel_connector->base; + state = connector->state; /* The documentation, for the older chipsets at least, recommend * using a polling method rather than hotplug detection for TVs. @@ -1597,12 +1548,12 @@ intel_tv_init(struct drm_i915_private *dev_priv) intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ - intel_tv->margin[TV_MARGIN_LEFT] = 54; - intel_tv->margin[TV_MARGIN_TOP] = 36; - intel_tv->margin[TV_MARGIN_RIGHT] = 46; - intel_tv->margin[TV_MARGIN_BOTTOM] = 37; + state->tv.margins.left = 54; + state->tv.margins.top = 36; + state->tv.margins.right = 46; + state->tv.margins.bottom = 37; - intel_tv->tv_format = tv_modes[initial_mode].name; + state->tv.mode = initial_mode; drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); connector->interlace_allowed = false; @@ -1616,17 +1567,17 @@ intel_tv_init(struct drm_i915_private *dev_priv) tv_format_names); drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, - initial_mode); + state->tv.mode); drm_object_attach_property(&connector->base, dev->mode_config.tv_left_margin_property, - intel_tv->margin[TV_MARGIN_LEFT]); + state->tv.margins.left); drm_object_attach_property(&connector->base, dev->mode_config.tv_top_margin_property, - intel_tv->margin[TV_MARGIN_TOP]); + state->tv.margins.top); drm_object_attach_property(&connector->base, dev->mode_config.tv_right_margin_property, - intel_tv->margin[TV_MARGIN_RIGHT]); + state->tv.margins.right); drm_object_attach_property(&connector->base, dev->mode_config.tv_bottom_margin_property, - intel_tv->margin[TV_MARGIN_BOTTOM]); + state->tv.margins.bottom); } From 200819ab5b4d2d35fde5aedf7f0ee7582a9c7263 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 12:51:10 +0200 Subject: [PATCH 0064/1270] drm/i915: Remove unused dp properties for dp-mst. Those properties are not hooked up on MST and were ignored. Best not expose them at all. Without this the next patch fails to start on X.org, because the DP-MST properties could not be read. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/751b85a0-81cd-09e2-9e60-6d4ddbf1c6ac@linux.intel.com Testcase: kms_properties Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_dp_mst.c | 1 - drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8389ed1848ac..944b1449b7f9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5145,7 +5145,7 @@ bool intel_dp_is_edp(struct drm_i915_private *dev_priv, enum port port) return intel_bios_is_port_edp(dev_priv, port); } -void +static void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 3451e2abb23b..b2f5de5b56f5 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -459,7 +459,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_mode_connector_attach_encoder(&intel_connector->base, &intel_dp->mst_encoders[i]->base.base); } - intel_dp_add_properties(intel_dp, connector); drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 703605456200..f78d7c5f3805 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1499,7 +1499,6 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp); void intel_edp_panel_vdd_on(struct intel_dp *intel_dp); void intel_edp_panel_on(struct intel_dp *intel_dp); void intel_edp_panel_off(struct intel_dp *intel_dp); -void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector); void intel_dp_mst_suspend(struct drm_device *dev); void intel_dp_mst_resume(struct drm_device *dev); int intel_dp_max_link_rate(struct intel_dp *intel_dp); From 2e222edabfebf8139b681fb17a9cd80bc9ca2896 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 11:07:09 +0200 Subject: [PATCH 0065/1270] drm/i915: Convert intel_dp_mst connector properties to atomic. MST doesn't support setting any properties, but it should still use the atomic helper for setting properties. Only path and tile properties are supported (read-only). Those are immutable, and handled by drm core. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491815239-10685-4-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp_mst.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index b2f5de5b56f5..5af22a7c11bf 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -294,14 +294,6 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force) return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port); } -static int -intel_dp_mst_set_property(struct drm_connector *connector, - struct drm_property *property, - uint64_t val) -{ - return 0; -} - static void intel_dp_mst_connector_destroy(struct drm_connector *connector) { @@ -318,8 +310,7 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .detect = intel_dp_mst_detect, .fill_modes = drm_helper_probe_single_connector_modes, - .set_property = intel_dp_mst_set_property, - .atomic_get_property = intel_connector_atomic_get_property, + .set_property = drm_atomic_helper_connector_set_property, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, .destroy = intel_dp_mst_connector_destroy, From eadc1db859c83324653ea640d5e06d4e2bba9e86 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 11:07:10 +0200 Subject: [PATCH 0066/1270] drm/i915: Convert intel_crt connector properties to atomic. No properties are supported, so just use the helper and reject everything. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491815239-10685-5-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 2797bf37c3ac..84a1f5e85153 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -777,13 +777,6 @@ out: return ret; } -static int intel_crt_set_property(struct drm_connector *connector, - struct drm_property *property, - uint64_t value) -{ - return 0; -} - void intel_crt_reset(struct drm_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->dev); @@ -814,10 +807,9 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, .destroy = intel_crt_destroy, - .set_property = intel_crt_set_property, + .set_property = drm_atomic_helper_connector_set_property, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_get_property = intel_connector_atomic_get_property, }; static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { From 9cb9be037c2e5eb21a759b15c1e428ba6d544c6d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 10 Apr 2017 11:07:11 +0200 Subject: [PATCH 0067/1270] drm/i915: Convert intel DVO connector to atomic No properties are supported, so just use the helper and reject everything. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491815239-10685-6-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 6025839ed3b7..c1544a53095d 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -350,7 +350,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = { .early_unregister = intel_connector_unregister, .destroy = intel_dvo_destroy, .fill_modes = drm_helper_probe_single_connector_modes, - .atomic_get_property = intel_connector_atomic_get_property, + .set_property = drm_atomic_helper_connector_set_property, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, }; From c50b4bf6e25a3ce2b058a132f49335ac9fa67062 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 4 Apr 2017 15:22:48 +0200 Subject: [PATCH 0068/1270] Revert "drm/i915: Lock mode_config.mutex in intel_display_resume." This reverts commit ea49c9acf2db7082f0406bb3a570cc6bad37082b. mode_config.mutex was originally added to fix WARNs in connector functions, but now that atomic nonblocking modeset support is included, we will likely never hold any any lock at all. The WARN mentioned in commit bbf35e9defb9a6d1 ("drm/i915: Pass atomic state to intel_audio_codec_enable, v2."), so it's safe to revert this now. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491312168-18147-1-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b6b40cd15644..48a546210d8b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15559,13 +15559,6 @@ void intel_display_resume(struct drm_device *dev) if (state) state->acquire_ctx = &ctx; - /* - * This is a cludge because with real atomic modeset mode_config.mutex - * won't be taken. Unfortunately some probed state like - * audio_codec_enable is still protected by mode_config.mutex, so lock - * it here for now. - */ - mutex_lock(&dev->mode_config.mutex); drm_modeset_acquire_init(&ctx, 0); while (1) { @@ -15581,7 +15574,6 @@ void intel_display_resume(struct drm_device *dev) drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); - mutex_unlock(&dev->mode_config.mutex); if (ret) DRM_ERROR("Restoring old state failed with %i\n", ret); From aab9094b032528da1b32cc5203964075cd04d5be Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 4 Apr 2017 15:24:57 +0200 Subject: [PATCH 0069/1270] drm/i915: Do not use lock all in hsw_trans_edp_pipe_A_crc_wa There is no need to acquire all locks here, doing a commit after forcing a modeset on the affected crtc is enough. Any other locks needed will be acquired as needed. Signed-off-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1491312297-18673-1-git-send-email-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pipe_crc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 206ee4f0150e..647426c75b0a 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -513,16 +513,20 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A); struct intel_crtc_state *pipe_config; struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; int ret = 0; - drm_modeset_lock_all(dev); + drm_modeset_acquire_init(&ctx, 0); + state = drm_atomic_state_alloc(dev); if (!state) { ret = -ENOMEM; goto unlock; } - state->acquire_ctx = crtc->base.dev->mode_config.acquire_ctx; + state->acquire_ctx = &ctx; + +retry: pipe_config = intel_atomic_get_crtc_state(state, crtc); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); @@ -537,10 +541,17 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, ret = drm_atomic_commit(state); put_state: + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + goto retry; + } + drm_atomic_state_put(state); unlock: WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret); - drm_modeset_unlock_all(dev); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); } static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, From ef74921bc679232c6590afa881d3ea605ebdddd8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 12:01:10 +0100 Subject: [PATCH 0070/1270] drm/i915: Combine write_domain flushes to a single function In the next patch, we will introduce a new cache domain for differentiating between GTT access and direct WC access. This will require us to include WC in our write_domain flushes. Rather than duplicate a third function, combine the existing two into one and flushing WC writes will then be automatically handled as well. v2: Be smarter and clearer by passing in the write domains to flush (Joonas) v3: One missed ~ in v2 conversion Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170412110111.26626-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 125 +++++++++--------- .../drm/i915/selftests/i915_gem_coherency.c | 4 +- .../gpu/drm/i915/selftests/i915_gem_object.c | 2 +- 3 files changed, 64 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cb8c6a94ba4e..f1c28668edbf 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,8 +46,6 @@ #include static void i915_gem_flush_free_objects(struct drm_i915_private *i915); -static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); -static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj) { @@ -705,6 +703,61 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, args->size, &args->handle); } +static inline enum fb_op_origin +fb_write_origin(struct drm_i915_gem_object *obj, unsigned int domain) +{ + return (domain == I915_GEM_DOMAIN_GTT ? + obj->frontbuffer_ggtt_origin : ORIGIN_CPU); +} + +static void +flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains) +{ + struct drm_i915_private *dev_priv = to_i915(obj->base.dev); + + if (!(obj->base.write_domain & flush_domains)) + return; + + /* No actual flushing is required for the GTT write domain. Writes + * to it "immediately" go to main memory as far as we know, so there's + * no chipset flush. It also doesn't land in render cache. + * + * However, we do have to enforce the order so that all writes through + * the GTT land before any writes to the device, such as updates to + * the GATT itself. + * + * We also have to wait a bit for the writes to land from the GTT. + * An uncached read (i.e. mmio) seems to be ideal for the round-trip + * timing. This issue has only been observed when switching quickly + * between GTT writes and CPU reads from inside the kernel on recent hw, + * and it appears to only affect discrete GTT blocks (i.e. on LLC + * system agents we cannot reproduce this behaviour). + */ + wmb(); + + switch (obj->base.write_domain) { + case I915_GEM_DOMAIN_GTT: + if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv)) { + if (intel_runtime_pm_get_if_in_use(dev_priv)) { + spin_lock_irq(&dev_priv->uncore.lock); + POSTING_READ_FW(RING_ACTHD(dev_priv->engine[RCS]->mmio_base)); + spin_unlock_irq(&dev_priv->uncore.lock); + intel_runtime_pm_put(dev_priv); + } + } + + intel_fb_obj_flush(obj, + fb_write_origin(obj, I915_GEM_DOMAIN_GTT)); + break; + + case I915_GEM_DOMAIN_CPU: + i915_gem_clflush_object(obj, I915_CLFLUSH_SYNC); + break; + } + + obj->base.write_domain = 0; +} + static inline int __copy_to_user_swizzled(char __user *cpu_vaddr, const char *gpu_vaddr, int gpu_offset, @@ -794,7 +847,7 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, goto out; } - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU); /* If we're not in the cpu read domain, set ourself into the gtt * read domain and manually flush cachelines (if required). This @@ -846,7 +899,7 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj, goto out; } - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU); /* If we're not in the cpu write domain, set ourself into the * gtt write domain and manually flush cachelines (as required). @@ -1501,13 +1554,6 @@ err: return ret; } -static inline enum fb_op_origin -write_origin(struct drm_i915_gem_object *obj, unsigned domain) -{ - return (domain == I915_GEM_DOMAIN_GTT ? - obj->frontbuffer_ggtt_origin : ORIGIN_CPU); -} - static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) { struct drm_i915_private *i915; @@ -1602,7 +1648,8 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, mutex_unlock(&dev->struct_mutex); if (write_domain != 0) - intel_fb_obj_invalidate(obj, write_origin(obj, write_domain)); + intel_fb_obj_invalidate(obj, + fb_write_origin(obj, write_domain)); out_unpin: i915_gem_object_unpin_pages(obj); @@ -3320,56 +3367,6 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) return ret; } -/** Flushes the GTT write domain for the object if it's dirty. */ -static void -i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - - if (obj->base.write_domain != I915_GEM_DOMAIN_GTT) - return; - - /* No actual flushing is required for the GTT write domain. Writes - * to it "immediately" go to main memory as far as we know, so there's - * no chipset flush. It also doesn't land in render cache. - * - * However, we do have to enforce the order so that all writes through - * the GTT land before any writes to the device, such as updates to - * the GATT itself. - * - * We also have to wait a bit for the writes to land from the GTT. - * An uncached read (i.e. mmio) seems to be ideal for the round-trip - * timing. This issue has only been observed when switching quickly - * between GTT writes and CPU reads from inside the kernel on recent hw, - * and it appears to only affect discrete GTT blocks (i.e. on LLC - * system agents we cannot reproduce this behaviour). - */ - wmb(); - if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv)) { - if (intel_runtime_pm_get_if_in_use(dev_priv)) { - spin_lock_irq(&dev_priv->uncore.lock); - POSTING_READ_FW(RING_ACTHD(dev_priv->engine[RCS]->mmio_base)); - spin_unlock_irq(&dev_priv->uncore.lock); - intel_runtime_pm_put(dev_priv); - } - } - - intel_fb_obj_flush(obj, write_origin(obj, I915_GEM_DOMAIN_GTT)); - - obj->base.write_domain = 0; -} - -/** Flushes the CPU write domain for the object if it's dirty. */ -static void -i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) -{ - if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) - return; - - i915_gem_clflush_object(obj, I915_CLFLUSH_SYNC); - obj->base.write_domain = 0; -} - static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj) { if (obj->base.write_domain != I915_GEM_DOMAIN_CPU && !obj->cache_dirty) @@ -3428,7 +3425,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; - i915_gem_object_flush_cpu_write_domain(obj); + flush_write_domain(obj, ~I915_GEM_DOMAIN_GTT); /* Serialise direct access to this object with the barriers for * coherent writes from the GPU, by effectively invalidating the @@ -3802,7 +3799,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) return 0; - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU); /* Flush the CPU cache if it's still invalid. */ if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) { diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index f08d0179b3df..c61d0ef2118c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -139,7 +139,7 @@ static int wc_set(struct drm_i915_gem_object *obj, int err; /* XXX GTT write followed by WC write go missing */ - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~0); err = i915_gem_object_set_to_gtt_domain(obj, true); if (err) @@ -163,7 +163,7 @@ static int wc_get(struct drm_i915_gem_object *obj, int err; /* XXX WC write followed by GTT write go missing */ - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~0); err = i915_gem_object_set_to_gtt_domain(obj, false); if (err) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 67d82bf1407f..163424748ee0 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -266,7 +266,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj, if (offset >= obj->base.size) continue; - i915_gem_object_flush_gtt_write_domain(obj); + flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU); p = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT); cpu = kmap(p) + offset_in_page(offset); From e22d8e3c69a9f432b40baaaf3f894a128fdc2222 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 12:01:11 +0100 Subject: [PATCH 0071/1270] drm/i915: Treat WC a separate cache domain When discussing a new WC mmap, we based the interface upon the assumption that GTT was fully coherent. How naive! Commits 3b5724d702ef ("drm/i915: Wait for writes through the GTT to land before reading back") and ed4596ea992d ("drm/i915/guc: WA to address the Ringbuffer coherency issue") demonstrate that writes through the GTT are indeed delayed and may be overtaken by direct WC access. To be safe, if userspace is mixing WC mmaps with other potential GTT access (pwrite, GTT mmaps) it should use set_domain(WC). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96563 Testcase: igt/gem_pwrite/small-gtt* Testcase: igt/drv_selftest/coherency Signed-off-by: Chris Wilson Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170412110111.26626-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_gem.c | 76 ++++++++++++++++++- drivers/gpu/drm/i915/intel_guc_log.c | 6 +- .../drm/i915/selftests/i915_gem_coherency.c | 10 +-- .../gpu/drm/i915/selftests/i915_gem_request.c | 2 +- include/uapi/drm/i915_drm.h | 2 + 6 files changed, 85 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ed079c244b5d..1af4e6f5410c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3453,8 +3453,9 @@ int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, #define I915_PRIORITY_DISPLAY I915_PRIORITY_MAX int __must_check -i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, - bool write); +i915_gem_object_set_to_wc_domain(struct drm_i915_gem_object *obj, bool write); +int __must_check +i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write); int __must_check i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write); struct i915_vma * __must_check diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f1c28668edbf..33fb11cc5acc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1637,10 +1637,12 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (err) goto out_unpin; - if (read_domains & I915_GEM_DOMAIN_GTT) - err = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); + if (read_domains & I915_GEM_DOMAIN_WC) + err = i915_gem_object_set_to_wc_domain(obj, write_domain); + else if (read_domains & I915_GEM_DOMAIN_GTT) + err = i915_gem_object_set_to_gtt_domain(obj, write_domain); else - err = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); + err = i915_gem_object_set_to_cpu_domain(obj, write_domain); /* And bump the LRU for this access */ i915_gem_object_bump_inactive_ggtt(obj); @@ -1784,6 +1786,9 @@ static unsigned int tile_row_pages(struct drm_i915_gem_object *obj) * into userspace. (This view is aligned and sized appropriately for * fenced access.) * + * 2 - Recognise WC as a separate cache domain so that we can flush the + * delayed writes via GTT before performing direct access via WC. + * * Restrictions: * * * snoopable objects cannot be accessed via the GTT. It can cause machine @@ -1811,7 +1816,7 @@ static unsigned int tile_row_pages(struct drm_i915_gem_object *obj) */ int i915_gem_mmap_gtt_version(void) { - return 1; + return 2; } static inline struct i915_ggtt_view @@ -3386,6 +3391,69 @@ void i915_gem_object_flush_if_display(struct drm_i915_gem_object *obj) mutex_unlock(&obj->base.dev->struct_mutex); } +/** + * Moves a single object to the WC read, and possibly write domain. + * @obj: object to act on + * @write: ask for write access or read only + * + * This function returns when the move is complete, including waiting on + * flushes to occur. + */ +int +i915_gem_object_set_to_wc_domain(struct drm_i915_gem_object *obj, bool write) +{ + int ret; + + lockdep_assert_held(&obj->base.dev->struct_mutex); + + ret = i915_gem_object_wait(obj, + I915_WAIT_INTERRUPTIBLE | + I915_WAIT_LOCKED | + (write ? I915_WAIT_ALL : 0), + MAX_SCHEDULE_TIMEOUT, + NULL); + if (ret) + return ret; + + if (obj->base.write_domain == I915_GEM_DOMAIN_WC) + return 0; + + /* Flush and acquire obj->pages so that we are coherent through + * direct access in memory with previous cached writes through + * shmemfs and that our cache domain tracking remains valid. + * For example, if the obj->filp was moved to swap without us + * being notified and releasing the pages, we would mistakenly + * continue to assume that the obj remained out of the CPU cached + * domain. + */ + ret = i915_gem_object_pin_pages(obj); + if (ret) + return ret; + + flush_write_domain(obj, ~I915_GEM_DOMAIN_WC); + + /* Serialise direct access to this object with the barriers for + * coherent writes from the GPU, by effectively invalidating the + * WC domain upon first access. + */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_WC) == 0) + mb(); + + /* It should now be out of any other write domains, and we can update + * the domain values for our changes. + */ + GEM_BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_WC) != 0); + obj->base.read_domains |= I915_GEM_DOMAIN_WC; + if (write) { + obj->base.read_domains = I915_GEM_DOMAIN_WC; + obj->base.write_domain = I915_GEM_DOMAIN_WC; + obj->mm.dirty = true; + } + + i915_gem_object_unpin_pages(obj); + return 0; +} + /** * Moves a single object to the GTT read, and possibly write domain. * @obj: object to act on diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 6fb63a3c65b0..16d3b8719cab 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -359,12 +359,16 @@ static int guc_log_runtime_create(struct intel_guc *guc) void *vaddr; struct rchan *guc_log_relay_chan; size_t n_subbufs, subbuf_size; - int ret = 0; + int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); GEM_BUG_ON(guc_log_has_runtime(guc)); + ret = i915_gem_object_set_to_wc_domain(guc->log.vma->obj, true); + if (ret) + return ret; + /* Create a WC (Uncached for read) vmalloc mapping of log * buffer pages, so that we can directly get the data * (up-to-date) from memory. diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index c61d0ef2118c..95d4aebc0181 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -138,10 +138,7 @@ static int wc_set(struct drm_i915_gem_object *obj, typeof(v) *map; int err; - /* XXX GTT write followed by WC write go missing */ - flush_write_domain(obj, ~0); - - err = i915_gem_object_set_to_gtt_domain(obj, true); + err = i915_gem_object_set_to_wc_domain(obj, true); if (err) return err; @@ -162,10 +159,7 @@ static int wc_get(struct drm_i915_gem_object *obj, typeof(v) map; int err; - /* XXX WC write followed by GTT write go missing */ - flush_write_domain(obj, ~0); - - err = i915_gem_object_set_to_gtt_domain(obj, false); + err = i915_gem_object_set_to_wc_domain(obj, false); if (err) return err; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_request.c b/drivers/gpu/drm/i915/selftests/i915_gem_request.c index 98b7aac41eec..6664cb2eb0b8 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_request.c @@ -580,7 +580,7 @@ static struct i915_vma *recursive_batch(struct drm_i915_private *i915) if (err) goto err; - err = i915_gem_object_set_to_gtt_domain(obj, true); + err = i915_gem_object_set_to_wc_domain(obj, true); if (err) goto err; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 3554495bef13..9ee06ec8a2d6 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -666,6 +666,8 @@ struct drm_i915_gem_relocation_entry { #define I915_GEM_DOMAIN_VERTEX 0x00000020 /** GTT domain - aperture and scanout */ #define I915_GEM_DOMAIN_GTT 0x00000040 +/** WC domain - uncached access */ +#define I915_GEM_DOMAIN_WC 0x00000080 /** @} */ struct drm_i915_gem_exec_object { From 0757ac8fc7c1dac32be080e6746324ff42b7a9b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 10:21:43 +0100 Subject: [PATCH 0072/1270] drm/i915: Add stub mmio read/write routines to mock device Provide dummy function pointers for the mock device in case we do hit mmio during testing. v2: Use ASSIGN_READ/WRITE_MMIO_FUNCS macros Signed-off-by: Chris Wilson Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20170412092143.3822-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_uncore.c | 47 +++++++++---------- .../gpu/drm/i915/selftests/mock_gem_device.c | 2 + drivers/gpu/drm/i915/selftests/mock_uncore.c | 46 ++++++++++++++++++ drivers/gpu/drm/i915/selftests/mock_uncore.h | 30 ++++++++++++ 4 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 drivers/gpu/drm/i915/selftests/mock_uncore.c create mode 100644 drivers/gpu/drm/i915/selftests/mock_uncore.h diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index fb38c7692fc2..0cd56bf00650 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1108,19 +1108,19 @@ __gen6_write(32) #undef GEN6_WRITE_FOOTER #undef GEN6_WRITE_HEADER -#define ASSIGN_WRITE_MMIO_VFUNCS(x) \ +#define ASSIGN_WRITE_MMIO_VFUNCS(i915, x) \ do { \ - dev_priv->uncore.funcs.mmio_writeb = x##_write8; \ - dev_priv->uncore.funcs.mmio_writew = x##_write16; \ - dev_priv->uncore.funcs.mmio_writel = x##_write32; \ + (i915)->uncore.funcs.mmio_writeb = x##_write8; \ + (i915)->uncore.funcs.mmio_writew = x##_write16; \ + (i915)->uncore.funcs.mmio_writel = x##_write32; \ } while (0) -#define ASSIGN_READ_MMIO_VFUNCS(x) \ +#define ASSIGN_READ_MMIO_VFUNCS(i915, x) \ do { \ - dev_priv->uncore.funcs.mmio_readb = x##_read8; \ - dev_priv->uncore.funcs.mmio_readw = x##_read16; \ - dev_priv->uncore.funcs.mmio_readl = x##_read32; \ - dev_priv->uncore.funcs.mmio_readq = x##_read64; \ + (i915)->uncore.funcs.mmio_readb = x##_read8; \ + (i915)->uncore.funcs.mmio_readw = x##_read16; \ + (i915)->uncore.funcs.mmio_readl = x##_read32; \ + (i915)->uncore.funcs.mmio_readq = x##_read64; \ } while (0) @@ -1310,34 +1310,34 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) i915_pmic_bus_access_notifier; if (IS_GEN(dev_priv, 2, 4) || intel_vgpu_active(dev_priv)) { - ASSIGN_WRITE_MMIO_VFUNCS(gen2); - ASSIGN_READ_MMIO_VFUNCS(gen2); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen2); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen2); } else if (IS_GEN5(dev_priv)) { - ASSIGN_WRITE_MMIO_VFUNCS(gen5); - ASSIGN_READ_MMIO_VFUNCS(gen5); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen5); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen5); } else if (IS_GEN(dev_priv, 6, 7)) { - ASSIGN_WRITE_MMIO_VFUNCS(gen6); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen6); if (IS_VALLEYVIEW(dev_priv)) { ASSIGN_FW_DOMAINS_TABLE(__vlv_fw_ranges); - ASSIGN_READ_MMIO_VFUNCS(fwtable); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, fwtable); } else { - ASSIGN_READ_MMIO_VFUNCS(gen6); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen6); } } else if (IS_GEN8(dev_priv)) { if (IS_CHERRYVIEW(dev_priv)) { ASSIGN_FW_DOMAINS_TABLE(__chv_fw_ranges); - ASSIGN_WRITE_MMIO_VFUNCS(fwtable); - ASSIGN_READ_MMIO_VFUNCS(fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, fwtable); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, fwtable); } else { - ASSIGN_WRITE_MMIO_VFUNCS(gen8); - ASSIGN_READ_MMIO_VFUNCS(gen6); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen8); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen6); } } else { ASSIGN_FW_DOMAINS_TABLE(__gen9_fw_ranges); - ASSIGN_WRITE_MMIO_VFUNCS(fwtable); - ASSIGN_READ_MMIO_VFUNCS(fwtable); + ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, fwtable); + ASSIGN_READ_MMIO_VFUNCS(dev_priv, fwtable); if (HAS_DECOUPLED_MMIO(dev_priv)) { dev_priv->uncore.funcs.mmio_readl = gen9_decoupled_read32; @@ -1353,8 +1353,6 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) i915_check_and_clear_faults(dev_priv); } -#undef ASSIGN_WRITE_MMIO_VFUNCS -#undef ASSIGN_READ_MMIO_VFUNCS void intel_uncore_fini(struct drm_i915_private *dev_priv) { @@ -1900,5 +1898,6 @@ intel_uncore_forcewake_for_reg(struct drm_i915_private *dev_priv, } #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) +#include "selftests/mock_uncore.c" #include "selftests/intel_uncore.c" #endif diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 6a8258eacdcb..f321bdfe0b5b 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -30,6 +30,7 @@ #include "mock_gem_device.h" #include "mock_gem_object.h" #include "mock_gtt.h" +#include "mock_uncore.h" void mock_device_flush(struct drm_i915_private *i915) { @@ -143,6 +144,7 @@ struct drm_i915_private *mock_gem_device(void) mkwrite_device_info(i915)->gen = -1; spin_lock_init(&i915->mm.object_stat_lock); + mock_uncore_init(i915); init_waitqueue_head(&i915->gpu_error.wait_queue); init_waitqueue_head(&i915->gpu_error.reset_queue); diff --git a/drivers/gpu/drm/i915/selftests/mock_uncore.c b/drivers/gpu/drm/i915/selftests/mock_uncore.c new file mode 100644 index 000000000000..8ef14c7e5e38 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/mock_uncore.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "mock_uncore.h" + +#define __nop_write(x) \ +static void \ +nop_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { } +__nop_write(8) +__nop_write(16) +__nop_write(32) + +#define __nop_read(x) \ +static u##x \ +nop_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { return 0; } +__nop_read(8) +__nop_read(16) +__nop_read(32) +__nop_read(64) + +void mock_uncore_init(struct drm_i915_private *i915) +{ + ASSIGN_WRITE_MMIO_VFUNCS(i915, nop); + ASSIGN_READ_MMIO_VFUNCS(i915, nop); +} diff --git a/drivers/gpu/drm/i915/selftests/mock_uncore.h b/drivers/gpu/drm/i915/selftests/mock_uncore.h new file mode 100644 index 000000000000..d79aa3ca4d51 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/mock_uncore.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifndef __MOCK_UNCORE_H +#define __MOCK_UNCORE_H + +void mock_uncore_init(struct drm_i915_private *i915); + +#endif /* !__MOCK_UNCORE_H */ From 8968a3649a7c09a0c7f92001b0a599b93a4d9685 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 00:44:26 +0100 Subject: [PATCH 0073/1270] drm/i915: Pretend the engine is always idle when mocking If we have a mock engine and it has no more requests in flight, report it as idle as there is no hardware to contradict us! Otherwise we attempt to query the hw that doesn't exist and find that the hw hasn't set its idle bit and we get upset. Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170411234427.14841-2-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index ee87ca7420de..402769d9d840 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1140,6 +1140,9 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) intel_engine_last_submit(engine))) return false; + if (I915_SELFTEST_ONLY(engine->breadcrumbs.mock)) + return true; + /* Interrupt/tasklet pending? */ if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) return false; From 10e9bd9ab0322a3929db0bf84ff1ca3f28ed0ee4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 00:44:27 +0100 Subject: [PATCH 0074/1270] drm/i915: Wake device for emitting request during selftest igt_mmap_offset_exhaustion() selftest was using live requests to make an object busy, but we did not hold a runtime pm wakeref for submitting the requests. Acquire it to avoid triggering "RPM wakelock ref not held during HW access" warnings. Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170411234427.14841-3-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 163424748ee0..8f011c447e41 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -545,7 +545,9 @@ static int igt_mmap_offset_exhaustion(void *arg) } mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); err = make_obj_busy(obj); + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); if (err) { pr_err("[loop %d] Failed to busy the object\n", loop); From 14c562c0cde36e87e69918244cdf51a544580d19 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Thu, 6 Apr 2017 14:00:12 -0700 Subject: [PATCH 0075/1270] drm/i915/dp: Validate cached link rate and lane count before retraining MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently intel_dp_check_link_status() tries to retrain the link if Clock recovery or Channel EQ for any of the lanes indicated by intel_dp->lane_count is not set. However these values cached in intel_dp structure can be stale if link training has failed for these values during previous modeset. Or these values can get stale since we have now re read the DPCD registers or it can be 0 in case of connected boot case. This patch validates these values against the max link rate and max lane count values. This is absolutely required incase the common_rates or max lane count are now different due to link fallback. v2: * Include the FIXME commnet inside the function (Ville Syrjala) * Remove the redundant parenthesis (Ville Syrjala) v3 by Jani: * rebase on the DP refactoring series * rename intel_dp_link_params_is_valid to intel_dp_link_params_valid * minor stylistic changes v4: * Compare the link rate against max link rate not the common_rates since common_rates does not account for the lowered fallback link rate value. (Ville Syrjala) v5: * Fixed a warning for unused variable (Manasi) Cc: Ville Syrjala Cc: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Manasi Navare Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1491512412-30016-1-git-send-email-manasi.d.navare@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 944b1449b7f9..16b7bf7af537 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -322,6 +322,24 @@ static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp, return 0; } +static bool intel_dp_link_params_valid(struct intel_dp *intel_dp) +{ + /* + * FIXME: we need to synchronize the current link parameters with + * hardware readout. Currently fast link training doesn't work on + * boot-up. + */ + if (intel_dp->link_rate == 0 || + intel_dp->link_rate > intel_dp->max_link_rate) + return false; + + if (intel_dp->lane_count == 0 || + intel_dp->lane_count > intel_dp_max_lane_count(intel_dp)) + return false; + + return true; +} + int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, int link_rate, uint8_t lane_count) { @@ -4253,9 +4271,11 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) if (!to_intel_crtc(intel_encoder->base.crtc)->active) return; - /* FIXME: we need to synchronize this sort of stuff with hardware - * readout. Currently fast link training doesn't work on boot-up. */ - if (!intel_dp->lane_count) + /* + * Validate the cached values of intel_dp->link_rate and + * intel_dp->lane_count before attempting to retrain. + */ + if (!intel_dp_link_params_valid(intel_dp)) return; /* Retrain if Channel EQ or CR not ok */ From 48ae80741da4b8a26b6df0f765713912bc7cc480 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Apr 2017 09:02:51 +0100 Subject: [PATCH 0076/1270] drm/i915: Fix use after free in lpe_audio_platdev_destroy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [31908.547136] BUG: KASAN: use-after-free in intel_lpe_audio_teardown+0x78/0xb0 [i915] at addr ffff8801f7788358 [31908.547297] Read of size 8 by task drv_selftest/3781 [31908.547405] CPU: 0 PID: 3781 Comm: drv_selftest Tainted: G BU W 4.10.0+ #451 [31908.547553] Hardware name: / , BIOS PYBSWCEL.86A.0027.2015.0507.1758 05/07/2015 [31908.547682] Call Trace: [31908.547772] dump_stack+0x68/0x9f [31908.547857] kasan_object_err+0x1c/0x70 [31908.547947] kasan_report_error+0x1f1/0x4f0 [31908.548038] ? kfree+0xaa/0x170 [31908.548121] kasan_report+0x34/0x40 [31908.548211] ? klist_children_get+0x20/0x30 [31908.548472] ? intel_lpe_audio_teardown+0x78/0xb0 [i915] [31908.548567] __asan_load8+0x5e/0x70 [31908.548824] intel_lpe_audio_teardown+0x78/0xb0 [i915] [31908.549080] intel_audio_deinit+0x28/0x80 [i915] [31908.549315] i915_driver_unload+0xe4/0x360 [i915] [31908.549551] ? i915_driver_load+0x1d70/0x1d70 [i915] [31908.549651] ? trace_hardirqs_on+0xd/0x10 [31908.549885] i915_pci_remove+0x23/0x30 [i915] [31908.549978] pci_device_remove+0x5c/0x100 [31908.550069] device_release_driver_internal+0x1db/0x2e0 [31908.550165] driver_detach+0x68/0xc0 [31908.550256] bus_remove_driver+0x8b/0x150 [31908.550346] driver_unregister+0x3e/0x60 [31908.550439] pci_unregister_driver+0x1d/0x110 [31908.550531] ? find_module_all+0x7a/0xa0 [31908.550791] i915_exit+0x1a/0x87 [i915] [31908.550881] SyS_delete_module+0x264/0x2c0 [31908.550971] ? free_module+0x430/0x430 [31908.551064] ? trace_hardirqs_off_caller+0x16/0x110 [31908.551159] ? trace_hardirqs_on_caller+0x16/0x280 [31908.551256] ? trace_hardirqs_on_thunk+0x1a/0x1c [31908.551350] entry_SYSCALL_64_fastpath+0x1c/0xb1 [31908.551440] RIP: 0033:0x7f1d67312ec7 [31908.551520] RSP: 002b:00007ffebe34e888 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 [31908.551650] RAX: ffffffffffffffda RBX: ffffffff811123f6 RCX: 00007f1d67312ec7 [31908.551743] RDX: 0000000000000000 RSI: 0000000000000800 RDI: 0000560d0af476b8 [31908.551837] RBP: ffff880233d87f98 R08: 0000000000000000 R09: 00007ffebe34e8b8 [31908.551930] R10: 00007f1d68adf8c0 R11: 0000000000000206 R12: 0000000000000000 [31908.552023] R13: 0000560d0af46440 R14: 0000000000000034 R15: 00007ffebe34d860 [31908.552121] ? trace_hardirqs_off_caller+0x16/0x110 [31908.552217] Object at ffff8801f7788000, in cache kmalloc-2048 size: 2048 [31908.552306] Allocated: [31908.552377] PID = 3781 [31908.552456] save_stack_trace+0x16/0x20 [31908.552539] kasan_kmalloc+0xee/0x190 [31908.552627] __kmalloc+0xdb/0x1b0 [31908.552713] platform_device_alloc+0x27/0x90 [31908.552804] platform_device_register_full+0x36/0x220 [31908.553066] intel_lpe_audio_init+0x41e/0x570 [i915] [31908.553320] intel_audio_init+0xd/0x40 [i915] [31908.553552] i915_driver_load+0x13f5/0x1d70 [i915] [31908.553788] i915_pci_probe+0x65/0xe0 [i915] [31908.553881] pci_device_probe+0xda/0x140 [31908.553969] driver_probe_device+0x400/0x660 [31908.554058] __driver_attach+0x11c/0x120 [31908.554147] bus_for_each_dev+0xe6/0x150 [31908.554237] driver_attach+0x26/0x30 [31908.554325] bus_add_driver+0x26b/0x3b0 [31908.554412] driver_register+0xce/0x190 [31908.554502] __pci_register_driver+0xaf/0xc0 [31908.554589] 0xffffffffa0550063 [31908.554675] do_one_initcall+0x8b/0x1e0 [31908.554764] do_init_module+0x102/0x325 [31908.554852] load_module+0x3aad/0x45e0 [31908.554944] SyS_finit_module+0x169/0x1a0 [31908.555033] entry_SYSCALL_64_fastpath+0x1c/0xb1 [31908.555119] Freed: [31908.555188] PID = 3781 [31908.555266] save_stack_trace+0x16/0x20 [31908.555349] kasan_slab_free+0xb0/0x180 [31908.555436] kfree+0xaa/0x170 [31908.555520] platform_device_release+0x76/0x80 [31908.555610] device_release+0x45/0xe0 [31908.555698] kobject_put+0x11f/0x260 [31908.555785] put_device+0x12/0x20 [31908.555871] platform_device_unregister+0x1b/0x20 [31908.556135] intel_lpe_audio_teardown+0x5c/0xb0 [i915] [31908.556390] intel_audio_deinit+0x28/0x80 [i915] [31908.556622] i915_driver_unload+0xe4/0x360 [i915] [31908.556858] i915_pci_remove+0x23/0x30 [i915] [31908.556948] pci_device_remove+0x5c/0x100 [31908.557037] device_release_driver_internal+0x1db/0x2e0 [31908.557129] driver_detach+0x68/0xc0 [31908.557217] bus_remove_driver+0x8b/0x150 [31908.557304] driver_unregister+0x3e/0x60 [31908.557394] pci_unregister_driver+0x1d/0x110 [31908.557653] i915_exit+0x1a/0x87 [i915] [31908.557741] SyS_delete_module+0x264/0x2c0 [31908.557834] entry_SYSCALL_64_fastpath+0x1c/0xb1 [31908.557919] Memory state around the buggy address: [31908.558005] ffff8801f7788200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [31908.558127] ffff8801f7788280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [31908.558255] >ffff8801f7788300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [31908.558374] ^ [31908.558467] ffff8801f7788380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [31908.558595] ffff8801f7788400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb v2: Just leak the memory (8 bytes) as freeing it ourselves is not safe, and we need to coordinate a proper fix in platform_device itself. Fixes: eef57324d926 ("drm/i915: setup bridge for HDMI LPE audio driver") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99952 Signed-off-by: Chris Wilson Cc: Pierre-Louis Bossart Cc: Jerome Anand Cc: Jani Nikula Cc: Takashi Iwai Link: http://patchwork.freedesktop.org/patch/msgid/20170412080251.30648-1-chris@chris-wilson.co.uk Reviewed-by: Takashi Iwai Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_lpe_audio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index d8ca187ae001..25d8e76489e4 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -131,8 +131,15 @@ err: static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv) { + /* XXX Note that platform_device_register_full() allocates a dma_mask + * and never frees it. We can't free it here as we cannot guarantee + * this is the last reference (i.e. that the dma_mask will not be + * used after our unregister). So ee choose to leak the sizeof(u64) + * allocation here - it should be fixed in the platform_device rather + * than us fiddle with its internals. + */ + platform_device_unregister(dev_priv->lpe_audio.platdev); - kfree(dev_priv->lpe_audio.platdev->dev.dma_mask); } static void lpe_audio_irq_unmask(struct irq_data *d) From a0752d4a027ce6f7e64099d2e2aa93edd2ffd9e2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 12 Apr 2017 17:27:22 +0100 Subject: [PATCH 0077/1270] drm: fix spelling mistake: "committing" Trivial fix to spelling mistake in DRM_DEBUG_ATOMIC debug message Signed-off-by: Colin Ian King Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170412162722.25087-1-colin.king@canonical.com --- drivers/gpu/drm/drm_atomic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f32506a7c1d6..30229ab719c0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1618,7 +1618,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_ATOMIC("commiting %p\n", state); + DRM_DEBUG_ATOMIC("committing %p\n", state); return config->funcs->atomic_commit(state->dev, state, false); } @@ -1647,7 +1647,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_ATOMIC("commiting %p nonblocking\n", state); + DRM_DEBUG_ATOMIC("committing %p nonblocking\n", state); return config->funcs->atomic_commit(state->dev, state, true); } From 3a753b9efebf870e8253c24d60d8fd49253f7de8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Apr 2017 09:40:07 +0200 Subject: [PATCH 0078/1270] drm/doc: Fix missing @ctx documentation Forgot to add this :( Fixes: 1931529448bc ("drm: Add acquire ctx parameter to ->plane_disable") Cc: Harry Wentland Reviewed-by: Neil Armstrong Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170413074007.7620-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index b84a295230fc..9854a503e201 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -381,6 +381,7 @@ EXPORT_SYMBOL(drm_primary_helper_update); /** * drm_primary_helper_disable() - Helper for primary plane disable * @plane: plane to disable + * @ctx: lock acquire context, not used here * * Provides a default plane disable handler for primary planes. This is handler * is called in response to a userspace SetPlane operation on the plane with a From ce9971ded5692fad3ecb4098376dcbc589ceae4c Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Tue, 11 Apr 2017 10:22:19 +0800 Subject: [PATCH 0079/1270] drm/bridge: sii902x: Add missing \n to the end of some dev_err messages Trivial fix. Some dev_err messages in this driver are missing \n, so add them. Signed-off-by: Liu Ying Signed-off-by: Andrzej Hajda Link: http://patchwork.freedesktop.org/patch/msgid/1491877339-19913-1-git-send-email-gnuiyl@gmail.com --- drivers/gpu/drm/bridge/sii902x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 9126d0306ab5..9b87067c022c 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -160,7 +160,7 @@ static int sii902x_get_modes(struct drm_connector *connector) time_before(jiffies, timeout)); if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus"); + dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n"); return -ETIMEDOUT; } @@ -202,7 +202,7 @@ static int sii902x_get_modes(struct drm_connector *connector) if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(&sii902x->i2c->dev, "failed to release the i2c bus"); + dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n"); return -ETIMEDOUT; } @@ -298,7 +298,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { dev_err(&sii902x->i2c->dev, - "sii902x driver is only compatible with DRM devices supporting atomic updates"); + "sii902x driver is only compatible with DRM devices supporting atomic updates\n"); return -ENOTSUPP; } From 13f6c719eb88f2a0c8981d7a0c45404194aa2ef5 Mon Sep 17 00:00:00 2001 From: "daniele.ceraolospurio@intel.com" Date: Thu, 6 Apr 2017 17:18:52 -0700 Subject: [PATCH 0080/1270] drm/i915/guc: write wopcm related register once during uc init The wopcm registers are write-once, so any write after the first one will just be ignored. The registers survive a GPU reset but not always a suspend/resume cycle, so to keep things simple keep the writes in the intel_uc_init_hw function instead of moving it earlier to make sure we attempt them every time we try to load GuC. Cc: Jeff McGee Cc: Anusha Srivatsa Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/1491524332-23860-1-git-send-email-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/intel_guc_loader.c | 4 ---- drivers/gpu/drm/i915/intel_huc.c | 5 ----- drivers/gpu/drm/i915/intel_uc.c | 5 +++++ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 12f80ece1d05..d9045b6e897b 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -285,10 +285,6 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv) intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); - /* init WOPCM */ - I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv)); - I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE); - /* Enable MIA caching. GuC clock gating is disabled. */ I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 7a0bf1593463..88b4cf3f764a 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -106,11 +106,6 @@ static int huc_ucode_xfer(struct drm_i915_private *dev_priv) intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); - /* init WOPCM */ - I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv)); - I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE | - HUC_LOADING_AGENT_GUC); - /* Set the source address for the uCode */ offset = guc_ggtt_offset(vma) + huc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 4364b1a9064e..900e3767a899 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -274,6 +274,11 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) goto err_guc; } + /* init WOPCM */ + I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv)); + I915_WRITE(DMA_GUC_WOPCM_OFFSET, + GUC_WOPCM_OFFSET_VALUE | HUC_LOADING_AGENT_GUC); + /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ if (IS_GEN9(dev_priv)) From 1a36147bb93921651f7fbd7a6e522da6c349081b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 12 Apr 2017 22:30:17 +0300 Subject: [PATCH 0081/1270] drm/i915: Perform link quality check unconditionally during long pulse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently some DP sinks are a little nuts and cause HPD to drop intermittently during modesets. This happens eg. on an ASUS PB287Q. In oder to recover from this we can't really use the previous connector status to determine if the link needs retraining, so let's just ignore that piece of information and do the retrain unconditionally. We do of course still check whether the link is supposed to be running or not. To actually get read out the EDID and update things properly we also need to nuke the goto out added by commit 7d23e3c37bb3 ("drm/i915: Cleaning up intel_dp_hpd_pulse"). I'm actually not sure why that was there. Perhaps to avoid an EDID read if the connector status didn't appear to change, but that sort of thing is quite racy and would have failed anyway if we failed to keep up with the hotplugs (if we missed the HPD down in between two HPD ups). And now that we take this codepath unconditionally we definitely need to drop the goto as otherwise we would never do the EDID read. v2: Drop the goto that made us skip EDID reads entirely. Doh! v3: Rebase due to locking changes s/apparely/apparently/ in the comment (Chris) Cc: stable@vger.kernel.org Cc: Manasi Navare Cc: Palmer Dabbelt Reported-by: Palmer Dabbelt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99766 References: https://lists.freedesktop.org/archives/intel-gfx/2017-February/119779.html Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170412193017.21029-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_dp.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 16b7bf7af537..09601a22d3cc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4685,9 +4685,20 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) */ status = connector_status_disconnected; goto out; - } else if (connector->status == connector_status_connected) { + } else { + /* + * If display is now connected check links status, + * there has been known issues of link loss triggerring + * long pulse. + * + * Some sinks (eg. ASUS PB287Q) seem to perform some + * weird HPD ping pong during modesets. So we can apparently + * end up with HPD going low during a modeset, and then + * going back up soon after. And once that happens we must + * retrain the link to get a picture. That's in case no + * userspace component reacted to intermittent HPD dip. + */ intel_dp_check_link_status(intel_dp); - goto out; } /* From cdec4d3613230fc15723fae206cb17825b914cee Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 12 Apr 2017 12:12:02 -0700 Subject: [PATCH 0082/1270] drm/vc4: Expose dma-buf fences for V3D rendering. This is needed for proper synchronization with display on another DRM device (pl111 or tinydrm) with buffers produced by vc4 V3D. Fixes the new igt vc4_dmabuf_poll testcase, and rendering of one of the glmark2 desktop tests on pl111+vc4. This doesn't yet introduce waits on another device's fences before vc4's rendering/display, because I don't have testcases for them. v2: Reuse dma_fence_free(), retitle commit message to clarify that it's not a full dma-buf fencing implementation yet. Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/20170412191202.22740-6-eric@anholt.net Acked-by: Daniel Vetter --- drivers/gpu/drm/vc4/Makefile | 1 + drivers/gpu/drm/vc4/vc4_bo.c | 37 ++++++++- drivers/gpu/drm/vc4/vc4_drv.c | 3 +- drivers/gpu/drm/vc4/vc4_drv.h | 30 +++++++ drivers/gpu/drm/vc4/vc4_fence.c | 56 +++++++++++++ drivers/gpu/drm/vc4/vc4_gem.c | 136 +++++++++++++++++++++++++++++++- drivers/gpu/drm/vc4/vc4_irq.c | 4 + 7 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/vc4/vc4_fence.c diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index 61f45d122bd0..ab687fba4916 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile @@ -9,6 +9,7 @@ vc4-y := \ vc4_drv.o \ vc4_dpi.o \ vc4_dsi.o \ + vc4_fence.o \ vc4_kms.o \ vc4_gem.o \ vc4_hdmi.o \ diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index af29432a6471..80b2f9e55c5c 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -19,6 +19,8 @@ * rendering can return quickly. */ +#include + #include "vc4_drv.h" #include "uapi/drm/vc4_drm.h" @@ -88,6 +90,10 @@ static void vc4_bo_destroy(struct vc4_bo *bo) vc4->bo_stats.num_allocated--; vc4->bo_stats.size_allocated -= obj->size; + + if (bo->resv == &bo->_resv) + reservation_object_fini(bo->resv); + drm_gem_cma_free_object(obj); } @@ -244,8 +250,12 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, return ERR_PTR(-ENOMEM); } } + bo = to_vc4_bo(&cma_obj->base); - return to_vc4_bo(&cma_obj->base); + bo->resv = &bo->_resv; + reservation_object_init(bo->resv); + + return bo; } int vc4_dumb_create(struct drm_file *file_priv, @@ -369,6 +379,13 @@ static void vc4_bo_cache_time_timer(unsigned long data) schedule_work(&vc4->bo_cache.time_work); } +struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj) +{ + struct vc4_bo *bo = to_vc4_bo(obj); + + return bo->resv; +} + struct dma_buf * vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { @@ -440,6 +457,24 @@ void *vc4_prime_vmap(struct drm_gem_object *obj) return drm_gem_cma_prime_vmap(obj); } +struct drm_gem_object * +vc4_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct drm_gem_object *obj; + struct vc4_bo *bo; + + obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + if (IS_ERR(obj)) + return obj; + + bo = to_vc4_bo(obj); + bo->resv = attach->dmabuf->resv; + + return obj; +} + int vc4_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 61e674baf3a6..92fb9a41fe7c 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -168,8 +168,9 @@ static struct drm_driver vc4_drm_driver = { .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = drm_gem_prime_import, .gem_prime_export = vc4_prime_export, + .gem_prime_res_obj = vc4_prime_res_obj, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, - .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_import_sg_table = vc4_prime_import_sg_table, .gem_prime_vmap = vc4_prime_vmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = vc4_prime_mmap, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index dffce6293d87..81d2bc08e766 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -8,7 +8,9 @@ #include "drmP.h" #include "drm_gem_cma_helper.h" +#include "drm_gem_cma_helper.h" +#include #include struct vc4_dev { @@ -56,6 +58,8 @@ struct vc4_dev { /* Protects bo_cache and the BO stats. */ struct mutex bo_lock; + uint64_t dma_fence_context; + /* Sequence number for the last job queued in bin_job_list. * Starts at 0 (no jobs emitted). */ @@ -150,6 +154,10 @@ struct vc4_bo { * DRM_IOCTL_VC4_CREATE_SHADER_BO. */ struct vc4_validated_shader_info *validated_shader; + + /* normally (resv == &_resv) except for imported bo's */ + struct reservation_object *resv; + struct reservation_object _resv; }; static inline struct vc4_bo * @@ -158,6 +166,19 @@ to_vc4_bo(struct drm_gem_object *bo) return (struct vc4_bo *)bo; } +struct vc4_fence { + struct dma_fence base; + struct drm_device *dev; + /* vc4 seqno for signaled() test */ + uint64_t seqno; +}; + +static inline struct vc4_fence * +to_vc4_fence(struct dma_fence *fence) +{ + return (struct vc4_fence *)fence; +} + struct vc4_seqno_cb { struct work_struct work; uint64_t seqno; @@ -230,6 +251,8 @@ struct vc4_exec_info { /* Latest write_seqno of any BO that binning depends on. */ uint64_t bin_dep_seqno; + struct dma_fence *fence; + /* Last current addresses the hardware was processing when the * hangcheck timer checked on us. */ @@ -436,7 +459,11 @@ int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_mmap(struct file *filp, struct vm_area_struct *vma); +struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj); int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); +struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt); void *vc4_prime_vmap(struct drm_gem_object *obj); void vc4_bo_cache_init(struct drm_device *dev); void vc4_bo_cache_destroy(struct drm_device *dev); @@ -468,6 +495,9 @@ int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); extern struct platform_driver vc4_dsi_driver; int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused); +/* vc4_fence.c */ +extern const struct dma_fence_ops vc4_fence_ops; + /* vc4_gem.c */ void vc4_gem_init(struct drm_device *dev); void vc4_gem_destroy(struct drm_device *dev); diff --git a/drivers/gpu/drm/vc4/vc4_fence.c b/drivers/gpu/drm/vc4/vc4_fence.c new file mode 100644 index 000000000000..dbf5a5a5d5f5 --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_fence.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2017 Broadcom + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vc4_drv.h" + +static const char *vc4_fence_get_driver_name(struct dma_fence *fence) +{ + return "vc4"; +} + +static const char *vc4_fence_get_timeline_name(struct dma_fence *fence) +{ + return "vc4-v3d"; +} + +static bool vc4_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static bool vc4_fence_signaled(struct dma_fence *fence) +{ + struct vc4_fence *f = to_vc4_fence(fence); + struct vc4_dev *vc4 = to_vc4_dev(f->dev); + + return vc4->finished_seqno >= f->seqno; +} + +const struct dma_fence_ops vc4_fence_ops = { + .get_driver_name = vc4_fence_get_driver_name, + .get_timeline_name = vc4_fence_get_timeline_name, + .enable_signaling = vc4_fence_enable_signaling, + .signaled = vc4_fence_signaled, + .wait = dma_fence_default_wait, + .release = dma_fence_free, +}; diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index e9c381c42139..a1a01044263c 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -463,6 +463,8 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) for (i = 0; i < exec->bo_count; i++) { bo = to_vc4_bo(&exec->bo[i]->base); bo->seqno = seqno; + + reservation_object_add_shared_fence(bo->resv, exec->fence); } list_for_each_entry(bo, &exec->unref_list, unref_head) { @@ -472,9 +474,105 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) for (i = 0; i < exec->rcl_write_bo_count; i++) { bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); bo->write_seqno = seqno; + + reservation_object_add_excl_fence(bo->resv, exec->fence); } } +static void +vc4_unlock_bo_reservations(struct drm_device *dev, + struct vc4_exec_info *exec, + struct ww_acquire_ctx *acquire_ctx) +{ + int i; + + for (i = 0; i < exec->bo_count; i++) { + struct vc4_bo *bo = to_vc4_bo(&exec->bo[i]->base); + + ww_mutex_unlock(&bo->resv->lock); + } + + ww_acquire_fini(acquire_ctx); +} + +/* Takes the reservation lock on all the BOs being referenced, so that + * at queue submit time we can update the reservations. + * + * We don't lock the RCL the tile alloc/state BOs, or overflow memory + * (all of which are on exec->unref_list). They're entirely private + * to vc4, so we don't attach dma-buf fences to them. + */ +static int +vc4_lock_bo_reservations(struct drm_device *dev, + struct vc4_exec_info *exec, + struct ww_acquire_ctx *acquire_ctx) +{ + int contended_lock = -1; + int i, ret; + struct vc4_bo *bo; + + ww_acquire_init(acquire_ctx, &reservation_ww_class); + +retry: + if (contended_lock != -1) { + bo = to_vc4_bo(&exec->bo[contended_lock]->base); + ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, + acquire_ctx); + if (ret) { + ww_acquire_done(acquire_ctx); + return ret; + } + } + + for (i = 0; i < exec->bo_count; i++) { + if (i == contended_lock) + continue; + + bo = to_vc4_bo(&exec->bo[i]->base); + + ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx); + if (ret) { + int j; + + for (j = 0; j < i; j++) { + bo = to_vc4_bo(&exec->bo[j]->base); + ww_mutex_unlock(&bo->resv->lock); + } + + if (contended_lock != -1 && contended_lock >= i) { + bo = to_vc4_bo(&exec->bo[contended_lock]->base); + + ww_mutex_unlock(&bo->resv->lock); + } + + if (ret == -EDEADLK) { + contended_lock = i; + goto retry; + } + + ww_acquire_done(acquire_ctx); + return ret; + } + } + + ww_acquire_done(acquire_ctx); + + /* Reserve space for our shared (read-only) fence references, + * before we commit the CL to the hardware. + */ + for (i = 0; i < exec->bo_count; i++) { + bo = to_vc4_bo(&exec->bo[i]->base); + + ret = reservation_object_reserve_shared(bo->resv); + if (ret) { + vc4_unlock_bo_reservations(dev, exec, acquire_ctx); + return ret; + } + } + + return 0; +} + /* Queues a struct vc4_exec_info for execution. If no job is * currently executing, then submits it. * @@ -484,19 +582,34 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) * then bump the end address. That's a change for a later date, * though. */ -static void -vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) +static int +vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, + struct ww_acquire_ctx *acquire_ctx) { struct vc4_dev *vc4 = to_vc4_dev(dev); uint64_t seqno; unsigned long irqflags; + struct vc4_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return -ENOMEM; + fence->dev = dev; spin_lock_irqsave(&vc4->job_lock, irqflags); seqno = ++vc4->emit_seqno; exec->seqno = seqno; + + dma_fence_init(&fence->base, &vc4_fence_ops, &vc4->job_lock, + vc4->dma_fence_context, exec->seqno); + fence->seqno = exec->seqno; + exec->fence = &fence->base; + vc4_update_bo_seqnos(exec, seqno); + vc4_unlock_bo_reservations(dev, exec, acquire_ctx); + list_add_tail(&exec->head, &vc4->bin_job_list); /* If no job was executing, kick ours off. Otherwise, it'll @@ -509,6 +622,8 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec) } spin_unlock_irqrestore(&vc4->job_lock, irqflags); + + return 0; } /** @@ -707,6 +822,12 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) struct vc4_dev *vc4 = to_vc4_dev(dev); unsigned i; + /* If we got force-completed because of GPU reset rather than + * through our IRQ handler, signal the fence now. + */ + if (exec->fence) + dma_fence_signal(exec->fence); + if (exec->bo) { for (i = 0; i < exec->bo_count; i++) drm_gem_object_unreference_unlocked(&exec->bo[i]->base); @@ -874,6 +995,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_vc4_submit_cl *args = data; struct vc4_exec_info *exec; + struct ww_acquire_ctx acquire_ctx; int ret = 0; if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) { @@ -916,12 +1038,18 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, if (ret) goto fail; + ret = vc4_lock_bo_reservations(dev, exec, &acquire_ctx); + if (ret) + goto fail; + /* Clear this out of the struct we'll be putting in the queue, * since it's part of our stack. */ exec->args = NULL; - vc4_queue_submit(dev, exec); + ret = vc4_queue_submit(dev, exec, &acquire_ctx); + if (ret) + goto fail; /* Return the seqno for our job. */ args->seqno = vc4->emit_seqno; @@ -939,6 +1067,8 @@ vc4_gem_init(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); + vc4->dma_fence_context = dma_fence_context_alloc(1); + INIT_LIST_HEAD(&vc4->bin_job_list); INIT_LIST_HEAD(&vc4->render_job_list); INIT_LIST_HEAD(&vc4->job_done_list); diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index cdc6e6760705..1384af9fc987 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -142,6 +142,10 @@ vc4_irq_finish_render_job(struct drm_device *dev) vc4->finished_seqno++; list_move_tail(&exec->head, &vc4->job_done_list); + if (exec->fence) { + dma_fence_signal_locked(exec->fence); + exec->fence = NULL; + } vc4_submit_next_render_job(dev); wake_up_all(&vc4->job_wait_queue); From 9301397a63b3bf1090dffe846c6f1c8efa032236 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Thu, 6 Apr 2017 16:44:19 +0300 Subject: [PATCH 0083/1270] drm/i915: Implement Link Rate fallback on Link training failure If link training at a link rate optimal for a particular mode fails during modeset's atomic commit phase, then we let the modeset complete and then retry. We save the link rate value at which link training failed, update the link status property to "BAD" and use a lower link rate to prune the modes. It will redo the modeset on the current mode at lower link rate or if the current mode gets pruned due to lower link constraints then, it will send a hotplug uevent for userspace to handle it. This is also required to pass DP CTS tests 4.3.1.3, 4.3.1.4, 4.3.1.6. This patch is a resend of the original commit id (233ce881dd91fb "drm/i915: Implement Link Rate fallback on Link training failure") which got reverted in this commit id (afc1ebf4562a14 Revert "drm/i915: Implement Link Rate fallback on Link training failure") due to CI failures. After investigating the CI failures it was found that these were essentially the failures which were always there but hidden because they used to be DRM_DEBUG_KMS messages for link failures so never got caught by CI. But now this patch actually throws DRM_ERROR if the link training fails at RBR and 1 lane. So it caught these link train failures. There were two failures: 1. On SKL 6700k this was because the machine in CI lab is a SKL desktop without eDP on Port A. But our VBT initialization code in the driver writes VBT defaults in a way that it always sets DP flag on Port A and this does not get cleared after parsing the VBT outputs. This has been fixed in commit id (bb1d132935c2f8 "drm/i915/vbt: split out defaults that are set when there is no VBT) and (665788572c6410b "drm/i915/vbt: don't propagate errors from intel_bios_init()) 2. On ILK-650 desktop - This was happening because of a bad monitor desktop combination. I switched the monitor in the CI lab and that helped get rid of the link failures on ILK system. v10: * Rebase on drm-tip and resend after revert v9: * Use the trimmed max values of link rate/lane count based on link train fallback (Daniel Vetter) v8: * Set link_status to BAD first and then call mode_valid (Jani Nikula) v7: Remove the redundant variable in previous patch itself v6: * Obtain link rate index from fallback_link_rate using the helper intel_dp_link_rate_index (Jani Nikula) * Include fallback within intel_dp_start_link_train (Jani Nikula) v5: * Move set link status to drm core (Daniel Vetter, Jani Nikula) v4: * Add fallback support for non DDI platforms too * Set connector->link status inside set_link_status function (Jani Nikula) v3: * Set link status property to BAd unconditionally (Jani Nikula) * Dont use two separate variables link_train_failed and link_status to indicate same thing (Jani Nikula) v2: * Squashed a few patches (Jani Nikula) Acked-by: Tony Cheng Acked-by: Harry Wentland Cc: Jani Nikula Cc: Daniel Vetter Cc: Ville Syrjala Signed-off-by: Manasi Navare Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/16ca48b1e74c618929245e9a085b9e3483c3a16d.1491485983.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 27 +++++++++++++++++++ drivers/gpu/drm/i915/intel_dp_link_training.c | 22 +++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 3 +++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 09601a22d3cc..08834f74d396 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5981,6 +5981,29 @@ intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port) } } +static void intel_dp_modeset_retry_work_fn(struct work_struct *work) +{ + struct intel_connector *intel_connector; + struct drm_connector *connector; + + intel_connector = container_of(work, typeof(*intel_connector), + modeset_retry_work); + connector = &intel_connector->base; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, + connector->name); + + /* Grab the locks before changing connector property*/ + mutex_lock(&connector->dev->mode_config.mutex); + /* Set connector link status to BAD and send a Uevent to notify + * userspace to do a modeset. + */ + drm_mode_connector_set_link_status_property(connector, + DRM_MODE_LINK_STATUS_BAD); + mutex_unlock(&connector->dev->mode_config.mutex); + /* Send Hotplug uevent so userspace can reprobe */ + drm_kms_helper_hotplug_event(connector->dev); +} + bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector) @@ -5993,6 +6016,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, enum port port = intel_dig_port->port; int type; + /* Initialize the work for modeset in case of link train failure */ + INIT_WORK(&intel_connector->modeset_retry_work, + intel_dp_modeset_retry_work_fn); + if (WARN(intel_dig_port->max_lanes < 1, "Not enough lanes (%d) for DP on port %c\n", intel_dig_port->max_lanes, port_name(port))) diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 694ad0ffb523..b79c1c0e404c 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -314,6 +314,24 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp) void intel_dp_start_link_train(struct intel_dp *intel_dp) { - intel_dp_link_training_clock_recovery(intel_dp); - intel_dp_link_training_channel_equalization(intel_dp); + struct intel_connector *intel_connector = intel_dp->attached_connector; + + if (!intel_dp_link_training_clock_recovery(intel_dp)) + goto failure_handling; + if (!intel_dp_link_training_channel_equalization(intel_dp)) + goto failure_handling; + + DRM_DEBUG_KMS("Link Training Passed at Link Rate = %d, Lane count = %d", + intel_dp->link_rate, intel_dp->lane_count); + return; + + failure_handling: + DRM_DEBUG_KMS("Link Training failed at link rate = %d, lane count = %d", + intel_dp->link_rate, intel_dp->lane_count); + if (!intel_dp_get_link_train_fallback_values(intel_dp, + intel_dp->link_rate, + intel_dp->lane_count)) + /* Schedule a Hotplug Uevent to userspace to start modeset */ + schedule_work(&intel_connector->modeset_retry_work); + return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f78d7c5f3805..100750c878e1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -321,6 +321,9 @@ struct intel_connector { void *port; /* store this opaque as its illegal to dereference it */ struct intel_dp *mst_port; + + /* Work struct to schedule a uevent on link train failure */ + struct work_struct modeset_retry_work; }; struct dpll { From be02f7556447a0dee672acb5e462f03377b98ae8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Apr 2017 22:52:17 +0300 Subject: [PATCH 0084/1270] drm/i915: checking for NULL instead of IS_ERR() in mock selftests i915_gem_request_alloc() uses error pointers. It never returns NULLs. Fixes: 0daf0113cff6 ("drm/i915: Mock infrastructure for request emission") Signed-off-by: Dan Carpenter Link: http://patchwork.freedesktop.org/patch/msgid/20170413195217.GA26108@mwanda Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/selftests/mock_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_request.c b/drivers/gpu/drm/i915/selftests/mock_request.c index 0e8d2e7f8c70..8097e3693ec4 100644 --- a/drivers/gpu/drm/i915/selftests/mock_request.c +++ b/drivers/gpu/drm/i915/selftests/mock_request.c @@ -35,7 +35,7 @@ mock_request(struct intel_engine_cs *engine, /* NB the i915->requests slab cache is enlarged to fit mock_request */ request = i915_gem_request_alloc(engine, context); - if (!request) + if (IS_ERR(request)) return NULL; mock = container_of(request, typeof(*mock), base); From 97bf3a9aa60f0d25541738feeb28e39decc41b76 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Fri, 14 Apr 2017 12:13:31 +0200 Subject: [PATCH 0085/1270] drm/cma: Update DEFINE_DRM_GEM_CMA_FOPS to add get_unmapped_area Missing field get_unmapped_area which is necessary with device without MMU Signed-off-by: Yannick Fertre Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/1492164819-10513-2-git-send-email-yannick.fertre@st.com Reviewed-by: Neil Armstrong Reviewed-by: Eric Anholt --- include/drm/drm_gem_cma_helper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index f962d33667cf..7320b140545a 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -50,6 +50,7 @@ to_drm_gem_cma_obj(struct drm_gem_object *gem_obj) .read = drm_read,\ .llseek = noop_llseek,\ .mmap = drm_gem_cma_mmap,\ + .get_unmapped_area = drm_gem_cma_get_unmapped_area,\ } /* free GEM object */ From 4636ce93d5b25632c2cdbeccebef912e1c990c8e Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Fri, 14 Apr 2017 12:13:32 +0200 Subject: [PATCH 0086/1270] drm/fb-cma-helper: Add drm_fb_cma_get_gem_addr() Add function drm_fb_cma_get_gem_addr() which return the physical address of framebuffer (1st pixel). This function will usually be called by plane callback (atomic_update). Signed-off-by: Yannick Fertre Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/1492164819-10513-3-git-send-email-yannick.fertre@st.com Reviewed-by: Neil Armstrong Reviewed-by: Eric Anholt --- drivers/gpu/drm/drm_fb_cma_helper.c | 27 +++++++++++++++++++++++++++ include/drm/drm_fb_cma_helper.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 50abd1faf38f..d2b77b02830d 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -259,6 +259,33 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); +/** + * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer + * @fb: The framebuffer + * @state: Which state of drm plane + * @plane: Which plane + * Return the CMA GEM address for given framebuffer. + * + * This function will usually be called from the PLANE callback functions. + */ +dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, + struct drm_plane_state *state, + unsigned int plane) +{ + struct drm_fb_cma *fb_cma = to_fb_cma(fb); + dma_addr_t paddr; + + if (plane >= 4) + return 0; + + paddr = fb_cma->obj[plane]->paddr + fb->offsets[plane]; + paddr += fb->format->cpp[plane] * (state->src_x >> 16); + paddr += fb->pitches[plane] * (state->src_y >> 16); + + return paddr; +} +EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); + /** * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer * @plane: Which plane diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index a5ecc0a58260..199a63f48659 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -41,6 +41,10 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); +dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, + struct drm_plane_state *state, + unsigned int plane); + int drm_fb_cma_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); From 7121926d4ca5869b730da760c1fdf3dc1d723224 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Fri, 14 Apr 2017 12:13:33 +0200 Subject: [PATCH 0087/1270] dt-bindings: display: Add STM32 LTDC driver This patch adds documentation of device tree bindings for the STM32 LTDC (Lcd-Tft Display Controller). Acked-by: Rob Herring Signed-off-by: Yannick Fertre Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/1492164819-10513-4-git-send-email-yannick.fertre@st.com --- .../bindings/display/st,stm32-ltdc.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/st,stm32-ltdc.txt diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt new file mode 100644 index 000000000000..8e1476941c0f --- /dev/null +++ b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt @@ -0,0 +1,36 @@ +* STMicroelectronics STM32 lcd-tft display controller + +- ltdc: lcd-tft display controller host + must be a sub-node of st-display-subsystem + Required properties: + - compatible: "st,stm32-ltdc" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: A list of phandle + clock-specifier pairs, one for each + entry in 'clock-names'. + - clock-names: A list of clock names. For ltdc it should contain: + - "lcd" for the clock feeding the output pixel clock & IP clock. + - resets: reset to be used by the device (defined by use of RCC macro). + Required nodes: + - Video port for RGB output. + +Example: + +/ { + ... + soc { + ... + ltdc: display-controller@40016800 { + compatible = "st,stm32-ltdc"; + reg = <0x40016800 0x200>; + interrupts = <88>, <89>; + resets = <&rcc STM32F4_APB2_RESET(LTDC)>; + clocks = <&rcc 1 CLK_LCD>; + clock-names = "lcd"; + + port { + ltdc_out_rgb: endpoint { + }; + }; + }; + }; +}; From b759012c5fa761ee08998c80fc4ad6343c258487 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Fri, 14 Apr 2017 12:13:34 +0200 Subject: [PATCH 0088/1270] drm/stm: Add STM32 LTDC driver This controller provides output signals to interface directly a variety of LCD and TFT panels. These output signals are: RGB signals (up to 24bpp), vertical & horizontal synchronisations, data enable and the pixel clock. Reviewed-by: Eric Anholt Signed-off-by: Yannick Fertre Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/1492164819-10513-5-git-send-email-yannick.fertre@st.com Reviewed-by: Neil Armstrong Reviewed-by: Eric Anholt --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/stm/Kconfig | 16 + drivers/gpu/drm/stm/Makefile | 7 + drivers/gpu/drm/stm/drv.c | 221 +++++++ drivers/gpu/drm/stm/ltdc.c | 1160 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/stm/ltdc.h | 40 ++ 7 files changed, 1447 insertions(+) create mode 100644 drivers/gpu/drm/stm/Kconfig create mode 100644 drivers/gpu/drm/stm/Makefile create mode 100644 drivers/gpu/drm/stm/drv.c create mode 100644 drivers/gpu/drm/stm/ltdc.c create mode 100644 drivers/gpu/drm/stm/ltdc.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 78d7fc0ebb57..f57540d2a783 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -246,6 +246,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" +source "drivers/gpu/drm/stm/Kconfig" + source "drivers/gpu/drm/panel/Kconfig" source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 59f0f9b696eb..aa62ded7144e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ +obj-$(CONFIG_DRM_STM) += stm/ obj-$(CONFIG_DRM_STI) += sti/ obj-$(CONFIG_DRM_IMX) += imx/ obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig new file mode 100644 index 000000000000..2c4817fb0890 --- /dev/null +++ b/drivers/gpu/drm/stm/Kconfig @@ -0,0 +1,16 @@ +config DRM_STM + tristate "DRM Support for STMicroelectronics SoC Series" + depends on DRM && (ARCH_STM32 || ARCH_MULTIPLATFORM) + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL + select VIDEOMODE_HELPERS + select FB_PROVIDE_GET_FB_UNMAPPED_AREA + default y + + help + Enable support for the on-chip display controller on + STMicroelectronics STM32 MCUs. + To compile this driver as a module, choose M here: the module + will be called stm-drm. diff --git a/drivers/gpu/drm/stm/Makefile b/drivers/gpu/drm/stm/Makefile new file mode 100644 index 000000000000..e114d45dbd42 --- /dev/null +++ b/drivers/gpu/drm/stm/Makefile @@ -0,0 +1,7 @@ +ccflags-y := -Iinclude/drm + +stm-drm-y := \ + drv.o \ + ltdc.o + +obj-$(CONFIG_DRM_STM) += stm-drm.o diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c new file mode 100644 index 000000000000..83ab48f1fd00 --- /dev/null +++ b/drivers/gpu/drm/stm/drv.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu + * Yannick Fertre + * Fabien Dessenne + * Mickael Reulier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "ltdc.h" + +#define DRIVER_NAME "stm" +#define DRIVER_DESC "STMicroelectronics SoC DRM" +#define DRIVER_DATE "20170330" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCH_LEVEL 0 + +#define STM_MAX_FB_WIDTH 2048 +#define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */ + +static void drv_output_poll_changed(struct drm_device *ddev) +{ + struct ltdc_device *ldev = ddev->dev_private; + + drm_fbdev_cma_hotplug_event(ldev->fbdev); +} + +static const struct drm_mode_config_funcs drv_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .output_poll_changed = drv_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void drv_lastclose(struct drm_device *ddev) +{ + struct ltdc_device *ldev = ddev->dev_private; + + DRM_DEBUG("%s\n", __func__); + + drm_fbdev_cma_restore_mode(ldev->fbdev); +} + +DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); + +static struct drm_driver drv_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | + DRIVER_ATOMIC, + .lastclose = drv_lastclose, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCH_LEVEL, + .fops = &drv_driver_fops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .enable_vblank = ltdc_crtc_enable_vblank, + .disable_vblank = ltdc_crtc_disable_vblank, +}; + +static int drv_load(struct drm_device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev->dev); + struct drm_fbdev_cma *fbdev; + struct ltdc_device *ldev; + int ret; + + DRM_DEBUG("%s\n", __func__); + + ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); + if (!ldev) + return -ENOMEM; + + ddev->dev_private = (void *)ldev; + + drm_mode_config_init(ddev); + + /* + * set max width and height as default value. + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + ddev->mode_config.min_width = 0; + ddev->mode_config.min_height = 0; + ddev->mode_config.max_width = STM_MAX_FB_WIDTH; + ddev->mode_config.max_height = STM_MAX_FB_HEIGHT; + ddev->mode_config.funcs = &drv_mode_config_funcs; + + ret = ltdc_load(ddev); + if (ret) + goto err; + + drm_mode_config_reset(ddev); + drm_kms_helper_poll_init(ddev); + + if (ddev->mode_config.num_connector) { + ldev = ddev->dev_private; + fbdev = drm_fbdev_cma_init(ddev, 16, + ddev->mode_config.num_connector); + if (IS_ERR(fbdev)) { + DRM_DEBUG("Warning: fails to create fbdev\n"); + fbdev = NULL; + } + ldev->fbdev = fbdev; + } + + platform_set_drvdata(pdev, ddev); + + return 0; +err: + drm_mode_config_cleanup(ddev); + return ret; +} + +static void drv_unload(struct drm_device *ddev) +{ + struct ltdc_device *ldev = ddev->dev_private; + + DRM_DEBUG("%s\n", __func__); + + if (ldev->fbdev) { + drm_fbdev_cma_fini(ldev->fbdev); + ldev->fbdev = NULL; + } + drm_kms_helper_poll_fini(ddev); + ltdc_unload(ddev); + drm_mode_config_cleanup(ddev); +} + +static int stm_drm_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct drm_device *ddev; + int ret; + + DRM_DEBUG("%s\n", __func__); + + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + + ddev = drm_dev_alloc(&drv_driver, dev); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + ret = drv_load(ddev); + if (ret) + goto err_unref; + + ret = drm_dev_register(ddev, 0); + if (ret) + goto err_unref; + + return 0; + +err_unref: + drm_dev_unref(ddev); + + return ret; +} + +static int stm_drm_platform_remove(struct platform_device *pdev) +{ + struct drm_device *ddev = platform_get_drvdata(pdev); + + DRM_DEBUG("%s\n", __func__); + + drm_dev_unregister(ddev); + drv_unload(ddev); + drm_dev_unref(ddev); + + return 0; +} + +static const struct of_device_id drv_dt_ids[] = { + { .compatible = "st,stm32-ltdc"}, + { /* end node */ }, +}; +MODULE_DEVICE_TABLE(of, drv_dt_ids); + +static struct platform_driver stm_drm_platform_driver = { + .probe = stm_drm_platform_probe, + .remove = stm_drm_platform_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = drv_dt_ids, + }, +}; + +module_platform_driver(stm_drm_platform_driver); + +MODULE_AUTHOR("Philippe Cornu "); +MODULE_AUTHOR("Yannick Fertre "); +MODULE_AUTHOR("Fabien Dessenne "); +MODULE_AUTHOR("Mickael Reulier "); +MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c new file mode 100644 index 000000000000..a40418cda74a --- /dev/null +++ b/drivers/gpu/drm/stm/ltdc.c @@ -0,0 +1,1160 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu + * Yannick Fertre + * Fabien Dessenne + * Mickael Reulier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include