drivers/vfio/pci/vfio_pci_dmabuf.c

Source file repositories/reference/linux-study-clean/drivers/vfio/pci/vfio_pci_dmabuf.c

File Facts

System
Linux kernel
Corpus path
drivers/vfio/pci/vfio_pci_dmabuf.c
Extension
.c
Size
10604 bytes
Lines
407
Domain
Driver Families
Bucket
drivers/vfio
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 vfio_pci_dma_buf {
	struct dma_buf *dmabuf;
	struct vfio_pci_core_device *vdev;
	struct list_head dmabufs_elm;
	size_t size;
	struct phys_vec *phys_vec;
	struct p2pdma_provider *provider;
	u32 nr_ranges;
	struct kref kref;
	struct completion comp;
	u8 revoked : 1;
};

static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
				   struct dma_buf_attachment *attachment)
{
	struct vfio_pci_dma_buf *priv = dmabuf->priv;

	if (!attachment->peer2peer)
		return -EOPNOTSUPP;

	if (priv->revoked)
		return -ENODEV;

	if (!dma_buf_attach_revocable(attachment))
		return -EOPNOTSUPP;

	return 0;
}

static void vfio_pci_dma_buf_done(struct kref *kref)
{
	struct vfio_pci_dma_buf *priv =
		container_of(kref, struct vfio_pci_dma_buf, kref);

	complete(&priv->comp);
}

static struct sg_table *
vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
		     enum dma_data_direction dir)
{
	struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
	struct sg_table *ret;

	dma_resv_assert_held(priv->dmabuf->resv);

	if (priv->revoked)
		return ERR_PTR(-ENODEV);

	ret = dma_buf_phys_vec_to_sgt(attachment, priv->provider,
				      priv->phys_vec, priv->nr_ranges,
				      priv->size, dir);
	if (IS_ERR(ret))
		return ret;

	kref_get(&priv->kref);
	return ret;
}

static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment,
				   struct sg_table *sgt,
				   enum dma_data_direction dir)
{
	struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;

	dma_resv_assert_held(priv->dmabuf->resv);

	dma_buf_free_sgt(attachment, sgt, dir);
	kref_put(&priv->kref, vfio_pci_dma_buf_done);
}

static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
{
	struct vfio_pci_dma_buf *priv = dmabuf->priv;

	/*
	 * Either this or vfio_pci_dma_buf_cleanup() will remove from the list.
	 * The refcount prevents both.
	 */
	if (priv->vdev) {
		down_write(&priv->vdev->memory_lock);
		list_del_init(&priv->dmabufs_elm);
		up_write(&priv->vdev->memory_lock);
		vfio_device_put_registration(&priv->vdev->vdev);
	}
	kfree(priv->phys_vec);
	kfree(priv);
}

Annotation

Implementation Notes