drivers/gpu/drm/xe/xe_preempt_fence.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/xe/xe_preempt_fence.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/xe/xe_preempt_fence.c
Extension
.c
Size
5454 bytes
Lines
185
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 (err == -EAGAIN) {
			xe_gt_dbg(q->gt, "PREEMPT FENCE RETRY guc_id=%d",
				  q->guc->id);
			queue_work(q->vm->xe->preempt_fence_wq,
				   &pfence->preempt_work);
			dma_fence_end_signalling(cookie);
			return;
		}

		if (err)
			dma_fence_set_error(&pfence->base, err);
	} else {
		dma_fence_set_error(&pfence->base, -ENOENT);
	}

	dma_fence_signal(&pfence->base);
	/*
	 * Opt for keep everything in the fence critical section. This looks really strange since we
	 * have just signalled the fence, however the preempt fences are all signalled via single
	 * global ordered-wq, therefore anything that happens in this callback can easily block
	 * progress on the entire wq, which itself may prevent other published preempt fences from
	 * ever signalling.  Therefore try to keep everything here in the callback in the fence
	 * critical section. For example if something below grabs a scary lock like vm->lock,
	 * lockdep should complain since we also hold that lock whilst waiting on preempt fences to
	 * complete.
	 */
	xe_vm_queue_rebind_worker(q->vm);
	xe_exec_queue_put(q);
	dma_fence_end_signalling(cookie);
}

static const char *
preempt_fence_get_driver_name(struct dma_fence *fence)
{
	return "xe";
}

static const char *
preempt_fence_get_timeline_name(struct dma_fence *fence)
{
	return "preempt";
}

static bool preempt_fence_enable_signaling(struct dma_fence *fence)
{
	struct xe_preempt_fence *pfence =
		container_of(fence, typeof(*pfence), base);
	struct xe_exec_queue *q = pfence->q;

	pfence->error = q->ops->suspend(q);
	queue_work(q->vm->xe->preempt_fence_wq, &pfence->preempt_work);
	return true;
}

static const struct dma_fence_ops preempt_fence_ops = {
	.get_driver_name = preempt_fence_get_driver_name,
	.get_timeline_name = preempt_fence_get_timeline_name,
	.enable_signaling = preempt_fence_enable_signaling,
};

/**
 * xe_preempt_fence_alloc() - Allocate a preempt fence with minimal
 * initialization
 *
 * Allocate a preempt fence, and initialize its list head.
 * If the preempt_fence allocated has been armed with
 * xe_preempt_fence_arm(), it must be freed using dma_fence_put(). If not,
 * it must be freed using xe_preempt_fence_free().
 *
 * Return: A struct xe_preempt_fence pointer used for calling into
 * xe_preempt_fence_arm() or xe_preempt_fence_free().
 * An error pointer on error.
 */
struct xe_preempt_fence *xe_preempt_fence_alloc(void)
{
	struct xe_preempt_fence *pfence;

	pfence = kmalloc_obj(*pfence);
	if (!pfence)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&pfence->link);
	INIT_WORK(&pfence->preempt_work, preempt_fence_work_func);

	return pfence;
}

/**
 * xe_preempt_fence_free() - Free a preempt fence allocated using
 * xe_preempt_fence_alloc().

Annotation

Implementation Notes