From 5c19e5ee394c36652c59c247855a3c7e5a83a015 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 7 Jan 2016 10:29:10 +0200 Subject: [PATCH 01/26] drm/i915: shut up gen8+ SDE irq dmesg noise, again We still keep getting [ 4.249930] [drm:gen8_irq_handler [i915]] *ERROR* The master control interrupt lied (SDE)! This reverts commit 820da7ae46332fa709b171eb7ba57cbd023fa6df Author: Jani Nikula Date: Wed Nov 25 16:47:23 2015 +0200 Revert "drm/i915: shut up gen8+ SDE irq dmesg noise" which in itself is a revert, so this is just doing commit 97e5ed1111dcc5300a0f59a55248cd243937a8ab Author: Daniel Vetter Date: Fri Oct 23 10:56:12 2015 +0200 drm/i915: shut up gen8+ SDE irq dmesg noise all over again. I'll stop pretending I understand what's going on like I did when I thought I'd fixed this for good in commit 6a39d7c986be4fd18eb019e9cdbf774ec36c9f77 Author: Jani Nikula Date: Wed Nov 25 16:47:22 2015 +0200 drm/i915: fix the SDE irq dmesg warnings properly Reported-by: Chris Wilson Reference: http://mid.gmane.org/20151213124945.GA5715@nuc-i3427.alporthouse.com Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92084 Cc: drm-intel-fixes@lists.freedesktop.org Fixes: 820da7ae4633 ("Revert "drm/i915: shut up gen8+ SDE irq dmesg noise"") Signed-off-by: Jani Nikula [Backported to 4.3.y by Josh Boyer ] --- drivers/gpu/drm/i915/i915_irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 39d73dbc1c47..fa7f82d54762 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2168,8 +2168,13 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) I915_WRITE(SDEIIR, pch_iir); ret = IRQ_HANDLED; cpt_irq_handler(dev, pch_iir); - } else - DRM_ERROR("The master control interrupt lied (SDE)!\n"); + } else { + /* + * Like on previous PCH there seems to be something + * fishy going on with forwarding PCH interrupts. + */ + DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n"); + } } -- 2.5.0 From 65dcf0f52e9705d0094e76a9225bbe770329c96d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:34:46 +0100 Subject: [PATCH 02/26] drm/i915: Fix userptr deadlock with aliased GTT mmappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit e4b946bfe1e36680e27a5f39163980979fa61a5d Michał Winiarski found a really evil way to trigger a struct_mutex deadlock with userptr. He found that if he allocated a userptr bo and then GTT mmaped another bo, or even itself, at the same address as the userptr using MAP_FIXED, he could then cause a deadlock any time we then had to invalidate the GTT mmappings (so at will). Tvrtko then found by repeatedly allocating GTT mmappings he could alias with an old userptr mmap and also trigger the deadlock. To counter act the deadlock, we make the observation that we only need to take the struct_mutex if the object has any pages to revoke, and that before userspace can alias with the userptr address space, it must have invalidated the userptr->pages. Thus if we can check for those pages outside of the struct_mutex, we can avoid the deadlock. To do so we introduce a separate flag for userptr objects that we can inspect from the mmu-notifier underneath its spinlock. The patch makes one eye-catching change. That is the removal serial=0 after detecting a to-be-freed object inside the invalidate walker. I felt setting serial=0 was a questionable pessimisation: it denies us the chance to reuse the current iterator for the next loop (before it is freed) and being explicit makes the reader question the validity of the locking (since the object-free race could occur elsewhere). The serialisation of the iterator is through the spinlock, if the object is freed before the next loop then the notifier.serial will be incremented and we start the walk from the beginning as we detect the invalid cache. To try and tame the error paths and interactions with the userptr->active flag, we have to do a fair amount of rearranging of get_pages_userptr(). v2: Grammar fixes v3: Reorder set-active so that it is only set when obj->pages is set (and so needs cancellation). Only the order of setting obj->pages and the active-flag is crucial. Calling gup after invalidate-range begin means the userptr sees the new set of backing storage (and so will not need to invalidate its new pages), but we have to be careful not to set the active-flag prior to successfully establishing obj->pages. v4: Take the active->flag early so we know in the mmu-notifier when we have to cancel a pending gup-worker. v5: Rearrange the error path so that is not so convoluted v6: Set pinned to 0 when negative before calling release_pages() Reported-by: Michał Winiarski Testcase: igt/gem_userptr_blits/map-fixed* Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Tvrtko Ursulin Cc: stable@vger.kernel.org Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_userptr.c | 176 ++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index a96b9006a51e..ba321f0c41c5 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -59,6 +59,7 @@ struct i915_mmu_object { struct interval_tree_node it; struct list_head link; struct drm_i915_gem_object *obj; + bool active; bool is_linear; }; @@ -114,7 +115,8 @@ restart: obj = mo->obj; - if (!kref_get_unless_zero(&obj->base.refcount)) + if (!mo->active || + !kref_get_unless_zero(&obj->base.refcount)) continue; spin_unlock(&mn->lock); @@ -151,7 +153,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, else it = interval_tree_iter_first(&mn->objects, start, end); if (it != NULL) { - obj = container_of(it, struct i915_mmu_object, it)->obj; + struct i915_mmu_object *mo = + container_of(it, struct i915_mmu_object, it); /* The mmu_object is released late when destroying the * GEM object so it is entirely possible to gain a @@ -160,11 +163,9 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, * the struct_mutex - and consequently use it after it * is freed and then double free it. */ - if (!kref_get_unless_zero(&obj->base.refcount)) { - spin_unlock(&mn->lock); - serial = 0; - continue; - } + if (mo->active && + kref_get_unless_zero(&mo->obj->base.refcount)) + obj = mo->obj; serial = mn->serial; } @@ -566,6 +567,30 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj, } static void +__i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, + bool value) +{ + /* During mm_invalidate_range we need to cancel any userptr that + * overlaps the range being invalidated. Doing so requires the + * struct_mutex, and that risks recursion. In order to cause + * recursion, the user must alias the userptr address space with + * a GTT mmapping (possible with a MAP_FIXED) - then when we have + * to invalidate that mmaping, mm_invalidate_range is called with + * the userptr address *and* the struct_mutex held. To prevent that + * we set a flag under the i915_mmu_notifier spinlock to indicate + * whether this object is valid. + */ +#if defined(CONFIG_MMU_NOTIFIER) + if (obj->userptr.mmu_object == NULL) + return; + + spin_lock(&obj->userptr.mmu_object->mn->lock); + obj->userptr.mmu_object->active = value; + spin_unlock(&obj->userptr.mmu_object->mn->lock); +#endif +} + +static void __i915_gem_userptr_get_pages_worker(struct work_struct *_work) { struct get_pages_work *work = container_of(_work, typeof(*work), work); @@ -612,6 +637,9 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) pinned = 0; } + obj->userptr.work = ERR_PTR(ret); + if (ret) + __i915_gem_userptr_set_active(obj, false); } obj->userptr.work = ERR_PTR(ret); @@ -627,11 +655,60 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) } static int +__i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj, + bool *active) +{ + struct get_pages_work *work; + + /* Spawn a worker so that we can acquire the + * user pages without holding our mutex. Access + * to the user pages requires mmap_sem, and we have + * a strict lock ordering of mmap_sem, struct_mutex - + * we already hold struct_mutex here and so cannot + * call gup without encountering a lock inversion. + * + * Userspace will keep on repeating the operation + * (thanks to EAGAIN) until either we hit the fast + * path or the worker completes. If the worker is + * cancelled or superseded, the task is still run + * but the results ignored. (This leads to + * complications that we may have a stray object + * refcount that we need to be wary of when + * checking for existing objects during creation.) + * If the worker encounters an error, it reports + * that error back to this function through + * obj->userptr.work = ERR_PTR. + */ + if (obj->userptr.workers >= I915_GEM_USERPTR_MAX_WORKERS) + return -EAGAIN; + + work = kmalloc(sizeof(*work), GFP_KERNEL); + if (work == NULL) + return -ENOMEM; + + obj->userptr.work = &work->work; + obj->userptr.workers++; + + work->obj = obj; + drm_gem_object_reference(&obj->base); + + work->task = current; + get_task_struct(work->task); + + INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); + schedule_work(&work->work); + + *active = true; + return -EAGAIN; +} + +static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) { const int num_pages = obj->base.size >> PAGE_SHIFT; struct page **pvec; int pinned, ret; + bool active; /* If userspace should engineer that these pages are replaced in * the vma between us binding this page into the GTT and completion @@ -649,6 +726,18 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) * to the vma (discard or cloning) which should prevent the more * egregious cases from causing harm. */ + if (IS_ERR(obj->userptr.work)) { + /* active flag will have been dropped already by the worker */ + ret = PTR_ERR(obj->userptr.work); + obj->userptr.work = NULL; + return ret; + } + if (obj->userptr.work) + /* active flag should still be held for the pending work */ + return -EAGAIN; + + /* Let the mmu-notifier know that we have begun and need cancellation */ + __i915_gem_userptr_set_active(obj, true); pvec = NULL; pinned = 0; @@ -657,73 +746,27 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (pvec == NULL) { pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); - if (pvec == NULL) + if (pvec == NULL) { + __i915_gem_userptr_set_active(obj, false); return -ENOMEM; + } } pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages, !obj->userptr.read_only, pvec); } - if (pinned < num_pages) { - if (pinned < 0) { - ret = pinned; - pinned = 0; - } else { - /* Spawn a worker so that we can acquire the - * user pages without holding our mutex. Access - * to the user pages requires mmap_sem, and we have - * a strict lock ordering of mmap_sem, struct_mutex - - * we already hold struct_mutex here and so cannot - * call gup without encountering a lock inversion. - * - * Userspace will keep on repeating the operation - * (thanks to EAGAIN) until either we hit the fast - * path or the worker completes. If the worker is - * cancelled or superseded, the task is still run - * but the results ignored. (This leads to - * complications that we may have a stray object - * refcount that we need to be wary of when - * checking for existing objects during creation.) - * If the worker encounters an error, it reports - * that error back to this function through - * obj->userptr.work = ERR_PTR. - */ - ret = -EAGAIN; - if (obj->userptr.work == NULL && - obj->userptr.workers < I915_GEM_USERPTR_MAX_WORKERS) { - struct get_pages_work *work; - - work = kmalloc(sizeof(*work), GFP_KERNEL); - if (work != NULL) { - obj->userptr.work = &work->work; - obj->userptr.workers++; - - work->obj = obj; - drm_gem_object_reference(&obj->base); - - work->task = current; - get_task_struct(work->task); - - INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); - schedule_work(&work->work); - } else - ret = -ENOMEM; - } else { - if (IS_ERR(obj->userptr.work)) { - ret = PTR_ERR(obj->userptr.work); - obj->userptr.work = NULL; - } - } - } - } else { + + active = false; + if (pinned < 0) + ret = pinned, pinned = 0; + else if (pinned < num_pages) + ret = __i915_gem_userptr_get_pages_schedule(obj, &active); + else ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages); - if (ret == 0) { - obj->userptr.work = NULL; - pinned = 0; - } + if (ret) { + __i915_gem_userptr_set_active(obj, active); + release_pages(pvec, pinned, 0); } - - release_pages(pvec, pinned, 0); drm_free_large(pvec); return ret; } @@ -734,6 +777,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj) struct sg_page_iter sg_iter; BUG_ON(obj->userptr.work != NULL); + __i915_gem_userptr_set_active(obj, false); if (obj->madv != I915_MADV_WILLNEED) obj->dirty = 0; -- 2.5.0 From d9cc6dc69e3a5f7f68e22227baf0e0f7743e448c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 22 Oct 2015 13:56:34 +0200 Subject: [PATCH 03/26] drm/i915/skl: Prevent unclaimed register writes on skylake. Upstream commit b10f1b20171945b49988b2b1fe68cb312cc36d32 I'm getting unclaimed register writes when checking the WM registers after the crtc is disabled. So I would imagine those are guarded by the crtc power well. Fix this by not reading out wm state when the power well is off. Cc: stable@vger.kernel.org # v4.3 Signed-off-by: Maarten Lankhorst Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92181 Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ddbb7ed0a193..5e91e795fd99 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2899,7 +2899,12 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, int plane; u32 val; + memset(ddb, 0, sizeof(*ddb)); + for_each_pipe(dev_priv, pipe) { + if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe))) + continue; + for_each_plane(dev_priv, pipe, plane) { val = I915_READ(PLANE_BUF_CFG(pipe, plane)); skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane], -- 2.5.0 From 0ee1dd6b04a4e8eb34f948842fe4385c09695270 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 30 Oct 2015 14:50:24 +0200 Subject: [PATCH 04/26] drm/i915: add quirk to enable backlight on Dell Chromebook 11 (2015) Upstream commit 9be64eee3a87dc03218ca9a12834d1150a57b8a8 Reported-by: Keith Webb Suggested-by: Keith Webb Cc: stable@vger.kernel.org Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=106671 Reviewed-by: Clint Taylor Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1446209424-28801-1-git-send-email-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d2ff8e6fb4a..8f258092cada 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14678,6 +14678,9 @@ static struct intel_quirk intel_quirks[] = { /* Dell Chromebook 11 */ { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present }, + + /* Dell Chromebook 11 (2015 version) */ + { 0x0a16, 0x1028, 0x0a35, quirk_backlight_present }, }; static void intel_init_quirks(struct drm_device *dev) -- 2.5.0 From 06d7e7fe18b63244ec4e6e633fc40dd5bea39099 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 3 Nov 2015 08:31:41 +0100 Subject: [PATCH 05/26] drm/i915: Extend DSL readout fix to BDW and SKL. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit b291681926a142958112eedde62823230d6afb84 Those platforms have the same bug as haswell, and the same fix applies to them. The original HSW fix that this extends is commit 41b578fb0e8b930f2470d3f673b0fa279e77a7b8 Author: Jesse Barnes Date: Tue Sep 22 12:15:54 2015 -0700 drm/i915: workaround bad DSL readout v3 Signed-off-by: Maarten Lankhorst Acked-by: Ville Syrjälä Cc: stable@vger.kernel.org # v4.3 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91579 Link: http://patchwork.freedesktop.org/patch/msgid/1446535913-31970-3-git-send-email-maarten.lankhorst@linux.intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index fa7f82d54762..d83d12eeb3fe 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -651,7 +651,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) * problem. We may need to extend this to include other platforms, * but so far testing only shows the problem on HSW. */ - if (IS_HASWELL(dev) && !position) { + if (HAS_DDI(dev) && !position) { int i, temp; for (i = 0; i < 100; i++) { -- 2.5.0 From f5268273f194155f0a5f3cbfa7bf271774a7a9d6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 5 Nov 2015 11:49:59 +0200 Subject: [PATCH 06/26] drm/i915: quirk backlight present on Macbook 4, 1 Upstream commit 1b9448b071caa7d10bb2569fabe3020a2c25ae59 Unsurprisingly macbooks have backlights, just the VBT doesn't seem to know it in this case. Reported-and-tested-by: Daniel Nicoletti Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=88325 Fixes: c675949ec58c ("drm/i915: do not setup backlight if not available according to VBT") Cc: stable@vger.kernel.org # v3.15+ Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1446716999-1796-1-git-send-email-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8f258092cada..2e348788ecaa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14670,6 +14670,9 @@ static struct intel_quirk intel_quirks[] = { /* Apple Macbook 2,1 (Core 2 T7400) */ { 0x27a2, 0x8086, 0x7270, quirk_backlight_present }, + /* Apple Macbook 4,1 */ + { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present }, + /* Toshiba CB35 Chromebook (Celeron 2955U) */ { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present }, -- 2.5.0 From dddd84b8b5f7f8c0b0037a1bb53f81f5bc70115b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 4 Nov 2015 21:25:32 +0200 Subject: [PATCH 07/26] drm/i915: get runtime PM reference around GEM set_caching IOCTL Upstream commit fd0fe6acf1dd88aabfbf383f7e4c16315387a7b7 After Damien's D3 fix I started to get runtime suspend residency for the first time and that revealed a breakage on the set_caching IOCTL path that accesses the HW but doesn't take an RPM ref. Fix this up. Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Cc: stable@vger.kernel.org Link: http://patchwork.freedesktop.org/patch/msgid/1446665132-22491-1-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4d631a946481..dee065c2b6d8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3728,6 +3728,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_caching *args = data; struct drm_i915_gem_object *obj; enum i915_cache_level level; @@ -3747,9 +3748,11 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, return -EINVAL; } + intel_runtime_pm_get(dev_priv); + ret = i915_mutex_lock_interruptible(dev); if (ret) - return ret; + goto rpm_put; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (&obj->base == NULL) { @@ -3762,6 +3765,9 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); +rpm_put: + intel_runtime_pm_put(dev_priv); + return ret; } -- 2.5.0 From df79b28d6a73835c70222506405bdb54774395c9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 16 Nov 2015 12:49:14 +0100 Subject: [PATCH 08/26] drm/i915: Clear intel_crtc->atomic before updating it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit ba8af3e592f7175b5f9a92d2cfcc00b82097d1be If an atomic update fails intel_crtc->atomic may have have some values left from the last atomic check. One example is atomic->wait_for_vblank, which results in spurious errors in kms_flip. [ 1551.892708] ------------[ cut here ]------------ [ 1551.892721] WARNING: CPU: 3 PID: 4179 at ../drivers/gpu/drm/drm_irq.c:1199 drm_wait_one_vblank+0x197/0x1a0 [drm]() [ 1551.892722] vblank not available on crtc 2, ret=-22 [ 1551.892751] Modules linked in: snd_hda_intel i915 drm_kms_helper drm intel_gtt i2c_algo_bit cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea agpgart cfg80211 binfmt_misc snd_hda_codec_hdmi intel_rapl iosf_mbi x86_pkg_temp_thermal coretemp kvm_intel snd_hda_codec_realtek kvm snd_hda_codec_generic iTCO_wdt aesni_intel aes_x86_64 glue_helper lrw snd_hda_codec gf128mul ablk_helper cryptd snd_hwdep psmouse snd_hda_core pcspkr snd_pcm snd_timer snd lpc_ich i2c_i801 mfd_core soundcore wmi evdev [last unloaded: drm] [ 1551.892753] CPU: 3 PID: 4179 Comm: kms_pipe_crc_ba Tainted: G U W 4.3.0-reg+ #6 [ 1551.892754] Hardware name: /DZ77BH-55K, BIOS BHZ7710H.86A.0100.2013.0517.0942 05/17/2013 [ 1551.892758] ffffffffa03128d8 ffff8800cec73890 ffffffff812c0f3c ffff8800cec738d8 [ 1551.892760] ffff8800cec738c8 ffffffff8104ff36 ffff880116ae2290 0000000000000002 [ 1551.892762] ffff8800d39fcda0 ffff8800d038b4d0 ffff8800d42b5550 ffff8800cec73928 [ 1551.892763] Call Trace: [ 1551.892768] [] dump_stack+0x4e/0x82 [ 1551.892771] [] warn_slowpath_common+0x86/0xc0 [ 1551.892773] [] warn_slowpath_fmt+0x4c/0x50 [ 1551.892781] [] ? drm_vblank_get+0x78/0xd0 [drm] [ 1551.892787] [] drm_wait_one_vblank+0x197/0x1a0 [drm] [ 1551.892813] [] intel_post_plane_update+0xef/0x120 [i915] [ 1551.892832] [] intel_atomic_commit+0x4c2/0x1600 [i915] [ 1551.892862] [] ? drm_atomic_check_only+0x147/0x5e0 [drm] [ 1551.892872] [] ? drm_atomic_add_affected_connectors+0x27/0xf0 [drm] [ 1551.892881] [] drm_atomic_commit+0x37/0x60 [drm] [ 1551.892887] [] restore_fbdev_mode+0x28a/0x2c0 [drm_kms_helper] [ 1551.892895] [] drm_fb_helper_restore_fbdev_mode_unlocked+0x33/0x80 [drm_kms_helper] [ 1551.892900] [] drm_fb_helper_set_par+0x2d/0x50 [drm_kms_helper] [ 1551.892920] [] intel_fbdev_set_par+0x1a/0x60 [i915] [ 1551.892923] [] fb_set_var+0x1a7/0x3f0 [ 1551.892927] [] ? trace_hardirqs_on_caller+0x12f/0x1c0 [ 1551.892931] [] fbcon_blank+0x212/0x2f0 [ 1551.892935] [] do_unblank_screen+0xba/0x1d0 [ 1551.892937] [] vt_ioctl+0x13d5/0x1450 [ 1551.892940] [] ? preempt_count_sub+0x41/0x50 [ 1551.892943] [] tty_ioctl+0x423/0xe30 [ 1551.892947] [] do_vfs_ioctl+0x301/0x560 [ 1551.892949] [] ? putname+0x53/0x60 [ 1551.892952] [] ? __fget_light+0x66/0x90 [ 1551.892955] [] SyS_ioctl+0x79/0x90 [ 1551.892958] [] entry_SYSCALL_64_fastpath+0x12/0x6f [ 1551.892961] ---[ end trace 3e764d4b6628c91c ]--- Testcase: kms_flip Reported-and-tested-by: Ville Syrjälä Cc: stable@vger.kernel.org #v4.3 Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/5649C2BA.6080300@mblankhorst.nl --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e348788ecaa..7e13bea3b4d5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13005,6 +13005,9 @@ static int intel_atomic_check(struct drm_device *dev, struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); + memset(&to_intel_crtc(crtc)->atomic, 0, + sizeof(struct intel_crtc_atomic_commit)); + /* Catch I915_MODE_FLAG_INHERITED */ if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) crtc_state->mode_changed = true; -- 2.5.0 From eb02e7a4b15ec47b50fd7447471ac3bb75cce53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 11 Nov 2015 19:11:28 +0200 Subject: [PATCH 09/26] drm/i915: Don't clobber the addfb2 ioctl params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit 76dc3769d7c3cdcfa7c4c7768a7cb87cd91af12f We try to convert the old way of of specifying fb tiling (obj->tiling) into the new fb modifiers. We store the result in the passed in mode_cmd structure. But that structure comes directly from the addfb2 ioctl, and gets copied back out to userspace, which means we're clobbering the modifiers that the user provided (all 0 since the DRM_MODE_FB_MODIFIERS flag wasn't even set by the user). Hence if the user reuses the struct for another addfb2, the ioctl will be rejected since it's now asking for some modifiers w/o the flag set. Fix the problem by making a copy of the user provided structure. We can play any games we want with the copy. IGT-Version: 1.12-git (x86_64) (Linux: 4.4.0-rc1-stereo+ x86_64) ... Subtest basic-X-tiled: SUCCESS (0.001s) Test assertion failure function pitch_tests, file kms_addfb_basic.c:167: Failed assertion: drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &f) == 0 Last errno: 22, Invalid argument Stack trace: #0 [__igt_fail_assert+0x101] #1 [pitch_tests+0x619] #2 [__real_main426+0x2f] #3 [main+0x23] #4 [__libc_start_main+0xf0] #5 [_start+0x29] #6 [+0x29] Subtest framebuffer-vs-set-tiling failed. **** DEBUG **** Test assertion failure function pitch_tests, file kms_addfb_basic.c:167: Failed assertion: drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &f) == 0 Last errno: 22, Invalid argument **** END **** Subtest framebuffer-vs-set-tiling: FAIL (0.003s) ... IGT-Version: 1.12-git (x86_64) (Linux: 4.4.0-rc1-stereo+ x86_64) Subtest framebuffer-vs-set-tiling: SUCCESS (0.000s) Cc: stable@vger.kernel.org # v4.1+ Cc: Daniel Vetter Cc: Tvrtko Ursulin Fixes: 2a80eada326f ("drm/i915: Add fb format modifier support") Testcase: igt/kms_addfb_basic/clobbered-modifier Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1447261890-3960-1-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e13bea3b4d5..d07d98aeb72c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14330,16 +14330,17 @@ static int intel_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_mode_fb_cmd2 *user_mode_cmd) { struct drm_i915_gem_object *obj; + struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; obj = to_intel_bo(drm_gem_object_lookup(dev, filp, - mode_cmd->handles[0])); + mode_cmd.handles[0])); if (&obj->base == NULL) return ERR_PTR(-ENOENT); - return intel_framebuffer_create(dev, mode_cmd, obj); + return intel_framebuffer_create(dev, &mode_cmd, obj); } #ifndef CONFIG_DRM_FBDEV_EMULATION -- 2.5.0 From 687b4f4810c6a23420994e9cf4bb2d420a80217d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 17 Nov 2015 18:14:26 +0200 Subject: [PATCH 10/26] drm/i915: Fix gpu frequency change tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit 0f94592efd36213c961145fe1ab0c3bc323ec053 With gen < 9 we have had always 50Mhz units as our hw ratio. With gen >= 9 the hw ratio changed to 16.667Mhz (50/3). The result was that our gpu frequency tracing started to output values 3 times larger than expected due to hardcoded scaling value. Fix this by using Use intel_gpu_freq() when generating Mhz value from ratio for 'intel_gpu_freq_change' trace event. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92591 Cc: stable@vger.kernel.org # v4.3+ Reported-by: Eero Tamminen Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1447776866-29384-1-git-send-email-mika.kuoppala@intel.com --- 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 5e91e795fd99..2a689522cd89 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4503,7 +4503,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val) POSTING_READ(GEN6_RPNSWREQ); dev_priv->rps.cur_freq = val; - trace_intel_gpu_freq_change(val * 50); + trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val)); } static void valleyview_set_rps(struct drm_device *dev, u8 val) -- 2.5.0 From efee83c75bf454e745ebaddd96b9fe741c706317 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Nov 2015 09:58:05 +0000 Subject: [PATCH 11/26] drm/i915: Mark uneven memory banks on gen4 desktop as unknown swizzling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit 0b466dc238cb660bbdb9ef6e121e1757057484c3 We have varied reports of swizzling corruption on gen4 desktop, and confirmation that one at least is triggered by uneven memory banks (L-shaped memory). The implication is that the swizzling varies between the paired channels and the remainder of memory on the single channel. As the object then has unpredictable swizzling (it will vary depending on exact page allocation and may even change during the object's lifetime as the pages are replaced), we have to report to userspace that the swizzling is unknown. However, some existing userspace is buggy when it meets an unknown swizzling configuration and so we need to tell another white lie and mark the swizzling as NONE but report it as UNKNOWN through the extended get-tiling-ioctl. See commit 5eb3e5a5e11d14f9deb2a4b83555443b69ab9940 Author: Chris Wilson Date: Sun Jun 28 09:19:26 2015 +0100 drm/i915: Declare the swizzling unknown for L-shaped configurations for the previous example where we found that telling the truth to userspace just ends up in a world of hurt. Also since we don't truly know what the swizzling is on the pages, we need to keep them pinned to prevent swapping as the reports also suggest that some gen4 devices have previously undetected bit17 swizzling. v2: Combine unknown + quirk patches to prevent userspace ever seeing unknown swizzling through the normal get-tiling-ioctl. Also use the same path for the existing uneven bank detection for mobile gen4. Reported-by: Matti Hämäläinen Tested-by: Matti Hämäläinen References: https://bugs.freedesktop.org/show_bug.cgi?id=90725 Signed-off-by: Chris Wilson Cc: Matti Hämäläinen Cc: Daniel Vetter Cc: Jani Nikula Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1447927085-31726-1-git-send-email-chris@chris-wilson.co.uk Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_fence.c | 36 ++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index af1f8c461060..716c3d8f027c 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -647,11 +647,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } /* check for L-shaped memory aka modified enhanced addressing */ - if (IS_GEN4(dev)) { - uint32_t ddc2 = I915_READ(DCC2); - - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) - dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + if (IS_GEN4(dev) && + !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) { + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; } if (dcc == 0xffffffff) { @@ -680,16 +679,35 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) * matching, which was the case for the swizzling required in * the table above, or from the 1-ch value being less than * the minimum size of a rank. + * + * Reports indicate that the swizzling actually + * varies depending upon page placement inside the + * channels, i.e. we see swizzled pages where the + * banks of memory are paired and unswizzled on the + * uneven portion, so leave that as unknown. */ - if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else { + if (I915_READ16(C0DRB3) == I915_READ16(C1DRB3)) { swizzle_x = I915_BIT_6_SWIZZLE_9_10; swizzle_y = I915_BIT_6_SWIZZLE_9; } } + if (swizzle_x == I915_BIT_6_SWIZZLE_UNKNOWN || + swizzle_y == I915_BIT_6_SWIZZLE_UNKNOWN) { + /* Userspace likes to explode if it sees unknown swizzling, + * so lie. We will finish the lie when reporting through + * the get-tiling-ioctl by reporting the physical swizzle + * mode as unknown instead. + * + * As we don't strictly know what the swizzling is, it may be + * bit17 dependent, and so we need to also prevent the pages + * from being moved. + */ + dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + dev_priv->mm.bit_6_swizzle_x = swizzle_x; dev_priv->mm.bit_6_swizzle_y = swizzle_y; } -- 2.5.0 From b9aa6e409916793c7b2c6302df80f9a8c36ddcf2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Nov 2015 15:26:47 +0100 Subject: [PATCH 12/26] drm/i915: Don't compare has_drrs strictly in pipe config Upstream commit 13b13dfaaa39ab52b0f433c6744f4638793cbf7b The commit [cfb23ed622d0: drm/i915: Allow fuzzy matching in pipe_config_compare, v2] relaxed the way to compare the pipe configurations, but one new comparison sneaked in there: it added the strict has_drrs value check. This causes a regression on many machines, typically HP laptops with a docking port, where the kernel spews warnings and eventually fails to set the mode properly like: [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in has_drrs (expected 1, found 0) ------------[ cut here ]------------ WARNING: CPU: 0 PID: 79 at drivers/gpu/drm/i915/intel_display.c:12700 intel_modeset_check_state+0x5aa/0x870 [i915]() pipe state doesn't match! .... This patch just removes the check again for fixing the regression. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104041 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92456 Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=956397 Fixes: cfb23ed622d0 ('drm/i915: Allow fuzzy matching in pipe_config_compare, v2') Cc: # v4.3+ Reported-and-tested-by: Max Lin Signed-off-by: Takashi Iwai Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1448461607-16868-1-git-send-email-tiwai@suse.de Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d07d98aeb72c..58e08fb47d1f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12427,7 +12427,6 @@ intel_pipe_config_compare(struct drm_device *dev, if (INTEL_INFO(dev)->gen < 8) { PIPE_CONF_CHECK_M_N(dp_m_n); - PIPE_CONF_CHECK_I(has_drrs); if (current_config->has_drrs) PIPE_CONF_CHECK_M_N(dp_m2_n2); } else -- 2.5.0 From 17e09098ed89ccc44a9420b0eee361b2e4f1f58c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Nov 2015 12:09:56 +0100 Subject: [PATCH 13/26] drm/i915: Don't override output type for DDI HDMI Upstream commit 2540058f7a9d9a843b4d9a28d4f8168dd034d030 Currently a DDI port may register the DP hotplug handler even though it's used with HDMI, and the DP HPD handler overrides the encoder type forcibly to DP. This caused the inconsistency on a machine connected with a HDMI monitor; upon a hotplug event, the DDI port is suddenly switched to be handled as a DP although the same monitor is kept connected, and this leads to the erroneous blank output. This patch papers over the bug by excluding the previous HDMI encoder type from this override. This should be fixed more fundamentally, e.g. by moving the encoder type reset from the HPD or by having individual encoder objects for HDMI and DP. But since the bug has been present for a long time (3.17), it's better to have a quick-n-dirty fix for now, and keep working on a cleaner fix. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=955190 Fixes: 0e32b39ceed6 ('drm/i915: add DP 1.2 MST support (v0.7)') Cc: # v3.17+ Signed-off-by: Takashi Iwai Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1447931396-19147-1-git-send-email-tiwai@suse.de Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0a2e33fbf20d..a7b7a64d8d27 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4921,7 +4921,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) enum intel_display_power_domain power_domain; enum irqreturn ret = IRQ_NONE; - if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) + if (intel_dig_port->base.type != INTEL_OUTPUT_EDP && + intel_dig_port->base.type != INTEL_OUTPUT_HDMI) intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) { -- 2.5.0 From 5cbff55f4355dc1cec8124c8741fdfd98f644c73 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Sat, 12 Sep 2015 10:17:50 +0530 Subject: [PATCH 14/26] drm/i915: Add IS_SKL_GT3 and IS_SKL_GT4 macro. Upstream commit 7a58bad0e63295dfa803973efcebc80cb730c7bd It will be usefull to specify w/a that affects only SKL GT3 and GT4. Signed-off-by: Sagar Arun Kamble Reviewed-by: Alex Dai Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e1db8de52851..3c16f6237251 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2475,6 +2475,11 @@ struct drm_i915_cmd_table { #define IS_SKL_ULX(dev) (INTEL_DEVID(dev) == 0x190E || \ INTEL_DEVID(dev) == 0x1915 || \ INTEL_DEVID(dev) == 0x191E) +#define IS_SKL_GT3(dev) (IS_SKYLAKE(dev) && \ + (INTEL_DEVID(dev) & 0x00F0) == 0x0020) +#define IS_SKL_GT4(dev) (IS_SKYLAKE(dev) && \ + (INTEL_DEVID(dev) & 0x00F0) == 0x0030) + #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) #define SKL_REVID_A0 (0x0) -- 2.5.0 From baed978880f2c32e82587cc514227aad82daecd5 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 18 Sep 2015 17:52:47 +0100 Subject: [PATCH 15/26] drm/i915/bxt: Update revision id for BXT C0 Upstream commit 5ca4163a612068d8f942c454218d3d631f22af1b Cc: Nick Hoath Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3c16f6237251..475b03e9d584 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2491,7 +2491,7 @@ struct drm_i915_cmd_table { #define BXT_REVID_A0 (0x0) #define BXT_REVID_B0 (0x3) -#define BXT_REVID_C0 (0x6) +#define BXT_REVID_C0 (0x9) /* * The genX designation typically refers to the render engine, so render -- 2.5.0 From c80bd95bfeb85ce970c5f7711718a274e4b38b55 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Sat, 12 Sep 2015 10:17:51 +0530 Subject: [PATCH 16/26] drm/i915: WaRsDisableCoarsePowerGating Upstream commit f2d2fe95072acd5404f8051b8bf1195c61a47fb5 WaRsDisableCoarsePowerGating: Coarse Power Gating (CPG) needs to be disabled for platforms prior to BXT B0 and SKL GT3/GT4 till E0. v2: Added GT3/GT4 Check. Change-Id: Ia3c4c16e050c88d3e259f601054875c812d69c3a Signed-off-by: Sagar Arun Kamble Reviewed-by: Alex Dai [danvet: Align continuation properly.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2a689522cd89..56a5568ffeb7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4851,11 +4851,14 @@ static void gen9_enable_rc6(struct drm_device *dev) /* * 3b: Enable Coarse Power Gating only when RC6 is enabled. - * WaDisableRenderPowerGating:skl,bxt - Render PG need to be disabled with RC6. + * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6. */ - I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? - GEN9_MEDIA_PG_ENABLE : 0); - + if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || + ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0))) + I915_WRITE(GEN9_PG_ENABLE, 0); + else + I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? + (GEN9_RENDER_PG_ENABLE | GEN9_MEDIA_PG_ENABLE) : 0); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); -- 2.5.0 From c6b1dd5d44c09a9c0032066415ccf8539efb5856 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Sat, 12 Sep 2015 10:17:52 +0530 Subject: [PATCH 17/26] drm/i915: WaRsUseTimeoutMode Upstream commit e3429cd240b06c79df3ea90f28065a7e011744cd Enable TO mode for RC6 for SKL till D0 and BXT till A0. Cc: Tom O'Rourke Cc: Akash Goel Signed-off-by: Sagar Arun Kamble Reviewed-by: Alex Dai [danvet: Fixup line continuation alignment.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 56a5568ffeb7..ab54c645c2ee 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4845,9 +4845,16 @@ static void gen9_enable_rc6(struct drm_device *dev) rc6_mask = GEN6_RC_CTL_RC6_ENABLE; DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off"); - I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | - GEN6_RC_CTL_EI_MODE(1) | - rc6_mask); + + if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) || + (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) + I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | + GEN7_RC_CTL_TO_MODE | + rc6_mask); + else + I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | + GEN6_RC_CTL_EI_MODE(1) | + rc6_mask); /* * 3b: Enable Coarse Power Gating only when RC6 is enabled. -- 2.5.0 From a7af36dfaaa2136be0454787130f73d207c2f34d Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Sat, 12 Sep 2015 10:17:53 +0530 Subject: [PATCH 18/26] drm/i915: WaRsDoubleRc6WrlWithCoarsePowerGating Upstream commit 63a4dec2c168b74a39df1eac494501f0f6bf3708 Cc: Tom O'Rourke Cc: Akash Goel Signed-off-by: Sagar Arun Kamble Reviewed-by: Alex Dai [danvet: Fix continuation alignment.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ab54c645c2ee..7c7b6386121f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4828,7 +4828,13 @@ static void gen9_enable_rc6(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, 0); /* 2b: Program RC6 thresholds.*/ - I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16); + + /* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */ + if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && + (INTEL_REVID(dev) <= SKL_REVID_E0))) + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16); + else + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16); I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */ I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */ for_each_ring(ring, dev_priv, unused) -- 2.5.0 From b925cfd49203fc37c491fa28310221be23a2634d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 7 Dec 2015 18:29:44 +0200 Subject: [PATCH 19/26] drm/i915/skl: Disable coarse power gating up until F0 Upstream commit 344df9809f4521c8c11d67c5ef18764b54358950 There is conflicting info between E0 and F0 steppings for this workarounds. Trust more authoritative source and be conservative and extend also for F0. This prevents numerous (>50) gpu hangs with SKL GT4e during piglit run. References: HSD: gen9lp/2134184 Cc: Sagar Arun Kamble Signed-off-by: Mika Kuoppala Reviewed-by: Sagar Arun Kamble Link: http://patchwork.freedesktop.org/patch/msgid/1449505785-20812-1-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 6686ece19f7446f0e29c77d9e0402e1d0ce10c48) Cc: stable@vger.kernel.org # v4.3+ Signed-off-by: Jani Nikula --- 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 7c7b6386121f..d04f123f4ccf 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4867,7 +4867,7 @@ static void gen9_enable_rc6(struct drm_device *dev) * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6. */ if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || - ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0))) + ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0))) I915_WRITE(GEN9_PG_ENABLE, 0); else I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? -- 2.5.0 From 302e759f64e1c4bed49f31459329acbb2cddce8a Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 7 Dec 2015 18:29:45 +0200 Subject: [PATCH 20/26] drm/i915/skl: Double RC6 WRL always on Upstream commit 6704d45528537ea6088aeea0667d87b605b82d51 WaRsDoubleRc6WrlWithCoarsePowerGating should be enabled for all Skylakes. Make it so. Cc: Sagar Arun Kamble Signed-off-by: Mika Kuoppala Reviewed-by: Sagar Arun Kamble Link: http://patchwork.freedesktop.org/patch/msgid/1449505785-20812-2-git-send-email-mika.kuoppala@intel.com (cherry picked from commit e7674b8c31717dd0c58b3a9493d43249722071eb) Cc: stable@vger.kernel.org # v4.3+ Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_pm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d04f123f4ccf..33db474fae02 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4830,8 +4830,7 @@ static void gen9_enable_rc6(struct drm_device *dev) /* 2b: Program RC6 thresholds.*/ /* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */ - if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && - (INTEL_REVID(dev) <= SKL_REVID_E0))) + if (IS_SKYLAKE(dev)) I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16); else I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16); -- 2.5.0 From c4c390176eaf6b4321c1f90065107711845e9aff Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 23 Nov 2015 10:25:28 +0100 Subject: [PATCH 21/26] drm/i915: Do a better job at disabling primary plane in the noatomic case. Upstream commit 634b3a4a476e96816d5d6cd5bb9f8900a53f56ba When disable_noatomic is called plane_mask is not correct yet, and plane_state->visible = true is left as true after disabling the primary plane. Other planes are already disabled as part of crtc sanitization, only the primary is left active. But the plane_mask is not updated here. It gets updated during fb takeover in modeset_gem_init, or set to the new value on resume. This means that to disable the primary plane 1 << drm_plane_index(primary) needs to be used. Afterwards because the crtc is no longer active it's forbidden to keep plane_state->visible set, or a WARN_ON in intel_plane_atomic_calc_changes triggers. There are other code points that rely on accurate plane_state->visible too, so make sure the bool is cleared. The other planes are already disabled in intel_sanitize_crtc, so they don't have to be handled here. Cc: stable@vger.kernel.org #v4.3, v4.2? Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92655 Tested-by: Tomas Mezzadra Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/5652DB88.9070208@linux.intel.com (cherry picked from commit 54a4196188eab82e6f0a5f05716626e9f18b8fb6) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58e08fb47d1f..35fad110cc26 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6225,9 +6225,11 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) if (to_intel_plane_state(crtc->primary->state)->visible) { intel_crtc_wait_for_pending_flips(crtc); intel_pre_disable_primary(crtc); + + intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary)); + to_intel_plane_state(crtc->primary->state)->visible = false; } - intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); intel_disable_shared_dpll(intel_crtc); -- 2.5.0 From 42ab5c413c7cf61fab4b2fbce9cb4ab7f7be6356 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 11 Dec 2015 11:32:57 +0000 Subject: [PATCH 22/26] drm/i915: Break busywaiting for requests on pending signals Upstream commit e7571f7fd66c77a760338340adbe41d994fe93ac The busywait in __i915_spin_request() does not respect pending signals and so may consume the entire timeslice for the task instead of returning to userspace to handle the signal. In the worst case this could cause a delay in signal processing of 20ms, which would be a noticeable jitter in cursor tracking. If a higher resolution signal was being used, for example to provide fairness of a server timeslices between clients, we could expect to detect some unfairness between clients (i.e. some windows not updating as fast as others). This issue was noticed when inspecting a report of poor interactivity resulting from excessively high __i915_spin_request usage. Fixes regression from commit 2def4ad99befa25775dd2f714fdd4d92faec6e34 [v4.2] Author: Chris Wilson Date: Tue Apr 7 16:20:41 2015 +0100 drm/i915: Optimistically spin for the request completion v2: Try to assess the impact of the bug Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin Cc: Jens Axboe Cc; "Rogozhkin, Dmitry V" Cc: Daniel Vetter Cc: Tvrtko Ursulin Cc: Eero Tamminen Cc: "Rantala, Valtteri" Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1449833608-22125-2-git-send-email-chris@chris-wilson.co.uk (cherry picked from commit 91b0c352ace9afec1fb51590c7b8bd60e0eb9fbd) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dee065c2b6d8..c6e3ab72882f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1144,7 +1144,7 @@ static bool missed_irq(struct drm_i915_private *dev_priv, return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings); } -static int __i915_spin_request(struct drm_i915_gem_request *req) +static int __i915_spin_request(struct drm_i915_gem_request *req, int state) { unsigned long timeout; @@ -1156,6 +1156,9 @@ static int __i915_spin_request(struct drm_i915_gem_request *req) if (i915_gem_request_completed(req, true)) return 0; + if (signal_pending_state(state, current)) + break; + if (time_after_eq(jiffies, timeout)) break; @@ -1195,6 +1198,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, struct drm_i915_private *dev_priv = dev->dev_private; const bool irq_test_in_progress = ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); + int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE; DEFINE_WAIT(wait); unsigned long timeout_expire; s64 before, now; @@ -1219,7 +1223,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, before = ktime_get_raw_ns(); /* Optimistic spin for the next jiffie before touching IRQs */ - ret = __i915_spin_request(req); + ret = __i915_spin_request(req, state); if (ret == 0) goto out; @@ -1231,8 +1235,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, for (;;) { struct timer_list timer; - prepare_to_wait(&ring->irq_queue, &wait, - interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + prepare_to_wait(&ring->irq_queue, &wait, state); /* We need to check whether any gpu reset happened in between * the caller grabbing the seqno and now ... */ @@ -1250,7 +1253,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req, break; } - if (interruptible && signal_pending(current)) { + if (signal_pending_state(state, current)) { ret = -ERESTARTSYS; break; } -- 2.5.0 From 8cbf415a2aadd85cf9dfab28296a821ffea96d87 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 11 Dec 2015 11:32:58 +0000 Subject: [PATCH 23/26] drm/i915: Limit the busy wait on requests to 5us not 10ms! Upstream commit f87a780f07b22b6dc4642dbaf44af65112076cb8 When waiting for high frequency requests, the finite amount of time required to set up the irq and wait upon it limits the response rate. By busywaiting on the request completion for a short while we can service the high frequency waits as quick as possible. However, if it is a slow request, we want to sleep as quickly as possible. The tradeoff between waiting and sleeping is roughly the time it takes to sleep on a request, on the order of a microsecond. Based on measurements of synchronous workloads from across big core and little atom, I have set the limit for busywaiting as 10 microseconds. In most of the synchronous cases, we can reduce the limit down to as little as 2 miscroseconds, but that leaves quite a few test cases regressing by factors of 3 and more. The code currently uses the jiffie clock, but that is far too coarse (on the order of 10 milliseconds) and results in poor interactivity as the CPU ends up being hogged by slow requests. To get microsecond resolution we need to use a high resolution timer. The cheapest of which is polling local_clock(), but that is only valid on the same CPU. If we switch CPUs because the task was preempted, we can also use that as an indicator that the system is too busy to waste cycles on spinning and we should sleep instead. __i915_spin_request was introduced in commit 2def4ad99befa25775dd2f714fdd4d92faec6e34 [v4.2] Author: Chris Wilson Date: Tue Apr 7 16:20:41 2015 +0100 drm/i915: Optimistically spin for the request completion v2: Drop full u64 for unsigned long - the timer is 32bit wraparound safe, so we can use native register sizes on smaller architectures. Mention the approximate microseconds units for elapsed time and add some extra comments describing the reason for busywaiting. v3: Raise the limit to 10us v4: Now 5us. Reported-by: Jens Axboe Link: https://lkml.org/lkml/2015/11/12/621 Reviewed-by: Tvrtko Ursulin Cc: "Rogozhkin, Dmitry V" Cc: Daniel Vetter Cc: Tvrtko Ursulin Cc: Eero Tamminen Cc: "Rantala, Valtteri" Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1449833608-22125-3-git-send-email-chris@chris-wilson.co.uk (cherry picked from commit ca5b721e238226af1d767103ac852aeb8e4c0764) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 47 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c6e3ab72882f..205316d056f1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1144,14 +1144,57 @@ static bool missed_irq(struct drm_i915_private *dev_priv, return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings); } +static unsigned long local_clock_us(unsigned *cpu) +{ + unsigned long t; + + /* Cheaply and approximately convert from nanoseconds to microseconds. + * The result and subsequent calculations are also defined in the same + * approximate microseconds units. The principal source of timing + * error here is from the simple truncation. + * + * Note that local_clock() is only defined wrt to the current CPU; + * the comparisons are no longer valid if we switch CPUs. Instead of + * blocking preemption for the entire busywait, we can detect the CPU + * switch and use that as indicator of system load and a reason to + * stop busywaiting, see busywait_stop(). + */ + *cpu = get_cpu(); + t = local_clock() >> 10; + put_cpu(); + + return t; +} + +static bool busywait_stop(unsigned long timeout, unsigned cpu) +{ + unsigned this_cpu; + + if (time_after(local_clock_us(&this_cpu), timeout)) + return true; + + return this_cpu != cpu; +} + static int __i915_spin_request(struct drm_i915_gem_request *req, int state) { unsigned long timeout; + unsigned cpu; + + /* When waiting for high frequency requests, e.g. during synchronous + * rendering split between the CPU and GPU, the finite amount of time + * required to set up the irq and wait upon it limits the response + * rate. By busywaiting on the request completion for a short while we + * can service the high frequency waits as quick as possible. However, + * if it is a slow request, we want to sleep as quickly as possible. + * The tradeoff between waiting and sleeping is roughly the time it + * takes to sleep on a request, on the order of a microsecond. + */ if (i915_gem_request_get_ring(req)->irq_refcount) return -EBUSY; - timeout = jiffies + 1; + timeout = local_clock_us(&cpu) + 5; while (!need_resched()) { if (i915_gem_request_completed(req, true)) return 0; @@ -1159,7 +1202,7 @@ static int __i915_spin_request(struct drm_i915_gem_request *req, int state) if (signal_pending_state(state, current)) break; - if (time_after_eq(jiffies, timeout)) + if (busywait_stop(timeout, cpu)) break; cpu_relax_lowlatency(); -- 2.5.0 From 7b94b8683d8d2ac4b29099e24e351e03f163e462 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 11 Dec 2015 11:32:59 +0000 Subject: [PATCH 24/26] drm/i915: Only spin whilst waiting on the current request Upstream commit 0f0cd472062eca6f9fac8be0cd5585f9a2df1ab2 Limit busywaiting only to the request currently being processed by the GPU. If the request is not currently being processed by the GPU, there is a very low likelihood of it being completed within the 2 microsecond spin timeout and so we will just be wasting CPU cycles. v2: Check for logical inversion when rebasing - we were incorrectly checking for this request being active, and instead busywaiting for when the GPU was not yet processing the request of interest. v3: Try another colour for the seqno names. v4: Another colour for the function names. v5: Remove the forced coherency when checking for the active request. On reflection and plenty of recent experimentation, the issue is not a cache coherency problem - but an irq/seqno ordering problem (timing issue). Here, we do not need the w/a to force ordering of the read with an interrupt. Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin Cc: "Rogozhkin, Dmitry V" Cc: Daniel Vetter Cc: Tvrtko Ursulin Cc: Eero Tamminen Cc: "Rantala, Valtteri" Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1449833608-22125-4-git-send-email-chris@chris-wilson.co.uk (cherry picked from commit 821485dc2ad665f136c57ee589bf7a8210160fe2) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 27 +++++++++++++++++++-------- drivers/gpu/drm/i915/i915_gem.c | 8 +++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 475b03e9d584..bd6df685ae61 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2178,8 +2178,17 @@ struct drm_i915_gem_request { struct drm_i915_private *i915; struct intel_engine_cs *ring; - /** GEM sequence number associated with this request. */ - uint32_t seqno; + /** GEM sequence number associated with the previous request, + * when the HWS breadcrumb is equal to this the GPU is processing + * this request. + */ + u32 previous_seqno; + + /** GEM sequence number associated with this request, + * when the HWS breadcrumb is equal or greater than this the GPU + * has finished processing this request. + */ + u32 seqno; /** Position in the ringbuffer of the start of the request */ u32 head; @@ -2880,15 +2889,17 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } +static inline bool i915_gem_request_started(struct drm_i915_gem_request *req, + bool lazy_coherency) +{ + u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency); + return i915_seqno_passed(seqno, req->previous_seqno); +} + static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req, bool lazy_coherency) { - u32 seqno; - - BUG_ON(req == NULL); - - seqno = req->ring->get_seqno(req->ring, lazy_coherency); - + u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency); return i915_seqno_passed(seqno, req->seqno); } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 205316d056f1..1bf658dc6553 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1191,9 +1191,13 @@ static int __i915_spin_request(struct drm_i915_gem_request *req, int state) * takes to sleep on a request, on the order of a microsecond. */ - if (i915_gem_request_get_ring(req)->irq_refcount) + if (req->ring->irq_refcount) return -EBUSY; + /* Only spin if we know the GPU is processing this request */ + if (!i915_gem_request_started(req, true)) + return -EAGAIN; + timeout = local_clock_us(&cpu) + 5; while (!need_resched()) { if (i915_gem_request_completed(req, true)) @@ -1207,6 +1211,7 @@ static int __i915_spin_request(struct drm_i915_gem_request *req, int state) cpu_relax_lowlatency(); } + if (i915_gem_request_completed(req, false)) return 0; @@ -2591,6 +2596,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, request->batch_obj = obj; request->emitted_jiffies = jiffies; + request->previous_seqno = ring->last_submitted_seqno; ring->last_submitted_seqno = request->seqno; list_add_tail(&request->list, &ring->request_list); -- 2.5.0 From bf0176f1bb4bb6316102f4ca4d9314a20c228098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Dec 2015 19:24:39 +0200 Subject: [PATCH 25/26] drm/i915: Workaround CHV pipe C cursor fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit ef8dd37af85a8f37ca3a29074647511e52c56181 Turns out CHV pipe C was glued on somewhat poorly, and there's something wrong with the cursor. If the cursor straddles the left screen edge, and is then moved away from the edge or disabled, the pipe will often underrun. If enough underruns are triggered quickly enough the pipe will fall over and die (it just scans out a solid color and reports a constant underrun). We need to turn the disp2d power well off and on again to recover the pipe. None of that is very nice for the user, so let's just refuse to place the cursor in the compromised position. The ddx appears to fall back to swcursor when the ioctl returns an error, so theoretically there's no loss of functionality for the user (discounting swcursor bugs). I suppose most cursors images actually have the hotspot not exactly at 0,0 so under typical conditions the fallback will in fact kick in as soon as the cursor touches the left edge of the screen. Any atomic compositor should anyway be prepared to fall back to GPU composition when things don't work out, so there should be no problem with those. Other things that I tried to solve this include flipping all display related clock gating knobs I could find, increasing the minimum gtt alignment all the way up to 512k. I also tried to see if there are more specific screen coordinates that hit the bug, but the findings were somewhat inconclusive. Sometimes the failures happen almost across the whole left edge, sometimes more at the very top and around the bottom half. I wasn't able to find any real pattern to these variations, so it seems our only choice is to just refuse to straddle the left screen edge at all. Cc: stable@vger.kernel.org Cc: Jason Plum Testcase: igt/kms_chv_cursor_fail Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92826 Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1450459479-16286-1-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Daniel Vetter (cherry picked from commit b29ec92c4f5e6d45d8bae8194e664427a01c6687) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 35fad110cc26..c70a6cb8914f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13614,6 +13614,7 @@ intel_check_cursor_plane(struct drm_plane *plane, struct drm_crtc *crtc = crtc_state->base.crtc; struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); + enum pipe pipe = to_intel_plane(plane)->pipe; unsigned stride; int ret; @@ -13647,6 +13648,22 @@ intel_check_cursor_plane(struct drm_plane *plane, return -EINVAL; } + /* + * There's something wrong with the cursor on CHV pipe C. + * If it straddles the left edge of the screen then + * moving it away from the edge or disabling it often + * results in a pipe underrun, and often that can lead to + * dead pipe (constant underrun reported, and it scans + * out just a solid color). To recover from that, the + * display power well must be turned off and on again. + * Refuse the put the cursor into that compromised position. + */ + if (IS_CHERRYVIEW(plane->dev) && pipe == PIPE_C && + state->visible && state->base.crtc_x < 0) { + DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n"); + return -EINVAL; + } + return 0; } -- 2.5.0 From 036933da945df1526e0b5ee17fe8a8a77c1380e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 10 Dec 2015 18:22:31 +0200 Subject: [PATCH 26/26] drm/i915: Unbreak check_digital_port_conflicts() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit ae35b56e367b9fef7f5de701cf8c1c3dd954dded Atomic changes broke check_digital_port_conflicts(). It needs to look at the global situation instead of just trying to find a conflict within the current atomic state. This bug made my HSW explode spectacularly after I had split the DDI encoders into separate DP and HDMI encoders. With the fix, things seem much more solid. I hope holding the connection_mutex is enough protection that we can actually walk the connectors even if they're not part of the current atomic state... v2: Regenerate the patch so that it actually applies (Jani) Cc: stable@vger.kernel.org Cc: Ander Conselvan de Oliveira Fixes: 5448a00d3f06 ("drm/i915: Don't use staged config in check_digital_port_conflicts()") Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1449764551-12466-1-git-send-email-ville.syrjala@linux.intel.com (cherry picked from commit 0bff4858653312a10c83709e0009c3adb87e6f1e) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c70a6cb8914f..aafe3e3de3ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12026,18 +12026,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, static bool check_digital_port_conflicts(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - struct intel_encoder *encoder; struct drm_connector *connector; - struct drm_connector_state *connector_state; unsigned int used_ports = 0; - int i; /* * Walk the connector list instead of the encoder * list to detect the problem on ddi platforms * where there's just one encoder per digital port. */ - for_each_connector_in_state(state, connector, connector_state, i) { + drm_for_each_connector(connector, dev) { + struct drm_connector_state *connector_state; + struct intel_encoder *encoder; + + connector_state = drm_atomic_get_existing_connector_state(state, connector); + if (!connector_state) + connector_state = connector->state; + if (!connector_state->best_encoder) continue; -- 2.5.0