From 3b347d011773d147b62f84ec60a7824629148be2 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Wed, 27 May 2026 09:50:47 -0400 Subject: [PATCH 01/24] drm/amdkfd: fix SMI event cross-process information leak kfd_smi_ev_enabled() skips the suser privilege check when pid=0. PROCESS_START, PROCESS_END, and VMFAULT events are emitted with pid=0 while carrying another process's PID and command name, so any /dev/kfd user in the render group can monitor all GPU workloads. Pass the target process PID into kfd_smi_event_add() for these events so the existing per-client filter restricts delivery to the owning process or CAP_SYS_ADMIN subscribers. Signed-off-by: Yongqiang Sun Acked-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit 92a8dba246d371fe268280e5fd74b0955688e6df) --- drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index 15975c23a88e..dfbde5a571f6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -254,8 +254,10 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid) if (task_info) { /* Report VM faults from user applications, not retry from kernel */ if (task_info->task.pid) - kfd_smi_event_add(0, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT( - task_info->task.pid, task_info->task.comm)); + kfd_smi_event_add(task_info->tgid, dev, + KFD_SMI_EVENT_VMFAULT, + KFD_EVENT_FMT_VMFAULT(task_info->task.pid, + task_info->task.comm)); amdgpu_vm_put_task_info(task_info); } } @@ -356,7 +358,7 @@ void kfd_smi_event_process(struct kfd_process_device *pdd, bool start) task_info = amdgpu_vm_get_task_info_vm(avm); if (task_info) { - kfd_smi_event_add(0, pdd->dev, + kfd_smi_event_add(task_info->tgid, pdd->dev, start ? KFD_SMI_EVENT_PROCESS_START : KFD_SMI_EVENT_PROCESS_END, KFD_EVENT_FMT_PROCESS(task_info->task.pid, From d097095dda7449f85d963911584112555071b2f5 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Sat, 13 Sep 2025 16:51:02 +0200 Subject: [PATCH 02/24] drm/amdgpu/userq: Fix reading timeline points in wait ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use correct u64 type. Signed-off-by: David Rosca Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit 0ac98160dfb6ab3c6d7b38e0ff9687780beed9cb) --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index a41fb72dba94..f74ad378e407 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -593,7 +593,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, static int amdgpu_userq_wait_count_fences(struct drm_file *filp, struct drm_amdgpu_userq_wait *wait_info, - u32 *syncobj_handles, u32 *timeline_points, + u32 *syncobj_handles, u64 *timeline_points, u32 *timeline_handles, struct drm_gem_object **gobj_write, struct drm_gem_object **gobj_read) @@ -703,7 +703,7 @@ amdgpu_userq_wait_add_fence(struct drm_amdgpu_userq_wait *wait_info, static int amdgpu_userq_wait_return_fence_info(struct drm_file *filp, struct drm_amdgpu_userq_wait *wait_info, - u32 *syncobj_handles, u32 *timeline_points, + u32 *syncobj_handles, u64 *timeline_points, u32 *timeline_handles, struct drm_gem_object **gobj_write, struct drm_gem_object **gobj_read) @@ -906,7 +906,8 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { int num_points, num_syncobj, num_read_bo_handles, num_write_bo_handles; - u32 *syncobj_handles, *timeline_points, *timeline_handles; + u32 *syncobj_handles, *timeline_handles; + u64 *timeline_points; struct drm_amdgpu_userq_wait *wait_info = data; struct drm_gem_object **gobj_write; struct drm_gem_object **gobj_read; @@ -935,7 +936,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, } ptr = u64_to_user_ptr(wait_info->syncobj_timeline_points); - timeline_points = memdup_array_user(ptr, num_points, sizeof(u32)); + timeline_points = memdup_array_user(ptr, num_points, sizeof(u64)); if (IS_ERR(timeline_points)) { r = PTR_ERR(timeline_points); goto free_timeline_handles; From 40396ffdf6120e2380706c59e1a84d7e765a37b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 25 Feb 2026 15:12:02 +0100 Subject: [PATCH 03/24] drm/amdgpu: restart the CS if some parts of the VM are still invalidated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that we only submit work with full up to date VM page tables. Backport to 7.1 and older. Signed-off-by: Christian König Reviewed-by: Vitaly Prosyak Tested-by: Vitaly Prosyak Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit 59720bfd8c6dbebeb8d5a7ab64241b007efd9213) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index b24d5d21be5f..583fd67a2c64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1277,6 +1277,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_job *leader = p->gang_leader; + struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_list_entry *e; struct drm_gem_object *gobj; unsigned long index; @@ -1322,7 +1323,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_hmm_range_free(e->range); e->range = NULL; } - if (r) { + + if (r || !list_empty(&vm->invalidated)) { r = -EAGAIN; mutex_unlock(&p->adev->notifier_lock); return r; From 9c6ffdb41fa5dcf47a262c656e9f443d0d26049c Mon Sep 17 00:00:00 2001 From: Sunday Clement Date: Tue, 19 May 2026 10:02:30 -0400 Subject: [PATCH 04/24] drm/amdkfd: Add bounds check for AMDKFD_IOC_WAIT_EVENTS The kfd_wait_on_events ioctl passes a user-supplied num_events parameter directly to alloc_event_waiters() which calls kcalloc() without validation. This allows unprivileged users with /dev/kfd access to trigger large kernel memory allocations, potentially causing memory exhaustion and denial of service via the OOM killer. Add a check to reject num_events values exceeding KFD_SIGNAL_EVENT_LIMIT (4096), which is the maximum number of events a single process can create. Signed-off-by: Sunday Clement Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alex Deucher (cherry picked from commit 39eb6da7acee8d0cc12a8959235b590f295d7b4c) --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 44150a71ffd5..e65b323aafbf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -795,6 +795,8 @@ static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events) struct kfd_event_waiter *event_waiters; uint32_t i; + if (num_events > KFD_SIGNAL_EVENT_LIMIT) + return NULL; event_waiters = kzalloc_objs(struct kfd_event_waiter, num_events); if (!event_waiters) return NULL; From a50676d5a72a26829d4885ff7d62df8d82f462b1 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Tue, 2 Jun 2026 09:59:44 -0400 Subject: [PATCH 05/24] drm/amdkfd: Unwind debug trap enable on copy_to_user failure If kfd_dbg_trap_enable() fails while copying runtime_info to userspace, it had already activated the trap, set debug_trap_enabled, taken an extra process reference, and opened the debug event file. Return -EFAULT without unwinding that state, leaving inconsistent trap state and a refcount imbalance that could break later DISABLE/ENABLE. On copy_to_user failure, deactivate the trap and undo the rest of the enable setup before returning. Signed-off-by: Yongqiang Sun Acked-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit 01112e241e37f9ac98b6f418d93ce2e0b87b7ee0) --- drivers/gpu/drm/amd/amdkfd/kfd_debug.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c index 0f7aa51b629e..0dd1fd448059 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c @@ -832,6 +832,12 @@ int kfd_dbg_trap_enable(struct kfd_process *target, uint32_t fd, if (copy_to_user(runtime_info, (void *)&target->runtime_info, copy_size)) { kfd_dbg_trap_deactivate(target, false, 0); + fput(target->dbg_ev_file); + target->dbg_ev_file = NULL; + if (target->debugger_process) + atomic_dec(&target->debugger_process->debugged_process_count); + target->debug_trap_enabled = false; + kfd_unref_process(target); r = -EFAULT; } From 2eeb342aff66477e0db9833a6393e581a6dac4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 18 May 2026 17:48:09 +0200 Subject: [PATCH 06/24] drm/amd/display: Consult MCCS FreeSync cap only if requested & supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the do_mccs parameter is false, we don't call dm_helpers_read_mccs_caps, so sink->mccs_caps.freesync_supported is unlikely to be true. Fixes: 6f71d5dd3206 ("drm/amd/display: Read sink freesync support via mccs") Bug: https://gitlab.freedesktop.org/drm/amd/-/work_items/5286 Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher (cherry picked from commit 115bf5ca318e18a3dc1888ec6271c7052774952a) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5fc5d5608506..122982b7a7b9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -13446,17 +13446,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } /* Handle MCCS */ - if (do_mccs) + if (do_mccs) { dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); - if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || - as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && - (!sink->edid_caps.freesync_vcp_code || - (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) - freesync_capable = false; + if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported) + freesync_capable = false; - if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable) - dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + if (sink->mccs_caps.freesync_supported && freesync_capable) + dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + } update: if (dm_con_state) From 3f26bb732cc136ab20176697c92f32c9c84cb125 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Sun, 7 Jun 2026 09:03:03 +0000 Subject: [PATCH 07/24] drm/virtio: fix dma_fence refcount leak on error in virtio_gpu_dma_fence_wait() dma_fence_unwrap_for_each() internally calls dma_fence_unwrap_first() which does cursor->chain = dma_fence_get(head), taking an extra reference. On normal loop completion, dma_fence_unwrap_next() releases this via dma_fence_chain_walk() -> dma_fence_put(). When virtio_gpu_do_fence_wait() fails and the function returns early from inside the loop, the cursor->chain reference is never released. This is the only caller in the entire kernel that does an early return inside dma_fence_unwrap_for_each. Add dma_fence_put(itr.chain) before the early return. Cc: stable@vger.kernel.org Fixes: eba57fb5498f ("drm/virtio: Wait for each dma-fence of in-fence array individually") Signed-off-by: Wentao Liang Reviewed-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://patch.msgid.link/20260607090303.92423-1-vulab@iscas.ac.cn --- drivers/gpu/drm/virtio/virtgpu_submit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c index dae761fa5788..32cb1e4aa425 100644 --- a/drivers/gpu/drm/virtio/virtgpu_submit.c +++ b/drivers/gpu/drm/virtio/virtgpu_submit.c @@ -65,8 +65,10 @@ static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit, dma_fence_unwrap_for_each(f, &itr, fence) { err = virtio_gpu_do_fence_wait(submit, f); - if (err) + if (err) { + dma_fence_put(itr.chain); return err; + } } return 0; From d9faef564438d1e4579c692c046603e7ada7bdf4 Mon Sep 17 00:00:00 2001 From: Andrzej Kacprowski Date: Mon, 1 Jun 2026 18:16:43 +0200 Subject: [PATCH 08/24] accel/ivpu: Fix signed integer truncation in IPC receive Fix potential buffer overflow where firmware-supplied data_size is cast to signed int before being used in min_t(). Large unsigned values (>= 0x80000000) become negative, causing unsigned wraparound and oversized memcpy operations that can overflow the stack buffer. Change min_t(int, ...) to min() as both values are unsigned and can be handled by min() without explicit cast. Fixes: 3b434a3445ff ("accel/ivpu: Use threaded IRQ to handle JOB done messages") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Andrzej Kacprowski Reviewed-by: Karol Wachowski Signed-off-by: Karol Wachowski Link: https://patch.msgid.link/20260601161643.229342-1-andrzej.kacprowski@linux.intel.com --- drivers/accel/ivpu/ivpu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index f47df092bb0d..9347f05a2b79 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -276,7 +276,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, if (ipc_buf) memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf)); if (rx_msg->jsm_msg) { - u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg)); + u32 size = min(rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg)); if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { ivpu_err(vdev, "IPC resp result error: %d\n", rx_msg->jsm_msg->result); From 2673cefa99ca918e7ac5b0388ff578a83656c896 Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Fri, 29 May 2026 17:57:58 +0300 Subject: [PATCH 09/24] drm/i915/edp: Check supported link rates DPCD read intel_edp_set_sink_rates() reads DP_SUPPORTED_LINK_RATES into a local stack array and then parses the array unconditionally. If the read fails, the array contents are not valid and may result in bogus sink link rates being used. Use drm_dp_dpcd_read_data() and clear the sink rate array on failure, so the existing parser falls back to the default sink rate handling. Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: 68f357cb7347 ("drm/i915/dp: generate and cache sink rate array for all DP, not just eDP 1.4") Signed-off-by: Nikita Zhandarovich Reviewed-by: Jani Nikula Link: https://patch.msgid.link/20260529145759.1640646-1-n.zhandarovich@fintech.ru Signed-off-by: Jani Nikula (cherry picked from commit bd61c7756b34157e093028225a69383b4b1203cc) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/display/intel_dp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6ef2a0043cda..5c3e816b0135 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4678,10 +4678,17 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) if (intel_dp->edp_dpcd[0] >= DP_EDP_14) { __le16 sink_rates[DP_MAX_SUPPORTED_RATES]; + int ret; int i; - drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES, - sink_rates, sizeof(sink_rates)); + ret = drm_dp_dpcd_read_data(&intel_dp->aux, + DP_SUPPORTED_LINK_RATES, + sink_rates, sizeof(sink_rates)); + if (ret < 0) { + drm_dbg_kms(display->drm, + "Unable to read eDP supported link rates, using default rates\n"); + memset(sink_rates, 0, sizeof(sink_rates)); + } for (i = 0; i < ARRAY_SIZE(sink_rates); i++) { int rate; From f329e8325e054bd6d84d10904f8dd51137281b92 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 4 Jun 2026 15:27:43 +0300 Subject: [PATCH 10/24] drm/virtio: Fix driver removal with disabled KMS DRM atomic and modesetting aren't initialized if virtio-gpu driver built with disabled KMS, leading to access of uninitialized data on driver removal/unbinding and crashing kernel. Fix it by skipping shutting down atomic core with unavailable KMS. Fixes: 72122c69d717 ("drm/virtio: Add option to disable KMS support") Signed-off-by: Dmitry Osipenko Tested-by: Ryosuke Yasuoka Reviewed-by: Ryosuke Yasuoka Link: https://patch.msgid.link/20260604122743.13383-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/virtio/virtgpu_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index a5ce96fb8a1d..9af740bda835 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -124,7 +124,10 @@ static void virtio_gpu_remove(struct virtio_device *vdev) struct drm_device *dev = vdev->priv; drm_dev_unplug(dev); - drm_atomic_helper_shutdown(dev); + + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) + drm_atomic_helper_shutdown(dev); + virtio_gpu_deinit(dev); drm_dev_put(dev); } From 5d563a5da8717629ae72f9eadf1e0e340bd1658b Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sat, 6 Jun 2026 14:38:10 +0200 Subject: [PATCH 11/24] drm/vc4: fix krealloc() memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't just overwrite the original pointer passed to krealloc() with its return value without checking latter: MEM = krealloc(MEM, SZ, GFP); If krealloc() returns NULL, that erases the pointer to the still allocated memory, hence leaks this memory. Instead, use a temporary variable, check it's not NULL and only then assign it to the original pointer: TMP = krealloc(MEM, SZ, GFP); if (!TMP) return; MEM = TMP; While on it, use krealloc_array(). Fixes: 6d45c81d229d ("drm/vc4: Add support for branching in shader validation.") Signed-off-by: Alexander A. Klimov Signed-off-by: Maíra Canal Link: https://patch.msgid.link/20260606123817.37222-1-grandmaster@al2klimov.de --- drivers/gpu/drm/vc4/vc4_validate_shaders.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c index d48cf76983c0..66502a6a4a8e 100644 --- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c +++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c @@ -290,15 +290,16 @@ static bool require_uniform_address_uniform(struct vc4_validated_shader_info *va { uint32_t o = validated_shader->num_uniform_addr_offsets; uint32_t num_uniforms = validated_shader->uniforms_size / 4; + u32 *offsets; - validated_shader->uniform_addr_offsets = - krealloc(validated_shader->uniform_addr_offsets, - (o + 1) * - sizeof(*validated_shader->uniform_addr_offsets), - GFP_KERNEL); - if (!validated_shader->uniform_addr_offsets) + offsets = krealloc_array(validated_shader->uniform_addr_offsets, + o + 1, + sizeof(*validated_shader->uniform_addr_offsets), + GFP_KERNEL); + if (!offsets) return false; + validated_shader->uniform_addr_offsets = offsets; validated_shader->uniform_addr_offsets[o] = num_uniforms; validated_shader->num_uniform_addr_offsets++; From d21ad938398bca695a511307de38a65889e3b354 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 10 Jun 2026 09:03:14 +0300 Subject: [PATCH 12/24] drm/i915/gem: Fix phys BO pread/pwrite with offset sg_page() returns struct page pointer not (void *) so the scaling of pread/pwrite is wrong for phys BO and wrong parts of BO would be accessed if non-zero offset is used. Last impacted platform with overlay or cursor planes using phys mapping was Gen3/945G/Lakeport. Reported-by: Matthew Wilcox (Oracle) Fixes: c6790dc22312 ("drm/i915: Wean off drm_pci_alloc/drm_pci_free") Cc: # v4.5+ Cc: Tvrtko Ursulin Cc: Simona Vetter Cc: Jani Nikula Cc: Rodrigo Vivi Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: https://patch.msgid.link/20260610060314.26111-1-joonas.lahtinen@linux.intel.com (cherry picked from commit 3e49a2f85070b2fb672c1e0fdba281a4ea3aebe6) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c index e375afbf458e..d53129eb5603 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -18,6 +18,17 @@ #include "i915_gem_tiling.h" #include "i915_scatterlist.h" +/* Abuse scatterlist to store pointer instead of struct page. */ +static inline void __set_phys_vaddr(struct scatterlist *sg, void *vaddr) +{ + sg_assign_page(sg, (struct page *)vaddr); +} + +static inline void *__get_phys_vaddr(struct scatterlist *sg) +{ + return (void *)sg_page(sg); +} + static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) { struct address_space *mapping = obj->base.filp->f_mapping; @@ -58,7 +69,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) sg->offset = 0; sg->length = obj->base.size; - sg_assign_page(sg, (struct page *)vaddr); + __set_phys_vaddr(sg, vaddr); sg_dma_address(sg) = dma; sg_dma_len(sg) = obj->base.size; @@ -99,7 +110,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, struct sg_table *pages) { dma_addr_t dma = sg_dma_address(pages->sgl); - void *vaddr = sg_page(pages->sgl); + void *vaddr = __get_phys_vaddr(pages->sgl); __i915_gem_object_release_shmem(obj, pages, false); @@ -139,7 +150,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj, const struct drm_i915_gem_pwrite *args) { - void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; + void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset; char __user *user_data = u64_to_user_ptr(args->data_ptr); struct drm_i915_private *i915 = to_i915(obj->base.dev); int err; @@ -170,7 +181,7 @@ int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj, int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj, const struct drm_i915_gem_pread *args) { - void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; + void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset; char __user *user_data = u64_to_user_ptr(args->data_ptr); int err; From e480228cf65583040c894bb9cc02e1d5b328cee0 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Tue, 9 Jun 2026 12:20:18 +0200 Subject: [PATCH 13/24] drm/colorop: Remove read-only comments from interpolation fields The lut1d_interpolation and lut3d_interpolation fields and their associated properties were marked as read-only, but userspace can set them via drm_atomic_colorop_set_property(). Fixes: 7fa3ee8c0a79 ("drm/colorop: Define LUT_1D interpolation") Fixes: db971856bbe0 ("drm/colorop: Add 3D LUT support to color pipeline") Reviewed-by: Chaitanya Kumar Borah Signed-off-by: Alex Hung Fixes: 9ba25915efba ("drm/amd/display: Add support for sRGB EOTF in DEGAM block") Signed-off-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patch.msgid.link/20260609110420.1298352-2-mwen@igalia.com --- include/drm/drm_colorop.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h index bd082854ca74..61cc8206b4c4 100644 --- a/include/drm/drm_colorop.h +++ b/include/drm/drm_colorop.h @@ -309,7 +309,6 @@ struct drm_colorop { /** * @lut1d_interpolation: * - * Read-only * Interpolation for DRM_COLOROP_1D_LUT */ enum drm_colorop_lut1d_interpolation_type lut1d_interpolation; @@ -317,7 +316,6 @@ struct drm_colorop { /** * @lut3d_interpolation: * - * Read-only * Interpolation for DRM_COLOROP_3D_LUT */ enum drm_colorop_lut3d_interpolation_type lut3d_interpolation; @@ -325,7 +323,7 @@ struct drm_colorop { /** * @lut1d_interpolation_property: * - * Read-only property for DRM_COLOROP_1D_LUT interpolation + * Property for DRM_COLOROP_1D_LUT interpolation */ struct drm_property *lut1d_interpolation_property; @@ -353,7 +351,7 @@ struct drm_colorop { /** * @lut3d_interpolation_property: * - * Read-only property for DRM_COLOROP_3D_LUT interpolation + * Property for DRM_COLOROP_3D_LUT interpolation */ struct drm_property *lut3d_interpolation_property; From 94ff735296d371045fce163451a3d65e44ac4729 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Tue, 9 Jun 2026 12:20:19 +0200 Subject: [PATCH 14/24] drm/colorop: make lut(1/3)d_interpolation props correctly behave as mutable As interpolation props are actually mutable props, any changes should be handled by drm_colorop_state. Move their enum and make it correctly behaves as mutable. Fixes: 7fa3ee8c0a79 ("drm/colorop: Define LUT_1D interpolation") Fixes: db971856bbe0 ("drm/colorop: Add 3D LUT support to color pipeline") Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Alex Hung Fixes: 9ba25915efba ("drm/amd/display: Add support for sRGB EOTF in DEGAM block") Signed-off-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patch.msgid.link/20260609110420.1298352-3-mwen@igalia.com --- drivers/gpu/drm/drm_atomic.c | 4 ++-- drivers/gpu/drm/drm_atomic_uapi.c | 8 ++++---- drivers/gpu/drm/drm_colorop.c | 16 ++++++++++++++-- include/drm/drm_colorop.h | 28 ++++++++++++++-------------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 41c57063f3b4..0eb52d1d5af2 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -830,7 +830,7 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p, case DRM_COLOROP_1D_LUT: drm_printf(p, "\tsize=%d\n", colorop->size); drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation)); + drm_get_colorop_lut1d_interpolation_name(state->lut1d_interpolation)); drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); break; case DRM_COLOROP_CTM_3X4: @@ -842,7 +842,7 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p, case DRM_COLOROP_3D_LUT: drm_printf(p, "\tsize=%d\n", colorop->size); drm_printf(p, "\tinterpolation=%s\n", - drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation)); + drm_get_colorop_lut3d_interpolation_name(state->lut3d_interpolation)); drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0); break; default: diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 5bd5bf6661df..b81dbba4d8c3 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -751,13 +751,13 @@ static int drm_atomic_colorop_set_property(struct drm_colorop *colorop, if (property == colorop->bypass_property) { state->bypass = val; } else if (property == colorop->lut1d_interpolation_property) { - colorop->lut1d_interpolation = val; + state->lut1d_interpolation = val; } else if (property == colorop->curve_1d_type_property) { state->curve_1d_type = val; } else if (property == colorop->multiplier_property) { state->multiplier = val; } else if (property == colorop->lut3d_interpolation_property) { - colorop->lut3d_interpolation = val; + state->lut3d_interpolation = val; } else if (property == colorop->data_property) { return drm_atomic_color_set_data_property(colorop, state, property, val); @@ -782,7 +782,7 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop, else if (property == colorop->bypass_property) *val = state->bypass; else if (property == colorop->lut1d_interpolation_property) - *val = colorop->lut1d_interpolation; + *val = state->lut1d_interpolation; else if (property == colorop->curve_1d_type_property) *val = state->curve_1d_type; else if (property == colorop->multiplier_property) @@ -790,7 +790,7 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop, else if (property == colorop->size_property) *val = colorop->size; else if (property == colorop->lut3d_interpolation_property) - *val = colorop->lut3d_interpolation; + *val = state->lut3d_interpolation; else if (property == colorop->data_property) *val = (state->data) ? state->data->base.id : 0; else diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c index 566816e3c6f0..509678e5371f 100644 --- a/drivers/gpu/drm/drm_colorop.c +++ b/drivers/gpu/drm/drm_colorop.c @@ -342,7 +342,6 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_color colorop->lut1d_interpolation_property = prop; drm_object_attach_property(&colorop->base, prop, interpolation); - colorop->lut1d_interpolation = interpolation; /* data */ ret = drm_colorop_create_data_prop(dev, colorop); @@ -442,7 +441,6 @@ int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *col colorop->lut3d_interpolation_property = prop; drm_object_attach_property(&colorop->base, prop, interpolation); - colorop->lut3d_interpolation = interpolation; /* data */ ret = drm_colorop_create_data_prop(dev, colorop); @@ -521,6 +519,20 @@ static void __drm_colorop_state_reset(struct drm_colorop_state *colorop_state, &val); colorop_state->curve_1d_type = val; } + + if (colorop->lut1d_interpolation_property) { + if (!drm_object_property_get_default_value(&colorop->base, + colorop->lut1d_interpolation_property, + &val)) + colorop_state->lut1d_interpolation = val; + } + + if (colorop->lut3d_interpolation_property) { + if (!drm_object_property_get_default_value(&colorop->base, + colorop->lut3d_interpolation_property, + &val)) + colorop_state->lut3d_interpolation = val; + } } /** diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h index 61cc8206b4c4..d5b45339333f 100644 --- a/include/drm/drm_colorop.h +++ b/include/drm/drm_colorop.h @@ -183,6 +183,20 @@ struct drm_colorop_state { */ struct drm_property_blob *data; + /** + * @lut1d_interpolation: + * + * Interpolation for DRM_COLOROP_1D_LUT + */ + enum drm_colorop_lut1d_interpolation_type lut1d_interpolation; + + /** + * @lut3d_interpolation: + * + * Interpolation for DRM_COLOROP_3D_LUT + */ + enum drm_colorop_lut3d_interpolation_type lut3d_interpolation; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; }; @@ -306,20 +320,6 @@ struct drm_colorop { */ uint32_t size; - /** - * @lut1d_interpolation: - * - * Interpolation for DRM_COLOROP_1D_LUT - */ - enum drm_colorop_lut1d_interpolation_type lut1d_interpolation; - - /** - * @lut3d_interpolation: - * - * Interpolation for DRM_COLOROP_3D_LUT - */ - enum drm_colorop_lut3d_interpolation_type lut3d_interpolation; - /** * @lut1d_interpolation_property: * From 2e235e2a2784b12b735321e5b42240ca51c49b0f Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Tue, 9 Jun 2026 12:20:20 +0200 Subject: [PATCH 15/24] drm/atomic: track individual colorop updates As we do for CRTC color mgmt properties, use color_mgmt_changed flag to track any value changes in the color pipeline of a given plane, so that drivers can update color blocks as soon as plane color pipeline or individual colorop values change. Since we're here, only announce and track changes to plane COLOR_PIPELINE prop if its value is actually changing. Fixes: 8c5ea1745f4c ("drm/colorop: Add BYPASS property") Fixes: 7fa3ee8c0a79 ("drm/colorop: Define LUT_1D interpolation") Fixes: 41651f9d42eb ("drm/colorop: Add 1D Curve subtype") Fixes: 3410108037d5 ("drm/colorop: Add multiplier type") Fixes: db971856bbe0 ("drm/colorop: Add 3D LUT support to color pipeline") Fixes: e5719e7f1900 ("drm/colorop: Add 3x4 CTM type") Fixes: 99a4e4f08abe ("drm/colorop: Add 1D Curve Custom LUT type") Fixes: 2afc3184f3b3 ("drm/plane: Add COLOR PIPELINE property") Reviewed-by: Harry Wentland #v1 Reviewed-by: Chaitanya Kumar Borah Reviewed-by: Alex Hung Fixes: 9ba25915efba ("drm/amd/display: Add support for sRGB EOTF in DEGAM block") Signed-off-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patch.msgid.link/20260609110420.1298352-4-mwen@igalia.com --- drivers/gpu/drm/drm_atomic_uapi.c | 64 ++++++++++++++++++++++++------- include/drm/drm_atomic_uapi.h | 4 +- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index b81dbba4d8c3..5eaf0e8a494b 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -265,13 +265,19 @@ EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); * * Helper function to select the color pipeline on a plane by setting * it to the first drm_colorop element of the pipeline. + * + * Return: true if plane color pipeline value changed, false otherwise. */ -void +bool drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state, struct drm_colorop *colorop) { struct drm_plane *plane = plane_state->plane; + /* Color pipeline didn't change */ + if (plane_state->color_pipeline == colorop) + return false; + if (colorop) drm_dbg_atomic(plane->dev, "Set [COLOROP:%d] for [PLANE:%d:%s] state %p\n", @@ -283,6 +289,8 @@ drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state, plane->base.id, plane->name, plane_state); plane_state->color_pipeline = colorop; + + return true; } EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane); @@ -604,7 +612,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, if (val && !colorop) return -EACCES; - drm_atomic_set_colorop_for_plane(state, colorop); + state->color_mgmt_changed |= drm_atomic_set_colorop_for_plane(state, colorop); } else if (property == config->prop_fb_damage_clips) { ret = drm_property_replace_blob_from_id(dev, &state->fb_damage_clips, @@ -713,11 +721,11 @@ drm_atomic_plane_get_property(struct drm_plane *plane, static int drm_atomic_color_set_data_property(struct drm_colorop *colorop, struct drm_colorop_state *state, struct drm_property *property, - uint64_t val) + uint64_t val, + bool *replaced) { ssize_t elem_size = -1; ssize_t size = -1; - bool replaced = false; switch (colorop->type) { case DRM_COLOROP_1D_LUT: @@ -739,28 +747,45 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop, &state->data, val, -1, size, elem_size, - &replaced); + replaced); } static int drm_atomic_colorop_set_property(struct drm_colorop *colorop, struct drm_colorop_state *state, struct drm_file *file_priv, struct drm_property *property, - uint64_t val) + uint64_t val, + bool *replaced) { if (property == colorop->bypass_property) { - state->bypass = val; + if (state->bypass != val) { + state->bypass = val; + *replaced = true; + } } else if (property == colorop->lut1d_interpolation_property) { - state->lut1d_interpolation = val; + if (state->lut1d_interpolation != val) { + state->lut1d_interpolation = val; + *replaced = true; + } } else if (property == colorop->curve_1d_type_property) { - state->curve_1d_type = val; + if (state->curve_1d_type != val) { + state->curve_1d_type = val; + *replaced = true; + } } else if (property == colorop->multiplier_property) { - state->multiplier = val; + if (state->multiplier != val) { + state->multiplier = val; + *replaced = true; + } } else if (property == colorop->lut3d_interpolation_property) { - state->lut3d_interpolation = val; + if (state->lut3d_interpolation != val) { + state->lut3d_interpolation = val; + *replaced = true; + } } else if (property == colorop->data_property) { return drm_atomic_color_set_data_property(colorop, state, - property, val); + property, val, + replaced); } else { drm_dbg_atomic(colorop->dev, "[COLOROP:%d:%d] unknown property [PROP:%d:%s]\n", @@ -1275,8 +1300,10 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } case DRM_MODE_OBJECT_COLOROP: { + struct drm_plane_state *plane_state; struct drm_colorop *colorop = obj_to_colorop(obj); struct drm_colorop_state *colorop_state; + bool replaced = false; colorop_state = drm_atomic_get_colorop_state(state, colorop); if (IS_ERR(colorop_state)) { @@ -1285,7 +1312,18 @@ int drm_atomic_set_property(struct drm_atomic_state *state, } ret = drm_atomic_colorop_set_property(colorop, colorop_state, - file_priv, prop, prop_value); + file_priv, prop, prop_value, + &replaced); + if (ret || !replaced) + break; + + plane_state = drm_atomic_get_plane_state(state, colorop->plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + break; + } + plane_state->color_mgmt_changed |= replaced; + break; } default: diff --git a/include/drm/drm_atomic_uapi.h b/include/drm/drm_atomic_uapi.h index 436315523326..4e7e78f711e2 100644 --- a/include/drm/drm_atomic_uapi.h +++ b/include/drm/drm_atomic_uapi.h @@ -29,6 +29,8 @@ #ifndef DRM_ATOMIC_UAPI_H_ #define DRM_ATOMIC_UAPI_H_ +#include + struct drm_crtc_state; struct drm_display_mode; struct drm_property_blob; @@ -50,7 +52,7 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb); -void drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state, +bool drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state, struct drm_colorop *colorop); int __must_check drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, From d79716401a954677a93c4dd51fec65beccb38296 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Tue, 9 Jun 2026 12:20:21 +0200 Subject: [PATCH 16/24] drm/amd/display: use plane color_mgmt_changed to track colorop changes Ensure the driver tracks changes in any colorop property of a plane color pipeline by using the same mechanism of CRTC color management and update plane color blocks when any colorop property changes. It fixes an issue observed on gamescope settings for night mode which is done via shaper/3D-LUT updates. Fixes: 9ba25915efba ("drm/amd/display: Add support for sRGB EOTF in DEGAM block") Reviewed-by: Harry Wentland Reviewed-by: Alex Hung Signed-off-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patch.msgid.link/20260609110420.1298352-5-mwen@igalia.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index e96a12ff2d31..d3237f61246c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10067,7 +10067,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, continue; bundle->surface_updates[planes_count].surface = dc_plane; - if (new_pcrtc_state->color_mgmt_changed) { + if (new_pcrtc_state->color_mgmt_changed || new_plane_state->color_mgmt_changed) { bundle->surface_updates[planes_count].gamma = &dc_plane->gamma_correction; bundle->surface_updates[planes_count].in_transfer_func = &dc_plane->in_transfer_func; bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; @@ -11808,6 +11808,10 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (new_crtc_state->color_mgmt_changed) return true; + /* Plane color pipeline or its colorop changes. */ + if (new_plane_state->color_mgmt_changed) + return true; + /* * On zpos change, planes need to be reordered by removing and re-adding * them one by one to the dc state, in order of descending zpos. From 68938cc08e23a94fd881e845837ff918de005ce7 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 15 May 2026 19:09:20 +0300 Subject: [PATCH 17/24] drm/xe/display: fix oops in suspend/shutdown without display The xe driver keeps track of whether to probe display, and whether display hardware is there, using xe->info.probe_display. It gets set to false if there's no display after intel_display_device_probe(). However, the display may also be disabled via fuses, detected at a later time in intel_display_device_info_runtime_init(). In this case, the xe driver does for_each_intel_crtc() on uninitialized mode config in xe_display_flush_cleanup_work(), leading to a NULL pointer dereference, and generally calls display code with display info cleared. Check for intel_display_device_present() after intel_display_device_info_runtime_init(), and reset xe->info.probe_display as necessary. Also do unset_display_features() for completeness, although display runtime init has already done that. This will need to be unified across all cases later. Move intel_display_device_info_runtime_init() call slightly earlier, similar to i915, to avoid a bunch of unnecessary setup for no display cases. Note #1: The xe driver has no business doing low level display plumbing like for_each_intel_crtc() to begin with. It all needs to happen in display code. Note #2: The actual bug is present already in commit 44e694958b95 ("drm/xe/display: Implement display support"), but the oops was likely introduced later at commit ddf6492e0e50 ("drm/xe/display: Make display suspend/resume work on discrete"). Fixes: 44e694958b95 ("drm/xe/display: Implement display support") Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7904 Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/6150 Cc: stable@vger.kernel.org # v6.8+ Reviewed-by: Suraj Kandpal Link: https://patch.msgid.link/20260515160920.1082842-1-jani.nikula@intel.com Signed-off-by: Jani Nikula (cherry picked from commit 7c3eb9f47533220888a67266448185fd0775d4da) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/display/xe_display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 00dfa68af29a..b17fb698d2f8 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -124,6 +124,15 @@ int xe_display_init_early(struct xe_device *xe) intel_display_driver_early_probe(display); + intel_display_device_info_runtime_init(display); + + /* Display may have been disabled at runtime init */ + if (!intel_display_device_present(display)) { + xe->info.probe_display = false; + unset_display_features(xe); + return 0; + } + /* Early display init.. */ intel_opregion_setup(display); @@ -137,8 +146,6 @@ int xe_display_init_early(struct xe_device *xe) intel_bw_init_hw(display); - intel_display_device_info_runtime_init(display); - err = intel_display_driver_probe_noirq(display); if (err) goto err_opregion; From 4dcfcdc9fbb5efef21e149adf349d42d84c9da04 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:42 +0530 Subject: [PATCH 18/24] drm/xe/drm_ras: Make counter allocation drm managed cleanup_node_param() is not registered for previous node in case of counter allocation failure, which results in stale memory of previous node that isn't cleaned up on unwind. Fix this using drm managed allocation, which is guaranteed to be cleaned up on unwind. Fixes: b40db12b542f ("drm/xe/xe_drm_ras: Add support for XE DRM RAS") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-3-raag.jadav@intel.com Signed-off-by: Matt Roper (cherry picked from commit 58d77c77ea0c5cb2b755ebe23e973c8272acd896) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_drm_ras.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index e07dc23a155e..7357100034e2 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -52,7 +52,7 @@ static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *x struct xe_drm_ras_counter *counter; int i; - counter = kcalloc(DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL); + counter = drmm_kcalloc(&xe->drm, DRM_XE_RAS_ERR_COMP_MAX, sizeof(*counter), GFP_KERNEL); if (!counter) return ERR_PTR(-ENOMEM); @@ -104,7 +104,6 @@ static void cleanup_node_param(struct xe_drm_ras *ras, const enum drm_xe_ras_err { struct drm_ras_node *node = &ras->node[severity]; - kfree(ras->info[severity]); ras->info[severity] = NULL; kfree(node->device_name); From 3e3f5b0c5ae6845b4d8d23f079e872635cd8b0ae Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:43 +0530 Subject: [PATCH 19/24] drm/xe/drm_ras: Add per node cleanup action cleanup_node_param() is not registered for previous node in case of counter allocation failure, which results in stale memory of previous node that isn't cleaned up on unwind. Add per node cleanup action which guarantees cleanup on unwind and also simplifies the cleanup logic. Fixes: b40db12b542f ("drm/xe/xe_drm_ras: Add support for XE DRM RAS") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-4-raag.jadav@intel.com Signed-off-by: Matt Roper (cherry picked from commit 67fc5543d8274b2fcbef87734fad0469358f4478) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_drm_ras.c | 58 +++++++++++++-------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index 7357100034e2..c6cd32b7eeda 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -100,53 +100,47 @@ static int assign_node_params(struct xe_device *xe, struct drm_ras_node *node, return 0; } -static void cleanup_node_param(struct xe_drm_ras *ras, const enum drm_xe_ras_error_severity severity) +static void cleanup_node_param(struct drm_ras_node *node) { - struct drm_ras_node *node = &ras->node[severity]; - - ras->info[severity] = NULL; - kfree(node->device_name); node->device_name = NULL; } +static void cleanup_node(struct drm_device *drm, void *node) +{ + drm_ras_node_unregister(node); + cleanup_node_param(node); +} + static int register_nodes(struct xe_device *xe) { struct xe_drm_ras *ras = &xe->ras; - int i; + struct drm_ras_node *node; + int i, ret; for_each_error_severity(i) { - struct drm_ras_node *node = &ras->node[i]; - int ret; + node = &ras->node[i]; ret = assign_node_params(xe, node, i); - if (ret) { - cleanup_node_param(ras, i); - return ret; - } + if (ret) + goto free_param; ret = drm_ras_node_register(node); - if (ret) { - cleanup_node_param(ras, i); - return ret; - } + if (ret) + goto free_param; + + ret = drmm_add_action_or_reset(&xe->drm, cleanup_node, node); + if (ret) + goto null_info; } return 0; -} -static void xe_drm_ras_unregister_nodes(struct drm_device *device, void *arg) -{ - struct xe_device *xe = arg; - struct xe_drm_ras *ras = &xe->ras; - int i; - - for_each_error_severity(i) { - struct drm_ras_node *node = &ras->node[i]; - - drm_ras_node_unregister(node); - cleanup_node_param(ras, i); - } +free_param: + cleanup_node_param(node); +null_info: + ras->info[i] = NULL; + return ret; } /** @@ -175,11 +169,5 @@ int xe_drm_ras_init(struct xe_device *xe) return err; } - err = drmm_add_action_or_reset(&xe->drm, xe_drm_ras_unregister_nodes, xe); - if (err) { - drm_err(&xe->drm, "Failed to add action for Xe DRM RAS (%pe)\n", ERR_PTR(err)); - return err; - } - return 0; } From 381b3576a87f4ed6e76adb78d7d9400428f8f4b7 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 2 Jun 2026 10:18:44 +0530 Subject: [PATCH 20/24] drm/xe/hw_error: Use HW_ERR prefix in log Hardware errors should be logged with HW_ERR prefix. Make them consistent with existing logs. Fixes: 01aab7e1c9d4 ("drm/xe/xe_hw_error: Add support for PVC SoC errors") Signed-off-by: Raag Jadav Reviewed-by: Riana Tauro Link: https://patch.msgid.link/20260602044919.702209-5-raag.jadav@intel.com Signed-off-by: Matt Roper (cherry picked from commit ad60a618c49fef07d1860bfb1091140d29f5eddb) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_hw_error.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index 2a31b430570e..e869bc3948d9 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -219,9 +219,9 @@ static void log_hw_error(struct xe_tile *tile, const char *name, struct xe_device *xe = tile_to_xe(tile); if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s %s detected\n", name, severity_str); + drm_warn(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str); else - drm_err_ratelimited(&xe->drm, "%s %s detected\n", name, severity_str); + drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected\n", name, severity_str); } static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err, @@ -231,10 +231,10 @@ static void log_gt_err(struct xe_tile *tile, const char *name, int i, u32 err, struct xe_device *xe = tile_to_xe(tile); if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", + drm_warn(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", name, severity_str, i, err); else - drm_err_ratelimited(&xe->drm, "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", + drm_err_ratelimited(&xe->drm, HW_ERR "%s %s detected, ERROR_STAT_GT_VECTOR%d:0x%08x\n", name, severity_str, i, err); } @@ -251,9 +251,9 @@ static void log_soc_error(struct xe_tile *tile, const char * const *reg_info, if (strcmp(name, "Undefined")) { if (severity == DRM_XE_RAS_ERR_SEV_CORRECTABLE) - drm_warn(&xe->drm, "%s SOC %s detected", name, severity_str); + drm_warn(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str); else - drm_err_ratelimited(&xe->drm, "%s SOC %s detected", name, severity_str); + drm_err_ratelimited(&xe->drm, HW_ERR "%s SOC %s detected", name, severity_str); atomic_inc(&info[index].counter); } } From e4aaac46593733a06ec1a1f1a63128206d67fcaa Mon Sep 17 00:00:00 2001 From: Tangudu Tilak Tirumalesh Date: Mon, 8 Jun 2026 21:57:44 +0530 Subject: [PATCH 21/24] drm/xe: include all registered queues in TLB invalidation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context-based TLB invalidation currently selects only scheduling-active exec queues via q->ops->active(). During rebind flows, queues may be suspended (or transitioning through resume) while still owning valid translations, causing them to be skipped from invalidation and leading to missed TLB invalidations on LR rebinds. The underlying issue is a TOCTOU: q->guc->state bits are flipped lock-free from enable_scheduling(), disable_scheduling{,_deregister}(), the suspend/resume sched-msg handlers, handle_sched_done(), and guc_exec_queue_stop(); nothing in send_tlb_inval_ctx_ppgtt() serializes against them, so any state-based predicate can race. Include all the registered queues so that TLB invalidations are not missed. This is race-free because list membership on vm->exec_queues.list is stable under vm->exec_queues.lock held by the caller. The performance impact is expected to be minimal and harmless. If it does turn out to be a concern, we can come back with a race-safe solution to ignore certain queues. Fixes: 6cdaa5346d6f ("drm/xe: Add context-based invalidation to GuC TLB invalidation backend") Assisted-by: Claude:claude-opus-4.6 Suggested-by: Thomas Hellstrom Signed-off-by: Tangudu Tilak Tirumalesh Reviewed-by: Thomas Hellström Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20260608162745.338725-2-tilak.tirumalesh.tangudu@intel.com Signed-off-by: Shuicheng Lin (cherry picked from commit aa625e1e9f0710e424fe4f0e3f032807df81b5b0) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index ced58f46f846..cf6d106e6036 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -255,9 +255,8 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, #undef EXEC_QUEUE_COUNT_FULL_THRESHOLD /* - * Move exec queues to a temporary list to issue invalidations. The exec - * queue must active and a reference must be taken to prevent concurrent - * deregistrations. + * Move exec queues to a temporary list to issue invalidations. A + * reference must be taken to prevent concurrent deregistrations. * * List modification is safe because we hold 'vm->exec_queues.lock' for * reading, which prevents external modifications. Using a per-GT list @@ -266,7 +265,7 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, */ list_for_each_entry_safe(q, next, &vm->exec_queues.list[id], vm_exec_queue_link) { - if (q->ops->active(q) && xe_exec_queue_get_unless_zero(q)) { + if (xe_exec_queue_get_unless_zero(q)) { last_q = q; list_move_tail(&q->vm_exec_queue_link, &tlb_inval_list); } From ba36786b21d19082e696eda85bfcd49e7071944a Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Wed, 10 Jun 2026 10:27:05 -0700 Subject: [PATCH 22/24] drm/xe: fix refcount leak in xe_range_fence_insert() xe_range_fence_insert() acquires a reference on fence via dma_fence_get() and stores it in rfence->fence. It then calls dma_fence_add_callback() and handles two cases: when the callback is successfully registered (err == 0) the fence is transferred to the tree for later cleanup; when the fence is already signaled (err == -ENOENT) it manually drops the extra reference with dma_fence_put(fence). However, dma_fence_add_callback() can fail with other errors (e.g. -EINVAL) and in that case the code falls through to the free: label without releasing the acquired reference, leaking it. Fix the leak by adding an else branch that calls dma_fence_put() before jumping to free: for any error other than -ENOENT. Fixes: 845f64bdbfc9 ("drm/xe: Introduce a range-fence utility") Signed-off-by: Wentao Liang Reviewed-by: Matthew Brost Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260610172705.3450560-1-matthew.brost@intel.com (cherry picked from commit 98c4a4201290823c2c5c7ba21692bd9a64b61021) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_range_fence.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_range_fence.c b/drivers/gpu/drm/xe/xe_range_fence.c index 372378e89e98..3d8fa194a7b0 100644 --- a/drivers/gpu/drm/xe/xe_range_fence.c +++ b/drivers/gpu/drm/xe/xe_range_fence.c @@ -77,6 +77,8 @@ int xe_range_fence_insert(struct xe_range_fence_tree *tree, } else if (err == 0) { xe_range_fence_tree_insert(rfence, &tree->root); return 0; + } else { + dma_fence_put(fence); } free: From 347ccc0453fca2c669e8dc8a72000e76ca4adf10 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 10 Jun 2026 11:25:49 -0400 Subject: [PATCH 23/24] drm/xe: fix job timeout recovery for unstarted jobs and kernel queues A job that GuC never scheduled (never started) indicates a GuC scheduling failure; previously such jobs were silently errored out instead of triggering a GT reset to recover. Trigger a GT reset and resubmit them, but only when the queue was not already killed or banned: an unstarted job on an already banned queue is the ban working as intended and must neither clear the ban nor kick off a reset, otherwise a banned userspace queue could be resurrected and spam GT resets. Kernel queues are always recovered this way and wedge the device once recovery attempts are exhausted, since kernel work must not silently fail. A started job that times out on a userspace VM bind queue stays banned rather than being reset and retried. The queue is banned early in the timeout handler to signal the G2H scheduling-done handler so it wakes the disable-scheduling waiter; without it the waiter sleeps the full 5s timeout. When a reset is warranted the ban is cleared before rearming so that guc_exec_queue_start() can resubmit jobs after the GT reset - a still-banned queue would block resubmission and cause an infinite TDR loop. The already-banned case is gated out before this point via skip_timeout_check, so it is unaffected. v2: (Himal) Do it for any queue type, not just kernel/migration v3: - (Sashiko and Sanjay): don't clear the ban / GT reset for already killed/banned queues on unstarted-job timeout - Update commit message - (Matt) Add Fixes tag Fixes: fe05cee4d953 ("drm/xe: Don't short circuit TDR on jobs not started") Cc: Matthew Auld Cc: Matthew Brost Cc: Sanjay Yadav Cc: Himal Prasad Ghimiray Assisted-by: GitHub-Copilot:claude-sonnet-4.6 Assisted-by: GitHub-Copilot:claude-opus-4.8 Tested-by: Sanjay Yadav Reviewed-by: Sanjay Yadav Reviewed-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20260610152548.404575-3-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi (cherry picked from commit b1107d085e7e8ed15ba6f80c102528a9c8a6cb0e) Signed-off-by: Matthew Brost --- drivers/gpu/drm/xe/xe_guc_submit.c | 49 +++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index a4a8f0d41fe8..42110e01b7d0 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -157,6 +157,11 @@ static void set_exec_queue_banned(struct xe_exec_queue *q) atomic_or(EXEC_QUEUE_STATE_BANNED, &q->guc->state); } +static void clear_exec_queue_banned(struct xe_exec_queue *q) +{ + atomic_andnot(EXEC_QUEUE_STATE_BANNED, &q->guc->state); +} + static bool exec_queue_suspended(struct xe_exec_queue *q) { return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_SUSPENDED; @@ -1361,7 +1366,8 @@ static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job) xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), q->guc->id); - return xe_sched_invalidate_job(job, 2); + /* GuC never scheduled this job - let the caller trigger a GT reset. */ + return true; } ctx_timestamp = lower_32_bits(xe_lrc_timestamp(q->lrc[0])); @@ -1458,6 +1464,21 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate) G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); } +/* + * Recover via GT reset for a kernel queue, or for a GuC scheduling failure (job + * never started) on a queue that was not already killed or banned. An already + * banned queue must stay banned, so its unstarted jobs do not clear the ban or + * trigger a reset. + */ +static bool timeout_needs_gt_reset(struct xe_exec_queue *q, struct xe_sched_job *job, + bool skip_timeout_check) +{ + if (q->flags & EXEC_QUEUE_FLAG_KERNEL) + return true; + + return !skip_timeout_check && !xe_sched_job_started(job); +} + static enum drm_gpu_sched_stat guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) { @@ -1606,19 +1627,19 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), q->guc->id, q->flags); - /* - * Kernel jobs should never fail, nor should VM jobs if they do - * somethings has gone wrong and the GT needs a reset - */ - xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_KERNEL, - "Kernel-submitted job timed out\n"); - xe_gt_WARN(q->gt, q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q), - "VM job timed out on non-killed execqueue\n"); - if (!wedged && (q->flags & EXEC_QUEUE_FLAG_KERNEL || - (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)))) { - if (!xe_sched_invalidate_job(job, 2)) { - xe_gt_reset_async(q->gt); - goto rearm; + if (!wedged) { + if (timeout_needs_gt_reset(q, job, skip_timeout_check)) { + if (!xe_sched_invalidate_job(job, 2)) { + clear_exec_queue_banned(q); + xe_gt_reset_async(q->gt); + goto rearm; + } + if (q->flags & EXEC_QUEUE_FLAG_KERNEL) { + xe_gt_WARN(q->gt, true, "Kernel-submitted job timed out\n"); + xe_device_declare_wedged(gt_to_xe(q->gt)); + } + } else if (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)) { + xe_gt_WARN(q->gt, true, "VM job timed out on non-killed execqueue\n"); } } From 2f41af638c92bac6f1f9275ea2d1901baef578f3 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Wed, 10 Jun 2026 08:11:27 -0700 Subject: [PATCH 24/24] accel/amdxdna: Fix mm_struct reference leak in aie2_populate_range() aie2_populate_range() jumps back to the again label without calling mmput(mm), leaking a reference to the mm_struct. Add the missing mmput() before jumping to again. Fixes: e486147c912f ("accel/amdxdna: Add BO import and export") Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260610151127.2994185-1-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie2_ctx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 286379d9511d..eed3d0ec5413 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -999,6 +999,7 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo) if (ret == -EBUSY) { amdxdna_umap_put(mapp); + mmput(mm); goto again; } @@ -1009,11 +1010,13 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo) if (mmu_interval_read_retry(&mapp->notifier, mapp->range.notifier_seq)) { up_write(&xdna->notifier_lock); amdxdna_umap_put(mapp); + mmput(mm); goto again; } mapp->invalid = false; up_write(&xdna->notifier_lock); amdxdna_umap_put(mapp); + mmput(mm); goto again; put_mm: