summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imagination/pvr_power.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-03-20 18:21:27 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-03-20 18:21:27 -0700
commita0c83177734ab98623795e1ba2cf4b72c23de5e7 (patch)
tree4226283eafe1d11029da957c2bd37e410e337bd3 /drivers/gpu/drm/imagination/pvr_power.c
parent42bddab0563fe67882b2722620a66dd98c8dbf33 (diff)
parenta6e77320badd1444b0429ff8b6f338b750a1dc4f (diff)
Merge tag 'drm-fixes-2026-03-21' of https://gitlab.freedesktop.org/drm/kernelmaster
Pull drm fixes from Dave Airlie: "Regular weekly pull request, from sunny San Diego. Usual suspects in xe/i915/amdgpu with small fixes all over, then some minor fixes across a few other drivers. It's probably a bit on the heavy side, but most of the fix seem well contained, core: - drm_dev_unplug UAF fix pagemap: - lock handling fix xe: - A number of teardown fixes - Skip over non-leaf PTE for PRL generation - Fix an uninitialized variable - Fix a missing runtime PM reference i915/display: - Fix #15771: Screen corruption and stuttering on P14s w/ 3K display - Fix for PSR entry setup frames count on rejected commit - Fix OOPS if firmware is not loaded and suspend is attempted - Fix unlikely NULL deref due to DC6 on probe amdgpu: - Fix gamma 2.2 colorop TFs - BO list fix - LTO fix - DC FP fix - DisplayID handling fix - DCN 2.01 fix - MMHUB boundary fixes - ISP fix - TLB fence fix - Hainan pm fix radeon: - Hainan pm fix vmwgfx: - memory leak fix - doc warning fix imagination: - deadlock fix - interrupt handling fixes dw-hdmi-qp: - multi channel audio fix" * tag 'drm-fixes-2026-03-21' of https://gitlab.freedesktop.org/drm/kernel: (40 commits) drm/xe: Fix missing runtime PM reference in ccs_mode_store drm/xe: Open-code GGTT MMIO access protection drm/xe/lrc: Fix uninitialized new_ts when capturing context timestamp drm/xe/oa: Allow reading after disabling OA stream drm/xe: Skip over non leaf pte for PRL generation drm/xe/guc: Ensure CT state transitions via STOP before DISABLED drm/xe: Trigger queue cleanup if not in wedged mode 2 drm/xe: Forcefully tear down exec queues in GuC submit fini drm/xe: Always kill exec queues in xe_guc_submit_pause_abort drm/xe/guc: Fail immediately on GuC load error drm/i915/gt: Check set_default_submission() before deferencing drm/radeon: apply state adjust rules to some additional HAINAN vairants drm/amdgpu: apply state adjust rules to some additional HAINAN vairants drm/amdgpu: rework how we handle TLB fences drm/bridge: dw-hdmi-qp: fix multi-channel audio output drm: Fix use-after-free on framebuffers and property blobs when calling drm_dev_unplug drm/amdgpu: Fix ISP segfault issue in kernel v7.0 drm/amdgpu/gmc9.0: add bounds checking for cid drm/amdgpu/mmhub4.2.0: add bounds checking for cid drm/amdgpu/mmhub4.1.0: add bounds checking for cid ...
Diffstat (limited to 'drivers/gpu/drm/imagination/pvr_power.c')
-rw-r--r--drivers/gpu/drm/imagination/pvr_power.c51
1 files changed, 39 insertions, 12 deletions
diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c
index 0cf7393f89c6..3ec4ec4276e4 100644
--- a/drivers/gpu/drm/imagination/pvr_power.c
+++ b/drivers/gpu/drm/imagination/pvr_power.c
@@ -90,11 +90,11 @@ pvr_power_request_pwr_off(struct pvr_device *pvr_dev)
}
static int
-pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset)
+pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspend)
{
- if (!hard_reset) {
- int err;
+ int err;
+ if (!hard_reset) {
cancel_delayed_work_sync(&pvr_dev->watchdog.work);
err = pvr_power_request_idle(pvr_dev);
@@ -106,29 +106,47 @@ pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset)
return err;
}
- return pvr_fw_stop(pvr_dev);
+ if (rpm_suspend) {
+ /* This also waits for late processing of GPU or firmware IRQs in other cores */
+ disable_irq(pvr_dev->irq);
+ }
+
+ err = pvr_fw_stop(pvr_dev);
+ if (err && rpm_suspend)
+ enable_irq(pvr_dev->irq);
+
+ return err;
}
static int
-pvr_power_fw_enable(struct pvr_device *pvr_dev)
+pvr_power_fw_enable(struct pvr_device *pvr_dev, bool rpm_resume)
{
int err;
+ if (rpm_resume)
+ enable_irq(pvr_dev->irq);
+
err = pvr_fw_start(pvr_dev);
if (err)
- return err;
+ goto out;
err = pvr_wait_for_fw_boot(pvr_dev);
if (err) {
drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n");
pvr_fw_stop(pvr_dev);
- return err;
+ goto out;
}
queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work,
msecs_to_jiffies(WATCHDOG_TIME_MS));
return 0;
+
+out:
+ if (rpm_resume)
+ disable_irq(pvr_dev->irq);
+
+ return err;
}
bool
@@ -361,7 +379,7 @@ pvr_power_device_suspend(struct device *dev)
return -EIO;
if (pvr_dev->fw_dev.booted) {
- err = pvr_power_fw_disable(pvr_dev, false);
+ err = pvr_power_fw_disable(pvr_dev, false, true);
if (err)
goto err_drm_dev_exit;
}
@@ -391,7 +409,7 @@ pvr_power_device_resume(struct device *dev)
goto err_drm_dev_exit;
if (pvr_dev->fw_dev.booted) {
- err = pvr_power_fw_enable(pvr_dev);
+ err = pvr_power_fw_enable(pvr_dev, true);
if (err)
goto err_power_off;
}
@@ -510,7 +528,16 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
}
/* Disable IRQs for the duration of the reset. */
- disable_irq(pvr_dev->irq);
+ if (hard_reset) {
+ disable_irq(pvr_dev->irq);
+ } else {
+ /*
+ * Soft reset is triggered as a response to a FW command to the Host and is
+ * processed from the threaded IRQ handler. This code cannot (nor needs to)
+ * wait for any IRQ processing to complete.
+ */
+ disable_irq_nosync(pvr_dev->irq);
+ }
do {
if (hard_reset) {
@@ -518,7 +545,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
queues_disabled = true;
}
- err = pvr_power_fw_disable(pvr_dev, hard_reset);
+ err = pvr_power_fw_disable(pvr_dev, hard_reset, false);
if (!err) {
if (hard_reset) {
pvr_dev->fw_dev.booted = false;
@@ -541,7 +568,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
pvr_fw_irq_clear(pvr_dev);
- err = pvr_power_fw_enable(pvr_dev);
+ err = pvr_power_fw_enable(pvr_dev, false);
}
if (err && hard_reset)