From f9486c7485fb67b159d728c183a5963e5e25077d Mon Sep 17 00:00:00 2001 From: Sk Anirban Date: Wed, 29 Jul 2026 16:54:47 +0530 Subject: [PATCH 1/7] drm/i915/selftests: Report missing RC0 power as an error The RC0 no-power case is a hard failure (-EINVAL); log it via pr_err instead of pr_debug so it is captured in default kernel logs. Signed-off-by: Sk Anirban Reviewed-by: Badal Nilawar Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260729112446.2919206-2-sk.anirban@intel.com --- drivers/gpu/drm/i915/gt/selftest_rc6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_rc6.c b/drivers/gpu/drm/i915/gt/selftest_rc6.c index 90f30b988d68..68fb1830d411 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rc6.c +++ b/drivers/gpu/drm/i915/gt/selftest_rc6.c @@ -92,8 +92,8 @@ int live_rc6_manual(void *arg) if (!rc0_power) { if (rc0_freq) - pr_debug("No power measured while in RC0! GPU Freq: %uMHz in RC0\n", - rc0_freq); + pr_err("No power measured while in RC0! GPU Freq: %uMHz in RC0\n", + rc0_freq); else pr_err("No power and freq measured while in RC0\n"); err = -EINVAL; From 7536eb9ea9058ce0dbcce7c862e586c2034a4c6e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 25 Aug 2026 11:35:52 +0200 Subject: [PATCH 2/7] drm/i915/gem: Use simpler versions of min*() Instead of harder to read min_array() and prone to mistakes min_t() use min3() and min(). No functional changes intended. The types of the values are unsigned, no side-effects are expected. Signed-off-by: Andy Shevchenko Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260825093552.4088094-1-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 06543ae60706..3ba8edb6888d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -153,11 +153,8 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, } } while (1); - nr_pages = min_array(((unsigned long[]) { - folio_nr_pages(folio), - page_count - i, - max_segment / PAGE_SIZE, - }), 3); + nr_pages = min3(folio_nr_pages(folio), + page_count - i, max_segment / PAGE_SIZE); if (!i || sg->length >= max_segment || @@ -168,8 +165,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, st->nents++; sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0); } else { - nr_pages = min_t(unsigned long, nr_pages, - (max_segment - sg->length) / PAGE_SIZE); + nr_pages = min(nr_pages, (max_segment - sg->length) / PAGE_SIZE); sg->length += nr_pages * PAGE_SIZE; } From 18ec6327d3456f5d8a9b55832d376935d2eb3577 Mon Sep 17 00:00:00 2001 From: Krzysztof Karas Date: Fri, 28 Aug 2026 10:03:32 +0000 Subject: [PATCH 3/7] drm/i915/selftest: Fix a typo in alloc_workqueue call The workqueue created by test_ipc() was named "i1915-selftest" instead of "i915-selftest". Correct the driver name in the workqueue name. Signed-off-by: Krzysztof Karas Reviewed-by: Janusz Krzysztofik Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260828100339.72304-2-krzysztof.karas@intel.com --- drivers/gpu/drm/i915/selftests/i915_sw_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c index 6a305322e30d..ecb2d718f6a6 100644 --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c @@ -526,7 +526,7 @@ static int test_ipc(void *arg) struct workqueue_struct *wq; int ret = 0; - wq = alloc_workqueue("i1915-selftest", WQ_PERCPU, 0); + wq = alloc_workqueue("i915-selftest", WQ_PERCPU, 0); if (wq == NULL) return -ENOMEM; From a9fab05df43215f62e9c79cf21aee434eac543ea Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 31 Aug 2026 11:33:08 +0200 Subject: [PATCH 4/7] drm/i915/selftests: Wait longer for request to start CI extremely sporadically (five times over last six months) reported failures of igt@i915_selftest@live@hangcheck on ARL-S machines. The selftest was timing out while waiting up to 1 second for a request supposed to trigger a GPU hang to be started. It occurred possible to reproduce this issue manually by running the selftest in a loop for a few hours. Among results from 5 occurrences reported by CI so far, and two manual reproductions, two of them contained messages that suggested a posssibility of the awaited request to actually start soon after timeout. With the timeout extended from 1 to 2 seconds, it occurred no longer possible to trigger the failure, even when running the test in a loop for 10, then for 12 hours, on the same machine where it was failing before in 2-3 hours. Assume the conditions that prevented the hang requests to start within 1 second were always transient, and 2 seconds is sufficient for those requests to start effectively on machines in the CI environment. Fix the issue by using that value as the timeout. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16624 Signed-off-by: Janusz Krzysztofik Reviewed-by: Krzysztof Karas Reviewed-by: Krzysztof Niemiec Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260831093510.3496388-2-janusz.krzysztofik@linux.intel.com --- drivers/gpu/drm/i915/gt/selftest_hangcheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c index 00dfc37221fa..53f3ce5c33a4 100644 --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c @@ -278,7 +278,7 @@ static bool wait_until_running(struct hang *h, struct i915_request *rq) 10) && wait_for(i915_seqno_passed(hws_seqno(h, rq), rq->fence.seqno), - 1000)); + 2000)); } static int igt_hang_sanitycheck(void *arg) From 5113479556025093bf8133bb2dcaa33be2d50921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 3 Sep 2026 13:36:21 +0200 Subject: [PATCH 5/7] drm/i915: fix incorrect RCU teardown order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_gem_busy_ioctl uses dma_resv_for_each_fence_unlocked() to iterate over the fences in an GEM object without holding a reference but only the RCU read side lock. What can happen here is that the GEM object is destroyed concurrently while i915_gem_busy_ioctl is still running. This won't free the GEM objects memory, but still drops all the dma_fence references. Now when dma_resv_for_each_fence_unlocked() sees a destroyed dma_fence it assumes that a new fence list was installed and re-starts the loop. But in the case of a destroyed GEM object a new fence list is never installed, only the old one freed and therefore the iteration never finishes resulting in an endless loop. The solution is to drop the fence references only after the RCU grace period. The fixes tag is not necessary the patch introducing the problem, but the one making it so worse that we need to address it. This problem was pointed out by Sashiko-bot. Signed-off-by: Christian König Fixes: 912ff2ebd695 ("drm/i915: use the new iterator in i915_gem_busy_ioctl v2") CC: stable@vger.kernel.org Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://lore.kernel.org/r/20260903113621.54660-1-christian.koenig@amd.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 5172d3982654..9e01f8b2079a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -89,6 +89,7 @@ struct drm_i915_gem_object *i915_gem_object_alloc(void) void i915_gem_object_free(struct drm_i915_gem_object *obj) { + dma_resv_fini(&obj->base._resv); return kmem_cache_free(slab_objects, obj); } @@ -144,7 +145,6 @@ void __i915_gem_object_fini(struct drm_i915_gem_object *obj) { mutex_destroy(&obj->mm.get_page.lock); mutex_destroy(&obj->mm.get_dma_page.lock); - dma_resv_fini(&obj->base._resv); } /** From 2a0158925fb943c7ba8f3216e2734952128defc9 Mon Sep 17 00:00:00 2001 From: Krzysztof Karas Date: Fri, 11 Sep 2026 06:11:45 +0000 Subject: [PATCH 6/7] drm/i915/gem: Prevent overstepping exec array boundary It is possible for eb_relocate_parse_slow() to call kvfree() on entries outside the original exec array during following scenario inside eb_relocate_parse_slow(): 1) eb_copy_relocations() allocates as many as eb->buffer_count copies for exec entries; 2) eb_parse() appends up to two VMAs, right after incrementing eb->buffer_count; 3) cleanup under "out" label uses this incremented buffer_count to release relocation pointers from exec array via kvfree(), not from VMA array. To amend this problem, ensure that relocation cleanup uses the original exec object count, excluding the VMAs appended by the command parser. Fixes: 8e4ba491b0ba ("drm/i915: Parse command buffer earlier in eb_relocate(slow)") Signed-off-by: Krzysztof Karas Assisted-by: GitHub-Copilot:gpt-6-astra Cc: stable@vger.kernel.org # 5.10+ Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260911061145.3535489-1-krzysztof.karas@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 1f303d4eaa4d..d5aadced7da0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -1766,6 +1766,7 @@ static int eb_reinit_userptr(struct i915_execbuffer *eb) static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb) { + const unsigned int count = eb->buffer_count; bool have_copy = false; struct eb_vma *ev; int err = 0; @@ -1868,7 +1869,6 @@ static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb) out: if (have_copy) { - const unsigned int count = eb->buffer_count; unsigned int i; for (i = 0; i < count; i++) { From ca4a6deadad15b91ee083afe445fa6bdbfb68206 Mon Sep 17 00:00:00 2001 From: Krzysztof Karas Date: Thu, 10 Sep 2026 08:13:29 +0000 Subject: [PATCH 7/7] drm/i915/gt: Unmask interrupts only when ACTIVE is true There is a small race window between intel_rps_boost() reading a stale ACTIVE state and queuing rps->work, where ACTIVE may be changed via asynchronous calls triggered by wakeref drop. This means that rps_work() could be triggered after the GT has been parked, so unmasking RPS PM interrupts would happen without holding PM wakelock. This sequence of events may be observed during live_rc6_ctx_wa() selftest: 1) live_rc6_ctx_wa() -> intel_engine_pm_put() -> wakeref_put() ASYNC1) wakeref_put() callback -> __engine_park() -> intel_gt_pm_put_async() -> intel_gt_pm_put_async_untracked() -> intel_wakeref_put_async() ASYNC2) wakeref_put_async() callback -> __gt_park() -> intel_rps_park() -> intel_rps_clear_active() [clear ACTIVE] WITH INTERRUPTS: -> rps_disable_interrupts() -> cancel_work_sync(rps->work) -> rps_reset_interrupts() [rps->pm_iir = 0] WITHOUT INTERRUPTS (TIMER mode): -> rps_stop_timer() -> cancel_work_sync(rps->work) 2) live_rc6_ctx_wa() -> intel_gt_wait_for_idle() -> intel_gt_retire_requests_timeout() -> dma_fence_wait_timeout() -> ops->wait() [i915_fence_wait()] -> i915_request_wait_timeout() -> intel_rps_boost() -> intel_rps_is_active() [check ACTIVE] [OPEN RACE WINDOW] -> queue_work(rps->work) -> retire_requests() -> i915_request_retire() -> intel_rps_dec_waiters() [from 1 to 0] If ASYNC1 and ASYNC2 would execute during [OPEN RACE WINDOW], then: 3) rps_work() executes from the workqueue and may satisfy "(!pm_iir && !client_boost)" test (in TIMER mode rps->pm_iir is zeroed by an earlier rps_work() call or never gets a new value after previous intel_rps_unpark() event), so it jumps to "out" label, bypassing intel_rps_is_active() guard and executes gen6_gt_pm_unmask_irq(); 4) GT is parked and runtime PM wakelock is dropped, so only a raw reference in __gt_park() -> intel_display_power_put_async() remains for 100ms, then the MMIO write in gen6_gt_pm_unmask_irq() detects missing wakelock via assert_rpm_wakelock_held() and emits "RPM wakelock ref not held during HW access" tainting kernel. Commit 3e7abf814193 ("drm/i915: Extract GT render power state management") dropped the "if (rps->interrupts_enabled)" guard that gen6_pm_rps_work() had around this unmask in i915_irq.c. INTEL_RPS_ACTIVE brackets the same window, since it is set in intel_rps_unpark() before rps_enable_interrupts() and rps_start_timer() and cleared in intel_rps_park() before rps_stop_timer() and rps_disable_interrupts(). Skip unmasking when RPS is no longer active (reaching unmask operation is independent of INTERRUPT mode). This does not prevent RPS operation from resuming on the next unpark. In interrupt mode, intel_rps_unpark() calls rps_enable_interrupts(), which enables and unmasks the PM interrupts. In timer mode, it calls rps_start_timer(), restarting periodic engine-busyness evaluation. The timer generates software RPS events and queues rps_work() directly, independently of PM interrupt delivery. Neither mode requires the late worker to unmask interrupts while the GT is parked Fixes: 3e7abf814193 ("drm/i915: Extract GT render power state management") Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/16562 Cc: stable@vger.kernel.org # v5.5+ Assisted-by: GitHub-Copilot:claude-opus-5 Assisted-by: GitHub-Copilot:gpt-6-astra Signed-off-by: Krzysztof Karas Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patch.msgid.link/20260910081329.3300417-1-krzysztof.karas@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index a33b19c04737..0f9b4f1dd3cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1904,7 +1904,8 @@ static void rps_work(struct work_struct *work) out: spin_lock_irq(gt->irq_lock); - gen6_gt_pm_unmask_irq(gt, rps->pm_events); + if (intel_rps_is_active(rps)) + gen6_gt_pm_unmask_irq(gt, rps->pm_events); spin_unlock_irq(gt->irq_lock); }