Merge tag 'drm-intel-fixes-2026-05-27' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-fixes

- Fix potential UAF in TTM object purge (Janusz Krzysztofik)
- Use polling when irqs are unavailable [aux] (Michał Grzelak)
- Fix HDR pre-CSC LUT programming loop [color] (Pranay Samala)
- Block DC states on vblank enable when Panel Replay supported [psr] (Jouni Högander)
- Use DC_OFF wake reference to block DC6 on vblank enable [psr] (Jouni Högander)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Tvrtko Ursulin <tursulin@igalia.com>
Link: https://patch.msgid.link/ahajfPMJE_qKzig5@linux
This commit is contained in:
Dave Airlie 2026-05-29 11:12:48 +10:00
commit 96c85df77f
7 changed files with 52 additions and 34 deletions

View File

@ -3976,7 +3976,7 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
intel_de_write_dsb(display, dsb,
PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0),
(1 << 24));
} while (i++ > 130);
} while (i++ < 130);
} else {
for (i = 0; i < lut_size; i++) {
u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1);

View File

@ -497,6 +497,7 @@ struct intel_display {
u8 vblank_enabled;
int vblank_enable_count;
bool vblank_status_last_notified;
struct work_struct vblank_notify_work;

View File

@ -1773,8 +1773,12 @@ static void intel_display_vblank_notify_work(struct work_struct *work)
struct intel_display *display =
container_of(work, typeof(*display), irq.vblank_notify_work);
int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count);
bool vblank_status = !!vblank_enable_count;
intel_psr_notify_vblank_enable_disable(display, vblank_enable_count);
if (display->irq.vblank_status_last_notified != vblank_status) {
intel_psr_notify_vblank_enable_disable(display, vblank_status);
display->irq.vblank_status_last_notified = vblank_status;
}
}
int bdw_enable_vblank(struct drm_crtc *_crtc)
@ -1787,10 +1791,10 @@ int bdw_enable_vblank(struct drm_crtc *_crtc)
if (gen11_dsi_configure_te(crtc, true))
return 0;
spin_lock_irqsave(&display->irq.lock, irqflags);
if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0)
schedule_work(&display->irq.vblank_notify_work);
spin_lock_irqsave(&display->irq.lock, irqflags);
bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK);
spin_unlock_irqrestore(&display->irq.lock, irqflags);

View File

@ -1790,6 +1790,8 @@ struct intel_psr {
u8 active_non_psr_pipes;
const char *no_psr_reason;
struct ref_tracker *vblank_wakeref;
};
struct intel_dp {

View File

@ -12,6 +12,7 @@
#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_dp_aux_regs.h"
#include "intel_parent.h"
#include "intel_pps.h"
#include "intel_quirks.h"
#include "intel_tc.h"
@ -60,18 +61,29 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
const unsigned int timeout_ms = 10;
bool done = true;
u32 status;
bool done;
int ret;
if (intel_parent_irq_enabled(display)) {
#define C (((status = intel_de_read_notrace(display, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
done = wait_event_timeout(display->gmbus.wait_queue, C,
msecs_to_jiffies_timeout(timeout_ms));
done = wait_event_timeout(display->gmbus.wait_queue, C,
msecs_to_jiffies_timeout(timeout_ms));
#undef C
} else {
ret = intel_de_wait_ms(display, ch_ctl,
DP_AUX_CH_CTL_SEND_BUSY, 0,
timeout_ms, &status);
if (ret == -ETIMEDOUT)
done = false;
}
if (!done)
drm_err(display->drm,
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
intel_dp->aux.name, timeout_ms, status);
#undef C
return status;
}

View File

@ -4156,27 +4156,22 @@ void intel_psr_notify_vblank_enable_disable(struct intel_display *display,
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_lock(&intel_dp->psr.lock);
if (intel_dp->psr.panel_replay_enabled) {
mutex_unlock(&intel_dp->psr.lock);
break;
if (CAN_PANEL_REPLAY(intel_dp)) {
if (enable)
intel_dp->psr.vblank_wakeref =
intel_display_power_get(display,
POWER_DOMAIN_DC_OFF);
else
intel_display_power_put(display, POWER_DOMAIN_DC_OFF,
intel_dp->psr.vblank_wakeref);
}
if (intel_dp->psr.enabled && intel_dp->psr.pkg_c_latency_used)
if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
intel_dp->psr.pkg_c_latency_used)
intel_psr_apply_underrun_on_idle_wa_locked(intel_dp);
mutex_unlock(&intel_dp->psr.lock);
return;
}
/*
* NOTE: intel_display_power_set_target_dc_state is used
* only by PSR * code for DC3CO handling. DC3CO target
* state is currently disabled in * PSR code. If DC3CO
* is taken into use we need take that into account here
* as well.
*/
intel_display_power_set_target_dc_state(display, enable ? DC_STATE_DISABLE :
DC_STATE_EN_UPTO_DC6);
}
static void

View File

@ -419,8 +419,6 @@ void i915_ttm_free_cached_io_rsgt(struct drm_i915_gem_object *obj)
int i915_ttm_purge(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
struct i915_ttm_tt *i915_tt =
container_of(bo->ttm, typeof(*i915_tt), ttm);
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = false,
@ -435,16 +433,22 @@ int i915_ttm_purge(struct drm_i915_gem_object *obj)
if (ret)
return ret;
if (bo->ttm && i915_tt->filp) {
/*
* The below fput(which eventually calls shmem_truncate) might
* be delayed by worker, so when directly called to purge the
* pages(like by the shrinker) we should try to be more
* aggressive and release the pages immediately.
*/
shmem_truncate_range(file_inode(i915_tt->filp),
0, (loff_t)-1);
fput(fetch_and_zero(&i915_tt->filp));
if (bo->ttm) {
struct i915_ttm_tt *i915_tt =
container_of(bo->ttm, typeof(*i915_tt), ttm);
if (i915_tt->filp) {
/*
* The below fput(which eventually calls shmem_truncate)
* might be delayed by worker, so when directly called
* to purge the pages(like by the shrinker) we should
* try to be more aggressive and release the pages
* immediately.
*/
shmem_truncate_range(file_inode(i915_tt->filp),
0, (loff_t)-1);
fput(fetch_and_zero(&i915_tt->filp));
}
}
obj->write_domain = 0;