drivers/gpu/drm/vmwgfx/vmwgfx_fence.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
Extension
.c
Size
19423 bytes
Lines
739
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

struct vmw_fence_manager {
	struct vmw_private *dev_priv;
	spinlock_t lock;
	struct list_head fence_list;
	bool fifo_down;
	u64 ctx;
};

struct vmw_user_fence {
	struct ttm_base_object base;
	struct vmw_fence_obj fence;
};

/**
 * struct vmw_event_fence_action - fence callback that delivers a DRM event.
 *
 * @base:  For use with dma_fence_add_callback(...)
 * @event: A pointer to the pending event.
 * @dev: Pointer to a struct drm_device so we can access the event stuff.
 * @tv_sec: If non-null, the variable pointed to will be assigned
 * current time tv_sec val when the fence signals.
 * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
 * be assigned the current time tv_usec val when the fence signals.
 */
struct vmw_event_fence_action {
	struct dma_fence_cb base;

	struct drm_pending_event *event;
	struct drm_device *dev;

	uint32_t *tv_sec;
	uint32_t *tv_usec;
};

static struct vmw_fence_manager *
fman_from_fence(struct vmw_fence_obj *fence)
{
	return container_of(fence->base.extern_lock, struct vmw_fence_manager,
			    lock);
}

static void vmw_fence_obj_destroy(struct dma_fence *f)
{
	struct vmw_fence_obj *fence =
		container_of(f, struct vmw_fence_obj, base);
	struct vmw_fence_manager *fman = fman_from_fence(fence);

	if (!list_empty(&fence->head)) {
		/* The fence manager still has an implicit reference to this
		 * fence via the fence list if head is set. Because the lock is
		 * required to be held when the fence manager updates the fence
		 * list either the fence will have been removed after we get
		 * the lock below or we can safely remove it and the fence
		 * manager will never see it. This implies the fence is being
		 * deleted without being signaled which is dubious but valid
		 * if there are no callbacks. The dma_fence code that calls
		 * this hook will warn about deleted unsignaled with callbacks
		 * so no need to warn again here.
		 */
		spin_lock(&fman->lock);
		list_del_init(&fence->head);
		if (fence->waiter_added)
			vmw_seqno_waiter_remove(fman->dev_priv);
		spin_unlock(&fman->lock);
	}
	fence->destroy(fence);
}

static const char *vmw_fence_get_driver_name(struct dma_fence *f)
{
	return "vmwgfx";
}

static const char *vmw_fence_get_timeline_name(struct dma_fence *f)
{
	return "svga";
}

/* When we toggle signaling for the SVGA device there is a race period from
 * the time we first read the fence seqno to the time we enable interrupts.
 * If we miss the interrupt for a fence during this period its likely the driver
 * will stall. As a result we need to re-read the seqno after interrupts are
 * enabled. If interrupts were already enabled we just increment the number of
 * seqno waiters.
 */
static bool vmw_fence_enable_signaling(struct dma_fence *f)
{
	u32 seqno;
	struct vmw_fence_obj *fence =
		container_of(f, struct vmw_fence_obj, base);

Annotation

Implementation Notes