drivers/gpu/drm/imagination/pvr_device.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/imagination/pvr_device.c
Extension
.c
Size
25248 bytes
Lines
923
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (READ_ONCE(pvr_dev->fw_dev.initialised)) {
			pvr_fwccb_process(pvr_dev);
			pvr_kccb_wake_up_waiters(pvr_dev);
			pvr_device_process_active_queues(pvr_dev);
		}

		pm_runtime_mark_last_busy(drm_dev->dev);

		ret = IRQ_HANDLED;
	}

	if (pvr_dev->has_safety_events) {
		while (pvr_device_safety_irq_pending(pvr_dev)) {
			pvr_device_safety_irq_clear(pvr_dev);
			pvr_device_handle_safety_events(pvr_dev);

			ret = IRQ_HANDLED;
		}
	}

	return ret;
}

static irqreturn_t pvr_device_irq_handler(int irq, void *data)
{
	struct pvr_device *pvr_dev = data;
	bool safety_irq_pending = false;

	if (pvr_dev->has_safety_events)
		safety_irq_pending = pvr_device_safety_irq_pending(pvr_dev);

	if (!pvr_fw_irq_pending(pvr_dev) && !safety_irq_pending)
		return IRQ_NONE; /* Spurious IRQ - ignore. */

	return IRQ_WAKE_THREAD;
}

static void pvr_device_safety_irq_init(struct pvr_device *pvr_dev)
{
	u32 num_ecc_rams = 0;

	/*
	 * Safety events are an optional feature of the RogueXE platform. They
	 * are only enabled if at least one of ECC memory or the watchdog timer
	 * are present in HW. While safety events can be generated by other
	 * systems, that will never happen if the above mentioned hardware is
	 * not present.
	 */
	if (!PVR_HAS_FEATURE(pvr_dev, roguexe)) {
		pvr_dev->has_safety_events = false;
		return;
	}

	PVR_FEATURE_VALUE(pvr_dev, ecc_rams, &num_ecc_rams);

	pvr_dev->has_safety_events =
		num_ecc_rams > 0 || PVR_HAS_FEATURE(pvr_dev, watchdog_timer);
}

/**
 * pvr_device_irq_init() - Initialise IRQ required by a PowerVR device
 * @pvr_dev: Target PowerVR device.
 *
 * Returns:
 *  * 0 on success,
 *  * Any error returned by platform_get_irq_byname(), or
 *  * Any error returned by request_irq().
 */
static int
pvr_device_irq_init(struct pvr_device *pvr_dev)
{
	struct drm_device *drm_dev = from_pvr_device(pvr_dev);
	struct platform_device *plat_dev = to_platform_device(drm_dev->dev);

	init_waitqueue_head(&pvr_dev->kccb.rtn_q);

	pvr_device_safety_irq_init(pvr_dev);

	pvr_dev->irq = platform_get_irq(plat_dev, 0);
	if (pvr_dev->irq < 0)
		return pvr_dev->irq;

	/* Clear any pending events before requesting the IRQ line. */
	pvr_fw_irq_clear(pvr_dev);

	if (pvr_dev->has_safety_events)
		pvr_device_safety_irq_clear(pvr_dev);

	/*
	 * The ONESHOT flag ensures IRQs are masked while the thread handler is

Annotation

Implementation Notes