Skip to content

Commit 74ef784

Browse files
alessiob-imgMTCoster
authored andcommitted
drm/imagination: Disable interrupts before suspending the GPU
This is an additional safety layer to ensure no accesses to the GPU registers can be made while it is powered off. While we can disable IRQ generation from GPU, META firmware, MIPS firmware and for safety events, we cannot do the same for the RISC-V firmware. To keep a unified approach, once the firmware has completed its power off sequence, disable IRQs for the while GPU at the kernel level instead. Signed-off-by: Alessio Belle <[email protected]> Reviewed-by: Matt Coster <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Matt Coster <[email protected]>
1 parent 2d7f05c commit 74ef784

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

drivers/gpu/drm/imagination/pvr_power.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ pvr_power_request_pwr_off(struct pvr_device *pvr_dev)
9292
static int
9393
pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspend)
9494
{
95-
if (!hard_reset) {
96-
int err;
95+
int err;
9796

97+
if (!hard_reset) {
9898
cancel_delayed_work_sync(&pvr_dev->watchdog.work);
9999

100100
err = pvr_power_request_idle(pvr_dev);
@@ -107,33 +107,46 @@ pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspe
107107
}
108108

109109
if (rpm_suspend) {
110-
/* Wait for late processing of GPU or firmware IRQs in other cores */
111-
synchronize_irq(pvr_dev->irq);
110+
/* This also waits for late processing of GPU or firmware IRQs in other cores */
111+
disable_irq(pvr_dev->irq);
112112
}
113113

114-
return pvr_fw_stop(pvr_dev);
114+
err = pvr_fw_stop(pvr_dev);
115+
if (err && rpm_suspend)
116+
enable_irq(pvr_dev->irq);
117+
118+
return err;
115119
}
116120

117121
static int
118-
pvr_power_fw_enable(struct pvr_device *pvr_dev)
122+
pvr_power_fw_enable(struct pvr_device *pvr_dev, bool rpm_resume)
119123
{
120124
int err;
121125

126+
if (rpm_resume)
127+
enable_irq(pvr_dev->irq);
128+
122129
err = pvr_fw_start(pvr_dev);
123130
if (err)
124-
return err;
131+
goto out;
125132

126133
err = pvr_wait_for_fw_boot(pvr_dev);
127134
if (err) {
128135
drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n");
129136
pvr_fw_stop(pvr_dev);
130-
return err;
137+
goto out;
131138
}
132139

133140
queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work,
134141
msecs_to_jiffies(WATCHDOG_TIME_MS));
135142

136143
return 0;
144+
145+
out:
146+
if (rpm_resume)
147+
disable_irq(pvr_dev->irq);
148+
149+
return err;
137150
}
138151

139152
bool
@@ -396,7 +409,7 @@ pvr_power_device_resume(struct device *dev)
396409
goto err_drm_dev_exit;
397410

398411
if (pvr_dev->fw_dev.booted) {
399-
err = pvr_power_fw_enable(pvr_dev);
412+
err = pvr_power_fw_enable(pvr_dev, true);
400413
if (err)
401414
goto err_power_off;
402415
}
@@ -555,7 +568,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
555568

556569
pvr_fw_irq_clear(pvr_dev);
557570

558-
err = pvr_power_fw_enable(pvr_dev);
571+
err = pvr_power_fw_enable(pvr_dev, false);
559572
}
560573

561574
if (err && hard_reset)

0 commit comments

Comments
 (0)