drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
Extension
.c
Size
27044 bytes
Lines
997
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 (!dma_fence_is_signaled(f)) {
			dma_fence_set_error(f, -ECANCELED);
			dma_fence_signal(f);
		}

		list_del(&fence->link);
		dma_fence_put(f);
	}
	spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);

	/* Free seq64 memory */
	amdgpu_seq64_free(adev, fence_drv->va);
	kfree(fence_drv);
}

void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv)
{
	kref_get(&fence_drv->refcount);
}

void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv)
{
	kref_put(&fence_drv->refcount, amdgpu_userq_fence_driver_destroy);
}

static int amdgpu_userq_fence_alloc(struct amdgpu_usermode_queue *userq,
				    struct amdgpu_userq_fence **pfence)
{
	struct amdgpu_userq_fence_driver *fence_drv = userq->fence_drv;
	struct amdgpu_userq_fence *userq_fence;
	void *entry;

	userq_fence = kmalloc(sizeof(*userq_fence), GFP_KERNEL);
	if (!userq_fence)
		return -ENOMEM;

	/*
	 * Get the next unused entry, since we fill from the start this can be
	 * used as size to allocate the array.
	 */
	mutex_lock(&userq->fence_drv_lock);
	XA_STATE(xas, &userq->fence_drv_xa, 0);

	rcu_read_lock();
	do {
		entry = xas_find_marked(&xas, ULONG_MAX, XA_FREE_MARK);
	} while (xas_retry(&xas, entry));
	rcu_read_unlock();

	userq_fence->fence_drv_array = kvmalloc_array(xas.xa_index,
						      sizeof(fence_drv),
						      GFP_KERNEL);
	if (!userq_fence->fence_drv_array) {
		mutex_unlock(&userq->fence_drv_lock);
		kfree(userq_fence);
		return -ENOMEM;
	}

	userq_fence->fence_drv_array_count = xas.xa_index;
	xa_extract(&userq->fence_drv_xa, (void **)userq_fence->fence_drv_array,
		   0, ULONG_MAX, xas.xa_index, XA_PRESENT);
	xa_destroy(&userq->fence_drv_xa);

	mutex_unlock(&userq->fence_drv_lock);

	amdgpu_userq_fence_driver_get(fence_drv);
	userq_fence->fence_drv = fence_drv;

	*pfence = userq_fence;
	return 0;
}

static void amdgpu_userq_fence_init(struct amdgpu_usermode_queue *userq,
				    struct amdgpu_userq_fence *fence,
				    u64 seq)
{
	struct amdgpu_userq_fence_driver *fence_drv = userq->fence_drv;
	unsigned long flags;
	bool signaled = false;

	spin_lock_init(&fence->lock);
	dma_fence_init64(&fence->base, &amdgpu_userq_fence_ops, &fence->lock,
			 fence_drv->context, seq);

	/* Make sure the fence is visible to the hang detect worker */
	dma_fence_put(userq->last_fence);
	userq->last_fence = dma_fence_get(&fence->base);

	/* Check if hardware has already processed the fence */
	spin_lock_irqsave(&fence_drv->fence_list_lock, flags);

Annotation

Implementation Notes