drivers/gpu/drm/imagination/pvr_power.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/imagination/pvr_power.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/imagination/pvr_power.c
Extension
.c
Size
16883 bytes
Lines
727
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (pvr_dev->watchdog.kccb_stall_count == 2) {
			pvr_dev->watchdog.kccb_stall_count = 0;
			return true;
		}
	} else if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed) {
		bool has_active_contexts;

		mutex_lock(&pvr_dev->queues.lock);
		has_active_contexts = list_empty(&pvr_dev->queues.active);
		mutex_unlock(&pvr_dev->queues.lock);

		if (has_active_contexts) {
			/* Send a HEALTH_CHECK command so we can verify FW is still alive. */
			struct rogue_fwif_kccb_cmd health_check_cmd;

			health_check_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_HEALTH_CHECK;

			pvr_kccb_send_cmd_powered(pvr_dev, &health_check_cmd, NULL);
		}
	} else {
		pvr_dev->watchdog.old_kccb_cmds_executed = kccb_cmds_executed;
		pvr_dev->watchdog.kccb_stall_count = 0;
	}

	return false;
}

static void
pvr_watchdog_worker(struct work_struct *work)
{
	struct pvr_device *pvr_dev = container_of(work, struct pvr_device,
						  watchdog.work.work);
	bool stalled;

	if (pvr_dev->lost)
		return;

	if (pm_runtime_get_if_in_use(from_pvr_device(pvr_dev)->dev) <= 0)
		goto out_requeue;

	if (!READ_ONCE(pvr_dev->fw_dev.initialised))
		goto out_pm_runtime_put;

	stalled = pvr_watchdog_kccb_stalled(pvr_dev);

	if (stalled) {
		drm_err(from_pvr_device(pvr_dev), "FW stalled, trying hard reset");

		pvr_power_reset(pvr_dev, true);
		/* Device may be lost at this point. */
	}

out_pm_runtime_put:
	pm_runtime_put(from_pvr_device(pvr_dev)->dev);

out_requeue:
	if (!pvr_dev->lost) {
		queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work,
				   msecs_to_jiffies(WATCHDOG_TIME_MS));
	}
}

/**
 * pvr_watchdog_init() - Initialise watchdog for device
 * @pvr_dev: Target PowerVR device.
 *
 * Returns:
 *  * 0 on success, or
 *  * -%ENOMEM on out of memory.
 */
int
pvr_watchdog_init(struct pvr_device *pvr_dev)
{
	INIT_DELAYED_WORK(&pvr_dev->watchdog.work, pvr_watchdog_worker);

	return 0;
}

static int pvr_power_init_manual(struct pvr_device *pvr_dev)
{
	struct drm_device *drm_dev = from_pvr_device(pvr_dev);
	struct reset_control *reset;

	reset = devm_reset_control_get_optional_exclusive(drm_dev->dev, NULL);
	if (IS_ERR(reset))
		return dev_err_probe(drm_dev->dev, PTR_ERR(reset),
				     "failed to get gpu reset line\n");

	pvr_dev->reset = reset;

Annotation

Implementation Notes