drivers/gpu/drm/scheduler/sched_entity.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/scheduler/sched_entity.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/scheduler/sched_entity.c
Extension
.c
Size
19042 bytes
Lines
641
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 (s_fence && f == &s_fence->scheduled) {
			/* The dependencies array had a reference on the scheduled
			 * fence, and the finished fence refcount might have
			 * dropped to zero. Use dma_fence_get_rcu() so we get
			 * a NULL fence in that case.
			 */
			f = dma_fence_get_rcu(&s_fence->finished);

			/* Now that we have a reference on the finished fence,
			 * we can release the reference the dependencies array
			 * had on the scheduled fence.
			 */
			dma_fence_put(&s_fence->scheduled);
		}

		xa_erase(&job->dependencies, index);
		if (f && !dma_fence_add_callback(f, &job->finish_cb,
						 drm_sched_entity_kill_jobs_cb))
			return;

		dma_fence_put(f);
	}

	drm_sched_fence_scheduled(job->s_fence, NULL);
	drm_sched_fence_finished(job->s_fence, -ESRCH);
	WARN_ON(job->s_fence->parent);
	job->sched->ops->free_job(job);
}

/* Signal the scheduler finished fence when the entity in question is killed. */
static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
					  struct dma_fence_cb *cb)
{
	struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
						 finish_cb);

	dma_fence_put(f);

	INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
	schedule_work(&job->work);
}

/**
 * drm_sched_entity_kill - kill an entity's pending jobs and remove it
 * @entity: the entity to remove
 *
 * Removes the entity from the scheduler's run queue and kills all pending jobs.
 *
 * This function should be used over drm_sched_entity_flush() if it is not
 * desired to actually wait for all pending jobs to finish.
 */
void drm_sched_entity_kill(struct drm_sched_entity *entity)
{
	struct drm_sched_job *job;
	struct dma_fence *prev;

	if (!entity->rq)
		return;

	spin_lock(&entity->lock);
	entity->stopped = true;
	drm_sched_rq_remove_entity(entity->rq, entity);
	spin_unlock(&entity->lock);

	/* Make sure this entity is not used by the scheduler at the moment */
	wait_for_completion(&entity->entity_idle);

	/* The entity is guaranteed to not be used by the scheduler */
	prev = rcu_dereference_check(entity->last_scheduled, true);
	dma_fence_get(prev);
	while ((job = drm_sched_entity_queue_pop(entity))) {
		struct drm_sched_fence *s_fence = job->s_fence;

		dma_fence_get(&s_fence->finished);
		if (!prev ||
		    dma_fence_add_callback(prev, &job->finish_cb,
					   drm_sched_entity_kill_jobs_cb)) {
			/*
			 * Adding callback above failed.
			 * dma_fence_put() checks for NULL.
			 */
			dma_fence_put(prev);
			drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb);
		}

		prev = &s_fence->finished;
	}
	dma_fence_put(prev);
}
EXPORT_SYMBOL(drm_sched_entity_kill);

Annotation

Implementation Notes