Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <alessio.belle@imgtec.com>
Reviewed-by: Matt Coster <matt.coster@imgtec.com>
Link: https://patch.msgid.link/20260310-drain-irqs-before-suspend-v1-2-bf4f9ed68e75@imgtec.com
Signed-off-by: Matt Coster <matt.coster@imgtec.com>

authored by

Alessio Belle and committed by
Matt Coster
74ef7844 2d7f05cd

+23 -10
+23 -10
drivers/gpu/drm/imagination/pvr_power.c
··· 92 92 static int 93 93 pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset, bool rpm_suspend) 94 94 { 95 - if (!hard_reset) { 96 - int err; 95 + int err; 97 96 97 + if (!hard_reset) { 98 98 cancel_delayed_work_sync(&pvr_dev->watchdog.work); 99 99 100 100 err = pvr_power_request_idle(pvr_dev); ··· 107 107 } 108 108 109 109 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); 112 112 } 113 113 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; 115 119 } 116 120 117 121 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) 119 123 { 120 124 int err; 121 125 126 + if (rpm_resume) 127 + enable_irq(pvr_dev->irq); 128 + 122 129 err = pvr_fw_start(pvr_dev); 123 130 if (err) 124 - return err; 131 + goto out; 125 132 126 133 err = pvr_wait_for_fw_boot(pvr_dev); 127 134 if (err) { 128 135 drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); 129 136 pvr_fw_stop(pvr_dev); 130 - return err; 137 + goto out; 131 138 } 132 139 133 140 queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, 134 141 msecs_to_jiffies(WATCHDOG_TIME_MS)); 135 142 136 143 return 0; 144 + 145 + out: 146 + if (rpm_resume) 147 + disable_irq(pvr_dev->irq); 148 + 149 + return err; 137 150 } 138 151 139 152 bool ··· 409 396 goto err_drm_dev_exit; 410 397 411 398 if (pvr_dev->fw_dev.booted) { 412 - err = pvr_power_fw_enable(pvr_dev); 399 + err = pvr_power_fw_enable(pvr_dev, true); 413 400 if (err) 414 401 goto err_power_off; 415 402 } ··· 568 555 569 556 pvr_fw_irq_clear(pvr_dev); 570 557 571 - err = pvr_power_fw_enable(pvr_dev); 558 + err = pvr_power_fw_enable(pvr_dev, false); 572 559 } 573 560 574 561 if (err && hard_reset)