/** * pvr_device_lost() - Mark GPU device as lost * @pvr_dev: Target PowerVR device. * * This will cause the DRM device to be unplugged.
*/ void
pvr_device_lost(struct pvr_device *pvr_dev)
{ if (!pvr_dev->lost) {
pvr_dev->lost = true;
drm_dev_unplug(from_pvr_device(pvr_dev));
}
}
bool
pvr_power_is_idle(struct pvr_device *pvr_dev)
{ /* * FW power state can be out of date if a KCCB command has been submitted but the FW hasn't * started processing it yet. So also check the KCCB status.
*/ enum rogue_fwif_pow_state pow_state = READ_ONCE(pvr_dev->fw_dev.fwif_sysdata->pow_state); bool kccb_idle = pvr_kccb_is_idle(pvr_dev);
if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed && !kccb_is_idle) {
pvr_dev->watchdog.kccb_stall_count++;
/* * If we have commands pending with no progress for 2 consecutive polls then * consider KCCB command processing stalled.
*/ if (pvr_dev->watchdog.kccb_stall_count == 2) {
pvr_dev->watchdog.kccb_stall_count = 0; returntrue;
}
} elseif (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed) { bool has_active_contexts;
int
pvr_power_device_resume(struct device *dev)
{ struct platform_device *plat_dev = to_platform_device(dev); struct drm_device *drm_dev = platform_get_drvdata(plat_dev); struct pvr_device *pvr_dev = to_pvr_device(drm_dev); int idx; int err;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
err = clk_prepare_enable(pvr_dev->core_clk); if (err) goto err_drm_dev_exit;
err = clk_prepare_enable(pvr_dev->sys_clk); if (err) goto err_core_clk_disable;
err = clk_prepare_enable(pvr_dev->mem_clk); if (err) goto err_sys_clk_disable;
/* * According to the hardware manual, a delay of at least 32 clock * cycles is required between de-asserting the clkgen reset and * de-asserting the GPU reset. Assuming a worst-case scenario with * a very high GPU clock frequency, a delay of 1 microsecond is * sufficient to ensure this requirement is met across all * feasible GPU clock speeds.
*/
udelay(1);
err = reset_control_deassert(pvr_dev->reset); if (err) goto err_mem_clk_disable;
if (pvr_dev->fw_dev.booted) {
err = pvr_power_fw_enable(pvr_dev); if (err) goto err_reset_assert;
}
/* Ensure the device state is known and nothing is happening past this point */
pm_runtime_disable(dev);
/* Attempt to clear the runtime PM error by setting the current state again */ if (pm_runtime_status_suspended(dev))
err = pm_runtime_set_suspended(dev); else
err = pm_runtime_set_active(dev);
if (err) {
drm_err(from_pvr_device(pvr_dev), "%s: Failed to clear runtime PM error (new error %d)\n",
__func__, err);
}
pm_runtime_enable(dev);
return err;
}
/** * pvr_power_get_clear() - Acquire a power reference, correcting any errors * @pvr_dev: Device pointer * * Attempt to acquire a power reference on the device. If the runtime PM * is in error state, attempt to clear the error and retry. * * Returns: * * 0 on success, or * * Any error code returned by pvr_power_get() or the runtime PM API.
*/ staticint
pvr_power_get_clear(struct pvr_device *pvr_dev)
{ int err;
err = pvr_power_get(pvr_dev); if (err == 0) return err;
drm_warn(from_pvr_device(pvr_dev), "%s: pvr_power_get returned error %d, attempting recovery\n",
__func__, err);
err = pvr_power_clear_error(pvr_dev); if (err) return err;
return pvr_power_get(pvr_dev);
}
/** * pvr_power_reset() - Reset the GPU * @pvr_dev: Device pointer * @hard_reset: %true for hard reset, %false for soft reset * * If @hard_reset is %false and the FW processor fails to respond during the reset process, this * function will attempt a hard reset. * * If a hard reset fails then the GPU device is reported as lost. * * Returns: * * 0 on success, or * * Any error code returned by pvr_power_get, pvr_power_fw_disable or pvr_power_fw_enable().
*/ int
pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
{ bool queues_disabled = false; int err;
/* * Take a power reference during the reset. This should prevent any interference with the * power state during reset.
*/
WARN_ON(pvr_power_get_clear(pvr_dev));
down_write(&pvr_dev->reset_sem);
if (pvr_dev->lost) {
err = -EIO; goto err_up_write;
}
/* Disable IRQs for the duration of the reset. */
disable_irq(pvr_dev->irq);
do { if (hard_reset) {
pvr_queue_device_pre_reset(pvr_dev);
queues_disabled = true;
}
err = pvr_power_fw_disable(pvr_dev, hard_reset); if (!err) { if (hard_reset) {
pvr_dev->fw_dev.booted = false;
WARN_ON(pvr_power_device_suspend(from_pvr_device(pvr_dev)->dev));
err = pvr_fw_hard_reset(pvr_dev); if (err) goto err_device_lost;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.