drivers/accel/ethosu/ethosu_job.c

Source file repositories/reference/linux-study-clean/drivers/accel/ethosu/ethosu_job.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/ethosu/ethosu_job.c
Extension
.c
Size
13025 bytes
Lines
519
Domain
Driver Families
Bucket
drivers/accel
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 (dev->in_flight_job) {
			dma_fence_signal(dev->in_flight_job->done_fence);
			dev->in_flight_job = NULL;
		}
	}
}

static irqreturn_t ethosu_job_irq_handler_thread(int irq, void *data)
{
	struct ethosu_device *dev = data;

	ethosu_job_handle_irq(dev);

	return IRQ_HANDLED;
}

static irqreturn_t ethosu_job_irq_handler(int irq, void *data)
{
	struct ethosu_device *dev = data;
	u32 status = readl_relaxed(dev->regs + NPU_REG_STATUS);

	if (!(status & STATUS_IRQ_RAISED))
		return IRQ_NONE;

	writel_relaxed(CMD_CLEAR_IRQ, dev->regs + NPU_REG_CMD);
	return IRQ_WAKE_THREAD;
}

static enum drm_gpu_sched_stat ethosu_job_timedout(struct drm_sched_job *bad)
{
	struct ethosu_job *job = to_ethosu_job(bad);
	struct ethosu_device *dev = job->dev;
	bool running;
	u32 *bocmds = to_drm_gem_dma_obj(job->cmd_bo)->vaddr;
	u32 cmdaddr;

	cmdaddr = readl_relaxed(dev->regs + NPU_REG_QREAD);
	running = FIELD_GET(STATUS_STATE_RUNNING, readl_relaxed(dev->regs + NPU_REG_STATUS));

	if (running) {
		int ret;
		u32 reg;

		ret = readl_relaxed_poll_timeout(dev->regs + NPU_REG_QREAD,
						 reg,
						 reg != cmdaddr,
						 USEC_PER_MSEC, 100 * USEC_PER_MSEC);

		/* If still running and progress is being made, just return */
		if (!ret)
			return DRM_GPU_SCHED_STAT_NO_HANG;
	}

	dev_err(dev->base.dev, "NPU sched timed out: NPU %s, cmdstream offset 0x%x: 0x%x\n",
		running ? "running" : "stopped",
		cmdaddr, bocmds[cmdaddr / 4]);

	drm_sched_stop(&dev->sched, bad);

	scoped_guard(mutex, &dev->job_lock)
		dev->in_flight_job = NULL;

	/* Proceed with reset now. */
	pm_runtime_force_suspend(dev->base.dev);
	pm_runtime_force_resume(dev->base.dev);

	/* Restart the scheduler */
	drm_sched_start(&dev->sched, 0);

	return DRM_GPU_SCHED_STAT_RESET;
}

static const struct drm_sched_backend_ops ethosu_sched_ops = {
	.run_job = ethosu_job_run,
	.timedout_job = ethosu_job_timedout,
	.free_job = ethosu_job_free
};

int ethosu_job_init(struct ethosu_device *edev)
{
	struct device *dev = edev->base.dev;
	struct drm_sched_init_args args = {
		.ops = &ethosu_sched_ops,
		.credit_limit = 1,
		.timeout = msecs_to_jiffies(JOB_TIMEOUT_MS),
		.name = dev_name(dev),
		.dev = dev,
	};
	int ret;

Annotation

Implementation Notes