drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c
Extension
.c
Size
10292 bytes
Lines
431
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 (state == NVKM_CGRP_RC_PENDING) {
			/* Disable all channels in them, and remove from runlist. */
			nvkm_cgrp_foreach_chan_safe(chan, ctmp, cgrp) {
				nvkm_chan_error(chan, false);
				nvkm_chan_remove_locked(chan);
			}
		}
	}

	/* On GPUs with runlist preempt, wait for PBDMA(s) servicing runlist to go idle. */
	if (runl->func->preempt) {
		for (i = 0; i < runl->runq_nr; i++) {
			struct nvkm_runq *runq = runl->runq[i];

			if (runq) {
				nvkm_msec(fifo->engine.subdev.device, 2000,
					if (runq->func->idle(runq))
						break;
				);
			}
		}
	}

	/* Look for engines that are still on flagged channel groups - reset them. */
	nvkm_runl_foreach_engn_cond(engn, runl, engn->func->cxid) {
		cgrp = nvkm_engn_cgrp_get(engn, &flags);
		if (!cgrp) {
			ENGN_DEBUG(engn, "cxid not valid");
			continue;
		}

		reset = atomic_read(&cgrp->rc) == NVKM_CGRP_RC_RUNNING;
		nvkm_cgrp_put(&cgrp, flags);
		if (!reset) {
			ENGN_DEBUG(engn, "cxid not in recovery");
			continue;
		}

		ENGN_DEBUG(engn, "resetting...");
		/*TODO: can we do something less of a potential catastrophe on failure? */
		WARN_ON(nvkm_engine_reset(engn->engine));
	}

	/* Submit runlist update, and clear any remaining exception state. */
	runl->func->update(runl);
	if (runl->func->fault_clear)
		runl->func->fault_clear(runl);

	/* Unblock runlist processing. */
	while (rc--)
		nvkm_runl_allow(runl);
	runl->func->wait(runl);
}

static void
nvkm_runl_rc_runl(struct nvkm_runl *runl)
{
	RUNL_ERROR(runl, "rc scheduled");

	nvkm_runl_block(runl);
	if (runl->func->preempt)
		runl->func->preempt(runl);

	atomic_inc(&runl->rc_pending);
	schedule_work(&runl->work);
}

void
nvkm_runl_rc_cgrp(struct nvkm_cgrp *cgrp)
{
	if (atomic_cmpxchg(&cgrp->rc, NVKM_CGRP_RC_NONE, NVKM_CGRP_RC_PENDING) != NVKM_CGRP_RC_NONE)
		return;

	CGRP_ERROR(cgrp, "rc scheduled");
	nvkm_runl_rc_runl(cgrp->runl);
}

void
nvkm_runl_rc_engn(struct nvkm_runl *runl, struct nvkm_engn *engn)
{
	struct nvkm_cgrp *cgrp;
	unsigned long flags;

	/* Lookup channel group currently on engine. */
	cgrp = nvkm_engn_cgrp_get(engn, &flags);
	if (!cgrp) {
		ENGN_DEBUG(engn, "rc skipped, not on channel");
		return;
	}

Annotation

Implementation Notes