Skip to content

Commit 551507e

Browse files
alessiob-imgMTCoster
authored andcommitted
drm/imagination: Clear runtime PM errors while resetting the GPU
The runtime PM might be left in error state if one of the callbacks returned an error, e.g. if the (auto)suspend callback failed following a firmware crash. When that happens, any further attempt to acquire or release a power reference will then also fail, making it impossible to do anything else with the GPU. The driver logic will eventually reach the reset code. In pvr_power_reset(), replace pvr_power_get() with a new API pvr_power_get_clear() which also attempts to clear any runtime PM error state if acquiring a power reference is not possible. Signed-off-by: Alessio Belle <alessio.belle@imgtec.com> Reviewed-by: Matt Coster <matt.coster@imgtec.com> Link: https://lore.kernel.org/r/20250624-clear-rpm-errors-gpu-reset-v1-1-b8ff2ae55aac@imgtec.com Signed-off-by: Matt Coster <matt.coster@imgtec.com>
1 parent c03ea34 commit 551507e

1 file changed

Lines changed: 58 additions & 1 deletion

File tree

drivers/gpu/drm/imagination/pvr_power.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,63 @@ pvr_power_device_idle(struct device *dev)
340340
return pvr_power_is_idle(pvr_dev) ? 0 : -EBUSY;
341341
}
342342

343+
static int
344+
pvr_power_clear_error(struct pvr_device *pvr_dev)
345+
{
346+
struct device *dev = from_pvr_device(pvr_dev)->dev;
347+
int err;
348+
349+
/* Ensure the device state is known and nothing is happening past this point */
350+
pm_runtime_disable(dev);
351+
352+
/* Attempt to clear the runtime PM error by setting the current state again */
353+
if (pm_runtime_status_suspended(dev))
354+
err = pm_runtime_set_suspended(dev);
355+
else
356+
err = pm_runtime_set_active(dev);
357+
358+
if (err) {
359+
drm_err(from_pvr_device(pvr_dev),
360+
"%s: Failed to clear runtime PM error (new error %d)\n",
361+
__func__, err);
362+
}
363+
364+
pm_runtime_enable(dev);
365+
366+
return err;
367+
}
368+
369+
/**
370+
* pvr_power_get_clear() - Acquire a power reference, correcting any errors
371+
* @pvr_dev: Device pointer
372+
*
373+
* Attempt to acquire a power reference on the device. If the runtime PM
374+
* is in error state, attempt to clear the error and retry.
375+
*
376+
* Returns:
377+
* * 0 on success, or
378+
* * Any error code returned by pvr_power_get() or the runtime PM API.
379+
*/
380+
static int
381+
pvr_power_get_clear(struct pvr_device *pvr_dev)
382+
{
383+
int err;
384+
385+
err = pvr_power_get(pvr_dev);
386+
if (err == 0)
387+
return err;
388+
389+
drm_warn(from_pvr_device(pvr_dev),
390+
"%s: pvr_power_get returned error %d, attempting recovery\n",
391+
__func__, err);
392+
393+
err = pvr_power_clear_error(pvr_dev);
394+
if (err)
395+
return err;
396+
397+
return pvr_power_get(pvr_dev);
398+
}
399+
343400
/**
344401
* pvr_power_reset() - Reset the GPU
345402
* @pvr_dev: Device pointer
@@ -364,7 +421,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
364421
* Take a power reference during the reset. This should prevent any interference with the
365422
* power state during reset.
366423
*/
367-
WARN_ON(pvr_power_get(pvr_dev));
424+
WARN_ON(pvr_power_get_clear(pvr_dev));
368425

369426
down_write(&pvr_dev->reset_sem);
370427

0 commit comments

Comments
 (0)