drivers/vdpa/vdpa_sim/vdpa_sim.c

Source file repositories/reference/linux-study-clean/drivers/vdpa/vdpa_sim/vdpa_sim.c

File Facts

System
Linux kernel
Corpus path
drivers/vdpa/vdpa_sim/vdpa_sim.c
Extension
.c
Size
22164 bytes
Lines
847
Domain
Driver Families
Bucket
drivers/vdpa
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

struct vdpasim_mm_work {
	struct kthread_work work;
	struct vdpasim *vdpasim;
	struct mm_struct *mm_to_bind;
	int ret;
};

static void vdpasim_mm_work_fn(struct kthread_work *work)
{
	struct vdpasim_mm_work *mm_work =
		container_of(work, struct vdpasim_mm_work, work);
	struct vdpasim *vdpasim = mm_work->vdpasim;

	mm_work->ret = 0;

	//TODO: should we attach the cgroup of the mm owner?
	vdpasim->mm_bound = mm_work->mm_to_bind;
}

static void vdpasim_worker_change_mm_sync(struct vdpasim *vdpasim,
					  struct vdpasim_mm_work *mm_work)
{
	struct kthread_work *work = &mm_work->work;

	kthread_init_work(work, vdpasim_mm_work_fn);
	kthread_queue_work(vdpasim->worker, work);

	kthread_flush_work(work);
}

static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa)
{
	return container_of(vdpa, struct vdpasim, vdpa);
}

static void vdpasim_vq_notify(struct vringh *vring)
{
	struct vdpasim_virtqueue *vq =
		container_of(vring, struct vdpasim_virtqueue, vring);

	if (!vq->cb)
		return;

	vq->cb(vq->private);
}

static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx)
{
	struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
	uint16_t last_avail_idx = vq->vring.last_avail_idx;
	struct vring_desc *desc = (struct vring_desc *)
				  (uintptr_t)vq->desc_addr;
	struct vring_avail *avail = (struct vring_avail *)
				    (uintptr_t)vq->driver_addr;
	struct vring_used *used = (struct vring_used *)
				  (uintptr_t)vq->device_addr;

	if (use_va && vdpasim->mm_bound) {
		vringh_init_iotlb_va(&vq->vring, vdpasim->features, vq->num,
				     true, desc, avail, used);
	} else {
		vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num,
				  true, desc, avail, used);
	}

	vq->vring.last_avail_idx = last_avail_idx;

	/*
	 * Since vdpa_sim does not support receive inflight descriptors as a
	 * destination of a migration, let's set both avail_idx and used_idx
	 * the same at vq start.  This is how vhost-user works in a
	 * VHOST_SET_VRING_BASE call.
	 *
	 * Although the simple fix is to set last_used_idx at
	 * vdpasim_set_vq_state, it would be reset at vdpasim_queue_ready.
	 */
	vq->vring.last_used_idx = last_avail_idx;
	vq->vring.notify = vdpasim_vq_notify;
}

static void vdpasim_vq_reset(struct vdpasim *vdpasim,
			     struct vdpasim_virtqueue *vq)
{
	vq->ready = false;
	vq->desc_addr = 0;
	vq->driver_addr = 0;
	vq->device_addr = 0;
	vq->cb = NULL;
	vq->private = NULL;
	vringh_init_iotlb(&vq->vring, vdpasim->dev_attr.supported_features,

Annotation

Implementation Notes