drivers/gpu/drm/virtio/virtgpu_vq.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/virtio/virtgpu_vq.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/virtio/virtgpu_vq.c
Extension
.c
Size
42877 bytes
Lines
1494
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 (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) {
			if (le32_to_cpu(resp->type) >= VIRTIO_GPU_RESP_ERR_UNSPEC) {
				struct virtio_gpu_ctrl_hdr *cmd;

				cmd = virtio_gpu_vbuf_ctrl_hdr(entry);
				DRM_ERROR_RATELIMITED("response 0x%x (command 0x%x)\n",
						      le32_to_cpu(resp->type),
						      le32_to_cpu(cmd->type));
			} else
				DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type));
		}
		if (resp->flags & cpu_to_le32(VIRTIO_GPU_FLAG_FENCE)) {
			fence_id = le64_to_cpu(resp->fence_id);
			virtio_gpu_fence_event_process(vgdev, fence_id);
		}
		if (entry->resp_cb)
			entry->resp_cb(vgdev, entry);
	}
	wake_up(&vgdev->ctrlq.ack_queue);

	list_for_each_entry_safe(entry, tmp, &reclaim_list, list) {
		if (entry->objs)
			virtio_gpu_array_put_free_delayed(vgdev, entry->objs);
		list_del(&entry->list);
		free_vbuf(vgdev, entry);
	}
}

void virtio_gpu_dequeue_cursor_func(struct work_struct *work)
{
	struct virtio_gpu_device *vgdev =
		container_of(work, struct virtio_gpu_device,
			     cursorq.dequeue_work);
	struct list_head reclaim_list;
	struct virtio_gpu_vbuffer *entry, *tmp;

	INIT_LIST_HEAD(&reclaim_list);
	spin_lock(&vgdev->cursorq.qlock);
	do {
		virtqueue_disable_cb(vgdev->cursorq.vq);
		reclaim_vbufs(vgdev->cursorq.vq, &reclaim_list);
	} while (!virtqueue_enable_cb(vgdev->cursorq.vq));
	spin_unlock(&vgdev->cursorq.qlock);

	list_for_each_entry_safe(entry, tmp, &reclaim_list, list) {
		struct virtio_gpu_ctrl_hdr *resp =
			(struct virtio_gpu_ctrl_hdr *)entry->resp_buf;

		trace_virtio_gpu_cmd_response(vgdev->cursorq.vq, resp, entry->seqno);
		list_del(&entry->list);
		free_vbuf(vgdev, entry);
	}
	wake_up(&vgdev->cursorq.ack_queue);
}

/* Create sg_table from a vmalloc'd buffer. */
static struct sg_table *vmalloc_to_sgt(char *data, uint32_t size, int *sg_ents)
{
	int ret, s, i;
	struct sg_table *sgt;
	struct scatterlist *sg;
	struct page *pg;

	if (WARN_ON(!PAGE_ALIGNED(data)))
		return NULL;

	sgt = kmalloc_obj(*sgt);
	if (!sgt)
		return NULL;

	*sg_ents = DIV_ROUND_UP(size, PAGE_SIZE);
	ret = sg_alloc_table(sgt, *sg_ents, GFP_KERNEL);
	if (ret) {
		kfree(sgt);
		return NULL;
	}

	for_each_sgtable_sg(sgt, sg, i) {
		pg = vmalloc_to_page(data);
		if (!pg) {
			sg_free_table(sgt);
			kfree(sgt);
			return NULL;
		}

		s = min_t(int, PAGE_SIZE, size);
		sg_set_page(sg, pg, s, 0);

		size -= s;
		data += s;

Annotation

Implementation Notes