* [PATCH V5 0/9] Refine virtio mapping API
@ 2025-08-13 5:48 Jason Wang
2025-08-13 5:48 ` [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers Jason Wang
` (8 more replies)
0 siblings, 9 replies; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel; +Cc: hch
Hi all:
Virtio used to be coupled with DMA API. This works fine for the device
that do real DMA but not the others. For example, VDUSE nees to craft
with DMA API in order to let the virtio-vdpa driver to work.
This series tries to solve this issue by introducing the mapping API
in the virtio core. So transport like vDPA can implement their own
mapping logic without the need to hack with DMA API. The mapping API
are abstracted with a new map operations in order to be re-used by
transprot or device. So device like VDUSE can implement its own
mapping loigc.
For device that uses DMA (for example PCI device), the virtio core
will still call DMA API directly without the need of implementing map
ops per device/transport.
Please review.
Changes since V4:
- Rename map_token to mapping_token
- Introduce a union container for opaque token as well as the DMA
device so we won't lose the type safety
- Do not try to set DMA mask for VDUSE device
- Introduce a new mapper_error op for API completeness
Changes since V3:
- Fix build error of PDS vDPA driver
Changes since V2:
- Drop VDUSE dependenct for HAS_DMA and ARCH_HAS_DMA_OPS
Changes since V1:
- Fix build error of mlx5_vdpa driver
Jason Wang (9):
virtio_ring: constify virtqueue pointer for DMA helpers
virtio_ring: switch to use dma_{map|unmap}_page()
virtio: rename dma helpers
virtio: introduce vring_mapping_token
virtio_ring: rename dma_handle to map_handle
virtio: introduce map ops in virtio core
vdpa: support mapping token
vdpa: introduce map ops
vduse: switch to use virtio map API instead of DMA API
drivers/net/virtio_net.c | 28 +-
drivers/vdpa/Kconfig | 8 +-
drivers/vdpa/alibaba/eni_vdpa.c | 5 +-
drivers/vdpa/ifcvf/ifcvf_main.c | 5 +-
drivers/vdpa/mlx5/core/mr.c | 4 +-
drivers/vdpa/mlx5/net/mlx5_vnet.c | 15 +-
drivers/vdpa/octeon_ep/octep_vdpa_main.c | 6 +-
drivers/vdpa/pds/vdpa_dev.c | 5 +-
drivers/vdpa/solidrun/snet_main.c | 8 +-
drivers/vdpa/vdpa.c | 5 +-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 4 +-
drivers/vdpa/vdpa_user/iova_domain.c | 2 +-
drivers/vdpa/vdpa_user/iova_domain.h | 2 +-
drivers/vdpa/vdpa_user/vduse_dev.c | 76 ++--
drivers/vdpa/virtio_pci/vp_vdpa.c | 5 +-
drivers/vhost/vdpa.c | 18 +-
drivers/virtio/virtio_ring.c | 471 ++++++++++++++---------
drivers/virtio/virtio_vdpa.c | 17 +-
include/linux/vdpa.h | 25 +-
include/linux/virtio.h | 43 ++-
include/linux/virtio_config.h | 72 ++++
include/linux/virtio_ring.h | 7 +-
22 files changed, 545 insertions(+), 286 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 7:14 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page() Jason Wang
` (7 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel
Cc: hch, Christoph Hellwig
This patch consities virtqueue point for DMA helpers.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/virtio/virtio_ring.c | 25 +++++++++++++------------
include/linux/virtio.h | 12 ++++++------
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index f5062061c408..103bad8cffff 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -3149,12 +3149,12 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
*
* return DMA address. Caller should check that by virtqueue_dma_mapping_error().
*/
-dma_addr_t virtqueue_dma_map_single_attrs(struct virtqueue *_vq, void *ptr,
+dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr,
size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
if (!vq->use_dma_api) {
kmsan_handle_dma(virt_to_page(ptr), offset_in_page(ptr), size, dir);
@@ -3176,11 +3176,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
* Unmap the address that is mapped by the virtqueue_dma_map_* APIs.
*
*/
-void virtqueue_dma_unmap_single_attrs(struct virtqueue *_vq, dma_addr_t addr,
+void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
+ dma_addr_t addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
if (!vq->use_dma_api)
return;
@@ -3196,9 +3197,9 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
*
* Returns 0 means dma valid. Other means invalid dma address.
*/
-int virtqueue_dma_mapping_error(struct virtqueue *_vq, dma_addr_t addr)
+int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
if (!vq->use_dma_api)
return 0;
@@ -3217,9 +3218,9 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_mapping_error);
*
* return bool
*/
-bool virtqueue_dma_need_sync(struct virtqueue *_vq, dma_addr_t addr)
+bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
if (!vq->use_dma_api)
return false;
@@ -3240,12 +3241,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_need_sync);
* the DMA address really needs to be synchronized
*
*/
-void virtqueue_dma_sync_single_range_for_cpu(struct virtqueue *_vq,
+void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
struct device *dev = vring_dma_dev(vq);
if (!vq->use_dma_api)
@@ -3266,12 +3267,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_cpu);
* Before calling this function, use virtqueue_dma_need_sync() to confirm that
* the DMA address really needs to be synchronized
*/
-void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq,
+void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir)
{
- struct vring_virtqueue *vq = to_vvq(_vq);
+ const struct vring_virtqueue *vq = to_vvq(_vq);
struct device *dev = vring_dma_dev(vq);
if (!vq->use_dma_api)
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 8b745ce0cf5f..cf8def717dfd 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -259,18 +259,18 @@ void unregister_virtio_driver(struct virtio_driver *drv);
module_driver(__virtio_driver, register_virtio_driver, \
unregister_virtio_driver)
-dma_addr_t virtqueue_dma_map_single_attrs(struct virtqueue *_vq, void *ptr, size_t size,
+dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
enum dma_data_direction dir, unsigned long attrs);
-void virtqueue_dma_unmap_single_attrs(struct virtqueue *_vq, dma_addr_t addr,
+void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs);
-int virtqueue_dma_mapping_error(struct virtqueue *_vq, dma_addr_t addr);
+int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
-bool virtqueue_dma_need_sync(struct virtqueue *_vq, dma_addr_t addr);
-void virtqueue_dma_sync_single_range_for_cpu(struct virtqueue *_vq, dma_addr_t addr,
+bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
+void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir);
-void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq, dma_addr_t addr,
+void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir);
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page()
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
2025-08-13 5:48 ` [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 7:15 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 3/9] virtio: rename dma helpers Jason Wang
` (6 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel
Cc: hch, Christoph Hellwig
This patch switches to use dma_{map|unmap}_page() to reduce the
coverage of DMA operations. This would help for the following rework
on the virtio map operations.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/virtio/virtio_ring.c | 55 +++++++++++++++---------------------
1 file changed, 23 insertions(+), 32 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 103bad8cffff..75e5f6336c8d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -405,8 +405,8 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
if (!vq->use_dma_api)
return (dma_addr_t)virt_to_phys(cpu_addr);
- return dma_map_single(vring_dma_dev(vq),
- cpu_addr, size, direction);
+ return virtqueue_dma_map_single_attrs(&vq->vq, cpu_addr,
+ size, direction, 0);
}
static int vring_mapping_error(const struct vring_virtqueue *vq,
@@ -451,22 +451,14 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
if (flags & VRING_DESC_F_INDIRECT) {
if (!vq->use_dma_api)
goto out;
+ } else if (!vring_need_unmap_buffer(vq, extra))
+ goto out;
- dma_unmap_single(vring_dma_dev(vq),
- extra->addr,
- extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- } else {
- if (!vring_need_unmap_buffer(vq, extra))
- goto out;
-
- dma_unmap_page(vring_dma_dev(vq),
- extra->addr,
- extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- }
+ dma_unmap_page(vring_dma_dev(vq),
+ extra->addr,
+ extra->len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
out:
return extra->next;
@@ -1276,20 +1268,13 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
if (flags & VRING_DESC_F_INDIRECT) {
if (!vq->use_dma_api)
return;
+ } else if (!vring_need_unmap_buffer(vq, extra))
+ return;
- dma_unmap_single(vring_dma_dev(vq),
- extra->addr, extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- } else {
- if (!vring_need_unmap_buffer(vq, extra))
- return;
-
- dma_unmap_page(vring_dma_dev(vq),
- extra->addr, extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- }
+ dma_unmap_page(vring_dma_dev(vq),
+ extra->addr, extra->len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
@@ -3161,7 +3146,13 @@ dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr
return (dma_addr_t)virt_to_phys(ptr);
}
- return dma_map_single_attrs(vring_dma_dev(vq), ptr, size, dir, attrs);
+ /* DMA must never operate on areas that might be remapped. */
+ if (dev_WARN_ONCE(&_vq->vdev->dev, is_vmalloc_addr(ptr),
+ "rejecting DMA map of vmalloc memory\n"))
+ return DMA_MAPPING_ERROR;
+
+ return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
+ offset_in_page(ptr), size, dir, attrs);
}
EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
@@ -3186,7 +3177,7 @@ void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
if (!vq->use_dma_api)
return;
- dma_unmap_single_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
+ dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
}
EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 3/9] virtio: rename dma helpers
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
2025-08-13 5:48 ` [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers Jason Wang
2025-08-13 5:48 ` [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page() Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 7:16 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
` (5 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel
Cc: hch, Christoph Hellwig
Following patch will introduce virtio mapping function to avoid
abusing DMA API for device that doesn't do DMA. To ease the
introduction, this patch rename "dma" to "map" for the current dma
mapping helpers.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/net/virtio_net.c | 28 ++++-----
drivers/virtio/virtio_ring.c | 114 +++++++++++++++++------------------
include/linux/virtio.h | 12 ++--
3 files changed, 77 insertions(+), 77 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5d674eb9a0f2..929db41a579b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -933,7 +933,7 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
if (dma->need_sync && len) {
offset = buf - (head + sizeof(*dma));
- virtqueue_dma_sync_single_range_for_cpu(rq->vq, dma->addr,
+ virtqueue_map_sync_single_range_for_cpu(rq->vq, dma->addr,
offset, len,
DMA_FROM_DEVICE);
}
@@ -941,8 +941,8 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
if (dma->ref)
return;
- virtqueue_dma_unmap_single_attrs(rq->vq, dma->addr, dma->len,
- DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ virtqueue_unmap_single_attrs(rq->vq, dma->addr, dma->len,
+ DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
put_page(page);
}
@@ -1009,13 +1009,13 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp)
dma->len = alloc_frag->size - sizeof(*dma);
- addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1,
- dma->len, DMA_FROM_DEVICE, 0);
- if (virtqueue_dma_mapping_error(rq->vq, addr))
+ addr = virtqueue_map_single_attrs(rq->vq, dma + 1,
+ dma->len, DMA_FROM_DEVICE, 0);
+ if (virtqueue_map_mapping_error(rq->vq, addr))
return NULL;
dma->addr = addr;
- dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr);
+ dma->need_sync = virtqueue_map_need_sync(rq->vq, addr);
/* Add a reference to dma to prevent the entire dma from
* being released during error handling. This reference
@@ -5921,9 +5921,9 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
if (!rq->xsk_buffs)
return -ENOMEM;
- hdr_dma = virtqueue_dma_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len,
- DMA_TO_DEVICE, 0);
- if (virtqueue_dma_mapping_error(sq->vq, hdr_dma)) {
+ hdr_dma = virtqueue_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len,
+ DMA_TO_DEVICE, 0);
+ if (virtqueue_map_mapping_error(sq->vq, hdr_dma)) {
err = -ENOMEM;
goto err_free_buffs;
}
@@ -5952,8 +5952,8 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
err_rq:
xsk_pool_dma_unmap(pool, 0);
err_xsk_map:
- virtqueue_dma_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len,
- DMA_TO_DEVICE, 0);
+ virtqueue_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len,
+ DMA_TO_DEVICE, 0);
err_free_buffs:
kvfree(rq->xsk_buffs);
return err;
@@ -5980,8 +5980,8 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
xsk_pool_dma_unmap(pool, 0);
- virtqueue_dma_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr,
- vi->hdr_len, DMA_TO_DEVICE, 0);
+ virtqueue_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr,
+ vi->hdr_len, DMA_TO_DEVICE, 0);
kvfree(rq->xsk_buffs);
return err;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 75e5f6336c8d..482a268af851 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -166,7 +166,7 @@ struct vring_virtqueue {
bool packed_ring;
/* Is DMA API used? */
- bool use_dma_api;
+ bool use_map_api;
/* Can we use weak barriers? */
bool weak_barriers;
@@ -268,7 +268,7 @@ static bool virtqueue_use_indirect(const struct vring_virtqueue *vq,
* unconditionally on data path.
*/
-static bool vring_use_dma_api(const struct virtio_device *vdev)
+static bool vring_use_map_api(const struct virtio_device *vdev)
{
if (!virtio_has_dma_quirk(vdev))
return true;
@@ -291,14 +291,14 @@ static bool vring_use_dma_api(const struct virtio_device *vdev)
static bool vring_need_unmap_buffer(const struct vring_virtqueue *vring,
const struct vring_desc_extra *extra)
{
- return vring->use_dma_api && (extra->addr != DMA_MAPPING_ERROR);
+ return vring->use_map_api && (extra->addr != DMA_MAPPING_ERROR);
}
size_t virtio_max_dma_size(const struct virtio_device *vdev)
{
size_t max_segment_size = SIZE_MAX;
- if (vring_use_dma_api(vdev))
+ if (vring_use_map_api(vdev))
max_segment_size = dma_max_mapping_size(vdev->dev.parent);
return max_segment_size;
@@ -309,7 +309,7 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
dma_addr_t *dma_handle, gfp_t flag,
struct device *dma_dev)
{
- if (vring_use_dma_api(vdev)) {
+ if (vring_use_map_api(vdev)) {
return dma_alloc_coherent(dma_dev, size,
dma_handle, flag);
} else {
@@ -343,7 +343,7 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size,
void *queue, dma_addr_t dma_handle,
struct device *dma_dev)
{
- if (vring_use_dma_api(vdev))
+ if (vring_use_map_api(vdev))
dma_free_coherent(dma_dev, size, queue, dma_handle);
else
free_pages_exact(queue, PAGE_ALIGN(size));
@@ -372,7 +372,7 @@ static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist
*len = sg->length;
- if (!vq->use_dma_api) {
+ if (!vq->use_map_api) {
/*
* If DMA is not used, KMSAN doesn't know that the scatterlist
* is initialized by the hardware. Explicitly check/unpoison it
@@ -402,17 +402,17 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
void *cpu_addr, size_t size,
enum dma_data_direction direction)
{
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return (dma_addr_t)virt_to_phys(cpu_addr);
- return virtqueue_dma_map_single_attrs(&vq->vq, cpu_addr,
- size, direction, 0);
+ return virtqueue_map_single_attrs(&vq->vq, cpu_addr,
+ size, direction, 0);
}
static int vring_mapping_error(const struct vring_virtqueue *vq,
dma_addr_t addr)
{
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return 0;
return dma_mapping_error(vring_dma_dev(vq), addr);
@@ -449,7 +449,7 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
flags = extra->flags;
if (flags & VRING_DESC_F_INDIRECT) {
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
goto out;
} else if (!vring_need_unmap_buffer(vq, extra))
goto out;
@@ -782,7 +782,7 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
extra = (struct vring_desc_extra *)&indir_desc[num];
- if (vq->use_dma_api) {
+ if (vq->use_map_api) {
for (j = 0; j < num; j++)
vring_unmap_one_split(vq, &extra[j]);
}
@@ -1150,7 +1150,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
vq->broken = false;
#endif
vq->dma_dev = dma_dev;
- vq->use_dma_api = vring_use_dma_api(vdev);
+ vq->use_map_api = vring_use_map_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
!context;
@@ -1266,7 +1266,7 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
flags = extra->flags;
if (flags & VRING_DESC_F_INDIRECT) {
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return;
} else if (!vring_need_unmap_buffer(vq, extra))
return;
@@ -1351,7 +1351,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
desc[i].addr = cpu_to_le64(addr);
desc[i].len = cpu_to_le32(len);
- if (unlikely(vq->use_dma_api)) {
+ if (unlikely(vq->use_map_api)) {
extra[i].addr = premapped ? DMA_MAPPING_ERROR : addr;
extra[i].len = len;
extra[i].flags = n < out_sgs ? 0 : VRING_DESC_F_WRITE;
@@ -1373,7 +1373,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
sizeof(struct vring_packed_desc));
vq->packed.vring.desc[head].id = cpu_to_le16(id);
- if (vq->use_dma_api) {
+ if (vq->use_map_api) {
vq->packed.desc_extra[id].addr = addr;
vq->packed.desc_extra[id].len = total_sg *
sizeof(struct vring_packed_desc);
@@ -1515,7 +1515,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
desc[i].len = cpu_to_le32(len);
desc[i].id = cpu_to_le16(id);
- if (unlikely(vq->use_dma_api)) {
+ if (unlikely(vq->use_map_api)) {
vq->packed.desc_extra[curr].addr = premapped ?
DMA_MAPPING_ERROR : addr;
vq->packed.desc_extra[curr].len = len;
@@ -1650,7 +1650,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
vq->free_head = id;
vq->vq.num_free += state->num;
- if (unlikely(vq->use_dma_api)) {
+ if (unlikely(vq->use_map_api)) {
curr = id;
for (i = 0; i < state->num; i++) {
vring_unmap_extra_packed(vq,
@@ -1668,7 +1668,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
if (!desc)
return;
- if (vq->use_dma_api) {
+ if (vq->use_map_api) {
len = vq->packed.desc_extra[id].len;
num = len / sizeof(struct vring_packed_desc);
@@ -2121,7 +2121,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
#endif
vq->packed_ring = true;
vq->dma_dev = dma_dev;
- vq->use_dma_api = vring_use_dma_api(vdev);
+ vq->use_map_api = vring_use_map_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
!context;
@@ -2433,7 +2433,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
- if (vq->use_dma_api)
+ if (vq->use_map_api)
return vring_dma_dev(vq);
else
return NULL;
@@ -3122,7 +3122,7 @@ const struct vring *virtqueue_get_vring(const struct virtqueue *vq)
EXPORT_SYMBOL_GPL(virtqueue_get_vring);
/**
- * virtqueue_dma_map_single_attrs - map DMA for _vq
+ * virtqueue_map_single_attrs - map DMA for _vq
* @_vq: the struct virtqueue we're talking about.
* @ptr: the pointer of the buffer to do dma
* @size: the size of the buffer to do dma
@@ -3132,16 +3132,16 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
* The caller calls this to do dma mapping in advance. The DMA address can be
* passed to this _vq when it is in pre-mapped mode.
*
- * return DMA address. Caller should check that by virtqueue_dma_mapping_error().
+ * return DMA address. Caller should check that by virtqueue_mapping_error().
*/
-dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr,
- size_t size,
- enum dma_data_direction dir,
- unsigned long attrs)
+dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
+ size_t size,
+ enum dma_data_direction dir,
+ unsigned long attrs)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- if (!vq->use_dma_api) {
+ if (!vq->use_map_api) {
kmsan_handle_dma(virt_to_page(ptr), offset_in_page(ptr), size, dir);
return (dma_addr_t)virt_to_phys(ptr);
}
@@ -3154,85 +3154,85 @@ dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr
return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
offset_in_page(ptr), size, dir, attrs);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
+EXPORT_SYMBOL_GPL(virtqueue_map_single_attrs);
/**
- * virtqueue_dma_unmap_single_attrs - unmap DMA for _vq
+ * virtqueue_unmap_single_attrs - unmap map for _vq
* @_vq: the struct virtqueue we're talking about.
* @addr: the dma address to unmap
* @size: the size of the buffer
* @dir: DMA direction
* @attrs: DMA Attrs
*
- * Unmap the address that is mapped by the virtqueue_dma_map_* APIs.
+ * Unmap the address that is mapped by the virtqueue_map_* APIs.
*
*/
-void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
- dma_addr_t addr,
- size_t size, enum dma_data_direction dir,
- unsigned long attrs)
+void virtqueue_unmap_single_attrs(const struct virtqueue *_vq,
+ dma_addr_t addr,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return;
dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
+EXPORT_SYMBOL_GPL(virtqueue_unmap_single_attrs);
/**
- * virtqueue_dma_mapping_error - check dma address
+ * virtqueue_map_mapping_error - check dma address
* @_vq: the struct virtqueue we're talking about.
* @addr: DMA address
*
* Returns 0 means dma valid. Other means invalid dma address.
*/
-int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
+int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return 0;
return dma_mapping_error(vring_dma_dev(vq), addr);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_mapping_error);
+EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
/**
- * virtqueue_dma_need_sync - check a dma address needs sync
+ * virtqueue_map_need_sync - check a dma address needs sync
* @_vq: the struct virtqueue we're talking about.
* @addr: DMA address
*
- * Check if the dma address mapped by the virtqueue_dma_map_* APIs needs to be
+ * Check if the dma address mapped by the virtqueue_map_* APIs needs to be
* synchronized
*
* return bool
*/
-bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
+bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return false;
return dma_need_sync(vring_dma_dev(vq), addr);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_need_sync);
+EXPORT_SYMBOL_GPL(virtqueue_map_need_sync);
/**
- * virtqueue_dma_sync_single_range_for_cpu - dma sync for cpu
+ * virtqueue_map_sync_single_range_for_cpu - map sync for cpu
* @_vq: the struct virtqueue we're talking about.
* @addr: DMA address
* @offset: DMA address offset
* @size: buf size for sync
* @dir: DMA direction
*
- * Before calling this function, use virtqueue_dma_need_sync() to confirm that
+ * Before calling this function, use virtqueue_map_need_sync() to confirm that
* the DMA address really needs to be synchronized
*
*/
-void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
+void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq,
dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir)
@@ -3240,25 +3240,25 @@ void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
const struct vring_virtqueue *vq = to_vvq(_vq);
struct device *dev = vring_dma_dev(vq);
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return;
dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_cpu);
+EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_cpu);
/**
- * virtqueue_dma_sync_single_range_for_device - dma sync for device
+ * virtqueue_map_sync_single_range_for_device - map sync for device
* @_vq: the struct virtqueue we're talking about.
* @addr: DMA address
* @offset: DMA address offset
* @size: buf size for sync
* @dir: DMA direction
*
- * Before calling this function, use virtqueue_dma_need_sync() to confirm that
+ * Before calling this function, use virtqueue_map_need_sync() to confirm that
* the DMA address really needs to be synchronized
*/
-void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
+void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq,
dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir)
@@ -3266,12 +3266,12 @@ void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
const struct vring_virtqueue *vq = to_vvq(_vq);
struct device *dev = vring_dma_dev(vq);
- if (!vq->use_dma_api)
+ if (!vq->use_map_api)
return;
dma_sync_single_range_for_device(dev, addr, offset, size, dir);
}
-EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_device);
+EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device);
MODULE_DESCRIPTION("Virtio ring implementation");
MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index cf8def717dfd..addbc209275a 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -259,18 +259,18 @@ void unregister_virtio_driver(struct virtio_driver *drv);
module_driver(__virtio_driver, register_virtio_driver, \
unregister_virtio_driver)
-dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
+dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
enum dma_data_direction dir, unsigned long attrs);
-void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
+void virtqueue_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs);
-int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
+int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
-bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
-void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
+bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
+void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir);
-void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
+void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
unsigned long offset, size_t size,
enum dma_data_direction dir);
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (2 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 3/9] virtio: rename dma helpers Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 7:46 ` Eugenio Perez Martin
` (2 more replies)
2025-08-13 5:48 ` [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle Jason Wang
` (4 subsequent siblings)
8 siblings, 3 replies; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel; +Cc: hch
Following patch will introduce the mapping operations for virtio
device. In order to achieve this, besides the dma device, virtio core
needs to support a transport or device specific mapping token as well.
So this patch introduces a union container of a dma device and opaque
mapping token. The idea is the allow the transport layer to pass
device specific mapping token which will be used as a parameter for
the virtio mapping operations. For the transport or device that is
using DMA, dma device is still being used.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
drivers/virtio/virtio_vdpa.c | 6 +-
include/linux/virtio.h | 7 +++
include/linux/virtio_ring.h | 7 ++-
4 files changed, 72 insertions(+), 58 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 482a268af851..fb1d407d5f1b 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -210,8 +210,7 @@ struct vring_virtqueue {
/* DMA, allocation, and size information */
bool we_own_ring;
- /* Device used for doing DMA */
- struct device *dma_dev;
+ union vring_mapping_token mapping_token;
#ifdef DEBUG
/* They're supposed to lock for us. */
@@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
dma_addr_t *dma_handle, gfp_t flag,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev)) {
- return dma_alloc_coherent(dma_dev, size,
+ return dma_alloc_coherent(mapping_token->dma_dev, size,
dma_handle, flag);
} else {
void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
@@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
static void vring_free_queue(struct virtio_device *vdev, size_t size,
void *queue, dma_addr_t dma_handle,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev))
- dma_free_coherent(dma_dev, size, queue, dma_handle);
+ dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
else
free_pages_exact(queue, PAGE_ALIGN(size));
}
/*
- * The DMA ops on various arches are rather gnarly right now, and
- * making all of the arch DMA ops work on the vring device itself
+ * The map ops on various arches are rather gnarly right now, and
+ * making all of the arch map ops work on the vring device itself
* is a mess.
*/
static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
{
- return vq->dma_dev;
+ return vq->mapping_token.dma_dev;
}
/* Map one sg entry. */
@@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
}
static void vring_free_split(struct vring_virtqueue_split *vring_split,
- struct virtio_device *vdev, struct device *dma_dev)
+ struct virtio_device *vdev,
+ union vring_mapping_token *mapping_token)
{
vring_free_queue(vdev, vring_split->queue_size_in_bytes,
vring_split->vring.desc,
vring_split->queue_dma_addr,
- dma_dev);
+ mapping_token);
kfree(vring_split->desc_state);
kfree(vring_split->desc_extra);
@@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
u32 num,
unsigned int vring_align,
bool may_reduce_num,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
void *queue = NULL;
dma_addr_t dma_addr;
@@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
&dma_addr,
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
- dma_dev);
+ mapping_token);
if (queue)
break;
if (!may_reduce_num)
@@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
/* Try to get a single page. You are my only hope! */
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
&dma_addr, GFP_KERNEL | __GFP_ZERO,
- dma_dev);
+ mapping_token);
}
if (!queue)
return -ENOMEM;
@@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
struct vring_virtqueue *vq;
int err;
@@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
#else
vq->broken = false;
#endif
- vq->dma_dev = dma_dev;
+ vq->mapping_token = *mapping_token;
vq->use_map_api = vring_use_map_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
@@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
struct vring_virtqueue_split vring_split = {};
struct virtqueue *vq;
int err;
err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
- may_reduce_num, dma_dev);
+ may_reduce_num, mapping_token);
if (err)
return NULL;
vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
- context, notify, callback, name, dma_dev);
+ context, notify, callback, name, mapping_token);
if (!vq) {
- vring_free_split(&vring_split, vdev, dma_dev);
+ vring_free_split(&vring_split, vdev, mapping_token);
return NULL;
}
@@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
err = vring_alloc_queue_split(&vring_split, vdev, num,
vq->split.vring_align,
vq->split.may_reduce_num,
- vring_dma_dev(vq));
+ &vq->mapping_token);
if (err)
goto err;
@@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
return 0;
err_state_extra:
- vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
+ vring_free_split(&vring_split, vdev, &vq->mapping_token);
err:
virtqueue_reinit_split(vq);
return -ENOMEM;
@@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
struct virtio_device *vdev,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
if (vring_packed->vring.desc)
vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
vring_packed->vring.desc,
vring_packed->ring_dma_addr,
- dma_dev);
+ mapping_token);
if (vring_packed->vring.driver)
vring_free_queue(vdev, vring_packed->event_size_in_bytes,
vring_packed->vring.driver,
vring_packed->driver_event_dma_addr,
- dma_dev);
+ mapping_token);
if (vring_packed->vring.device)
vring_free_queue(vdev, vring_packed->event_size_in_bytes,
vring_packed->vring.device,
vring_packed->device_event_dma_addr,
- dma_dev);
+ mapping_token);
kfree(vring_packed->desc_state);
kfree(vring_packed->desc_extra);
@@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
struct virtio_device *vdev,
- u32 num, struct device *dma_dev)
+ u32 num, union vring_mapping_token *mapping_token)
{
struct vring_packed_desc *ring;
struct vring_packed_desc_event *driver, *device;
@@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
ring = vring_alloc_queue(vdev, ring_size_in_bytes,
&ring_dma_addr,
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
- dma_dev);
+ mapping_token);
if (!ring)
goto err;
@@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
driver = vring_alloc_queue(vdev, event_size_in_bytes,
&driver_event_dma_addr,
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
- dma_dev);
+ mapping_token);
if (!driver)
goto err;
@@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
device = vring_alloc_queue(vdev, event_size_in_bytes,
&device_event_dma_addr,
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
- dma_dev);
+ mapping_token);
if (!device)
goto err;
@@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
return 0;
err:
- vring_free_packed(vring_packed, vdev, dma_dev);
+ vring_free_packed(vring_packed, vdev, mapping_token);
return -ENOMEM;
}
@@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
struct vring_virtqueue *vq;
int err;
@@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
vq->broken = false;
#endif
vq->packed_ring = true;
- vq->dma_dev = dma_dev;
+ vq->mapping_token = *mapping_token;
vq->use_map_api = vring_use_map_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
@@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
struct vring_virtqueue_packed vring_packed = {};
struct virtqueue *vq;
- if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
+ if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
return NULL;
vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
- context, notify, callback, name, dma_dev);
+ context, notify, callback, name, mapping_token);
if (!vq) {
- vring_free_packed(&vring_packed, vdev, dma_dev);
+ vring_free_packed(&vring_packed, vdev, mapping_token);
return NULL;
}
@@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
struct virtio_device *vdev = _vq->vdev;
int err;
- if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
+ if (vring_alloc_queue_packed(&vring_packed, vdev,
+ num, &vq->mapping_token))
goto err_ring;
err = vring_alloc_state_extra_packed(&vring_packed);
@@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
return 0;
err_state_extra:
- vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
+ vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
err_ring:
virtqueue_reinit_packed(vq);
return -ENOMEM;
@@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
+
/**
* virtqueue_dma_dev - get the dma dev
* @_vq: the struct virtqueue we're talking about.
@@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
struct vring_virtqueue *vq = to_vvq(_vq);
if (vq->use_map_api)
- return vring_dma_dev(vq);
+ return vq->mapping_token.dma_dev;
else
return NULL;
}
@@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
void (*callback)(struct virtqueue *),
const char *name)
{
+ union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
return vring_create_virtqueue_packed(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name, vdev->dev.parent);
+ context, notify, callback, name, &mapping_token);
return vring_create_virtqueue_split(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name, vdev->dev.parent);
+ context, notify, callback, name, &mapping_token);
}
EXPORT_SYMBOL_GPL(vring_create_virtqueue);
-struct virtqueue *vring_create_virtqueue_dma(
+struct virtqueue *vring_create_virtqueue_map(
unsigned int index,
unsigned int num,
unsigned int vring_align,
@@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name,
- struct device *dma_dev)
+ union vring_mapping_token *mapping_token)
{
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
return vring_create_virtqueue_packed(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name, dma_dev);
+ context, notify, callback, name, mapping_token);
return vring_create_virtqueue_split(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name, dma_dev);
+ context, notify, callback, name, mapping_token);
}
-EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
+EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
/**
* virtqueue_resize - resize the vring of vq
@@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
const char *name)
{
struct vring_virtqueue_split vring_split = {};
+ union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
struct vring_virtqueue_packed vring_packed = {};
@@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
return __vring_new_virtqueue_packed(index, &vring_packed,
vdev, weak_barriers,
context, notify, callback,
- name, vdev->dev.parent);
+ name, &mapping_token);
}
vring_init(&vring_split.vring, num, pages, vring_align);
return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
context, notify, callback, name,
- vdev->dev.parent);
+ &mapping_token);
}
EXPORT_SYMBOL_GPL(vring_new_virtqueue);
@@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
vq->packed.ring_size_in_bytes,
vq->packed.vring.desc,
vq->packed.ring_dma_addr,
- vring_dma_dev(vq));
+ &vq->mapping_token);
vring_free_queue(vq->vq.vdev,
vq->packed.event_size_in_bytes,
vq->packed.vring.driver,
vq->packed.driver_event_dma_addr,
- vring_dma_dev(vq));
+ &vq->mapping_token);
vring_free_queue(vq->vq.vdev,
vq->packed.event_size_in_bytes,
vq->packed.vring.device,
vq->packed.device_event_dma_addr,
- vring_dma_dev(vq));
+ &vq->mapping_token);
kfree(vq->packed.desc_state);
kfree(vq->packed.desc_extra);
@@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
vq->split.queue_size_in_bytes,
vq->split.vring.desc,
vq->split.queue_dma_addr,
- vring_dma_dev(vq));
+ &vq->mapping_token);
}
}
if (!vq->packed_ring) {
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
index e25610e3393a..acea98ab08ee 100644
--- a/drivers/virtio/virtio_vdpa.c
+++ b/drivers/virtio/virtio_vdpa.c
@@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
struct vdpa_callback cb;
struct virtqueue *vq;
u64 desc_addr, driver_addr, device_addr;
+ union vring_mapping_token mapping_token = {0};
/* Assume split virtqueue, switch to packed if necessary */
struct vdpa_vq_state state = {0};
u32 align, max_num, min_num = 1;
@@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
dma_dev = ops->get_vq_dma_dev(vdpa, index);
else
dma_dev = vdpa_get_dma_dev(vdpa);
- vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
+ mapping_token.dma_dev = dma_dev;
+ vq = vring_create_virtqueue_map(index, max_num, align, vdev,
true, may_reduce_num, ctx,
- notify, callback, name, dma_dev);
+ notify, callback, name, &mapping_token);
if (!vq) {
err = -ENOMEM;
goto error_new_virtqueue;
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index addbc209275a..37029df94aaf 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -40,6 +40,13 @@ struct virtqueue {
void *priv;
};
+union vring_mapping_token {
+ /* Device that performs DMA */
+ struct device *dma_dev;
+ /* Transport specific token used for doing map */
+ void *opaque;
+};
+
int virtqueue_add_outbuf(struct virtqueue *vq,
struct scatterlist sg[], unsigned int num,
void *data,
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 9b33df741b63..fd997178da2a 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -3,6 +3,7 @@
#define _LINUX_VIRTIO_RING_H
#include <asm/barrier.h>
+#include <linux/virtio.h>
#include <linux/irqreturn.h>
#include <uapi/linux/virtio_ring.h>
@@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
/*
* Creates a virtqueue and allocates the descriptor ring with per
- * virtqueue DMA device.
+ * virtqueue mapping operations.
*/
-struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
+struct virtqueue *vring_create_virtqueue_map(unsigned int index,
unsigned int num,
unsigned int vring_align,
struct virtio_device *vdev,
@@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq),
const char *name,
- struct device *dma_dev);
+ union vring_mapping_token *mapping_token);
/*
* Creates a virtqueue with a standard layout but a caller-allocated
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (3 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 7:47 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 6/9] virtio: introduce map ops in virtio core Jason Wang
` (3 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel
Cc: hch, Christoph Hellwig
Following patch will introduce virtio map opreations which means the
address is not necessarily used for DMA. Let's rename the dma_handle
to map_handle first.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/virtio/virtio_ring.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fb1d407d5f1b..94b2a8f3acc2 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -305,18 +305,18 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev)
EXPORT_SYMBOL_GPL(virtio_max_dma_size);
static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag,
+ dma_addr_t *map_handle, gfp_t flag,
union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev)) {
return dma_alloc_coherent(mapping_token->dma_dev, size,
- dma_handle, flag);
+ map_handle, flag);
} else {
void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
if (queue) {
phys_addr_t phys_addr = virt_to_phys(queue);
- *dma_handle = (dma_addr_t)phys_addr;
+ *map_handle = (dma_addr_t)phys_addr;
/*
* Sanity check: make sure we dind't truncate
@@ -329,7 +329,7 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
* warning and abort if we end up with an
* unrepresentable address.
*/
- if (WARN_ON_ONCE(*dma_handle != phys_addr)) {
+ if (WARN_ON_ONCE(*map_handle != phys_addr)) {
free_pages_exact(queue, PAGE_ALIGN(size));
return NULL;
}
@@ -339,11 +339,11 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
}
static void vring_free_queue(struct virtio_device *vdev, size_t size,
- void *queue, dma_addr_t dma_handle,
+ void *queue, dma_addr_t map_handle,
union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev))
- dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
+ dma_free_coherent(mapping_token->dma_dev, size, queue, map_handle);
else
free_pages_exact(queue, PAGE_ALIGN(size));
}
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 6/9] virtio: introduce map ops in virtio core
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (4 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 8:40 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 7/9] vdpa: support mapping token Jason Wang
` (2 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel; +Cc: hch
This patch introduces map operations for virtio device. Virtio use to
use DMA API which is not necessarily the case since some devices
doesn't do DMA. Instead of using tricks and abusing DMA API, let's
simply abstract the current mapping logic into a virtio specific
mapping operations. For the device or transport that doesn't do DMA,
they can implement their own mapping logic without the need to trick
DMA core. In this case the map_token is opaque to the virtio core that
will be passed back to the transport or device specific map
operations. For other devices, DMA API will still be used, so map
token will still be the dma device to minimize the changeset and
performance impact.
The mapping operations are abstracted as a independent structure
instead of reusing virtio_config_ops. This allows the transport can
simply reuse the structure for lower layers like vDPA.
A set of new mapping helpers were introduced for the device that want
to do mapping by themselves.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/virtio/virtio_ring.c | 217 +++++++++++++++++++++++++++-------
include/linux/virtio.h | 26 +++-
include/linux/virtio_config.h | 72 +++++++++++
3 files changed, 271 insertions(+), 44 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 94b2a8f3acc2..86188ffbce00 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -297,8 +297,14 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev)
{
size_t max_segment_size = SIZE_MAX;
- if (vring_use_map_api(vdev))
- max_segment_size = dma_max_mapping_size(vdev->dev.parent);
+ if (vring_use_map_api(vdev)) {
+ if (vdev->map)
+ max_segment_size =
+ vdev->map->max_mapping_size(vdev->dev.parent);
+ else
+ max_segment_size =
+ dma_max_mapping_size(vdev->dev.parent);
+ }
return max_segment_size;
}
@@ -309,8 +315,8 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev)) {
- return dma_alloc_coherent(mapping_token->dma_dev, size,
- map_handle, flag);
+ return virtqueue_map_alloc_coherent(vdev, mapping_token, size,
+ map_handle, flag);
} else {
void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
@@ -343,7 +349,8 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size,
union vring_mapping_token *mapping_token)
{
if (vring_use_map_api(vdev))
- dma_free_coherent(mapping_token->dma_dev, size, queue, map_handle);
+ virtqueue_map_free_coherent(vdev, mapping_token, size,
+ queue, map_handle);
else
free_pages_exact(queue, PAGE_ALIGN(size));
}
@@ -358,6 +365,25 @@ static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
return vq->mapping_token.dma_dev;
}
+static void *vring_mapping_token(const struct vring_virtqueue *vq)
+{
+ return vq->mapping_token.token;
+}
+
+static int vring_mapping_error(const struct vring_virtqueue *vq,
+ dma_addr_t addr)
+{
+ struct virtio_device *vdev = vq->vq.vdev;
+
+ if (!vq->use_map_api)
+ return 0;
+
+ if (vdev->map)
+ return vdev->map->mapping_error(vring_mapping_token(vq), addr);
+ else
+ return dma_mapping_error(vring_dma_dev(vq), addr);
+}
+
/* Map one sg entry. */
static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist *sg,
enum dma_data_direction direction, dma_addr_t *addr,
@@ -387,11 +413,11 @@ static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist
* the way it expects (we don't guarantee that the scatterlist
* will exist for the lifetime of the mapping).
*/
- *addr = dma_map_page(vring_dma_dev(vq),
- sg_page(sg), sg->offset, sg->length,
- direction);
+ *addr = virtqueue_map_page_attrs(&vq->vq, sg_page(sg),
+ sg->offset, sg->length,
+ direction, 0);
- if (dma_mapping_error(vring_dma_dev(vq), *addr))
+ if (vring_mapping_error(vq, *addr))
return -ENOMEM;
return 0;
@@ -408,15 +434,6 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
size, direction, 0);
}
-static int vring_mapping_error(const struct vring_virtqueue *vq,
- dma_addr_t addr)
-{
- if (!vq->use_map_api)
- return 0;
-
- return dma_mapping_error(vring_dma_dev(vq), addr);
-}
-
static void virtqueue_init(struct vring_virtqueue *vq, u32 num)
{
vq->vq.num_free = num;
@@ -453,11 +470,12 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
} else if (!vring_need_unmap_buffer(vq, extra))
goto out;
- dma_unmap_page(vring_dma_dev(vq),
- extra->addr,
- extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ virtqueue_unmap_page_attrs(&vq->vq,
+ extra->addr,
+ extra->len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE,
+ 0);
out:
return extra->next;
@@ -1271,10 +1289,11 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
} else if (!vring_need_unmap_buffer(vq, extra))
return;
- dma_unmap_page(vring_dma_dev(vq),
- extra->addr, extra->len,
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ virtqueue_unmap_page_attrs(&vq->vq,
+ extra->addr, extra->len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE,
+ 0);
}
static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
@@ -2434,8 +2453,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
struct device *virtqueue_dma_dev(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
-
- if (vq->use_map_api)
+ if (vq->use_map_api && !_vq->vdev->map)
return vq->mapping_token.dma_dev;
else
return NULL;
@@ -3125,6 +3143,107 @@ const struct vring *virtqueue_get_vring(const struct virtqueue *vq)
}
EXPORT_SYMBOL_GPL(virtqueue_get_vring);
+/**
+ * virtqueue_map_alloc_coherent - alloc coherent mapping
+ * @vdev: the virtio device we are talking to
+ * @mapping_token: device specific mapping token
+ * @size: the size of the buffer
+ * @map_handle: the pointer to the mapped address
+ * @gfp: allocation flag (GFP_XXX)
+ *
+ * return virtual address or NULL on error
+ */
+void *virtqueue_map_alloc_coherent(struct virtio_device *vdev,
+ union vring_mapping_token *mapping_token,
+ size_t size, dma_addr_t *map_handle,
+ gfp_t gfp)
+{
+ if (vdev->map)
+ return vdev->map->alloc(mapping_token->token, size,
+ map_handle, gfp);
+ else
+ return dma_alloc_coherent(mapping_token->dma_dev, size,
+ map_handle, gfp);
+}
+EXPORT_SYMBOL_GPL(virtqueue_map_alloc_coherent);
+
+/**
+ * virtqueue_map_free_coherent - free coherent mapping
+ * @vdev: the virtio device we are talking to
+ * @token: device specific mapping token
+ * @size: the size of the buffer
+ * @map_handle: the mapped address that needs to be freed
+ *
+ */
+void virtqueue_map_free_coherent(struct virtio_device *vdev,
+ union vring_mapping_token *mapping_token, size_t size, void *vaddr,
+ dma_addr_t map_handle)
+{
+ if (vdev->map)
+ vdev->map->free(mapping_token->token, size, vaddr,
+ map_handle, 0);
+ else
+ dma_free_coherent(mapping_token->dma_dev, size, vaddr, map_handle);
+}
+EXPORT_SYMBOL_GPL(virtqueue_map_free_coherent);
+
+/**
+ * virtqueue_map_page_attrs - map a page to the device
+ * @_vq: the virtqueue we are talking to
+ * @page: the page that will be mapped by the device
+ * @offset: the offset in the page for a buffer
+ * @size: the buffer size
+ * @dir: mapping direction
+ * @attrs: mapping attributes
+ *
+ * Returns mapped address. Caller should check that by virtqueue_mapping_error().
+ */
+dma_addr_t virtqueue_map_page_attrs(const struct virtqueue *_vq,
+ struct page *page,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ const struct vring_virtqueue *vq = to_vvq(_vq);
+ struct virtio_device *vdev = _vq->vdev;
+
+ if (vdev->map)
+ return vdev->map->map_page(vring_mapping_token(vq),
+ page, offset, size,
+ dir, attrs);
+
+ return dma_map_page_attrs(vring_dma_dev(vq),
+ page, offset, size,
+ dir, attrs);
+}
+EXPORT_SYMBOL_GPL(virtqueue_map_page_attrs);
+
+/**
+ * virtqueue_unmap_page_attrs - map a page to the device
+ * @_vq: the virtqueue we are talking to
+ * @map_handle: the mapped address
+ * @size: the buffer size
+ * @dir: mapping direction
+ * @attrs: unmapping attributes
+ */
+void virtqueue_unmap_page_attrs(const struct virtqueue *_vq,
+ dma_addr_t map_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ const struct vring_virtqueue *vq = to_vvq(_vq);
+ struct virtio_device *vdev = _vq->vdev;
+
+ if (vdev->map)
+ vdev->map->unmap_page(vring_mapping_token(vq), map_handle,
+ size, dir, attrs);
+ else
+ dma_unmap_page_attrs(vring_dma_dev(vq), map_handle,
+ size, dir, attrs);
+}
+EXPORT_SYMBOL_GPL(virtqueue_unmap_page_attrs);
+
/**
* virtqueue_map_single_attrs - map DMA for _vq
* @_vq: the struct virtqueue we're talking about.
@@ -3136,7 +3255,7 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
* The caller calls this to do dma mapping in advance. The DMA address can be
* passed to this _vq when it is in pre-mapped mode.
*
- * return DMA address. Caller should check that by virtqueue_mapping_error().
+ * return mapped address. Caller should check that by virtqueue_mapping_error().
*/
dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
size_t size,
@@ -3155,8 +3274,8 @@ dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
"rejecting DMA map of vmalloc memory\n"))
return DMA_MAPPING_ERROR;
- return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
- offset_in_page(ptr), size, dir, attrs);
+ return virtqueue_map_page_attrs(&vq->vq, virt_to_page(ptr),
+ offset_in_page(ptr), size, dir, attrs);
}
EXPORT_SYMBOL_GPL(virtqueue_map_single_attrs);
@@ -3181,12 +3300,12 @@ void virtqueue_unmap_single_attrs(const struct virtqueue *_vq,
if (!vq->use_map_api)
return;
- dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
+ virtqueue_unmap_page_attrs(_vq, addr, size, dir, attrs);
}
EXPORT_SYMBOL_GPL(virtqueue_unmap_single_attrs);
/**
- * virtqueue_map_mapping_error - check dma address
+ * virtqueue_mapping_error - check dma address
* @_vq: the struct virtqueue we're talking about.
* @addr: DMA address
*
@@ -3196,10 +3315,7 @@ int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- if (!vq->use_map_api)
- return 0;
-
- return dma_mapping_error(vring_dma_dev(vq), addr);
+ return vring_mapping_error(vq, addr);
}
EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
@@ -3216,11 +3332,15 @@ EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
+ struct virtio_device *vdev = _vq->vdev;
if (!vq->use_map_api)
return false;
- return dma_need_sync(vring_dma_dev(vq), addr);
+ if (vdev->map)
+ return vdev->map->need_sync(vring_mapping_token(vq), addr);
+ else
+ return dma_need_sync(vring_dma_dev(vq), addr);
}
EXPORT_SYMBOL_GPL(virtqueue_map_need_sync);
@@ -3242,12 +3362,17 @@ void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq,
enum dma_data_direction dir)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- struct device *dev = vring_dma_dev(vq);
+ struct virtio_device *vdev = _vq->vdev;
if (!vq->use_map_api)
return;
- dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
+ if (vdev->map)
+ vdev->map->sync_single_for_cpu(vring_mapping_token(vq),
+ addr + offset, size, dir);
+ else
+ dma_sync_single_range_for_cpu(vring_dma_dev(vq),
+ addr, offset, size, dir);
}
EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_cpu);
@@ -3268,12 +3393,18 @@ void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq,
enum dma_data_direction dir)
{
const struct vring_virtqueue *vq = to_vvq(_vq);
- struct device *dev = vring_dma_dev(vq);
+ struct virtio_device *vdev = _vq->vdev;
if (!vq->use_map_api)
return;
- dma_sync_single_range_for_device(dev, addr, offset, size, dir);
+ if (vdev->map)
+ vdev->map->sync_single_for_device(vring_mapping_token(vq),
+ addr + offset,
+ size, dir);
+ else
+ dma_sync_single_range_for_device(vring_dma_dev(vq), addr,
+ offset, size, dir);
}
EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device);
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 37029df94aaf..e1973c7b1d1c 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -44,7 +44,7 @@ union vring_mapping_token {
/* Device that performs DMA */
struct device *dma_dev;
/* Transport specific token used for doing map */
- void *opaque;
+ void *token;
};
int virtqueue_add_outbuf(struct virtqueue *vq,
@@ -165,6 +165,7 @@ struct virtio_device {
struct virtio_device_id id;
const struct virtio_config_ops *config;
const struct vringh_config_ops *vringh_config;
+ const struct virtio_map_ops *map;
struct list_head vqs;
u64 features;
void *priv;
@@ -266,6 +267,29 @@ void unregister_virtio_driver(struct virtio_driver *drv);
module_driver(__virtio_driver, register_virtio_driver, \
unregister_virtio_driver)
+
+void *virtqueue_map_alloc_coherent(struct virtio_device *vdev,
+ union vring_mapping_token *mapping_token,
+ size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp);
+
+void virtqueue_map_free_coherent(struct virtio_device *vdev,
+ union vring_mapping_token *mapping_token,
+ size_t size, void *vaddr,
+ dma_addr_t dma_handle);
+
+dma_addr_t virtqueue_map_page_attrs(const struct virtqueue *_vq,
+ struct page *page,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction dir,
+ unsigned long attrs);
+
+void virtqueue_unmap_page_attrs(const struct virtqueue *_vq,
+ dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+
dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
enum dma_data_direction dir, unsigned long attrs);
void virtqueue_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index b3e1d30c765b..784ce56197c4 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -133,6 +133,78 @@ struct virtio_config_ops {
int (*enable_vq_after_reset)(struct virtqueue *vq);
};
+/**
+ * struct virtio_map_ops - operations for mapping buffer for a virtio device
+ * Note: For transport that has its own mapping logic it must
+ * implements all of the operations
+ * @map_page: map a buffer to the device
+ * token: device specific mapping token
+ * page: the page that will be mapped by the device
+ * offset: the offset in the page for a buffer
+ * size: the buffer size
+ * dir: mapping direction
+ * attrs: mapping attributes
+ * Returns: the mapped address
+ * @unmap_page: unmap a buffer from the device
+ * token: device specific mapping token
+ * map_handle: the mapped address
+ * size: the buffer size
+ * dir: mapping direction
+ * attrs: unmapping attributes
+ * @sync_single_for_cpu: sync a single buffer from device to cpu
+ * token: device specific mapping token
+ * map_handle: the mapping address to sync
+ * size: the size of the buffer
+ * dir: synchronization direction
+ * @sync_single_for_device: sync a single buffer from cpu to device
+ * token: device specific mapping token
+ * map_handle: the mapping address to sync
+ * size: the size of the buffer
+ * dir: synchronization direction
+ * @alloc: alloc a coherent buffer mapping
+ * token: device specific mapping token
+ * size: the size of the buffer
+ * map_handle: the mapping address to sync
+ * gfp: allocation flag (GFP_XXX)
+ * Returns: virtual address of the allocated buffer
+ * @free: free a coherent buffer mapping
+ * token: device specific mapping token
+ * size: the size of the buffer
+ * vaddr: virtual address of the buffer
+ * map_handle: the mapping address to sync
+ * attrs: unmapping attributes
+ * @need_sync: if the buffer needs synchronization
+ * token: device specific mapping token
+ * map_handle: the mapped address
+ * Returns: whether the buffer needs synchronization
+ * @mapping_error: if the mapping address is error
+ * token: device specific mapping token
+ * map_handle: the mapped address
+ * @max_mapping_size: get the maximum buffer size that can be mapped
+ * token: device specific mapping token
+ * Returns: the maximum buffer size that can be mapped
+ */
+struct virtio_map_ops {
+ dma_addr_t (*map_page)(void *token, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir, unsigned long attrs);
+ void (*unmap_page)(void *token, dma_addr_t map_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+ void (*sync_single_for_cpu)(void *token, dma_addr_t map_handle,
+ size_t size, enum dma_data_direction dir);
+ void (*sync_single_for_device)(void *token,
+ dma_addr_t map_handle, size_t size,
+ enum dma_data_direction dir);
+ void *(*alloc)(void *token, size_t size,
+ dma_addr_t *map_handle, gfp_t gfp);
+ void (*free)(void *token, size_t size, void *vaddr,
+ dma_addr_t map_handle, unsigned long attrs);
+ bool (*need_sync)(void *token, dma_addr_t map_handle);
+ int (*mapping_error)(void *token, dma_addr_t map_handle);
+ size_t (*max_mapping_size)(void *token);
+};
+
/* If driver didn't advertise the feature, it will never appear. */
void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
unsigned int fbit);
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 7/9] vdpa: support mapping token
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (5 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 6/9] virtio: introduce map ops in virtio core Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 8:45 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 8/9] vdpa: introduce map ops Jason Wang
2025-08-13 5:48 ` [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API Jason Wang
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel; +Cc: hch
Virtio core switches from DMA device to mapping token, let's do that
as well for vDPA.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/vdpa/alibaba/eni_vdpa.c | 2 +-
drivers/vdpa/ifcvf/ifcvf_main.c | 2 +-
drivers/vdpa/mlx5/core/mr.c | 4 ++--
drivers/vdpa/mlx5/net/mlx5_vnet.c | 13 ++++++++-----
drivers/vdpa/octeon_ep/octep_vdpa_main.c | 2 +-
drivers/vdpa/pds/vdpa_dev.c | 2 +-
drivers/vdpa/solidrun/snet_main.c | 4 ++--
drivers/vdpa/vdpa.c | 2 +-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 2 +-
drivers/vdpa/vdpa_user/vduse_dev.c | 2 +-
drivers/vdpa/virtio_pci/vp_vdpa.c | 2 +-
drivers/vhost/vdpa.c | 8 ++++++--
drivers/virtio/virtio_vdpa.c | 11 +++++------
include/linux/vdpa.h | 15 ++++++++-------
14 files changed, 39 insertions(+), 32 deletions(-)
diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
index ad7f3447fe90..cbec3fcffaef 100644
--- a/drivers/vdpa/alibaba/eni_vdpa.c
+++ b/drivers/vdpa/alibaba/eni_vdpa.c
@@ -496,7 +496,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
pci_set_drvdata(pdev, eni_vdpa);
- eni_vdpa->vdpa.dma_dev = &pdev->dev;
+ eni_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
eni_vdpa->queues = eni_vdpa_get_num_queues(eni_vdpa);
eni_vdpa->vring = devm_kcalloc(&pdev->dev, eni_vdpa->queues,
diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
index ccf64d7bbfaa..520a7d4db435 100644
--- a/drivers/vdpa/ifcvf/ifcvf_main.c
+++ b/drivers/vdpa/ifcvf/ifcvf_main.c
@@ -713,7 +713,7 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
ifcvf_mgmt_dev->adapter = adapter;
adapter->pdev = pdev;
- adapter->vdpa.dma_dev = &pdev->dev;
+ adapter->vdpa.mapping_token.dma_dev = &pdev->dev;
adapter->vdpa.mdev = mdev;
adapter->vf = vf;
vdpa_dev = &adapter->vdpa;
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index c7a20278bc3c..b4806324afa0 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -378,7 +378,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
u64 pa, offset;
u64 paend;
struct scatterlist *sg;
- struct device *dma = mvdev->vdev.dma_dev;
+ struct device *dma = mvdev->vdev.mapping_token.dma_dev;
for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
map; map = vhost_iotlb_itree_next(map, mr->start, mr->end - 1)) {
@@ -432,7 +432,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
{
- struct device *dma = mvdev->vdev.dma_dev;
+ struct device *dma = mvdev->vdev.mapping_token.dma_dev;
destroy_direct_mr(mvdev, mr);
dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 0ed2fc28e1ce..4a1a8b0a0123 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -3395,14 +3395,17 @@ static int mlx5_vdpa_reset_map(struct vdpa_device *vdev, unsigned int asid)
return err;
}
-static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx)
+static union vring_mapping_token mlx5_get_vq_mapping_token(struct vdpa_device *vdev, u16 idx)
{
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
+ union vring_mapping_token mapping_token;
if (is_ctrl_vq_idx(mvdev, idx))
- return &vdev->dev;
+ mapping_token.dma_dev = &vdev->dev;
+ else
+ mapping_token.dma_dev = mvdev->vdev.mapping_token.dma_dev;
- return mvdev->vdev.dma_dev;
+ return mapping_token;
}
static void free_irqs(struct mlx5_vdpa_net *ndev)
@@ -3686,7 +3689,7 @@ static const struct vdpa_config_ops mlx5_vdpa_ops = {
.set_map = mlx5_vdpa_set_map,
.reset_map = mlx5_vdpa_reset_map,
.set_group_asid = mlx5_set_group_asid,
- .get_vq_dma_dev = mlx5_get_vq_dma_dev,
+ .get_vq_mapping_token = mlx5_get_vq_mapping_token,
.free = mlx5_vdpa_free,
.suspend = mlx5_vdpa_suspend,
.resume = mlx5_vdpa_resume, /* Op disabled if not supported. */
@@ -3965,7 +3968,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
}
ndev->mvdev.mlx_features = device_features;
- mvdev->vdev.dma_dev = &mdev->pdev->dev;
+ mvdev->vdev.mapping_token.dma_dev = &mdev->pdev->dev;
err = mlx5_vdpa_alloc_resources(&ndev->mvdev);
if (err)
goto err_alloc;
diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
index 9b49efd24391..e229b421d194 100644
--- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c
+++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
@@ -516,7 +516,7 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
}
oct_vdpa->pdev = pdev;
- oct_vdpa->vdpa.dma_dev = &pdev->dev;
+ oct_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
oct_vdpa->vdpa.mdev = mdev;
oct_vdpa->oct_hw = oct_hw;
vdpa_dev = &oct_vdpa->vdpa;
diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c
index 301d95e08596..c9da0e519d5c 100644
--- a/drivers/vdpa/pds/vdpa_dev.c
+++ b/drivers/vdpa/pds/vdpa_dev.c
@@ -643,7 +643,7 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
pdev = vdpa_aux->padev->vf_pdev;
dma_dev = &pdev->dev;
- pdsv->vdpa_dev.dma_dev = dma_dev;
+ pdsv->vdpa_dev.mapping_token.dma_dev = dma_dev;
status = pds_vdpa_get_status(&pdsv->vdpa_dev);
if (status == 0xff) {
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
index 55ec51c17ab3..d7b4eff77c95 100644
--- a/drivers/vdpa/solidrun/snet_main.c
+++ b/drivers/vdpa/solidrun/snet_main.c
@@ -1052,8 +1052,8 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)
*/
snet_reserve_irq_idx(pf_irqs ? pdev_pf : pdev, snet);
- /*set DMA device*/
- snet->vdpa.dma_dev = &pdev->dev;
+ /* set map token */
+ snet->vdpa.mapping_token.dma_dev = &pdev->dev;
/* Register VDPA device */
ret = vdpa_register_device(&snet->vdpa, snet->cfg->vq_num);
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 8a372b51c21a..0115ce04979c 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -151,7 +151,7 @@ static void vdpa_release_dev(struct device *d)
* Driver should use vdpa_alloc_device() wrapper macro instead of
* using this directly.
*
- * Return: Returns an error when parent/config/dma_dev is not set or fail to get
+ * Return: Returns an error when parent/config/mapping_token is not set or fail to get
* ida.
*/
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index c204fc8e471a..9a07063aaff7 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -272,7 +272,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0],
&vdpasim->iommu_lock);
- vdpasim->vdpa.dma_dev = dev;
+ vdpasim->vdpa.mapping_token.dma_dev = dev;
return vdpasim;
diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index 04620bb77203..8e32b3db8608 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -2022,7 +2022,7 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
return ret;
}
set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
- vdev->vdpa.dma_dev = &vdev->vdpa.dev;
+ vdev->vdpa.mapping_token.dma_dev = &vdev->vdpa.dev;
vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
return 0;
diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
index 8787407f75b0..2cb0dbf1740e 100644
--- a/drivers/vdpa/virtio_pci/vp_vdpa.c
+++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
@@ -520,7 +520,7 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
vp_vdpa_mgtdev->vp_vdpa = vp_vdpa;
- vp_vdpa->vdpa.dma_dev = &pdev->dev;
+ vp_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
vp_vdpa->queues = vp_modern_get_num_queues(mdev);
vp_vdpa->mdev = mdev;
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index 5a49b5a6d496..3d4c44b3f2b7 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -1320,7 +1320,9 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
{
struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config;
- struct device *dma_dev = vdpa_get_dma_dev(vdpa);
+ union vring_mapping_token *mapping_token =
+ vdpa_get_mapping_token(vdpa);
+ struct device *dma_dev = mapping_token->dma_dev;
int ret;
/* Device want to do DMA by itself */
@@ -1355,7 +1357,9 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
{
struct vdpa_device *vdpa = v->vdpa;
- struct device *dma_dev = vdpa_get_dma_dev(vdpa);
+ union vring_mapping_token *mapping_token =
+ vdpa_get_mapping_token(vdpa);
+ struct device *dma_dev = mapping_token->dma_dev;
if (v->domain) {
iommu_detach_device(v->domain, dma_dev);
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
index acea98ab08ee..1a10024a8e4f 100644
--- a/drivers/virtio/virtio_vdpa.c
+++ b/drivers/virtio/virtio_vdpa.c
@@ -133,7 +133,6 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
const char *name, bool ctx)
{
struct vdpa_device *vdpa = vd_get_vdpa(vdev);
- struct device *dma_dev;
const struct vdpa_config_ops *ops = vdpa->config;
bool (*notify)(struct virtqueue *vq) = virtio_vdpa_notify;
struct vdpa_callback cb;
@@ -182,11 +181,11 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
/* Create the vring */
align = ops->get_vq_align(vdpa);
- if (ops->get_vq_dma_dev)
- dma_dev = ops->get_vq_dma_dev(vdpa, index);
+ if (ops->get_vq_mapping_token)
+ mapping_token = ops->get_vq_mapping_token(vdpa, index);
else
- dma_dev = vdpa_get_dma_dev(vdpa);
- mapping_token.dma_dev = dma_dev;
+ mapping_token = *vdpa_get_mapping_token(vdpa);
+
vq = vring_create_virtqueue_map(index, max_num, align, vdev,
true, may_reduce_num, ctx,
notify, callback, name, &mapping_token);
@@ -463,7 +462,7 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa)
if (!vd_dev)
return -ENOMEM;
- vd_dev->vdev.dev.parent = vdpa_get_dma_dev(vdpa);
+ vd_dev->vdev.dev.parent = vdpa_get_mapping_token(vdpa)->dma_dev;
vd_dev->vdev.dev.release = virtio_vdpa_release_dev;
vd_dev->vdev.config = &virtio_vdpa_config_ops;
vd_dev->vdpa = vdpa;
diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
index 2e7a30fe6b92..f806f13ca260 100644
--- a/include/linux/vdpa.h
+++ b/include/linux/vdpa.h
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/virtio.h>
#include <linux/vhost_iotlb.h>
#include <linux/virtio_net.h>
#include <linux/virtio_blk.h>
@@ -70,7 +71,7 @@ struct vdpa_mgmt_dev;
/**
* struct vdpa_device - representation of a vDPA device
* @dev: underlying device
- * @dma_dev: the actual device that is performing DMA
+ * @mapping_token: the token passed to upper layer to be used for mapping
* @driver_override: driver name to force a match; do not set directly,
* because core frees it; use driver_set_override() to
* set or clear it.
@@ -87,7 +88,7 @@ struct vdpa_mgmt_dev;
*/
struct vdpa_device {
struct device dev;
- struct device *dma_dev;
+ union vring_mapping_token mapping_token;
const char *driver_override;
const struct vdpa_config_ops *config;
struct rw_semaphore cf_lock; /* Protects get/set config */
@@ -352,11 +353,11 @@ struct vdpa_map_file {
* @vdev: vdpa device
* @asid: address space identifier
* Returns integer: success (0) or error (< 0)
- * @get_vq_dma_dev: Get the dma device for a specific
+ * @get_vq_mapping_token: Get the map token for a specific
* virtqueue (optional)
* @vdev: vdpa device
* @idx: virtqueue index
- * Returns pointer to structure device or error (NULL)
+ * Returns map token union error (NULL)
* @bind_mm: Bind the device to a specific address space
* so the vDPA framework can use VA when this
* callback is implemented. (optional)
@@ -436,7 +437,7 @@ struct vdpa_config_ops {
int (*reset_map)(struct vdpa_device *vdev, unsigned int asid);
int (*set_group_asid)(struct vdpa_device *vdev, unsigned int group,
unsigned int asid);
- struct device *(*get_vq_dma_dev)(struct vdpa_device *vdev, u16 idx);
+ union vring_mapping_token (*get_vq_mapping_token)(struct vdpa_device *vdev, u16 idx);
int (*bind_mm)(struct vdpa_device *vdev, struct mm_struct *mm);
void (*unbind_mm)(struct vdpa_device *vdev);
@@ -520,9 +521,9 @@ static inline void vdpa_set_drvdata(struct vdpa_device *vdev, void *data)
dev_set_drvdata(&vdev->dev, data);
}
-static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev)
+static inline union vring_mapping_token *vdpa_get_mapping_token(struct vdpa_device *vdev)
{
- return vdev->dma_dev;
+ return &vdev->mapping_token;
}
static inline int vdpa_reset(struct vdpa_device *vdev, u32 flags)
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 8/9] vdpa: introduce map ops
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (6 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 7/9] vdpa: support mapping token Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 8:46 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API Jason Wang
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel
Cc: hch, Christoph Hellwig
Virtio core allows the transport to provide device or transport
specific mapping functions. This patch adds this support to vDPA. We
can simply do this by allowing the vDPA parent to register a
virtio_map_ops.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/vdpa/alibaba/eni_vdpa.c | 3 ++-
drivers/vdpa/ifcvf/ifcvf_main.c | 3 ++-
drivers/vdpa/mlx5/net/mlx5_vnet.c | 2 +-
drivers/vdpa/octeon_ep/octep_vdpa_main.c | 4 ++--
drivers/vdpa/pds/vdpa_dev.c | 3 ++-
drivers/vdpa/solidrun/snet_main.c | 4 ++--
drivers/vdpa/vdpa.c | 3 +++
drivers/vdpa/vdpa_sim/vdpa_sim.c | 2 +-
drivers/vdpa/vdpa_user/vduse_dev.c | 3 ++-
drivers/vdpa/virtio_pci/vp_vdpa.c | 3 ++-
drivers/vhost/vdpa.c | 10 ++++++++++
drivers/virtio/virtio_vdpa.c | 4 +++-
include/linux/vdpa.h | 10 +++++++---
13 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
index cbec3fcffaef..a0420da37863 100644
--- a/drivers/vdpa/alibaba/eni_vdpa.c
+++ b/drivers/vdpa/alibaba/eni_vdpa.c
@@ -478,7 +478,8 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
eni_vdpa = vdpa_alloc_device(struct eni_vdpa, vdpa,
- dev, &eni_vdpa_ops, 1, 1, NULL, false);
+ dev, &eni_vdpa_ops, NULL,
+ 1, 1, NULL, false);
if (IS_ERR(eni_vdpa)) {
ENI_ERR(pdev, "failed to allocate vDPA structure\n");
return PTR_ERR(eni_vdpa);
diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
index 520a7d4db435..2fd8a9b20ac3 100644
--- a/drivers/vdpa/ifcvf/ifcvf_main.c
+++ b/drivers/vdpa/ifcvf/ifcvf_main.c
@@ -705,7 +705,8 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
vf = &ifcvf_mgmt_dev->vf;
pdev = vf->pdev;
adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
- &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false);
+ &pdev->dev, &ifc_vdpa_ops,
+ NULL, 1, 1, NULL, false);
if (IS_ERR(adapter)) {
IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
return PTR_ERR(adapter);
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 4a1a8b0a0123..8a8cf6942998 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -3882,7 +3882,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
}
ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mgtdev->vdpa_ops,
- MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false);
+ NULL, MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false);
if (IS_ERR(ndev))
return PTR_ERR(ndev);
diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
index e229b421d194..3ef9c2fd8f57 100644
--- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c
+++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
@@ -508,8 +508,8 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
u64 device_features;
int ret;
- oct_vdpa = vdpa_alloc_device(struct octep_vdpa, vdpa, &pdev->dev, &octep_vdpa_ops, 1, 1,
- NULL, false);
+ oct_vdpa = vdpa_alloc_device(struct octep_vdpa, vdpa, &pdev->dev, &octep_vdpa_ops,
+ NULL, 1, 1, NULL, false);
if (IS_ERR(oct_vdpa)) {
dev_err(&pdev->dev, "Failed to allocate vDPA structure for octep vdpa device");
return PTR_ERR(oct_vdpa);
diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c
index c9da0e519d5c..ed3e015c4668 100644
--- a/drivers/vdpa/pds/vdpa_dev.c
+++ b/drivers/vdpa/pds/vdpa_dev.c
@@ -632,7 +632,8 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
}
pdsv = vdpa_alloc_device(struct pds_vdpa_device, vdpa_dev,
- dev, &pds_vdpa_ops, 1, 1, name, false);
+ dev, &pds_vdpa_ops, NULL,
+ 1, 1, name, false);
if (IS_ERR(pdsv)) {
dev_err(dev, "Failed to allocate vDPA structure: %pe\n", pdsv);
return PTR_ERR(pdsv);
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
index d7b4eff77c95..849d325cab31 100644
--- a/drivers/vdpa/solidrun/snet_main.c
+++ b/drivers/vdpa/solidrun/snet_main.c
@@ -1008,8 +1008,8 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)
}
/* Allocate vdpa device */
- snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops, 1, 1, NULL,
- false);
+ snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops,
+ NULL, 1, 1, NULL, false);
if (!snet) {
SNET_ERR(pdev, "Failed to allocate a vdpa device\n");
ret = -ENOMEM;
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 0115ce04979c..8421c882f4d6 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -142,6 +142,7 @@ static void vdpa_release_dev(struct device *d)
* initialized but before registered.
* @parent: the parent device
* @config: the bus operations that is supported by this device
+ * @map: the map opeartions that is supported by this device
* @ngroups: number of groups supported by this device
* @nas: number of address spaces supported by this device
* @size: size of the parent structure that contains private data
@@ -156,6 +157,7 @@ static void vdpa_release_dev(struct device *d)
*/
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
const struct vdpa_config_ops *config,
+ const struct virtio_map_ops *map,
unsigned int ngroups, unsigned int nas,
size_t size, const char *name,
bool use_va)
@@ -187,6 +189,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
vdev->dev.release = vdpa_release_dev;
vdev->index = err;
vdev->config = config;
+ vdev->map = map;
vdev->features_valid = false;
vdev->use_va = use_va;
vdev->ngroups = ngroups;
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index 9a07063aaff7..fa288960d53f 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -215,7 +215,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
else
ops = &vdpasim_config_ops;
- vdpa = __vdpa_alloc_device(NULL, ops,
+ vdpa = __vdpa_alloc_device(NULL, ops, NULL,
dev_attr->ngroups, dev_attr->nas,
dev_attr->alloc_size,
dev_attr->name, use_va);
diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index 8e32b3db8608..f161059d543e 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -2009,7 +2009,8 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
return -EEXIST;
vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
- &vduse_vdpa_config_ops, 1, 1, name, true);
+ &vduse_vdpa_config_ops, NULL,
+ 1, 1, name, true);
if (IS_ERR(vdev))
return PTR_ERR(vdev);
diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
index 2cb0dbf1740e..e908b2a37c92 100644
--- a/drivers/vdpa/virtio_pci/vp_vdpa.c
+++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
@@ -511,7 +511,8 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
int ret, i;
vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa,
- dev, &vp_vdpa_ops, 1, 1, name, false);
+ dev, &vp_vdpa_ops, NULL,
+ 1, 1, name, false);
if (IS_ERR(vp_vdpa)) {
dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n");
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index 3d4c44b3f2b7..147fdef02f06 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -1322,13 +1322,23 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
const struct vdpa_config_ops *ops = vdpa->config;
union vring_mapping_token *mapping_token =
vdpa_get_mapping_token(vdpa);
+ const struct virtio_map_ops *map = vdpa->map;
struct device *dma_dev = mapping_token->dma_dev;
int ret;
+ /* IOMMU domain only works for DMA device */
+ if (vdpa->map)
+ return -EINVAL;
+
/* Device want to do DMA by itself */
if (ops->set_map || ops->dma_map)
return 0;
+ if (map) {
+ dev_warn(&v->dev, "Can't allocate a domian, device use vendor specific mappings\n");
+ return -EINVAL;
+ }
+
if (!device_iommu_capable(dma_dev, IOMMU_CAP_CACHE_COHERENCY)) {
dev_warn_once(&v->dev,
"Failed to allocate domain, device is not IOMMU cache coherent capable\n");
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
index 1a10024a8e4f..fddfcfabf28e 100644
--- a/drivers/virtio/virtio_vdpa.c
+++ b/drivers/virtio/virtio_vdpa.c
@@ -462,9 +462,11 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa)
if (!vd_dev)
return -ENOMEM;
- vd_dev->vdev.dev.parent = vdpa_get_mapping_token(vdpa)->dma_dev;
+ vd_dev->vdev.dev.parent = vdpa->map ? &vdpa->dev :
+ vdpa_get_mapping_token(vdpa)->dma_dev;
vd_dev->vdev.dev.release = virtio_vdpa_release_dev;
vd_dev->vdev.config = &virtio_vdpa_config_ops;
+ vd_dev->vdev.map = vdpa->map;
vd_dev->vdpa = vdpa;
vd_dev->vdev.id.device = ops->get_device_id(vdpa);
diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
index f806f13ca260..d328ec1ab5ea 100644
--- a/include/linux/vdpa.h
+++ b/include/linux/vdpa.h
@@ -76,6 +76,7 @@ struct vdpa_mgmt_dev;
* because core frees it; use driver_set_override() to
* set or clear it.
* @config: the configuration ops for this device.
+ * @map: the map ops for this device
* @cf_lock: Protects get and set access to configuration layout.
* @index: device index
* @features_valid: were features initialized? for legacy guests
@@ -91,6 +92,7 @@ struct vdpa_device {
union vring_mapping_token mapping_token;
const char *driver_override;
const struct vdpa_config_ops *config;
+ const struct virtio_map_ops *map;
struct rw_semaphore cf_lock; /* Protects get/set config */
unsigned int index;
bool features_valid;
@@ -447,6 +449,7 @@ struct vdpa_config_ops {
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
const struct vdpa_config_ops *config,
+ const struct virtio_map_ops *map,
unsigned int ngroups, unsigned int nas,
size_t size, const char *name,
bool use_va);
@@ -458,6 +461,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
* @member: the name of struct vdpa_device within the @dev_struct
* @parent: the parent device
* @config: the bus operations that is supported by this device
+ * @map: the map operations that is supported by this device
* @ngroups: the number of virtqueue groups supported by this device
* @nas: the number of address spaces
* @name: name of the vdpa device
@@ -465,10 +469,10 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
*
* Return allocated data structure or ERR_PTR upon error
*/
-#define vdpa_alloc_device(dev_struct, member, parent, config, ngroups, nas, \
- name, use_va) \
+#define vdpa_alloc_device(dev_struct, member, parent, config, map, \
+ ngroups, nas, name, use_va) \
container_of((__vdpa_alloc_device( \
- parent, config, ngroups, nas, \
+ parent, config, map, ngroups, nas, \
(sizeof(dev_struct) + \
BUILD_BUG_ON_ZERO(offsetof( \
dev_struct, member))), name, use_va)), \
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
` (7 preceding siblings ...)
2025-08-13 5:48 ` [PATCH V5 8/9] vdpa: introduce map ops Jason Wang
@ 2025-08-13 5:48 ` Jason Wang
2025-08-13 9:02 ` Eugenio Perez Martin
8 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-13 5:48 UTC (permalink / raw)
To: mst, jasowang, xuanzhuo, eperezma, virtualization, linux-kernel; +Cc: hch
Lacking the support of device specific mapping supported in virtio,
VDUSE must trick the DMA API in order to make virtio-vdpa transport
work. This is done by advertising vDPA device as dma device with a
VDUSE specific dma_ops even if it doesn't do DMA at all.
This will be fixed by this patch. Thanks to the new mapping operations
support by virtio and vDPA. VDUSE can simply switch to advertise its
specific mappings operations to virtio via virtio-vdpa then DMA API is
not needed for VDUSE any more and iova domain could be used as the
mapping token instead.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/vdpa/Kconfig | 8 +--
drivers/vdpa/vdpa_user/iova_domain.c | 2 +-
drivers/vdpa/vdpa_user/iova_domain.h | 2 +-
drivers/vdpa/vdpa_user/vduse_dev.c | 75 ++++++++++++++--------------
4 files changed, 41 insertions(+), 46 deletions(-)
diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
index 559fb9d3271f..857cf288c876 100644
--- a/drivers/vdpa/Kconfig
+++ b/drivers/vdpa/Kconfig
@@ -34,13 +34,7 @@ config VDPA_SIM_BLOCK
config VDPA_USER
tristate "VDUSE (vDPA Device in Userspace) support"
- depends on EVENTFD && MMU && HAS_DMA
- #
- # This driver incorrectly tries to override the dma_ops. It should
- # never have done that, but for now keep it working on architectures
- # that use dma ops
- #
- depends on ARCH_HAS_DMA_OPS
+ depends on EVENTFD && MMU
select VHOST_IOTLB
select IOMMU_IOVA
help
diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
index 58116f89d8da..ccaed24b7ef8 100644
--- a/drivers/vdpa/vdpa_user/iova_domain.c
+++ b/drivers/vdpa/vdpa_user/iova_domain.c
@@ -447,7 +447,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
size_t size, dma_addr_t *dma_addr,
- gfp_t flag, unsigned long attrs)
+ gfp_t flag)
{
struct iova_domain *iovad = &domain->consistent_iovad;
unsigned long limit = domain->iova_limit;
diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h
index 7f3f0928ec78..1f3c30be272a 100644
--- a/drivers/vdpa/vdpa_user/iova_domain.h
+++ b/drivers/vdpa/vdpa_user/iova_domain.h
@@ -64,7 +64,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
size_t size, dma_addr_t *dma_addr,
- gfp_t flag, unsigned long attrs);
+ gfp_t flag);
void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
void *vaddr, dma_addr_t dma_addr,
diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index f161059d543e..3260edefdf0d 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -88,6 +88,7 @@ struct vduse_dev {
struct device *dev;
struct vduse_virtqueue **vqs;
struct vduse_iova_domain *domain;
+ struct vduse_iova_domain *dom;
char *name;
struct mutex lock;
spinlock_t msg_lock;
@@ -814,59 +815,53 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
.free = vduse_vdpa_free,
};
-static void vduse_dev_sync_single_for_device(struct device *dev,
+static void vduse_dev_sync_single_for_device(void *token,
dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
vduse_domain_sync_single_for_device(domain, dma_addr, size, dir);
}
-static void vduse_dev_sync_single_for_cpu(struct device *dev,
+static void vduse_dev_sync_single_for_cpu(void *token,
dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
}
-static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
+static dma_addr_t vduse_dev_map_page(void *token, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
return vduse_domain_map_page(domain, page, offset, size, dir, attrs);
}
-static void vduse_dev_unmap_page(struct device *dev, dma_addr_t dma_addr,
+static void vduse_dev_unmap_page(void *token, dma_addr_t dma_addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs);
}
-static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag,
- unsigned long attrs)
+static void *vduse_dev_alloc_coherent(void *token, size_t size,
+ dma_addr_t *dma_addr, gfp_t flag)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
unsigned long iova;
void *addr;
*dma_addr = DMA_MAPPING_ERROR;
addr = vduse_domain_alloc_coherent(domain, size,
- (dma_addr_t *)&iova, flag, attrs);
+ (dma_addr_t *)&iova, flag);
if (!addr)
return NULL;
@@ -875,31 +870,45 @@ static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
return addr;
}
-static void vduse_dev_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_addr,
- unsigned long attrs)
+static void vduse_dev_free_coherent(void *token, size_t size,
+ void *vaddr, dma_addr_t dma_addr,
+ unsigned long attrs)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs);
}
-static size_t vduse_dev_max_mapping_size(struct device *dev)
+static bool vduse_dev_need_sync(void *token, dma_addr_t dma_addr)
{
- struct vduse_dev *vdev = dev_to_vduse(dev);
- struct vduse_iova_domain *domain = vdev->domain;
+ struct vduse_iova_domain *domain = token;
+
+ return dma_addr < domain->bounce_size;
+}
+
+static int vduse_dev_mapping_error(void *token, dma_addr_t dma_addr)
+{
+ if (unlikely(dma_addr == DMA_MAPPING_ERROR))
+ return -ENOMEM;
+ return 0;
+}
+
+static size_t vduse_dev_max_mapping_size(void *token)
+{
+ struct vduse_iova_domain *domain = token;
return domain->bounce_size;
}
-static const struct dma_map_ops vduse_dev_dma_ops = {
+static const struct virtio_map_ops vduse_map_ops = {
.sync_single_for_device = vduse_dev_sync_single_for_device,
.sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
.map_page = vduse_dev_map_page,
.unmap_page = vduse_dev_unmap_page,
.alloc = vduse_dev_alloc_coherent,
.free = vduse_dev_free_coherent,
+ .need_sync = vduse_dev_need_sync,
+ .mapping_error = vduse_dev_mapping_error,
.max_mapping_size = vduse_dev_max_mapping_size,
};
@@ -2003,27 +2012,18 @@ static struct vduse_mgmt_dev *vduse_mgmt;
static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
{
struct vduse_vdpa *vdev;
- int ret;
if (dev->vdev)
return -EEXIST;
vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
- &vduse_vdpa_config_ops, NULL,
+ &vduse_vdpa_config_ops, &vduse_map_ops,
1, 1, name, true);
if (IS_ERR(vdev))
return PTR_ERR(vdev);
dev->vdev = vdev;
vdev->dev = dev;
- vdev->vdpa.dev.dma_mask = &vdev->vdpa.dev.coherent_dma_mask;
- ret = dma_set_mask_and_coherent(&vdev->vdpa.dev, DMA_BIT_MASK(64));
- if (ret) {
- put_device(&vdev->vdpa.dev);
- return ret;
- }
- set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
- vdev->vdpa.mapping_token.dma_dev = &vdev->vdpa.dev;
vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
return 0;
@@ -2056,6 +2056,7 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
return -ENOMEM;
}
+ dev->vdev->vdpa.mapping_token.token = dev->domain;
ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num);
if (ret) {
put_device(&dev->vdev->vdpa.dev);
--
2.31.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers
2025-08-13 5:48 ` [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers Jason Wang
@ 2025-08-13 7:14 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 7:14 UTC (permalink / raw)
To: Jason Wang
Cc: mst, xuanzhuo, virtualization, linux-kernel, hch,
Christoph Hellwig
On Wed, Aug 13, 2025 at 7:48 AM Jason Wang <jasowang@redhat.com> wrote:
>
> This patch consities virtqueue point for DMA helpers.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 25 +++++++++++++------------
> include/linux/virtio.h | 12 ++++++------
> 2 files changed, 19 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index f5062061c408..103bad8cffff 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -3149,12 +3149,12 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
> *
> * return DMA address. Caller should check that by virtqueue_dma_mapping_error().
> */
> -dma_addr_t virtqueue_dma_map_single_attrs(struct virtqueue *_vq, void *ptr,
> +dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr,
> size_t size,
> enum dma_data_direction dir,
> unsigned long attrs)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (!vq->use_dma_api) {
> kmsan_handle_dma(virt_to_page(ptr), offset_in_page(ptr), size, dir);
> @@ -3176,11 +3176,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
> * Unmap the address that is mapped by the virtqueue_dma_map_* APIs.
> *
> */
> -void virtqueue_dma_unmap_single_attrs(struct virtqueue *_vq, dma_addr_t addr,
> +void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
> + dma_addr_t addr,
> size_t size, enum dma_data_direction dir,
> unsigned long attrs)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (!vq->use_dma_api)
> return;
> @@ -3196,9 +3197,9 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
> *
> * Returns 0 means dma valid. Other means invalid dma address.
> */
> -int virtqueue_dma_mapping_error(struct virtqueue *_vq, dma_addr_t addr)
> +int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (!vq->use_dma_api)
> return 0;
> @@ -3217,9 +3218,9 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_mapping_error);
> *
> * return bool
> */
> -bool virtqueue_dma_need_sync(struct virtqueue *_vq, dma_addr_t addr)
> +bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (!vq->use_dma_api)
> return false;
> @@ -3240,12 +3241,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_need_sync);
> * the DMA address really needs to be synchronized
> *
> */
> -void virtqueue_dma_sync_single_range_for_cpu(struct virtqueue *_vq,
> +void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
> dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
> struct device *dev = vring_dma_dev(vq);
>
> if (!vq->use_dma_api)
> @@ -3266,12 +3267,12 @@ EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_cpu);
> * Before calling this function, use virtqueue_dma_need_sync() to confirm that
> * the DMA address really needs to be synchronized
> */
> -void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq,
> +void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
> dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir)
> {
> - struct vring_virtqueue *vq = to_vvq(_vq);
> + const struct vring_virtqueue *vq = to_vvq(_vq);
> struct device *dev = vring_dma_dev(vq);
>
> if (!vq->use_dma_api)
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index 8b745ce0cf5f..cf8def717dfd 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -259,18 +259,18 @@ void unregister_virtio_driver(struct virtio_driver *drv);
> module_driver(__virtio_driver, register_virtio_driver, \
> unregister_virtio_driver)
>
> -dma_addr_t virtqueue_dma_map_single_attrs(struct virtqueue *_vq, void *ptr, size_t size,
> +dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
> enum dma_data_direction dir, unsigned long attrs);
> -void virtqueue_dma_unmap_single_attrs(struct virtqueue *_vq, dma_addr_t addr,
> +void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
> size_t size, enum dma_data_direction dir,
> unsigned long attrs);
> -int virtqueue_dma_mapping_error(struct virtqueue *_vq, dma_addr_t addr);
> +int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
>
> -bool virtqueue_dma_need_sync(struct virtqueue *_vq, dma_addr_t addr);
> -void virtqueue_dma_sync_single_range_for_cpu(struct virtqueue *_vq, dma_addr_t addr,
> +bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
> +void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir);
> -void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq, dma_addr_t addr,
> +void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir);
>
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page()
2025-08-13 5:48 ` [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page() Jason Wang
@ 2025-08-13 7:15 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 7:15 UTC (permalink / raw)
To: Jason Wang
Cc: mst, xuanzhuo, virtualization, linux-kernel, hch,
Christoph Hellwig
On Wed, Aug 13, 2025 at 7:48 AM Jason Wang <jasowang@redhat.com> wrote:
>
> This patch switches to use dma_{map|unmap}_page() to reduce the
> coverage of DMA operations. This would help for the following rework
> on the virtio map operations.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 55 +++++++++++++++---------------------
> 1 file changed, 23 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 103bad8cffff..75e5f6336c8d 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -405,8 +405,8 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
> if (!vq->use_dma_api)
> return (dma_addr_t)virt_to_phys(cpu_addr);
>
> - return dma_map_single(vring_dma_dev(vq),
> - cpu_addr, size, direction);
> + return virtqueue_dma_map_single_attrs(&vq->vq, cpu_addr,
> + size, direction, 0);
> }
>
> static int vring_mapping_error(const struct vring_virtqueue *vq,
> @@ -451,22 +451,14 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
> if (flags & VRING_DESC_F_INDIRECT) {
> if (!vq->use_dma_api)
> goto out;
> + } else if (!vring_need_unmap_buffer(vq, extra))
> + goto out;
>
> - dma_unmap_single(vring_dma_dev(vq),
> - extra->addr,
> - extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> - } else {
> - if (!vring_need_unmap_buffer(vq, extra))
> - goto out;
> -
> - dma_unmap_page(vring_dma_dev(vq),
> - extra->addr,
> - extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> - }
> + dma_unmap_page(vring_dma_dev(vq),
> + extra->addr,
> + extra->len,
> + (flags & VRING_DESC_F_WRITE) ?
> + DMA_FROM_DEVICE : DMA_TO_DEVICE);
>
> out:
> return extra->next;
> @@ -1276,20 +1268,13 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
> if (flags & VRING_DESC_F_INDIRECT) {
> if (!vq->use_dma_api)
> return;
> + } else if (!vring_need_unmap_buffer(vq, extra))
> + return;
>
> - dma_unmap_single(vring_dma_dev(vq),
> - extra->addr, extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> - } else {
> - if (!vring_need_unmap_buffer(vq, extra))
> - return;
> -
> - dma_unmap_page(vring_dma_dev(vq),
> - extra->addr, extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> - }
> + dma_unmap_page(vring_dma_dev(vq),
> + extra->addr, extra->len,
> + (flags & VRING_DESC_F_WRITE) ?
> + DMA_FROM_DEVICE : DMA_TO_DEVICE);
> }
>
> static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
> @@ -3161,7 +3146,13 @@ dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr
> return (dma_addr_t)virt_to_phys(ptr);
> }
>
> - return dma_map_single_attrs(vring_dma_dev(vq), ptr, size, dir, attrs);
> + /* DMA must never operate on areas that might be remapped. */
> + if (dev_WARN_ONCE(&_vq->vdev->dev, is_vmalloc_addr(ptr),
> + "rejecting DMA map of vmalloc memory\n"))
> + return DMA_MAPPING_ERROR;
> +
> + return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
> + offset_in_page(ptr), size, dir, attrs);
> }
> EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
>
> @@ -3186,7 +3177,7 @@ void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
> if (!vq->use_dma_api)
> return;
>
> - dma_unmap_single_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
> + dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
> }
> EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
>
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 3/9] virtio: rename dma helpers
2025-08-13 5:48 ` [PATCH V5 3/9] virtio: rename dma helpers Jason Wang
@ 2025-08-13 7:16 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 7:16 UTC (permalink / raw)
To: Jason Wang
Cc: mst, xuanzhuo, virtualization, linux-kernel, hch,
Christoph Hellwig
On Wed, Aug 13, 2025 at 7:48 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Following patch will introduce virtio mapping function to avoid
> abusing DMA API for device that doesn't do DMA. To ease the
> introduction, this patch rename "dma" to "map" for the current dma
> mapping helpers.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/net/virtio_net.c | 28 ++++-----
> drivers/virtio/virtio_ring.c | 114 +++++++++++++++++------------------
> include/linux/virtio.h | 12 ++--
> 3 files changed, 77 insertions(+), 77 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 5d674eb9a0f2..929db41a579b 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -933,7 +933,7 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
> if (dma->need_sync && len) {
> offset = buf - (head + sizeof(*dma));
>
> - virtqueue_dma_sync_single_range_for_cpu(rq->vq, dma->addr,
> + virtqueue_map_sync_single_range_for_cpu(rq->vq, dma->addr,
> offset, len,
> DMA_FROM_DEVICE);
> }
> @@ -941,8 +941,8 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
> if (dma->ref)
> return;
>
> - virtqueue_dma_unmap_single_attrs(rq->vq, dma->addr, dma->len,
> - DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
> + virtqueue_unmap_single_attrs(rq->vq, dma->addr, dma->len,
> + DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
> put_page(page);
> }
>
> @@ -1009,13 +1009,13 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp)
>
> dma->len = alloc_frag->size - sizeof(*dma);
>
> - addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1,
> - dma->len, DMA_FROM_DEVICE, 0);
> - if (virtqueue_dma_mapping_error(rq->vq, addr))
> + addr = virtqueue_map_single_attrs(rq->vq, dma + 1,
> + dma->len, DMA_FROM_DEVICE, 0);
> + if (virtqueue_map_mapping_error(rq->vq, addr))
> return NULL;
>
> dma->addr = addr;
> - dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr);
> + dma->need_sync = virtqueue_map_need_sync(rq->vq, addr);
>
> /* Add a reference to dma to prevent the entire dma from
> * being released during error handling. This reference
> @@ -5921,9 +5921,9 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
> if (!rq->xsk_buffs)
> return -ENOMEM;
>
> - hdr_dma = virtqueue_dma_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len,
> - DMA_TO_DEVICE, 0);
> - if (virtqueue_dma_mapping_error(sq->vq, hdr_dma)) {
> + hdr_dma = virtqueue_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len,
> + DMA_TO_DEVICE, 0);
> + if (virtqueue_map_mapping_error(sq->vq, hdr_dma)) {
> err = -ENOMEM;
> goto err_free_buffs;
> }
> @@ -5952,8 +5952,8 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
> err_rq:
> xsk_pool_dma_unmap(pool, 0);
> err_xsk_map:
> - virtqueue_dma_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len,
> - DMA_TO_DEVICE, 0);
> + virtqueue_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len,
> + DMA_TO_DEVICE, 0);
> err_free_buffs:
> kvfree(rq->xsk_buffs);
> return err;
> @@ -5980,8 +5980,8 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
>
> xsk_pool_dma_unmap(pool, 0);
>
> - virtqueue_dma_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr,
> - vi->hdr_len, DMA_TO_DEVICE, 0);
> + virtqueue_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr,
> + vi->hdr_len, DMA_TO_DEVICE, 0);
> kvfree(rq->xsk_buffs);
>
> return err;
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 75e5f6336c8d..482a268af851 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -166,7 +166,7 @@ struct vring_virtqueue {
> bool packed_ring;
>
> /* Is DMA API used? */
> - bool use_dma_api;
> + bool use_map_api;
>
> /* Can we use weak barriers? */
> bool weak_barriers;
> @@ -268,7 +268,7 @@ static bool virtqueue_use_indirect(const struct vring_virtqueue *vq,
> * unconditionally on data path.
> */
>
> -static bool vring_use_dma_api(const struct virtio_device *vdev)
> +static bool vring_use_map_api(const struct virtio_device *vdev)
> {
> if (!virtio_has_dma_quirk(vdev))
> return true;
> @@ -291,14 +291,14 @@ static bool vring_use_dma_api(const struct virtio_device *vdev)
> static bool vring_need_unmap_buffer(const struct vring_virtqueue *vring,
> const struct vring_desc_extra *extra)
> {
> - return vring->use_dma_api && (extra->addr != DMA_MAPPING_ERROR);
> + return vring->use_map_api && (extra->addr != DMA_MAPPING_ERROR);
> }
>
> size_t virtio_max_dma_size(const struct virtio_device *vdev)
> {
> size_t max_segment_size = SIZE_MAX;
>
> - if (vring_use_dma_api(vdev))
> + if (vring_use_map_api(vdev))
> max_segment_size = dma_max_mapping_size(vdev->dev.parent);
>
> return max_segment_size;
> @@ -309,7 +309,7 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> dma_addr_t *dma_handle, gfp_t flag,
> struct device *dma_dev)
> {
> - if (vring_use_dma_api(vdev)) {
> + if (vring_use_map_api(vdev)) {
> return dma_alloc_coherent(dma_dev, size,
> dma_handle, flag);
> } else {
> @@ -343,7 +343,7 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size,
> void *queue, dma_addr_t dma_handle,
> struct device *dma_dev)
> {
> - if (vring_use_dma_api(vdev))
> + if (vring_use_map_api(vdev))
> dma_free_coherent(dma_dev, size, queue, dma_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> @@ -372,7 +372,7 @@ static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist
>
> *len = sg->length;
>
> - if (!vq->use_dma_api) {
> + if (!vq->use_map_api) {
> /*
> * If DMA is not used, KMSAN doesn't know that the scatterlist
> * is initialized by the hardware. Explicitly check/unpoison it
> @@ -402,17 +402,17 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
> void *cpu_addr, size_t size,
> enum dma_data_direction direction)
> {
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return (dma_addr_t)virt_to_phys(cpu_addr);
>
> - return virtqueue_dma_map_single_attrs(&vq->vq, cpu_addr,
> - size, direction, 0);
> + return virtqueue_map_single_attrs(&vq->vq, cpu_addr,
> + size, direction, 0);
> }
>
> static int vring_mapping_error(const struct vring_virtqueue *vq,
> dma_addr_t addr)
> {
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return 0;
>
> return dma_mapping_error(vring_dma_dev(vq), addr);
> @@ -449,7 +449,7 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
> flags = extra->flags;
>
> if (flags & VRING_DESC_F_INDIRECT) {
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> goto out;
> } else if (!vring_need_unmap_buffer(vq, extra))
> goto out;
> @@ -782,7 +782,7 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
>
> extra = (struct vring_desc_extra *)&indir_desc[num];
>
> - if (vq->use_dma_api) {
> + if (vq->use_map_api) {
> for (j = 0; j < num; j++)
> vring_unmap_one_split(vq, &extra[j]);
> }
> @@ -1150,7 +1150,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> vq->broken = false;
> #endif
> vq->dma_dev = dma_dev;
> - vq->use_dma_api = vring_use_dma_api(vdev);
> + vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> !context;
> @@ -1266,7 +1266,7 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
> flags = extra->flags;
>
> if (flags & VRING_DESC_F_INDIRECT) {
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return;
> } else if (!vring_need_unmap_buffer(vq, extra))
> return;
> @@ -1351,7 +1351,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
> desc[i].addr = cpu_to_le64(addr);
> desc[i].len = cpu_to_le32(len);
>
> - if (unlikely(vq->use_dma_api)) {
> + if (unlikely(vq->use_map_api)) {
> extra[i].addr = premapped ? DMA_MAPPING_ERROR : addr;
> extra[i].len = len;
> extra[i].flags = n < out_sgs ? 0 : VRING_DESC_F_WRITE;
> @@ -1373,7 +1373,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
> sizeof(struct vring_packed_desc));
> vq->packed.vring.desc[head].id = cpu_to_le16(id);
>
> - if (vq->use_dma_api) {
> + if (vq->use_map_api) {
> vq->packed.desc_extra[id].addr = addr;
> vq->packed.desc_extra[id].len = total_sg *
> sizeof(struct vring_packed_desc);
> @@ -1515,7 +1515,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
> desc[i].len = cpu_to_le32(len);
> desc[i].id = cpu_to_le16(id);
>
> - if (unlikely(vq->use_dma_api)) {
> + if (unlikely(vq->use_map_api)) {
> vq->packed.desc_extra[curr].addr = premapped ?
> DMA_MAPPING_ERROR : addr;
> vq->packed.desc_extra[curr].len = len;
> @@ -1650,7 +1650,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
> vq->free_head = id;
> vq->vq.num_free += state->num;
>
> - if (unlikely(vq->use_dma_api)) {
> + if (unlikely(vq->use_map_api)) {
> curr = id;
> for (i = 0; i < state->num; i++) {
> vring_unmap_extra_packed(vq,
> @@ -1668,7 +1668,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
> if (!desc)
> return;
>
> - if (vq->use_dma_api) {
> + if (vq->use_map_api) {
> len = vq->packed.desc_extra[id].len;
> num = len / sizeof(struct vring_packed_desc);
>
> @@ -2121,7 +2121,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> #endif
> vq->packed_ring = true;
> vq->dma_dev = dma_dev;
> - vq->use_dma_api = vring_use_dma_api(vdev);
> + vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> !context;
> @@ -2433,7 +2433,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> {
> struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (vq->use_dma_api)
> + if (vq->use_map_api)
> return vring_dma_dev(vq);
> else
> return NULL;
> @@ -3122,7 +3122,7 @@ const struct vring *virtqueue_get_vring(const struct virtqueue *vq)
> EXPORT_SYMBOL_GPL(virtqueue_get_vring);
>
> /**
> - * virtqueue_dma_map_single_attrs - map DMA for _vq
> + * virtqueue_map_single_attrs - map DMA for _vq
> * @_vq: the struct virtqueue we're talking about.
> * @ptr: the pointer of the buffer to do dma
> * @size: the size of the buffer to do dma
> @@ -3132,16 +3132,16 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
> * The caller calls this to do dma mapping in advance. The DMA address can be
> * passed to this _vq when it is in pre-mapped mode.
> *
> - * return DMA address. Caller should check that by virtqueue_dma_mapping_error().
> + * return DMA address. Caller should check that by virtqueue_mapping_error().
> */
> -dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr,
> - size_t size,
> - enum dma_data_direction dir,
> - unsigned long attrs)
> +dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
> + size_t size,
> + enum dma_data_direction dir,
> + unsigned long attrs)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (!vq->use_dma_api) {
> + if (!vq->use_map_api) {
> kmsan_handle_dma(virt_to_page(ptr), offset_in_page(ptr), size, dir);
> return (dma_addr_t)virt_to_phys(ptr);
> }
> @@ -3154,85 +3154,85 @@ dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr
> return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
> offset_in_page(ptr), size, dir, attrs);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_map_single_attrs);
> +EXPORT_SYMBOL_GPL(virtqueue_map_single_attrs);
>
> /**
> - * virtqueue_dma_unmap_single_attrs - unmap DMA for _vq
> + * virtqueue_unmap_single_attrs - unmap map for _vq
> * @_vq: the struct virtqueue we're talking about.
> * @addr: the dma address to unmap
> * @size: the size of the buffer
> * @dir: DMA direction
> * @attrs: DMA Attrs
> *
> - * Unmap the address that is mapped by the virtqueue_dma_map_* APIs.
> + * Unmap the address that is mapped by the virtqueue_map_* APIs.
> *
> */
> -void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq,
> - dma_addr_t addr,
> - size_t size, enum dma_data_direction dir,
> - unsigned long attrs)
> +void virtqueue_unmap_single_attrs(const struct virtqueue *_vq,
> + dma_addr_t addr,
> + size_t size, enum dma_data_direction dir,
> + unsigned long attrs)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return;
>
> dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_unmap_single_attrs);
> +EXPORT_SYMBOL_GPL(virtqueue_unmap_single_attrs);
>
> /**
> - * virtqueue_dma_mapping_error - check dma address
> + * virtqueue_map_mapping_error - check dma address
> * @_vq: the struct virtqueue we're talking about.
> * @addr: DMA address
> *
> * Returns 0 means dma valid. Other means invalid dma address.
> */
> -int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
> +int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return 0;
>
> return dma_mapping_error(vring_dma_dev(vq), addr);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_mapping_error);
> +EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
>
> /**
> - * virtqueue_dma_need_sync - check a dma address needs sync
> + * virtqueue_map_need_sync - check a dma address needs sync
> * @_vq: the struct virtqueue we're talking about.
> * @addr: DMA address
> *
> - * Check if the dma address mapped by the virtqueue_dma_map_* APIs needs to be
> + * Check if the dma address mapped by the virtqueue_map_* APIs needs to be
> * synchronized
> *
> * return bool
> */
> -bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
> +bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return false;
>
> return dma_need_sync(vring_dma_dev(vq), addr);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_need_sync);
> +EXPORT_SYMBOL_GPL(virtqueue_map_need_sync);
>
> /**
> - * virtqueue_dma_sync_single_range_for_cpu - dma sync for cpu
> + * virtqueue_map_sync_single_range_for_cpu - map sync for cpu
> * @_vq: the struct virtqueue we're talking about.
> * @addr: DMA address
> * @offset: DMA address offset
> * @size: buf size for sync
> * @dir: DMA direction
> *
> - * Before calling this function, use virtqueue_dma_need_sync() to confirm that
> + * Before calling this function, use virtqueue_map_need_sync() to confirm that
> * the DMA address really needs to be synchronized
> *
> */
> -void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
> +void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq,
> dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir)
> @@ -3240,25 +3240,25 @@ void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq,
> const struct vring_virtqueue *vq = to_vvq(_vq);
> struct device *dev = vring_dma_dev(vq);
>
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return;
>
> dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_cpu);
> +EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_cpu);
>
> /**
> - * virtqueue_dma_sync_single_range_for_device - dma sync for device
> + * virtqueue_map_sync_single_range_for_device - map sync for device
> * @_vq: the struct virtqueue we're talking about.
> * @addr: DMA address
> * @offset: DMA address offset
> * @size: buf size for sync
> * @dir: DMA direction
> *
> - * Before calling this function, use virtqueue_dma_need_sync() to confirm that
> + * Before calling this function, use virtqueue_map_need_sync() to confirm that
> * the DMA address really needs to be synchronized
> */
> -void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
> +void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq,
> dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir)
> @@ -3266,12 +3266,12 @@ void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq,
> const struct vring_virtqueue *vq = to_vvq(_vq);
> struct device *dev = vring_dma_dev(vq);
>
> - if (!vq->use_dma_api)
> + if (!vq->use_map_api)
> return;
>
> dma_sync_single_range_for_device(dev, addr, offset, size, dir);
> }
> -EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_device);
> +EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device);
>
> MODULE_DESCRIPTION("Virtio ring implementation");
> MODULE_LICENSE("GPL");
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index cf8def717dfd..addbc209275a 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -259,18 +259,18 @@ void unregister_virtio_driver(struct virtio_driver *drv);
> module_driver(__virtio_driver, register_virtio_driver, \
> unregister_virtio_driver)
>
> -dma_addr_t virtqueue_dma_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
> +dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
> enum dma_data_direction dir, unsigned long attrs);
> -void virtqueue_dma_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
> +void virtqueue_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
> size_t size, enum dma_data_direction dir,
> unsigned long attrs);
> -int virtqueue_dma_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
> +int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr);
>
> -bool virtqueue_dma_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
> -void virtqueue_dma_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
> +bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr);
> +void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq, dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir);
> -void virtqueue_dma_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
> +void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq, dma_addr_t addr,
> unsigned long offset, size_t size,
> enum dma_data_direction dir);
>
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
@ 2025-08-13 7:46 ` Eugenio Perez Martin
2025-08-13 8:55 ` Michael S. Tsirkin
2025-08-13 8:58 ` Michael S. Tsirkin
2 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 7:46 UTC (permalink / raw)
To: Jason Wang; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Following patch will introduce the mapping operations for virtio
> device. In order to achieve this, besides the dma device, virtio core
> needs to support a transport or device specific mapping token as well.
> So this patch introduces a union container of a dma device and opaque
> mapping token. The idea is the allow the transport layer to pass
> device specific mapping token which will be used as a parameter for
> the virtio mapping operations. For the transport or device that is
> using DMA, dma device is still being used.
>
Acked-by: Eugenio Pérez <eperezma@redhat.com>
But some nits:
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> drivers/virtio/virtio_vdpa.c | 6 +-
> include/linux/virtio.h | 7 +++
> include/linux/virtio_ring.h | 7 ++-
> 4 files changed, 72 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 482a268af851..fb1d407d5f1b 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -210,8 +210,7 @@ struct vring_virtqueue {
> /* DMA, allocation, and size information */
> bool we_own_ring;
>
> - /* Device used for doing DMA */
> - struct device *dma_dev;
> + union vring_mapping_token mapping_token;
>
> #ifdef DEBUG
> /* They're supposed to lock for us. */
> @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
>
> static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> dma_addr_t *dma_handle, gfp_t flag,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
I think the compiler will omit it but we're adding another pointer
indirection here.
> {
> if (vring_use_map_api(vdev)) {
> - return dma_alloc_coherent(dma_dev, size,
> + return dma_alloc_coherent(mapping_token->dma_dev, size,
> dma_handle, flag);
> } else {
> void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
>
> static void vring_free_queue(struct virtio_device *vdev, size_t size,
> void *queue, dma_addr_t dma_handle,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev))
> - dma_free_coherent(dma_dev, size, queue, dma_handle);
> + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> }
>
> /*
> - * The DMA ops on various arches are rather gnarly right now, and
> - * making all of the arch DMA ops work on the vring device itself
> + * The map ops on various arches are rather gnarly right now, and
> + * making all of the arch map ops work on the vring device itself
> * is a mess.
> */
> static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> {
> - return vq->dma_dev;
> + return vq->mapping_token.dma_dev;
> }
>
> /* Map one sg entry. */
> @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> }
>
> static void vring_free_split(struct vring_virtqueue_split *vring_split,
> - struct virtio_device *vdev, struct device *dma_dev)
> + struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token)
> {
> vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> vring_split->vring.desc,
> vring_split->queue_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_split->desc_state);
> kfree(vring_split->desc_extra);
> @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> u32 num,
> unsigned int vring_align,
> bool may_reduce_num,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> void *queue = NULL;
> dma_addr_t dma_addr;
> @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (queue)
> break;
> if (!may_reduce_num)
> @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> /* Try to get a single page. You are my only hope! */
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr, GFP_KERNEL | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> }
> if (!queue)
> return -ENOMEM;
> @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> #else
> vq->broken = false;
> #endif
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_split vring_split = {};
> struct virtqueue *vq;
> int err;
>
> err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> - may_reduce_num, dma_dev);
> + may_reduce_num, mapping_token);
> if (err)
> return NULL;
>
> vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_split(&vring_split, vdev, dma_dev);
> + vring_free_split(&vring_split, vdev, mapping_token);
> return NULL;
> }
>
> @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> err = vring_alloc_queue_split(&vring_split, vdev, num,
> vq->split.vring_align,
> vq->split.may_reduce_num,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> if (err)
> goto err;
>
> @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> err:
> virtqueue_reinit_split(vq);
> return -ENOMEM;
> @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
>
> static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_packed->vring.desc)
> vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> vring_packed->vring.desc,
> vring_packed->ring_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.driver)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.driver,
> vring_packed->driver_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.device)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.device,
> vring_packed->device_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_packed->desc_state);
> kfree(vring_packed->desc_extra);
> @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
>
> static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - u32 num, struct device *dma_dev)
> + u32 num, union vring_mapping_token *mapping_token)
> {
> struct vring_packed_desc *ring;
> struct vring_packed_desc_event *driver, *device;
> @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> &ring_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!ring)
> goto err;
>
> @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> driver = vring_alloc_queue(vdev, event_size_in_bytes,
> &driver_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!driver)
> goto err;
>
> @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> device = vring_alloc_queue(vdev, event_size_in_bytes,
> &device_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!device)
> goto err;
>
> @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> return 0;
>
> err:
> - vring_free_packed(vring_packed, vdev, dma_dev);
> + vring_free_packed(vring_packed, vdev, mapping_token);
> return -ENOMEM;
> }
>
> @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> vq->broken = false;
> #endif
> vq->packed_ring = true;
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_packed vring_packed = {};
> struct virtqueue *vq;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> return NULL;
>
> vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_packed(&vring_packed, vdev, dma_dev);
> + vring_free_packed(&vring_packed, vdev, mapping_token);
> return NULL;
> }
>
> @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> struct virtio_device *vdev = _vq->vdev;
> int err;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> + if (vring_alloc_queue_packed(&vring_packed, vdev,
> + num, &vq->mapping_token))
> goto err_ring;
>
> err = vring_alloc_state_extra_packed(&vring_packed);
> @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> err_ring:
> virtqueue_reinit_packed(vq);
> return -ENOMEM;
> @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> }
> EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
>
> +
> /**
> * virtqueue_dma_dev - get the dma dev
> * @_vq: the struct virtqueue we're talking about.
> @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (vq->use_map_api)
> - return vring_dma_dev(vq);
> + return vq->mapping_token.dma_dev;
> else
> return NULL;
> }
> @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> void (*callback)(struct virtqueue *),
> const char *name)
> {
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_create_virtqueue);
>
> -struct virtqueue *vring_create_virtqueue_dma(
> +struct virtqueue *vring_create_virtqueue_map(
> unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> }
> -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
>
> /**
> * virtqueue_resize - resize the vring of vq
> @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> const char *name)
> {
> struct vring_virtqueue_split vring_split = {};
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> struct vring_virtqueue_packed vring_packed = {};
> @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> return __vring_new_virtqueue_packed(index, &vring_packed,
> vdev, weak_barriers,
> context, notify, callback,
> - name, vdev->dev.parent);
> + name, &mapping_token);
> }
>
> vring_init(&vring_split.vring, num, pages, vring_align);
> return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> context, notify, callback, name,
> - vdev->dev.parent);
> + &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_new_virtqueue);
>
> @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> vq->packed.ring_size_in_bytes,
> vq->packed.vring.desc,
> vq->packed.ring_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.driver,
> vq->packed.driver_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.device,
> vq->packed.device_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> kfree(vq->packed.desc_state);
> kfree(vq->packed.desc_extra);
> @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> vq->split.queue_size_in_bytes,
> vq->split.vring.desc,
> vq->split.queue_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> }
> }
> if (!vq->packed_ring) {
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index e25610e3393a..acea98ab08ee 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> struct vdpa_callback cb;
> struct virtqueue *vq;
> u64 desc_addr, driver_addr, device_addr;
> + union vring_mapping_token mapping_token = {0};
> /* Assume split virtqueue, switch to packed if necessary */
> struct vdpa_vq_state state = {0};
> u32 align, max_num, min_num = 1;
> @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> dma_dev = ops->get_vq_dma_dev(vdpa, index);
> else
> dma_dev = vdpa_get_dma_dev(vdpa);
> - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> + mapping_token.dma_dev = dma_dev;
> + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> true, may_reduce_num, ctx,
> - notify, callback, name, dma_dev);
> + notify, callback, name, &mapping_token);
> if (!vq) {
> err = -ENOMEM;
> goto error_new_virtqueue;
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index addbc209275a..37029df94aaf 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -40,6 +40,13 @@ struct virtqueue {
> void *priv;
> };
>
I would add some doc here like "vq uses dma_dev if vq->use_map_api,
opaque is used otherwise". Maybe we can move use_map_api here
actually, like:
struct vring_mapping_token {
bool use_map_api;
union {
struct device *dma_dev;
void *opaque;
};
}
What do you think?
> +union vring_mapping_token {
> + /* Device that performs DMA */
> + struct device *dma_dev;
> + /* Transport specific token used for doing map */
> + void *opaque;
> +};
> +
> int virtqueue_add_outbuf(struct virtqueue *vq,
> struct scatterlist sg[], unsigned int num,
> void *data,
> diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> index 9b33df741b63..fd997178da2a 100644
> --- a/include/linux/virtio_ring.h
> +++ b/include/linux/virtio_ring.h
> @@ -3,6 +3,7 @@
> #define _LINUX_VIRTIO_RING_H
>
> #include <asm/barrier.h>
> +#include <linux/virtio.h>
> #include <linux/irqreturn.h>
> #include <uapi/linux/virtio_ring.h>
>
> @@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
>
> /*
> * Creates a virtqueue and allocates the descriptor ring with per
> - * virtqueue DMA device.
> + * virtqueue mapping operations.
> */
> -struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> +struct virtqueue *vring_create_virtqueue_map(unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> struct virtio_device *vdev,
> @@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> bool (*notify)(struct virtqueue *vq),
> void (*callback)(struct virtqueue *vq),
> const char *name,
> - struct device *dma_dev);
> + union vring_mapping_token *mapping_token);
>
> /*
> * Creates a virtqueue with a standard layout but a caller-allocated
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle
2025-08-13 5:48 ` [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle Jason Wang
@ 2025-08-13 7:47 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 7:47 UTC (permalink / raw)
To: Jason Wang
Cc: mst, xuanzhuo, virtualization, linux-kernel, hch,
Christoph Hellwig
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Following patch will introduce virtio map opreations which means the
> address is not necessarily used for DMA. Let's rename the dma_handle
> to map_handle first.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index fb1d407d5f1b..94b2a8f3acc2 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -305,18 +305,18 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev)
> EXPORT_SYMBOL_GPL(virtio_max_dma_size);
>
> static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> - dma_addr_t *dma_handle, gfp_t flag,
> + dma_addr_t *map_handle, gfp_t flag,
> union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev)) {
> return dma_alloc_coherent(mapping_token->dma_dev, size,
> - dma_handle, flag);
> + map_handle, flag);
> } else {
> void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
>
> if (queue) {
> phys_addr_t phys_addr = virt_to_phys(queue);
> - *dma_handle = (dma_addr_t)phys_addr;
> + *map_handle = (dma_addr_t)phys_addr;
>
> /*
> * Sanity check: make sure we dind't truncate
> @@ -329,7 +329,7 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> * warning and abort if we end up with an
> * unrepresentable address.
> */
> - if (WARN_ON_ONCE(*dma_handle != phys_addr)) {
> + if (WARN_ON_ONCE(*map_handle != phys_addr)) {
> free_pages_exact(queue, PAGE_ALIGN(size));
> return NULL;
> }
> @@ -339,11 +339,11 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> }
>
> static void vring_free_queue(struct virtio_device *vdev, size_t size,
> - void *queue, dma_addr_t dma_handle,
> + void *queue, dma_addr_t map_handle,
> union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev))
> - dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> + dma_free_coherent(mapping_token->dma_dev, size, queue, map_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> }
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 6/9] virtio: introduce map ops in virtio core
2025-08-13 5:48 ` [PATCH V5 6/9] virtio: introduce map ops in virtio core Jason Wang
@ 2025-08-13 8:40 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 8:40 UTC (permalink / raw)
To: Jason Wang; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> This patch introduces map operations for virtio device. Virtio use to
> use DMA API which is not necessarily the case since some devices
> doesn't do DMA. Instead of using tricks and abusing DMA API, let's
> simply abstract the current mapping logic into a virtio specific
> mapping operations. For the device or transport that doesn't do DMA,
> they can implement their own mapping logic without the need to trick
> DMA core. In this case the map_token is opaque to the virtio core that
> will be passed back to the transport or device specific map
> operations. For other devices, DMA API will still be used, so map
> token will still be the dma device to minimize the changeset and
> performance impact.
>
> The mapping operations are abstracted as a independent structure
> instead of reusing virtio_config_ops. This allows the transport can
> simply reuse the structure for lower layers like vDPA.
>
> A set of new mapping helpers were introduced for the device that want
> to do mapping by themselves.
>
Acked-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 217 +++++++++++++++++++++++++++-------
> include/linux/virtio.h | 26 +++-
> include/linux/virtio_config.h | 72 +++++++++++
> 3 files changed, 271 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 94b2a8f3acc2..86188ffbce00 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -297,8 +297,14 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev)
> {
> size_t max_segment_size = SIZE_MAX;
>
> - if (vring_use_map_api(vdev))
> - max_segment_size = dma_max_mapping_size(vdev->dev.parent);
> + if (vring_use_map_api(vdev)) {
> + if (vdev->map)
> + max_segment_size =
> + vdev->map->max_mapping_size(vdev->dev.parent);
> + else
> + max_segment_size =
> + dma_max_mapping_size(vdev->dev.parent);
> + }
>
> return max_segment_size;
> }
> @@ -309,8 +315,8 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev)) {
> - return dma_alloc_coherent(mapping_token->dma_dev, size,
> - map_handle, flag);
> + return virtqueue_map_alloc_coherent(vdev, mapping_token, size,
> + map_handle, flag);
> } else {
> void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
>
> @@ -343,7 +349,8 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size,
> union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev))
> - dma_free_coherent(mapping_token->dma_dev, size, queue, map_handle);
> + virtqueue_map_free_coherent(vdev, mapping_token, size,
> + queue, map_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> }
> @@ -358,6 +365,25 @@ static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> return vq->mapping_token.dma_dev;
> }
>
> +static void *vring_mapping_token(const struct vring_virtqueue *vq)
> +{
> + return vq->mapping_token.token;
> +}
> +
> +static int vring_mapping_error(const struct vring_virtqueue *vq,
> + dma_addr_t addr)
> +{
> + struct virtio_device *vdev = vq->vq.vdev;
> +
> + if (!vq->use_map_api)
> + return 0;
> +
> + if (vdev->map)
> + return vdev->map->mapping_error(vring_mapping_token(vq), addr);
> + else
> + return dma_mapping_error(vring_dma_dev(vq), addr);
> +}
> +
> /* Map one sg entry. */
> static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist *sg,
> enum dma_data_direction direction, dma_addr_t *addr,
> @@ -387,11 +413,11 @@ static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist
> * the way it expects (we don't guarantee that the scatterlist
> * will exist for the lifetime of the mapping).
> */
> - *addr = dma_map_page(vring_dma_dev(vq),
> - sg_page(sg), sg->offset, sg->length,
> - direction);
> + *addr = virtqueue_map_page_attrs(&vq->vq, sg_page(sg),
> + sg->offset, sg->length,
> + direction, 0);
>
> - if (dma_mapping_error(vring_dma_dev(vq), *addr))
> + if (vring_mapping_error(vq, *addr))
> return -ENOMEM;
>
> return 0;
> @@ -408,15 +434,6 @@ static dma_addr_t vring_map_single(const struct vring_virtqueue *vq,
> size, direction, 0);
> }
>
> -static int vring_mapping_error(const struct vring_virtqueue *vq,
> - dma_addr_t addr)
> -{
> - if (!vq->use_map_api)
> - return 0;
> -
> - return dma_mapping_error(vring_dma_dev(vq), addr);
> -}
> -
> static void virtqueue_init(struct vring_virtqueue *vq, u32 num)
> {
> vq->vq.num_free = num;
> @@ -453,11 +470,12 @@ static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
> } else if (!vring_need_unmap_buffer(vq, extra))
> goto out;
>
> - dma_unmap_page(vring_dma_dev(vq),
> - extra->addr,
> - extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> + virtqueue_unmap_page_attrs(&vq->vq,
> + extra->addr,
> + extra->len,
> + (flags & VRING_DESC_F_WRITE) ?
> + DMA_FROM_DEVICE : DMA_TO_DEVICE,
> + 0);
>
> out:
> return extra->next;
> @@ -1271,10 +1289,11 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
> } else if (!vring_need_unmap_buffer(vq, extra))
> return;
>
> - dma_unmap_page(vring_dma_dev(vq),
> - extra->addr, extra->len,
> - (flags & VRING_DESC_F_WRITE) ?
> - DMA_FROM_DEVICE : DMA_TO_DEVICE);
> + virtqueue_unmap_page_attrs(&vq->vq,
> + extra->addr, extra->len,
> + (flags & VRING_DESC_F_WRITE) ?
> + DMA_FROM_DEVICE : DMA_TO_DEVICE,
> + 0);
> }
>
> static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
> @@ -2434,8 +2453,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
> struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> {
> struct vring_virtqueue *vq = to_vvq(_vq);
> -
> - if (vq->use_map_api)
> + if (vq->use_map_api && !_vq->vdev->map)
> return vq->mapping_token.dma_dev;
> else
> return NULL;
> @@ -3125,6 +3143,107 @@ const struct vring *virtqueue_get_vring(const struct virtqueue *vq)
> }
> EXPORT_SYMBOL_GPL(virtqueue_get_vring);
>
> +/**
> + * virtqueue_map_alloc_coherent - alloc coherent mapping
> + * @vdev: the virtio device we are talking to
> + * @mapping_token: device specific mapping token
> + * @size: the size of the buffer
> + * @map_handle: the pointer to the mapped address
> + * @gfp: allocation flag (GFP_XXX)
> + *
> + * return virtual address or NULL on error
> + */
> +void *virtqueue_map_alloc_coherent(struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token,
> + size_t size, dma_addr_t *map_handle,
> + gfp_t gfp)
> +{
> + if (vdev->map)
> + return vdev->map->alloc(mapping_token->token, size,
> + map_handle, gfp);
> + else
> + return dma_alloc_coherent(mapping_token->dma_dev, size,
> + map_handle, gfp);
> +}
> +EXPORT_SYMBOL_GPL(virtqueue_map_alloc_coherent);
> +
> +/**
> + * virtqueue_map_free_coherent - free coherent mapping
> + * @vdev: the virtio device we are talking to
> + * @token: device specific mapping token
> + * @size: the size of the buffer
> + * @map_handle: the mapped address that needs to be freed
> + *
> + */
> +void virtqueue_map_free_coherent(struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token, size_t size, void *vaddr,
> + dma_addr_t map_handle)
> +{
> + if (vdev->map)
> + vdev->map->free(mapping_token->token, size, vaddr,
> + map_handle, 0);
> + else
> + dma_free_coherent(mapping_token->dma_dev, size, vaddr, map_handle);
> +}
> +EXPORT_SYMBOL_GPL(virtqueue_map_free_coherent);
> +
> +/**
> + * virtqueue_map_page_attrs - map a page to the device
> + * @_vq: the virtqueue we are talking to
> + * @page: the page that will be mapped by the device
> + * @offset: the offset in the page for a buffer
> + * @size: the buffer size
> + * @dir: mapping direction
> + * @attrs: mapping attributes
> + *
> + * Returns mapped address. Caller should check that by virtqueue_mapping_error().
> + */
> +dma_addr_t virtqueue_map_page_attrs(const struct virtqueue *_vq,
> + struct page *page,
> + unsigned long offset,
> + size_t size,
> + enum dma_data_direction dir,
> + unsigned long attrs)
> +{
> + const struct vring_virtqueue *vq = to_vvq(_vq);
> + struct virtio_device *vdev = _vq->vdev;
> +
> + if (vdev->map)
> + return vdev->map->map_page(vring_mapping_token(vq),
> + page, offset, size,
> + dir, attrs);
> +
> + return dma_map_page_attrs(vring_dma_dev(vq),
> + page, offset, size,
> + dir, attrs);
> +}
> +EXPORT_SYMBOL_GPL(virtqueue_map_page_attrs);
> +
> +/**
> + * virtqueue_unmap_page_attrs - map a page to the device
> + * @_vq: the virtqueue we are talking to
> + * @map_handle: the mapped address
> + * @size: the buffer size
> + * @dir: mapping direction
> + * @attrs: unmapping attributes
> + */
> +void virtqueue_unmap_page_attrs(const struct virtqueue *_vq,
> + dma_addr_t map_handle,
> + size_t size, enum dma_data_direction dir,
> + unsigned long attrs)
> +{
> + const struct vring_virtqueue *vq = to_vvq(_vq);
> + struct virtio_device *vdev = _vq->vdev;
> +
> + if (vdev->map)
> + vdev->map->unmap_page(vring_mapping_token(vq), map_handle,
> + size, dir, attrs);
> + else
> + dma_unmap_page_attrs(vring_dma_dev(vq), map_handle,
> + size, dir, attrs);
> +}
> +EXPORT_SYMBOL_GPL(virtqueue_unmap_page_attrs);
> +
> /**
> * virtqueue_map_single_attrs - map DMA for _vq
> * @_vq: the struct virtqueue we're talking about.
> @@ -3136,7 +3255,7 @@ EXPORT_SYMBOL_GPL(virtqueue_get_vring);
> * The caller calls this to do dma mapping in advance. The DMA address can be
> * passed to this _vq when it is in pre-mapped mode.
> *
> - * return DMA address. Caller should check that by virtqueue_mapping_error().
> + * return mapped address. Caller should check that by virtqueue_mapping_error().
> */
> dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
> size_t size,
> @@ -3155,8 +3274,8 @@ dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr,
> "rejecting DMA map of vmalloc memory\n"))
> return DMA_MAPPING_ERROR;
>
> - return dma_map_page_attrs(vring_dma_dev(vq), virt_to_page(ptr),
> - offset_in_page(ptr), size, dir, attrs);
> + return virtqueue_map_page_attrs(&vq->vq, virt_to_page(ptr),
> + offset_in_page(ptr), size, dir, attrs);
> }
> EXPORT_SYMBOL_GPL(virtqueue_map_single_attrs);
>
> @@ -3181,12 +3300,12 @@ void virtqueue_unmap_single_attrs(const struct virtqueue *_vq,
> if (!vq->use_map_api)
> return;
>
> - dma_unmap_page_attrs(vring_dma_dev(vq), addr, size, dir, attrs);
> + virtqueue_unmap_page_attrs(_vq, addr, size, dir, attrs);
> }
> EXPORT_SYMBOL_GPL(virtqueue_unmap_single_attrs);
>
> /**
> - * virtqueue_map_mapping_error - check dma address
> + * virtqueue_mapping_error - check dma address
> * @_vq: the struct virtqueue we're talking about.
> * @addr: DMA address
> *
> @@ -3196,10 +3315,7 @@ int virtqueue_map_mapping_error(const struct virtqueue *_vq, dma_addr_t addr)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
>
> - if (!vq->use_map_api)
> - return 0;
> -
> - return dma_mapping_error(vring_dma_dev(vq), addr);
> + return vring_mapping_error(vq, addr);
> }
> EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
>
> @@ -3216,11 +3332,15 @@ EXPORT_SYMBOL_GPL(virtqueue_map_mapping_error);
> bool virtqueue_map_need_sync(const struct virtqueue *_vq, dma_addr_t addr)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
> + struct virtio_device *vdev = _vq->vdev;
>
> if (!vq->use_map_api)
> return false;
>
> - return dma_need_sync(vring_dma_dev(vq), addr);
> + if (vdev->map)
> + return vdev->map->need_sync(vring_mapping_token(vq), addr);
> + else
> + return dma_need_sync(vring_dma_dev(vq), addr);
> }
> EXPORT_SYMBOL_GPL(virtqueue_map_need_sync);
>
> @@ -3242,12 +3362,17 @@ void virtqueue_map_sync_single_range_for_cpu(const struct virtqueue *_vq,
> enum dma_data_direction dir)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
> - struct device *dev = vring_dma_dev(vq);
> + struct virtio_device *vdev = _vq->vdev;
>
> if (!vq->use_map_api)
> return;
>
> - dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
> + if (vdev->map)
> + vdev->map->sync_single_for_cpu(vring_mapping_token(vq),
> + addr + offset, size, dir);
> + else
> + dma_sync_single_range_for_cpu(vring_dma_dev(vq),
> + addr, offset, size, dir);
> }
> EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_cpu);
>
> @@ -3268,12 +3393,18 @@ void virtqueue_map_sync_single_range_for_device(const struct virtqueue *_vq,
> enum dma_data_direction dir)
> {
> const struct vring_virtqueue *vq = to_vvq(_vq);
> - struct device *dev = vring_dma_dev(vq);
> + struct virtio_device *vdev = _vq->vdev;
>
> if (!vq->use_map_api)
> return;
>
> - dma_sync_single_range_for_device(dev, addr, offset, size, dir);
> + if (vdev->map)
> + vdev->map->sync_single_for_device(vring_mapping_token(vq),
> + addr + offset,
> + size, dir);
> + else
> + dma_sync_single_range_for_device(vring_dma_dev(vq), addr,
> + offset, size, dir);
> }
> EXPORT_SYMBOL_GPL(virtqueue_map_sync_single_range_for_device);
>
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index 37029df94aaf..e1973c7b1d1c 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -44,7 +44,7 @@ union vring_mapping_token {
> /* Device that performs DMA */
> struct device *dma_dev;
> /* Transport specific token used for doing map */
> - void *opaque;
> + void *token;
> };
>
> int virtqueue_add_outbuf(struct virtqueue *vq,
> @@ -165,6 +165,7 @@ struct virtio_device {
> struct virtio_device_id id;
> const struct virtio_config_ops *config;
> const struct vringh_config_ops *vringh_config;
> + const struct virtio_map_ops *map;
> struct list_head vqs;
> u64 features;
> void *priv;
> @@ -266,6 +267,29 @@ void unregister_virtio_driver(struct virtio_driver *drv);
> module_driver(__virtio_driver, register_virtio_driver, \
> unregister_virtio_driver)
>
> +
> +void *virtqueue_map_alloc_coherent(struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token,
> + size_t size, dma_addr_t *dma_handle,
> + gfp_t gfp);
> +
> +void virtqueue_map_free_coherent(struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token,
> + size_t size, void *vaddr,
> + dma_addr_t dma_handle);
> +
> +dma_addr_t virtqueue_map_page_attrs(const struct virtqueue *_vq,
> + struct page *page,
> + unsigned long offset,
> + size_t size,
> + enum dma_data_direction dir,
> + unsigned long attrs);
> +
> +void virtqueue_unmap_page_attrs(const struct virtqueue *_vq,
> + dma_addr_t dma_handle,
> + size_t size, enum dma_data_direction dir,
> + unsigned long attrs);
> +
> dma_addr_t virtqueue_map_single_attrs(const struct virtqueue *_vq, void *ptr, size_t size,
> enum dma_data_direction dir, unsigned long attrs);
> void virtqueue_unmap_single_attrs(const struct virtqueue *_vq, dma_addr_t addr,
> diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> index b3e1d30c765b..784ce56197c4 100644
> --- a/include/linux/virtio_config.h
> +++ b/include/linux/virtio_config.h
> @@ -133,6 +133,78 @@ struct virtio_config_ops {
> int (*enable_vq_after_reset)(struct virtqueue *vq);
> };
>
> +/**
> + * struct virtio_map_ops - operations for mapping buffer for a virtio device
> + * Note: For transport that has its own mapping logic it must
> + * implements all of the operations
> + * @map_page: map a buffer to the device
> + * token: device specific mapping token
> + * page: the page that will be mapped by the device
> + * offset: the offset in the page for a buffer
> + * size: the buffer size
> + * dir: mapping direction
> + * attrs: mapping attributes
> + * Returns: the mapped address
> + * @unmap_page: unmap a buffer from the device
> + * token: device specific mapping token
> + * map_handle: the mapped address
> + * size: the buffer size
> + * dir: mapping direction
> + * attrs: unmapping attributes
> + * @sync_single_for_cpu: sync a single buffer from device to cpu
> + * token: device specific mapping token
> + * map_handle: the mapping address to sync
> + * size: the size of the buffer
> + * dir: synchronization direction
> + * @sync_single_for_device: sync a single buffer from cpu to device
> + * token: device specific mapping token
> + * map_handle: the mapping address to sync
> + * size: the size of the buffer
> + * dir: synchronization direction
> + * @alloc: alloc a coherent buffer mapping
> + * token: device specific mapping token
> + * size: the size of the buffer
> + * map_handle: the mapping address to sync
> + * gfp: allocation flag (GFP_XXX)
> + * Returns: virtual address of the allocated buffer
> + * @free: free a coherent buffer mapping
> + * token: device specific mapping token
> + * size: the size of the buffer
> + * vaddr: virtual address of the buffer
> + * map_handle: the mapping address to sync
> + * attrs: unmapping attributes
> + * @need_sync: if the buffer needs synchronization
> + * token: device specific mapping token
> + * map_handle: the mapped address
> + * Returns: whether the buffer needs synchronization
> + * @mapping_error: if the mapping address is error
> + * token: device specific mapping token
> + * map_handle: the mapped address
> + * @max_mapping_size: get the maximum buffer size that can be mapped
> + * token: device specific mapping token
> + * Returns: the maximum buffer size that can be mapped
> + */
> +struct virtio_map_ops {
> + dma_addr_t (*map_page)(void *token, struct page *page,
> + unsigned long offset, size_t size,
> + enum dma_data_direction dir, unsigned long attrs);
> + void (*unmap_page)(void *token, dma_addr_t map_handle,
> + size_t size, enum dma_data_direction dir,
> + unsigned long attrs);
> + void (*sync_single_for_cpu)(void *token, dma_addr_t map_handle,
> + size_t size, enum dma_data_direction dir);
> + void (*sync_single_for_device)(void *token,
> + dma_addr_t map_handle, size_t size,
> + enum dma_data_direction dir);
> + void *(*alloc)(void *token, size_t size,
> + dma_addr_t *map_handle, gfp_t gfp);
> + void (*free)(void *token, size_t size, void *vaddr,
> + dma_addr_t map_handle, unsigned long attrs);
> + bool (*need_sync)(void *token, dma_addr_t map_handle);
> + int (*mapping_error)(void *token, dma_addr_t map_handle);
> + size_t (*max_mapping_size)(void *token);
> +};
> +
> /* If driver didn't advertise the feature, it will never appear. */
> void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
> unsigned int fbit);
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 7/9] vdpa: support mapping token
2025-08-13 5:48 ` [PATCH V5 7/9] vdpa: support mapping token Jason Wang
@ 2025-08-13 8:45 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 8:45 UTC (permalink / raw)
To: Jason Wang; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Virtio core switches from DMA device to mapping token, let's do that
> as well for vDPA.
>
Acked-by: Eugenio Pérez <eperezma@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vdpa/alibaba/eni_vdpa.c | 2 +-
> drivers/vdpa/ifcvf/ifcvf_main.c | 2 +-
> drivers/vdpa/mlx5/core/mr.c | 4 ++--
> drivers/vdpa/mlx5/net/mlx5_vnet.c | 13 ++++++++-----
> drivers/vdpa/octeon_ep/octep_vdpa_main.c | 2 +-
> drivers/vdpa/pds/vdpa_dev.c | 2 +-
> drivers/vdpa/solidrun/snet_main.c | 4 ++--
> drivers/vdpa/vdpa.c | 2 +-
> drivers/vdpa/vdpa_sim/vdpa_sim.c | 2 +-
> drivers/vdpa/vdpa_user/vduse_dev.c | 2 +-
> drivers/vdpa/virtio_pci/vp_vdpa.c | 2 +-
> drivers/vhost/vdpa.c | 8 ++++++--
> drivers/virtio/virtio_vdpa.c | 11 +++++------
> include/linux/vdpa.h | 15 ++++++++-------
> 14 files changed, 39 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
> index ad7f3447fe90..cbec3fcffaef 100644
> --- a/drivers/vdpa/alibaba/eni_vdpa.c
> +++ b/drivers/vdpa/alibaba/eni_vdpa.c
> @@ -496,7 +496,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> pci_set_master(pdev);
> pci_set_drvdata(pdev, eni_vdpa);
>
> - eni_vdpa->vdpa.dma_dev = &pdev->dev;
> + eni_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
> eni_vdpa->queues = eni_vdpa_get_num_queues(eni_vdpa);
>
> eni_vdpa->vring = devm_kcalloc(&pdev->dev, eni_vdpa->queues,
> diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
> index ccf64d7bbfaa..520a7d4db435 100644
> --- a/drivers/vdpa/ifcvf/ifcvf_main.c
> +++ b/drivers/vdpa/ifcvf/ifcvf_main.c
> @@ -713,7 +713,7 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
>
> ifcvf_mgmt_dev->adapter = adapter;
> adapter->pdev = pdev;
> - adapter->vdpa.dma_dev = &pdev->dev;
> + adapter->vdpa.mapping_token.dma_dev = &pdev->dev;
> adapter->vdpa.mdev = mdev;
> adapter->vf = vf;
> vdpa_dev = &adapter->vdpa;
> diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
> index c7a20278bc3c..b4806324afa0 100644
> --- a/drivers/vdpa/mlx5/core/mr.c
> +++ b/drivers/vdpa/mlx5/core/mr.c
> @@ -378,7 +378,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
> u64 pa, offset;
> u64 paend;
> struct scatterlist *sg;
> - struct device *dma = mvdev->vdev.dma_dev;
> + struct device *dma = mvdev->vdev.mapping_token.dma_dev;
>
> for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
> map; map = vhost_iotlb_itree_next(map, mr->start, mr->end - 1)) {
> @@ -432,7 +432,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
>
> static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
> {
> - struct device *dma = mvdev->vdev.dma_dev;
> + struct device *dma = mvdev->vdev.mapping_token.dma_dev;
>
> destroy_direct_mr(mvdev, mr);
> dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
> diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
> index 0ed2fc28e1ce..4a1a8b0a0123 100644
> --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
> +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
> @@ -3395,14 +3395,17 @@ static int mlx5_vdpa_reset_map(struct vdpa_device *vdev, unsigned int asid)
> return err;
> }
>
> -static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx)
> +static union vring_mapping_token mlx5_get_vq_mapping_token(struct vdpa_device *vdev, u16 idx)
> {
> struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
> + union vring_mapping_token mapping_token;
>
> if (is_ctrl_vq_idx(mvdev, idx))
> - return &vdev->dev;
> + mapping_token.dma_dev = &vdev->dev;
> + else
> + mapping_token.dma_dev = mvdev->vdev.mapping_token.dma_dev;
>
> - return mvdev->vdev.dma_dev;
> + return mapping_token;
> }
>
> static void free_irqs(struct mlx5_vdpa_net *ndev)
> @@ -3686,7 +3689,7 @@ static const struct vdpa_config_ops mlx5_vdpa_ops = {
> .set_map = mlx5_vdpa_set_map,
> .reset_map = mlx5_vdpa_reset_map,
> .set_group_asid = mlx5_set_group_asid,
> - .get_vq_dma_dev = mlx5_get_vq_dma_dev,
> + .get_vq_mapping_token = mlx5_get_vq_mapping_token,
> .free = mlx5_vdpa_free,
> .suspend = mlx5_vdpa_suspend,
> .resume = mlx5_vdpa_resume, /* Op disabled if not supported. */
> @@ -3965,7 +3968,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
> }
>
> ndev->mvdev.mlx_features = device_features;
> - mvdev->vdev.dma_dev = &mdev->pdev->dev;
> + mvdev->vdev.mapping_token.dma_dev = &mdev->pdev->dev;
> err = mlx5_vdpa_alloc_resources(&ndev->mvdev);
> if (err)
> goto err_alloc;
> diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> index 9b49efd24391..e229b421d194 100644
> --- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> +++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> @@ -516,7 +516,7 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> }
>
> oct_vdpa->pdev = pdev;
> - oct_vdpa->vdpa.dma_dev = &pdev->dev;
> + oct_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
> oct_vdpa->vdpa.mdev = mdev;
> oct_vdpa->oct_hw = oct_hw;
> vdpa_dev = &oct_vdpa->vdpa;
> diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c
> index 301d95e08596..c9da0e519d5c 100644
> --- a/drivers/vdpa/pds/vdpa_dev.c
> +++ b/drivers/vdpa/pds/vdpa_dev.c
> @@ -643,7 +643,7 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
>
> pdev = vdpa_aux->padev->vf_pdev;
> dma_dev = &pdev->dev;
> - pdsv->vdpa_dev.dma_dev = dma_dev;
> + pdsv->vdpa_dev.mapping_token.dma_dev = dma_dev;
>
> status = pds_vdpa_get_status(&pdsv->vdpa_dev);
> if (status == 0xff) {
> diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
> index 55ec51c17ab3..d7b4eff77c95 100644
> --- a/drivers/vdpa/solidrun/snet_main.c
> +++ b/drivers/vdpa/solidrun/snet_main.c
> @@ -1052,8 +1052,8 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)
> */
> snet_reserve_irq_idx(pf_irqs ? pdev_pf : pdev, snet);
>
> - /*set DMA device*/
> - snet->vdpa.dma_dev = &pdev->dev;
> + /* set map token */
> + snet->vdpa.mapping_token.dma_dev = &pdev->dev;
>
> /* Register VDPA device */
> ret = vdpa_register_device(&snet->vdpa, snet->cfg->vq_num);
> diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
> index 8a372b51c21a..0115ce04979c 100644
> --- a/drivers/vdpa/vdpa.c
> +++ b/drivers/vdpa/vdpa.c
> @@ -151,7 +151,7 @@ static void vdpa_release_dev(struct device *d)
> * Driver should use vdpa_alloc_device() wrapper macro instead of
> * using this directly.
> *
> - * Return: Returns an error when parent/config/dma_dev is not set or fail to get
> + * Return: Returns an error when parent/config/mapping_token is not set or fail to get
> * ida.
> */
> struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
> index c204fc8e471a..9a07063aaff7 100644
> --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
> +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
> @@ -272,7 +272,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
> vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0],
> &vdpasim->iommu_lock);
>
> - vdpasim->vdpa.dma_dev = dev;
> + vdpasim->vdpa.mapping_token.dma_dev = dev;
>
> return vdpasim;
>
> diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> index 04620bb77203..8e32b3db8608 100644
> --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> @@ -2022,7 +2022,7 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
> return ret;
> }
> set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
> - vdev->vdpa.dma_dev = &vdev->vdpa.dev;
> + vdev->vdpa.mapping_token.dma_dev = &vdev->vdpa.dev;
> vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
>
> return 0;
> diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
> index 8787407f75b0..2cb0dbf1740e 100644
> --- a/drivers/vdpa/virtio_pci/vp_vdpa.c
> +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
> @@ -520,7 +520,7 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
>
> vp_vdpa_mgtdev->vp_vdpa = vp_vdpa;
>
> - vp_vdpa->vdpa.dma_dev = &pdev->dev;
> + vp_vdpa->vdpa.mapping_token.dma_dev = &pdev->dev;
> vp_vdpa->queues = vp_modern_get_num_queues(mdev);
> vp_vdpa->mdev = mdev;
>
> diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
> index 5a49b5a6d496..3d4c44b3f2b7 100644
> --- a/drivers/vhost/vdpa.c
> +++ b/drivers/vhost/vdpa.c
> @@ -1320,7 +1320,9 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
> {
> struct vdpa_device *vdpa = v->vdpa;
> const struct vdpa_config_ops *ops = vdpa->config;
> - struct device *dma_dev = vdpa_get_dma_dev(vdpa);
> + union vring_mapping_token *mapping_token =
> + vdpa_get_mapping_token(vdpa);
> + struct device *dma_dev = mapping_token->dma_dev;
> int ret;
>
> /* Device want to do DMA by itself */
> @@ -1355,7 +1357,9 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
> static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
> {
> struct vdpa_device *vdpa = v->vdpa;
> - struct device *dma_dev = vdpa_get_dma_dev(vdpa);
> + union vring_mapping_token *mapping_token =
> + vdpa_get_mapping_token(vdpa);
> + struct device *dma_dev = mapping_token->dma_dev;
>
> if (v->domain) {
> iommu_detach_device(v->domain, dma_dev);
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index acea98ab08ee..1a10024a8e4f 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -133,7 +133,6 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> const char *name, bool ctx)
> {
> struct vdpa_device *vdpa = vd_get_vdpa(vdev);
> - struct device *dma_dev;
> const struct vdpa_config_ops *ops = vdpa->config;
> bool (*notify)(struct virtqueue *vq) = virtio_vdpa_notify;
> struct vdpa_callback cb;
> @@ -182,11 +181,11 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> /* Create the vring */
> align = ops->get_vq_align(vdpa);
>
> - if (ops->get_vq_dma_dev)
> - dma_dev = ops->get_vq_dma_dev(vdpa, index);
> + if (ops->get_vq_mapping_token)
> + mapping_token = ops->get_vq_mapping_token(vdpa, index);
> else
> - dma_dev = vdpa_get_dma_dev(vdpa);
> - mapping_token.dma_dev = dma_dev;
> + mapping_token = *vdpa_get_mapping_token(vdpa);
> +
> vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> true, may_reduce_num, ctx,
> notify, callback, name, &mapping_token);
> @@ -463,7 +462,7 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa)
> if (!vd_dev)
> return -ENOMEM;
>
> - vd_dev->vdev.dev.parent = vdpa_get_dma_dev(vdpa);
> + vd_dev->vdev.dev.parent = vdpa_get_mapping_token(vdpa)->dma_dev;
> vd_dev->vdev.dev.release = virtio_vdpa_release_dev;
> vd_dev->vdev.config = &virtio_vdpa_config_ops;
> vd_dev->vdpa = vdpa;
> diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
> index 2e7a30fe6b92..f806f13ca260 100644
> --- a/include/linux/vdpa.h
> +++ b/include/linux/vdpa.h
> @@ -5,6 +5,7 @@
> #include <linux/kernel.h>
> #include <linux/device.h>
> #include <linux/interrupt.h>
> +#include <linux/virtio.h>
> #include <linux/vhost_iotlb.h>
> #include <linux/virtio_net.h>
> #include <linux/virtio_blk.h>
> @@ -70,7 +71,7 @@ struct vdpa_mgmt_dev;
> /**
> * struct vdpa_device - representation of a vDPA device
> * @dev: underlying device
> - * @dma_dev: the actual device that is performing DMA
> + * @mapping_token: the token passed to upper layer to be used for mapping
> * @driver_override: driver name to force a match; do not set directly,
> * because core frees it; use driver_set_override() to
> * set or clear it.
> @@ -87,7 +88,7 @@ struct vdpa_mgmt_dev;
> */
> struct vdpa_device {
> struct device dev;
> - struct device *dma_dev;
> + union vring_mapping_token mapping_token;
> const char *driver_override;
> const struct vdpa_config_ops *config;
> struct rw_semaphore cf_lock; /* Protects get/set config */
> @@ -352,11 +353,11 @@ struct vdpa_map_file {
> * @vdev: vdpa device
> * @asid: address space identifier
> * Returns integer: success (0) or error (< 0)
> - * @get_vq_dma_dev: Get the dma device for a specific
> + * @get_vq_mapping_token: Get the map token for a specific
> * virtqueue (optional)
> * @vdev: vdpa device
> * @idx: virtqueue index
> - * Returns pointer to structure device or error (NULL)
> + * Returns map token union error (NULL)
Nit again, maybe we can define a macro for UNION_TOKEN_ERROR as we're
returning it by value. But I'm happy with dev / token == NULL too.
Maybe to document it here?
> * @bind_mm: Bind the device to a specific address space
> * so the vDPA framework can use VA when this
> * callback is implemented. (optional)
> @@ -436,7 +437,7 @@ struct vdpa_config_ops {
> int (*reset_map)(struct vdpa_device *vdev, unsigned int asid);
> int (*set_group_asid)(struct vdpa_device *vdev, unsigned int group,
> unsigned int asid);
> - struct device *(*get_vq_dma_dev)(struct vdpa_device *vdev, u16 idx);
> + union vring_mapping_token (*get_vq_mapping_token)(struct vdpa_device *vdev, u16 idx);
> int (*bind_mm)(struct vdpa_device *vdev, struct mm_struct *mm);
> void (*unbind_mm)(struct vdpa_device *vdev);
>
> @@ -520,9 +521,9 @@ static inline void vdpa_set_drvdata(struct vdpa_device *vdev, void *data)
> dev_set_drvdata(&vdev->dev, data);
> }
>
> -static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev)
> +static inline union vring_mapping_token *vdpa_get_mapping_token(struct vdpa_device *vdev)
> {
> - return vdev->dma_dev;
> + return &vdev->mapping_token;
> }
>
> static inline int vdpa_reset(struct vdpa_device *vdev, u32 flags)
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 8/9] vdpa: introduce map ops
2025-08-13 5:48 ` [PATCH V5 8/9] vdpa: introduce map ops Jason Wang
@ 2025-08-13 8:46 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 8:46 UTC (permalink / raw)
To: Jason Wang
Cc: mst, xuanzhuo, virtualization, linux-kernel, hch,
Christoph Hellwig
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Virtio core allows the transport to provide device or transport
> specific mapping functions. This patch adds this support to vDPA. We
> can simply do this by allowing the vDPA parent to register a
> virtio_map_ops.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vdpa/alibaba/eni_vdpa.c | 3 ++-
> drivers/vdpa/ifcvf/ifcvf_main.c | 3 ++-
> drivers/vdpa/mlx5/net/mlx5_vnet.c | 2 +-
> drivers/vdpa/octeon_ep/octep_vdpa_main.c | 4 ++--
> drivers/vdpa/pds/vdpa_dev.c | 3 ++-
> drivers/vdpa/solidrun/snet_main.c | 4 ++--
> drivers/vdpa/vdpa.c | 3 +++
> drivers/vdpa/vdpa_sim/vdpa_sim.c | 2 +-
> drivers/vdpa/vdpa_user/vduse_dev.c | 3 ++-
> drivers/vdpa/virtio_pci/vp_vdpa.c | 3 ++-
> drivers/vhost/vdpa.c | 10 ++++++++++
> drivers/virtio/virtio_vdpa.c | 4 +++-
> include/linux/vdpa.h | 10 +++++++---
> 13 files changed, 39 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
> index cbec3fcffaef..a0420da37863 100644
> --- a/drivers/vdpa/alibaba/eni_vdpa.c
> +++ b/drivers/vdpa/alibaba/eni_vdpa.c
> @@ -478,7 +478,8 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> return ret;
>
> eni_vdpa = vdpa_alloc_device(struct eni_vdpa, vdpa,
> - dev, &eni_vdpa_ops, 1, 1, NULL, false);
> + dev, &eni_vdpa_ops, NULL,
> + 1, 1, NULL, false);
> if (IS_ERR(eni_vdpa)) {
> ENI_ERR(pdev, "failed to allocate vDPA structure\n");
> return PTR_ERR(eni_vdpa);
> diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
> index 520a7d4db435..2fd8a9b20ac3 100644
> --- a/drivers/vdpa/ifcvf/ifcvf_main.c
> +++ b/drivers/vdpa/ifcvf/ifcvf_main.c
> @@ -705,7 +705,8 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> vf = &ifcvf_mgmt_dev->vf;
> pdev = vf->pdev;
> adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
> - &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false);
> + &pdev->dev, &ifc_vdpa_ops,
> + NULL, 1, 1, NULL, false);
> if (IS_ERR(adapter)) {
> IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
> return PTR_ERR(adapter);
> diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
> index 4a1a8b0a0123..8a8cf6942998 100644
> --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
> +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
> @@ -3882,7 +3882,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
> }
>
> ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mgtdev->vdpa_ops,
> - MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false);
> + NULL, MLX5_VDPA_NUMVQ_GROUPS, MLX5_VDPA_NUM_AS, name, false);
> if (IS_ERR(ndev))
> return PTR_ERR(ndev);
>
> diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> index e229b421d194..3ef9c2fd8f57 100644
> --- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> +++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
> @@ -508,8 +508,8 @@ static int octep_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> u64 device_features;
> int ret;
>
> - oct_vdpa = vdpa_alloc_device(struct octep_vdpa, vdpa, &pdev->dev, &octep_vdpa_ops, 1, 1,
> - NULL, false);
> + oct_vdpa = vdpa_alloc_device(struct octep_vdpa, vdpa, &pdev->dev, &octep_vdpa_ops,
> + NULL, 1, 1, NULL, false);
> if (IS_ERR(oct_vdpa)) {
> dev_err(&pdev->dev, "Failed to allocate vDPA structure for octep vdpa device");
> return PTR_ERR(oct_vdpa);
> diff --git a/drivers/vdpa/pds/vdpa_dev.c b/drivers/vdpa/pds/vdpa_dev.c
> index c9da0e519d5c..ed3e015c4668 100644
> --- a/drivers/vdpa/pds/vdpa_dev.c
> +++ b/drivers/vdpa/pds/vdpa_dev.c
> @@ -632,7 +632,8 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> }
>
> pdsv = vdpa_alloc_device(struct pds_vdpa_device, vdpa_dev,
> - dev, &pds_vdpa_ops, 1, 1, name, false);
> + dev, &pds_vdpa_ops, NULL,
> + 1, 1, name, false);
> if (IS_ERR(pdsv)) {
> dev_err(dev, "Failed to allocate vDPA structure: %pe\n", pdsv);
> return PTR_ERR(pdsv);
> diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
> index d7b4eff77c95..849d325cab31 100644
> --- a/drivers/vdpa/solidrun/snet_main.c
> +++ b/drivers/vdpa/solidrun/snet_main.c
> @@ -1008,8 +1008,8 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev)
> }
>
> /* Allocate vdpa device */
> - snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops, 1, 1, NULL,
> - false);
> + snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops,
> + NULL, 1, 1, NULL, false);
> if (!snet) {
> SNET_ERR(pdev, "Failed to allocate a vdpa device\n");
> ret = -ENOMEM;
> diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
> index 0115ce04979c..8421c882f4d6 100644
> --- a/drivers/vdpa/vdpa.c
> +++ b/drivers/vdpa/vdpa.c
> @@ -142,6 +142,7 @@ static void vdpa_release_dev(struct device *d)
> * initialized but before registered.
> * @parent: the parent device
> * @config: the bus operations that is supported by this device
> + * @map: the map opeartions that is supported by this device
s/opeartions/operations/
Apart from that,
Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
> * @ngroups: number of groups supported by this device
> * @nas: number of address spaces supported by this device
> * @size: size of the parent structure that contains private data
> @@ -156,6 +157,7 @@ static void vdpa_release_dev(struct device *d)
> */
> struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> const struct vdpa_config_ops *config,
> + const struct virtio_map_ops *map,
> unsigned int ngroups, unsigned int nas,
> size_t size, const char *name,
> bool use_va)
> @@ -187,6 +189,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> vdev->dev.release = vdpa_release_dev;
> vdev->index = err;
> vdev->config = config;
> + vdev->map = map;
> vdev->features_valid = false;
> vdev->use_va = use_va;
> vdev->ngroups = ngroups;
> diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
> index 9a07063aaff7..fa288960d53f 100644
> --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
> +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
> @@ -215,7 +215,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
> else
> ops = &vdpasim_config_ops;
>
> - vdpa = __vdpa_alloc_device(NULL, ops,
> + vdpa = __vdpa_alloc_device(NULL, ops, NULL,
> dev_attr->ngroups, dev_attr->nas,
> dev_attr->alloc_size,
> dev_attr->name, use_va);
> diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> index 8e32b3db8608..f161059d543e 100644
> --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> @@ -2009,7 +2009,8 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
> return -EEXIST;
>
> vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
> - &vduse_vdpa_config_ops, 1, 1, name, true);
> + &vduse_vdpa_config_ops, NULL,
> + 1, 1, name, true);
> if (IS_ERR(vdev))
> return PTR_ERR(vdev);
>
> diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
> index 2cb0dbf1740e..e908b2a37c92 100644
> --- a/drivers/vdpa/virtio_pci/vp_vdpa.c
> +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
> @@ -511,7 +511,8 @@ static int vp_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
> int ret, i;
>
> vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa,
> - dev, &vp_vdpa_ops, 1, 1, name, false);
> + dev, &vp_vdpa_ops, NULL,
> + 1, 1, name, false);
>
> if (IS_ERR(vp_vdpa)) {
> dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n");
> diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
> index 3d4c44b3f2b7..147fdef02f06 100644
> --- a/drivers/vhost/vdpa.c
> +++ b/drivers/vhost/vdpa.c
> @@ -1322,13 +1322,23 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
> const struct vdpa_config_ops *ops = vdpa->config;
> union vring_mapping_token *mapping_token =
> vdpa_get_mapping_token(vdpa);
> + const struct virtio_map_ops *map = vdpa->map;
> struct device *dma_dev = mapping_token->dma_dev;
> int ret;
>
> + /* IOMMU domain only works for DMA device */
> + if (vdpa->map)
> + return -EINVAL;
> +
> /* Device want to do DMA by itself */
> if (ops->set_map || ops->dma_map)
> return 0;
>
> + if (map) {
> + dev_warn(&v->dev, "Can't allocate a domian, device use vendor specific mappings\n");
> + return -EINVAL;
> + }
> +
> if (!device_iommu_capable(dma_dev, IOMMU_CAP_CACHE_COHERENCY)) {
> dev_warn_once(&v->dev,
> "Failed to allocate domain, device is not IOMMU cache coherent capable\n");
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index 1a10024a8e4f..fddfcfabf28e 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -462,9 +462,11 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa)
> if (!vd_dev)
> return -ENOMEM;
>
> - vd_dev->vdev.dev.parent = vdpa_get_mapping_token(vdpa)->dma_dev;
> + vd_dev->vdev.dev.parent = vdpa->map ? &vdpa->dev :
> + vdpa_get_mapping_token(vdpa)->dma_dev;
> vd_dev->vdev.dev.release = virtio_vdpa_release_dev;
> vd_dev->vdev.config = &virtio_vdpa_config_ops;
> + vd_dev->vdev.map = vdpa->map;
> vd_dev->vdpa = vdpa;
>
> vd_dev->vdev.id.device = ops->get_device_id(vdpa);
> diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
> index f806f13ca260..d328ec1ab5ea 100644
> --- a/include/linux/vdpa.h
> +++ b/include/linux/vdpa.h
> @@ -76,6 +76,7 @@ struct vdpa_mgmt_dev;
> * because core frees it; use driver_set_override() to
> * set or clear it.
> * @config: the configuration ops for this device.
> + * @map: the map ops for this device
> * @cf_lock: Protects get and set access to configuration layout.
> * @index: device index
> * @features_valid: were features initialized? for legacy guests
> @@ -91,6 +92,7 @@ struct vdpa_device {
> union vring_mapping_token mapping_token;
> const char *driver_override;
> const struct vdpa_config_ops *config;
> + const struct virtio_map_ops *map;
> struct rw_semaphore cf_lock; /* Protects get/set config */
> unsigned int index;
> bool features_valid;
> @@ -447,6 +449,7 @@ struct vdpa_config_ops {
>
> struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> const struct vdpa_config_ops *config,
> + const struct virtio_map_ops *map,
> unsigned int ngroups, unsigned int nas,
> size_t size, const char *name,
> bool use_va);
> @@ -458,6 +461,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> * @member: the name of struct vdpa_device within the @dev_struct
> * @parent: the parent device
> * @config: the bus operations that is supported by this device
> + * @map: the map operations that is supported by this device
> * @ngroups: the number of virtqueue groups supported by this device
> * @nas: the number of address spaces
> * @name: name of the vdpa device
> @@ -465,10 +469,10 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
> *
> * Return allocated data structure or ERR_PTR upon error
> */
> -#define vdpa_alloc_device(dev_struct, member, parent, config, ngroups, nas, \
> - name, use_va) \
> +#define vdpa_alloc_device(dev_struct, member, parent, config, map, \
> + ngroups, nas, name, use_va) \
> container_of((__vdpa_alloc_device( \
> - parent, config, ngroups, nas, \
> + parent, config, map, ngroups, nas, \
> (sizeof(dev_struct) + \
> BUILD_BUG_ON_ZERO(offsetof( \
> dev_struct, member))), name, use_va)), \
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
2025-08-13 7:46 ` Eugenio Perez Martin
@ 2025-08-13 8:55 ` Michael S. Tsirkin
2025-08-13 9:13 ` Eugenio Perez Martin
2025-08-14 3:36 ` Jason Wang
2025-08-13 8:58 ` Michael S. Tsirkin
2 siblings, 2 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2025-08-13 8:55 UTC (permalink / raw)
To: Jason Wang; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> Following patch will introduce the mapping operations for virtio
> device. In order to achieve this, besides the dma device, virtio core
> needs to support a transport or device specific mapping token as well.
> So this patch introduces a union container of a dma device and opaque
> mapping token. The idea is the allow the transport layer to pass
> device specific mapping token which will be used as a parameter for
> the virtio mapping operations. For the transport or device that is
> using DMA, dma device is still being used.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> drivers/virtio/virtio_vdpa.c | 6 +-
> include/linux/virtio.h | 7 +++
> include/linux/virtio_ring.h | 7 ++-
> 4 files changed, 72 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 482a268af851..fb1d407d5f1b 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -210,8 +210,7 @@ struct vring_virtqueue {
> /* DMA, allocation, and size information */
> bool we_own_ring;
>
> - /* Device used for doing DMA */
> - struct device *dma_dev;
> + union vring_mapping_token mapping_token;
>
> #ifdef DEBUG
> /* They're supposed to lock for us. */
> @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
>
> static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> dma_addr_t *dma_handle, gfp_t flag,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
Why are you passing it by pointer? It's just an 8 bit value, pass it
as is.
> {
> if (vring_use_map_api(vdev)) {
> - return dma_alloc_coherent(dma_dev, size,
> + return dma_alloc_coherent(mapping_token->dma_dev, size,
> dma_handle, flag);
> } else {
> void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
>
> static void vring_free_queue(struct virtio_device *vdev, size_t size,
> void *queue, dma_addr_t dma_handle,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev))
> - dma_free_coherent(dma_dev, size, queue, dma_handle);
> + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> }
>
> /*
> - * The DMA ops on various arches are rather gnarly right now, and
> - * making all of the arch DMA ops work on the vring device itself
> + * The map ops on various arches are rather gnarly right now, and
how does this make sense?
> + * making all of the arch map ops work on the vring device itself
> * is a mess.
> */
> static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> {
> - return vq->dma_dev;
> + return vq->mapping_token.dma_dev;
> }
>
> /* Map one sg entry. */
> @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> }
>
> static void vring_free_split(struct vring_virtqueue_split *vring_split,
> - struct virtio_device *vdev, struct device *dma_dev)
> + struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token)
> {
> vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> vring_split->vring.desc,
> vring_split->queue_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_split->desc_state);
> kfree(vring_split->desc_extra);
> @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> u32 num,
> unsigned int vring_align,
> bool may_reduce_num,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> void *queue = NULL;
> dma_addr_t dma_addr;
> @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (queue)
> break;
> if (!may_reduce_num)
> @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> /* Try to get a single page. You are my only hope! */
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr, GFP_KERNEL | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> }
> if (!queue)
> return -ENOMEM;
> @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> #else
> vq->broken = false;
> #endif
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_split vring_split = {};
> struct virtqueue *vq;
> int err;
>
> err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> - may_reduce_num, dma_dev);
> + may_reduce_num, mapping_token);
> if (err)
> return NULL;
>
> vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_split(&vring_split, vdev, dma_dev);
> + vring_free_split(&vring_split, vdev, mapping_token);
> return NULL;
> }
>
> @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> err = vring_alloc_queue_split(&vring_split, vdev, num,
> vq->split.vring_align,
> vq->split.may_reduce_num,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> if (err)
> goto err;
>
> @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> err:
> virtqueue_reinit_split(vq);
> return -ENOMEM;
> @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
>
> static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_packed->vring.desc)
> vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> vring_packed->vring.desc,
> vring_packed->ring_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.driver)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.driver,
> vring_packed->driver_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.device)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.device,
> vring_packed->device_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_packed->desc_state);
> kfree(vring_packed->desc_extra);
> @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
>
> static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - u32 num, struct device *dma_dev)
> + u32 num, union vring_mapping_token *mapping_token)
> {
> struct vring_packed_desc *ring;
> struct vring_packed_desc_event *driver, *device;
> @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> &ring_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!ring)
> goto err;
>
> @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> driver = vring_alloc_queue(vdev, event_size_in_bytes,
> &driver_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!driver)
> goto err;
>
> @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> device = vring_alloc_queue(vdev, event_size_in_bytes,
> &device_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!device)
> goto err;
>
> @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> return 0;
>
> err:
> - vring_free_packed(vring_packed, vdev, dma_dev);
> + vring_free_packed(vring_packed, vdev, mapping_token);
> return -ENOMEM;
> }
>
> @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> vq->broken = false;
> #endif
> vq->packed_ring = true;
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_packed vring_packed = {};
> struct virtqueue *vq;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> return NULL;
>
> vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_packed(&vring_packed, vdev, dma_dev);
> + vring_free_packed(&vring_packed, vdev, mapping_token);
> return NULL;
> }
>
> @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> struct virtio_device *vdev = _vq->vdev;
> int err;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> + if (vring_alloc_queue_packed(&vring_packed, vdev,
> + num, &vq->mapping_token))
> goto err_ring;
>
> err = vring_alloc_state_extra_packed(&vring_packed);
> @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> err_ring:
> virtqueue_reinit_packed(vq);
> return -ENOMEM;
> @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> }
> EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
>
> +
> /**
> * virtqueue_dma_dev - get the dma dev
> * @_vq: the struct virtqueue we're talking about.
and this?
> @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (vq->use_map_api)
> - return vring_dma_dev(vq);
> + return vq->mapping_token.dma_dev;
> else
> return NULL;
> }
> @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> void (*callback)(struct virtqueue *),
> const char *name)
> {
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_create_virtqueue);
>
> -struct virtqueue *vring_create_virtqueue_dma(
> +struct virtqueue *vring_create_virtqueue_map(
> unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> }
> -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
>
> /**
> * virtqueue_resize - resize the vring of vq
> @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> const char *name)
> {
> struct vring_virtqueue_split vring_split = {};
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> struct vring_virtqueue_packed vring_packed = {};
> @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> return __vring_new_virtqueue_packed(index, &vring_packed,
> vdev, weak_barriers,
> context, notify, callback,
> - name, vdev->dev.parent);
> + name, &mapping_token);
> }
>
> vring_init(&vring_split.vring, num, pages, vring_align);
> return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> context, notify, callback, name,
> - vdev->dev.parent);
> + &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_new_virtqueue);
>
> @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> vq->packed.ring_size_in_bytes,
> vq->packed.vring.desc,
> vq->packed.ring_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.driver,
> vq->packed.driver_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.device,
> vq->packed.device_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> kfree(vq->packed.desc_state);
> kfree(vq->packed.desc_extra);
> @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> vq->split.queue_size_in_bytes,
> vq->split.vring.desc,
> vq->split.queue_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> }
> }
> if (!vq->packed_ring) {
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index e25610e3393a..acea98ab08ee 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> struct vdpa_callback cb;
> struct virtqueue *vq;
> u64 desc_addr, driver_addr, device_addr;
> + union vring_mapping_token mapping_token = {0};
> /* Assume split virtqueue, switch to packed if necessary */
> struct vdpa_vq_state state = {0};
> u32 align, max_num, min_num = 1;
> @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> dma_dev = ops->get_vq_dma_dev(vdpa, index);
> else
> dma_dev = vdpa_get_dma_dev(vdpa);
> - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> + mapping_token.dma_dev = dma_dev;
> + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> true, may_reduce_num, ctx,
> - notify, callback, name, dma_dev);
> + notify, callback, name, &mapping_token);
> if (!vq) {
> err = -ENOMEM;
> goto error_new_virtqueue;
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index addbc209275a..37029df94aaf 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -40,6 +40,13 @@ struct virtqueue {
> void *priv;
> };
>
> +union vring_mapping_token {
> + /* Device that performs DMA */
> + struct device *dma_dev;
> + /* Transport specific token used for doing map */
> + void *opaque;
Please just declare whatever structure you want it to be.
> +};
> +
> int virtqueue_add_outbuf(struct virtqueue *vq,
> struct scatterlist sg[], unsigned int num,
> void *data,
> diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> index 9b33df741b63..fd997178da2a 100644
> --- a/include/linux/virtio_ring.h
> +++ b/include/linux/virtio_ring.h
> @@ -3,6 +3,7 @@
> #define _LINUX_VIRTIO_RING_H
>
> #include <asm/barrier.h>
> +#include <linux/virtio.h>
> #include <linux/irqreturn.h>
> #include <uapi/linux/virtio_ring.h>
>
> @@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
>
> /*
> * Creates a virtqueue and allocates the descriptor ring with per
> - * virtqueue DMA device.
> + * virtqueue mapping operations.
> */
> -struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> +struct virtqueue *vring_create_virtqueue_map(unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> struct virtio_device *vdev,
> @@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> bool (*notify)(struct virtqueue *vq),
> void (*callback)(struct virtqueue *vq),
> const char *name,
> - struct device *dma_dev);
> + union vring_mapping_token *mapping_token);
>
> /*
> * Creates a virtqueue with a standard layout but a caller-allocated
> --
> 2.31.1
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
2025-08-13 7:46 ` Eugenio Perez Martin
2025-08-13 8:55 ` Michael S. Tsirkin
@ 2025-08-13 8:58 ` Michael S. Tsirkin
2025-08-14 3:37 ` Jason Wang
2 siblings, 1 reply; 32+ messages in thread
From: Michael S. Tsirkin @ 2025-08-13 8:58 UTC (permalink / raw)
To: Jason Wang; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> Following patch will introduce the mapping operations for virtio
> device. In order to achieve this, besides the dma device, virtio core
> needs to support a transport or device specific mapping token as well.
> So this patch introduces a union container of a dma device and opaque
> mapping token. The idea is the allow the transport layer to pass
> device specific mapping token which will be used as a parameter for
> the virtio mapping operations. For the transport or device that is
> using DMA, dma device is still being used.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> drivers/virtio/virtio_vdpa.c | 6 +-
> include/linux/virtio.h | 7 +++
> include/linux/virtio_ring.h | 7 ++-
> 4 files changed, 72 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> index 482a268af851..fb1d407d5f1b 100644
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -210,8 +210,7 @@ struct vring_virtqueue {
> /* DMA, allocation, and size information */
> bool we_own_ring;
>
> - /* Device used for doing DMA */
> - struct device *dma_dev;
> + union vring_mapping_token mapping_token;
For name I don't much like "token". and it's not just
mapping right? maybe it is just union virtio_dma ?
> #ifdef DEBUG
> /* They're supposed to lock for us. */
> @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
>
> static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> dma_addr_t *dma_handle, gfp_t flag,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev)) {
> - return dma_alloc_coherent(dma_dev, size,
> + return dma_alloc_coherent(mapping_token->dma_dev, size,
> dma_handle, flag);
> } else {
> void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
>
> static void vring_free_queue(struct virtio_device *vdev, size_t size,
> void *queue, dma_addr_t dma_handle,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_use_map_api(vdev))
> - dma_free_coherent(dma_dev, size, queue, dma_handle);
> + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> else
> free_pages_exact(queue, PAGE_ALIGN(size));
> }
>
> /*
> - * The DMA ops on various arches are rather gnarly right now, and
> - * making all of the arch DMA ops work on the vring device itself
> + * The map ops on various arches are rather gnarly right now, and
> + * making all of the arch map ops work on the vring device itself
> * is a mess.
> */
> static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> {
> - return vq->dma_dev;
> + return vq->mapping_token.dma_dev;
> }
>
> /* Map one sg entry. */
> @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> }
>
> static void vring_free_split(struct vring_virtqueue_split *vring_split,
> - struct virtio_device *vdev, struct device *dma_dev)
> + struct virtio_device *vdev,
> + union vring_mapping_token *mapping_token)
> {
> vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> vring_split->vring.desc,
> vring_split->queue_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_split->desc_state);
> kfree(vring_split->desc_extra);
> @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> u32 num,
> unsigned int vring_align,
> bool may_reduce_num,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> void *queue = NULL;
> dma_addr_t dma_addr;
> @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (queue)
> break;
> if (!may_reduce_num)
> @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> /* Try to get a single page. You are my only hope! */
> queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> &dma_addr, GFP_KERNEL | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> }
> if (!queue)
> return -ENOMEM;
> @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> #else
> vq->broken = false;
> #endif
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_split vring_split = {};
> struct virtqueue *vq;
> int err;
>
> err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> - may_reduce_num, dma_dev);
> + may_reduce_num, mapping_token);
> if (err)
> return NULL;
>
> vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_split(&vring_split, vdev, dma_dev);
> + vring_free_split(&vring_split, vdev, mapping_token);
> return NULL;
> }
>
> @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> err = vring_alloc_queue_split(&vring_split, vdev, num,
> vq->split.vring_align,
> vq->split.may_reduce_num,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> if (err)
> goto err;
>
> @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> err:
> virtqueue_reinit_split(vq);
> return -ENOMEM;
> @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
>
> static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> if (vring_packed->vring.desc)
> vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> vring_packed->vring.desc,
> vring_packed->ring_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.driver)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.driver,
> vring_packed->driver_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> if (vring_packed->vring.device)
> vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> vring_packed->vring.device,
> vring_packed->device_event_dma_addr,
> - dma_dev);
> + mapping_token);
>
> kfree(vring_packed->desc_state);
> kfree(vring_packed->desc_extra);
> @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
>
> static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> struct virtio_device *vdev,
> - u32 num, struct device *dma_dev)
> + u32 num, union vring_mapping_token *mapping_token)
> {
> struct vring_packed_desc *ring;
> struct vring_packed_desc_event *driver, *device;
> @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> &ring_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!ring)
> goto err;
>
> @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> driver = vring_alloc_queue(vdev, event_size_in_bytes,
> &driver_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!driver)
> goto err;
>
> @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> device = vring_alloc_queue(vdev, event_size_in_bytes,
> &device_event_dma_addr,
> GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> - dma_dev);
> + mapping_token);
> if (!device)
> goto err;
>
> @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> return 0;
>
> err:
> - vring_free_packed(vring_packed, vdev, dma_dev);
> + vring_free_packed(vring_packed, vdev, mapping_token);
> return -ENOMEM;
> }
>
> @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue *vq;
> int err;
> @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> vq->broken = false;
> #endif
> vq->packed_ring = true;
> - vq->dma_dev = dma_dev;
> + vq->mapping_token = *mapping_token;
> vq->use_map_api = vring_use_map_api(vdev);
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
> struct vring_virtqueue_packed vring_packed = {};
> struct virtqueue *vq;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> return NULL;
>
> vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> if (!vq) {
> - vring_free_packed(&vring_packed, vdev, dma_dev);
> + vring_free_packed(&vring_packed, vdev, mapping_token);
> return NULL;
> }
>
> @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> struct virtio_device *vdev = _vq->vdev;
> int err;
>
> - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> + if (vring_alloc_queue_packed(&vring_packed, vdev,
> + num, &vq->mapping_token))
> goto err_ring;
>
> err = vring_alloc_state_extra_packed(&vring_packed);
> @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> return 0;
>
> err_state_extra:
> - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> err_ring:
> virtqueue_reinit_packed(vq);
> return -ENOMEM;
> @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> }
> EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
>
> +
> /**
> * virtqueue_dma_dev - get the dma dev
> * @_vq: the struct virtqueue we're talking about.
> @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> struct vring_virtqueue *vq = to_vvq(_vq);
>
> if (vq->use_map_api)
> - return vring_dma_dev(vq);
> + return vq->mapping_token.dma_dev;
> else
> return NULL;
> }
> @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> void (*callback)(struct virtqueue *),
> const char *name)
> {
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, vdev->dev.parent);
> + context, notify, callback, name, &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_create_virtqueue);
>
> -struct virtqueue *vring_create_virtqueue_dma(
> +struct virtqueue *vring_create_virtqueue_map(
> unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> bool (*notify)(struct virtqueue *),
> void (*callback)(struct virtqueue *),
> const char *name,
> - struct device *dma_dev)
> + union vring_mapping_token *mapping_token)
> {
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> return vring_create_virtqueue_packed(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
>
> return vring_create_virtqueue_split(index, num, vring_align,
> vdev, weak_barriers, may_reduce_num,
> - context, notify, callback, name, dma_dev);
> + context, notify, callback, name, mapping_token);
> }
> -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
>
> /**
> * virtqueue_resize - resize the vring of vq
> @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> const char *name)
> {
> struct vring_virtqueue_split vring_split = {};
> + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
>
> if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> struct vring_virtqueue_packed vring_packed = {};
> @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> return __vring_new_virtqueue_packed(index, &vring_packed,
> vdev, weak_barriers,
> context, notify, callback,
> - name, vdev->dev.parent);
> + name, &mapping_token);
> }
>
> vring_init(&vring_split.vring, num, pages, vring_align);
> return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> context, notify, callback, name,
> - vdev->dev.parent);
> + &mapping_token);
> }
> EXPORT_SYMBOL_GPL(vring_new_virtqueue);
>
> @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> vq->packed.ring_size_in_bytes,
> vq->packed.vring.desc,
> vq->packed.ring_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.driver,
> vq->packed.driver_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> vring_free_queue(vq->vq.vdev,
> vq->packed.event_size_in_bytes,
> vq->packed.vring.device,
> vq->packed.device_event_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
>
> kfree(vq->packed.desc_state);
> kfree(vq->packed.desc_extra);
> @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> vq->split.queue_size_in_bytes,
> vq->split.vring.desc,
> vq->split.queue_dma_addr,
> - vring_dma_dev(vq));
> + &vq->mapping_token);
> }
> }
> if (!vq->packed_ring) {
> diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> index e25610e3393a..acea98ab08ee 100644
> --- a/drivers/virtio/virtio_vdpa.c
> +++ b/drivers/virtio/virtio_vdpa.c
> @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> struct vdpa_callback cb;
> struct virtqueue *vq;
> u64 desc_addr, driver_addr, device_addr;
> + union vring_mapping_token mapping_token = {0};
> /* Assume split virtqueue, switch to packed if necessary */
> struct vdpa_vq_state state = {0};
> u32 align, max_num, min_num = 1;
> @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> dma_dev = ops->get_vq_dma_dev(vdpa, index);
> else
> dma_dev = vdpa_get_dma_dev(vdpa);
> - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> + mapping_token.dma_dev = dma_dev;
> + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> true, may_reduce_num, ctx,
> - notify, callback, name, dma_dev);
> + notify, callback, name, &mapping_token);
> if (!vq) {
> err = -ENOMEM;
> goto error_new_virtqueue;
> diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> index addbc209275a..37029df94aaf 100644
> --- a/include/linux/virtio.h
> +++ b/include/linux/virtio.h
> @@ -40,6 +40,13 @@ struct virtqueue {
> void *priv;
> };
>
> +union vring_mapping_token {
> + /* Device that performs DMA */
> + struct device *dma_dev;
> + /* Transport specific token used for doing map */
> + void *opaque;
> +};
> +
> int virtqueue_add_outbuf(struct virtqueue *vq,
> struct scatterlist sg[], unsigned int num,
> void *data,
> diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> index 9b33df741b63..fd997178da2a 100644
> --- a/include/linux/virtio_ring.h
> +++ b/include/linux/virtio_ring.h
> @@ -3,6 +3,7 @@
> #define _LINUX_VIRTIO_RING_H
>
> #include <asm/barrier.h>
> +#include <linux/virtio.h>
> #include <linux/irqreturn.h>
> #include <uapi/linux/virtio_ring.h>
>
> @@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
>
> /*
> * Creates a virtqueue and allocates the descriptor ring with per
> - * virtqueue DMA device.
> + * virtqueue mapping operations.
> */
> -struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> +struct virtqueue *vring_create_virtqueue_map(unsigned int index,
> unsigned int num,
> unsigned int vring_align,
> struct virtio_device *vdev,
> @@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> bool (*notify)(struct virtqueue *vq),
> void (*callback)(struct virtqueue *vq),
> const char *name,
> - struct device *dma_dev);
> + union vring_mapping_token *mapping_token);
>
> /*
> * Creates a virtqueue with a standard layout but a caller-allocated
> --
> 2.31.1
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API
2025-08-13 5:48 ` [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API Jason Wang
@ 2025-08-13 9:02 ` Eugenio Perez Martin
2025-08-14 3:33 ` Jason Wang
0 siblings, 1 reply; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 9:02 UTC (permalink / raw)
To: Jason Wang; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
>
> Lacking the support of device specific mapping supported in virtio,
> VDUSE must trick the DMA API in order to make virtio-vdpa transport
> work. This is done by advertising vDPA device as dma device with a
> VDUSE specific dma_ops even if it doesn't do DMA at all.
>
> This will be fixed by this patch. Thanks to the new mapping operations
> support by virtio and vDPA. VDUSE can simply switch to advertise its
> specific mappings operations to virtio via virtio-vdpa then DMA API is
> not needed for VDUSE any more and iova domain could be used as the
> mapping token instead.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vdpa/Kconfig | 8 +--
> drivers/vdpa/vdpa_user/iova_domain.c | 2 +-
> drivers/vdpa/vdpa_user/iova_domain.h | 2 +-
> drivers/vdpa/vdpa_user/vduse_dev.c | 75 ++++++++++++++--------------
> 4 files changed, 41 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
> index 559fb9d3271f..857cf288c876 100644
> --- a/drivers/vdpa/Kconfig
> +++ b/drivers/vdpa/Kconfig
> @@ -34,13 +34,7 @@ config VDPA_SIM_BLOCK
>
> config VDPA_USER
> tristate "VDUSE (vDPA Device in Userspace) support"
> - depends on EVENTFD && MMU && HAS_DMA
> - #
> - # This driver incorrectly tries to override the dma_ops. It should
> - # never have done that, but for now keep it working on architectures
> - # that use dma ops
> - #
> - depends on ARCH_HAS_DMA_OPS
> + depends on EVENTFD && MMU
> select VHOST_IOTLB
> select IOMMU_IOVA
> help
> diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
> index 58116f89d8da..ccaed24b7ef8 100644
> --- a/drivers/vdpa/vdpa_user/iova_domain.c
> +++ b/drivers/vdpa/vdpa_user/iova_domain.c
> @@ -447,7 +447,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
>
> void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> size_t size, dma_addr_t *dma_addr,
> - gfp_t flag, unsigned long attrs)
> + gfp_t flag)
> {
> struct iova_domain *iovad = &domain->consistent_iovad;
> unsigned long limit = domain->iova_limit;
> diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h
> index 7f3f0928ec78..1f3c30be272a 100644
> --- a/drivers/vdpa/vdpa_user/iova_domain.h
> +++ b/drivers/vdpa/vdpa_user/iova_domain.h
> @@ -64,7 +64,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
>
> void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> size_t size, dma_addr_t *dma_addr,
> - gfp_t flag, unsigned long attrs);
> + gfp_t flag);
>
> void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
> void *vaddr, dma_addr_t dma_addr,
> diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> index f161059d543e..3260edefdf0d 100644
> --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> @@ -88,6 +88,7 @@ struct vduse_dev {
> struct device *dev;
> struct vduse_virtqueue **vqs;
> struct vduse_iova_domain *domain;
> + struct vduse_iova_domain *dom;
*dom is not used
> char *name;
> struct mutex lock;
> spinlock_t msg_lock;
> @@ -814,59 +815,53 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
> .free = vduse_vdpa_free,
> };
>
> -static void vduse_dev_sync_single_for_device(struct device *dev,
> +static void vduse_dev_sync_single_for_device(void *token,
> dma_addr_t dma_addr, size_t size,
> enum dma_data_direction dir)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
If I add ASID support to VDUSE I'll need to replace the token by a vq
group representor. Is that ok?
I think it is as I like how using *domain here makes this patch
clearer, and adding something else will make this patch harder to
review.
>
> vduse_domain_sync_single_for_device(domain, dma_addr, size, dir);
> }
>
> -static void vduse_dev_sync_single_for_cpu(struct device *dev,
> +static void vduse_dev_sync_single_for_cpu(void *token,
> dma_addr_t dma_addr, size_t size,
> enum dma_data_direction dir)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
>
> vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
> }
>
> -static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
> +static dma_addr_t vduse_dev_map_page(void *token, struct page *page,
> unsigned long offset, size_t size,
> enum dma_data_direction dir,
> unsigned long attrs)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
>
> return vduse_domain_map_page(domain, page, offset, size, dir, attrs);
> }
>
> -static void vduse_dev_unmap_page(struct device *dev, dma_addr_t dma_addr,
> +static void vduse_dev_unmap_page(void *token, dma_addr_t dma_addr,
> size_t size, enum dma_data_direction dir,
> unsigned long attrs)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
>
> return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs);
> }
>
> -static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> - dma_addr_t *dma_addr, gfp_t flag,
> - unsigned long attrs)
> +static void *vduse_dev_alloc_coherent(void *token, size_t size,
> + dma_addr_t *dma_addr, gfp_t flag)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
> unsigned long iova;
> void *addr;
>
> *dma_addr = DMA_MAPPING_ERROR;
> addr = vduse_domain_alloc_coherent(domain, size,
> - (dma_addr_t *)&iova, flag, attrs);
> + (dma_addr_t *)&iova, flag);
> if (!addr)
> return NULL;
>
> @@ -875,31 +870,45 @@ static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> return addr;
> }
>
> -static void vduse_dev_free_coherent(struct device *dev, size_t size,
> - void *vaddr, dma_addr_t dma_addr,
> - unsigned long attrs)
> +static void vduse_dev_free_coherent(void *token, size_t size,
> + void *vaddr, dma_addr_t dma_addr,
> + unsigned long attrs)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
>
> vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs);
> }
>
> -static size_t vduse_dev_max_mapping_size(struct device *dev)
> +static bool vduse_dev_need_sync(void *token, dma_addr_t dma_addr)
> {
> - struct vduse_dev *vdev = dev_to_vduse(dev);
> - struct vduse_iova_domain *domain = vdev->domain;
> + struct vduse_iova_domain *domain = token;
> +
> + return dma_addr < domain->bounce_size;
> +}
> +
> +static int vduse_dev_mapping_error(void *token, dma_addr_t dma_addr)
> +{
> + if (unlikely(dma_addr == DMA_MAPPING_ERROR))
> + return -ENOMEM;
> + return 0;
> +}
> +
> +static size_t vduse_dev_max_mapping_size(void *token)
> +{
> + struct vduse_iova_domain *domain = token;
>
> return domain->bounce_size;
> }
>
> -static const struct dma_map_ops vduse_dev_dma_ops = {
> +static const struct virtio_map_ops vduse_map_ops = {
> .sync_single_for_device = vduse_dev_sync_single_for_device,
> .sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
> .map_page = vduse_dev_map_page,
> .unmap_page = vduse_dev_unmap_page,
> .alloc = vduse_dev_alloc_coherent,
> .free = vduse_dev_free_coherent,
> + .need_sync = vduse_dev_need_sync,
> + .mapping_error = vduse_dev_mapping_error,
I think that adding these functions here is problematic,
In the case of mapping error vring_mapping_error only checks for
vdev->map, not for vdev->map->mapping_error:
static int vring_mapping_error(const struct vring_virtqueue *vq,
dma_addr_t addr)
{
struct virtio_device *vdev = vq->vq.vdev;
if (!vq->use_map_api)
return 0;
if (vdev->map)
return vdev->map->mapping_error(vring_mapping_token(vq), addr);
else
return dma_mapping_error(vring_dma_dev(vq), addr);
}
So we either add the check for the member or we define them from the beginning.
> .max_mapping_size = vduse_dev_max_mapping_size,
> };
>
> @@ -2003,27 +2012,18 @@ static struct vduse_mgmt_dev *vduse_mgmt;
> static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
> {
> struct vduse_vdpa *vdev;
> - int ret;
>
> if (dev->vdev)
> return -EEXIST;
>
> vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
> - &vduse_vdpa_config_ops, NULL,
> + &vduse_vdpa_config_ops, &vduse_map_ops,
> 1, 1, name, true);
> if (IS_ERR(vdev))
> return PTR_ERR(vdev);
>
> dev->vdev = vdev;
> vdev->dev = dev;
> - vdev->vdpa.dev.dma_mask = &vdev->vdpa.dev.coherent_dma_mask;
> - ret = dma_set_mask_and_coherent(&vdev->vdpa.dev, DMA_BIT_MASK(64));
> - if (ret) {
> - put_device(&vdev->vdpa.dev);
> - return ret;
> - }
> - set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
> - vdev->vdpa.mapping_token.dma_dev = &vdev->vdpa.dev;
> vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
>
> return 0;
> @@ -2056,6 +2056,7 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> return -ENOMEM;
> }
>
> + dev->vdev->vdpa.mapping_token.token = dev->domain;
> ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num);
> if (ret) {
> put_device(&dev->vdev->vdpa.dev);
> --
> 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 8:55 ` Michael S. Tsirkin
@ 2025-08-13 9:13 ` Eugenio Perez Martin
2025-08-14 3:39 ` Jason Wang
2025-08-14 3:36 ` Jason Wang
1 sibling, 1 reply; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-13 9:13 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Jason Wang, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 10:55 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> > Following patch will introduce the mapping operations for virtio
> > device. In order to achieve this, besides the dma device, virtio core
> > needs to support a transport or device specific mapping token as well.
> > So this patch introduces a union container of a dma device and opaque
> > mapping token. The idea is the allow the transport layer to pass
> > device specific mapping token which will be used as a parameter for
> > the virtio mapping operations. For the transport or device that is
> > using DMA, dma device is still being used.
> >
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> > drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> > drivers/virtio/virtio_vdpa.c | 6 +-
> > include/linux/virtio.h | 7 +++
> > include/linux/virtio_ring.h | 7 ++-
> > 4 files changed, 72 insertions(+), 58 deletions(-)
> >
> > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > index 482a268af851..fb1d407d5f1b 100644
> > --- a/drivers/virtio/virtio_ring.c
> > +++ b/drivers/virtio/virtio_ring.c
> > @@ -210,8 +210,7 @@ struct vring_virtqueue {
> > /* DMA, allocation, and size information */
> > bool we_own_ring;
> >
> > - /* Device used for doing DMA */
> > - struct device *dma_dev;
> > + union vring_mapping_token mapping_token;
> >
> > #ifdef DEBUG
> > /* They're supposed to lock for us. */
> > @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
> >
> > static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> > dma_addr_t *dma_handle, gfp_t flag,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
>
> Why are you passing it by pointer? It's just an 8 bit value, pass it
> as is.
>
>
> > {
> > if (vring_use_map_api(vdev)) {
> > - return dma_alloc_coherent(dma_dev, size,
> > + return dma_alloc_coherent(mapping_token->dma_dev, size,
> > dma_handle, flag);
> > } else {
> > void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> > @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> >
> > static void vring_free_queue(struct virtio_device *vdev, size_t size,
> > void *queue, dma_addr_t dma_handle,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > if (vring_use_map_api(vdev))
> > - dma_free_coherent(dma_dev, size, queue, dma_handle);
> > + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> > else
> > free_pages_exact(queue, PAGE_ALIGN(size));
> > }
> >
> > /*
> > - * The DMA ops on various arches are rather gnarly right now, and
> > - * making all of the arch DMA ops work on the vring device itself
> > + * The map ops on various arches are rather gnarly right now, and
>
>
> how does this make sense?
>
> > + * making all of the arch map ops work on the vring device itself
> > * is a mess.
> > */
> > static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> > {
> > - return vq->dma_dev;
> > + return vq->mapping_token.dma_dev;
> > }
> >
> > /* Map one sg entry. */
> > @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> > }
> >
> > static void vring_free_split(struct vring_virtqueue_split *vring_split,
> > - struct virtio_device *vdev, struct device *dma_dev)
> > + struct virtio_device *vdev,
> > + union vring_mapping_token *mapping_token)
> > {
> > vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> > vring_split->vring.desc,
> > vring_split->queue_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > kfree(vring_split->desc_state);
> > kfree(vring_split->desc_extra);
> > @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > u32 num,
> > unsigned int vring_align,
> > bool may_reduce_num,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > void *queue = NULL;
> > dma_addr_t dma_addr;
> > @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > &dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (queue)
> > break;
> > if (!may_reduce_num)
> > @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > /* Try to get a single page. You are my only hope! */
> > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > &dma_addr, GFP_KERNEL | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > }
> > if (!queue)
> > return -ENOMEM;
> > @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue *vq;
> > int err;
> > @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > #else
> > vq->broken = false;
> > #endif
> > - vq->dma_dev = dma_dev;
> > + vq->mapping_token = *mapping_token;
> > vq->use_map_api = vring_use_map_api(vdev);
> >
> > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue_split vring_split = {};
> > struct virtqueue *vq;
> > int err;
> >
> > err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> > - may_reduce_num, dma_dev);
> > + may_reduce_num, mapping_token);
> > if (err)
> > return NULL;
> >
> > vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > if (!vq) {
> > - vring_free_split(&vring_split, vdev, dma_dev);
> > + vring_free_split(&vring_split, vdev, mapping_token);
> > return NULL;
> > }
> >
> > @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > err = vring_alloc_queue_split(&vring_split, vdev, num,
> > vq->split.vring_align,
> > vq->split.may_reduce_num,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> > if (err)
> > goto err;
> >
> > @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > return 0;
> >
> > err_state_extra:
> > - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> > + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> > err:
> > virtqueue_reinit_split(vq);
> > return -ENOMEM;
> > @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
> >
> > static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> > struct virtio_device *vdev,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > if (vring_packed->vring.desc)
> > vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> > vring_packed->vring.desc,
> > vring_packed->ring_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > if (vring_packed->vring.driver)
> > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > vring_packed->vring.driver,
> > vring_packed->driver_event_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > if (vring_packed->vring.device)
> > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > vring_packed->vring.device,
> > vring_packed->device_event_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > kfree(vring_packed->desc_state);
> > kfree(vring_packed->desc_extra);
> > @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> >
> > static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > struct virtio_device *vdev,
> > - u32 num, struct device *dma_dev)
> > + u32 num, union vring_mapping_token *mapping_token)
> > {
> > struct vring_packed_desc *ring;
> > struct vring_packed_desc_event *driver, *device;
> > @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> > &ring_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!ring)
> > goto err;
> >
> > @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > driver = vring_alloc_queue(vdev, event_size_in_bytes,
> > &driver_event_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!driver)
> > goto err;
> >
> > @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > device = vring_alloc_queue(vdev, event_size_in_bytes,
> > &device_event_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!device)
> > goto err;
> >
> > @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > return 0;
> >
> > err:
> > - vring_free_packed(vring_packed, vdev, dma_dev);
> > + vring_free_packed(vring_packed, vdev, mapping_token);
> > return -ENOMEM;
> > }
> >
> > @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue *vq;
> > int err;
> > @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > vq->broken = false;
> > #endif
> > vq->packed_ring = true;
> > - vq->dma_dev = dma_dev;
> > + vq->mapping_token = *mapping_token;
> > vq->use_map_api = vring_use_map_api(vdev);
> >
> > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue_packed vring_packed = {};
> > struct virtqueue *vq;
> >
> > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> > + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> > return NULL;
> >
> > vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > if (!vq) {
> > - vring_free_packed(&vring_packed, vdev, dma_dev);
> > + vring_free_packed(&vring_packed, vdev, mapping_token);
> > return NULL;
> > }
> >
> > @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > struct virtio_device *vdev = _vq->vdev;
> > int err;
> >
> > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> > + if (vring_alloc_queue_packed(&vring_packed, vdev,
> > + num, &vq->mapping_token))
> > goto err_ring;
> >
> > err = vring_alloc_state_extra_packed(&vring_packed);
> > @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > return 0;
> >
> > err_state_extra:
> > - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> > + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> > err_ring:
> > virtqueue_reinit_packed(vq);
> > return -ENOMEM;
> > @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> > }
> > EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
> >
> > +
> > /**
> > * virtqueue_dma_dev - get the dma dev
> > * @_vq: the struct virtqueue we're talking about.
>
>
> and this?
>
> > @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> > struct vring_virtqueue *vq = to_vvq(_vq);
> >
> > if (vq->use_map_api)
> > - return vring_dma_dev(vq);
> > + return vq->mapping_token.dma_dev;
> > else
> > return NULL;
> > }
> > @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> > void (*callback)(struct virtqueue *),
> > const char *name)
> > {
> > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > return vring_create_virtqueue_packed(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, vdev->dev.parent);
> > + context, notify, callback, name, &mapping_token);
> >
> > return vring_create_virtqueue_split(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, vdev->dev.parent);
> > + context, notify, callback, name, &mapping_token);
> > }
> > EXPORT_SYMBOL_GPL(vring_create_virtqueue);
> >
> > -struct virtqueue *vring_create_virtqueue_dma(
> > +struct virtqueue *vring_create_virtqueue_map(
> > unsigned int index,
> > unsigned int num,
> > unsigned int vring_align,
> > @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > return vring_create_virtqueue_packed(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> >
> > return vring_create_virtqueue_split(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > }
> > -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> > +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
> >
> > /**
> > * virtqueue_resize - resize the vring of vq
> > @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > const char *name)
> > {
> > struct vring_virtqueue_split vring_split = {};
> > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> > struct vring_virtqueue_packed vring_packed = {};
> > @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > return __vring_new_virtqueue_packed(index, &vring_packed,
> > vdev, weak_barriers,
> > context, notify, callback,
> > - name, vdev->dev.parent);
> > + name, &mapping_token);
> > }
> >
> > vring_init(&vring_split.vring, num, pages, vring_align);
> > return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > context, notify, callback, name,
> > - vdev->dev.parent);
> > + &mapping_token);
> > }
> > EXPORT_SYMBOL_GPL(vring_new_virtqueue);
> >
> > @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> > vq->packed.ring_size_in_bytes,
> > vq->packed.vring.desc,
> > vq->packed.ring_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > vring_free_queue(vq->vq.vdev,
> > vq->packed.event_size_in_bytes,
> > vq->packed.vring.driver,
> > vq->packed.driver_event_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > vring_free_queue(vq->vq.vdev,
> > vq->packed.event_size_in_bytes,
> > vq->packed.vring.device,
> > vq->packed.device_event_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > kfree(vq->packed.desc_state);
> > kfree(vq->packed.desc_extra);
> > @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> > vq->split.queue_size_in_bytes,
> > vq->split.vring.desc,
> > vq->split.queue_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> > }
> > }
> > if (!vq->packed_ring) {
> > diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> > index e25610e3393a..acea98ab08ee 100644
> > --- a/drivers/virtio/virtio_vdpa.c
> > +++ b/drivers/virtio/virtio_vdpa.c
> > @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > struct vdpa_callback cb;
> > struct virtqueue *vq;
> > u64 desc_addr, driver_addr, device_addr;
> > + union vring_mapping_token mapping_token = {0};
> > /* Assume split virtqueue, switch to packed if necessary */
> > struct vdpa_vq_state state = {0};
> > u32 align, max_num, min_num = 1;
> > @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > dma_dev = ops->get_vq_dma_dev(vdpa, index);
> > else
> > dma_dev = vdpa_get_dma_dev(vdpa);
> > - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> > + mapping_token.dma_dev = dma_dev;
> > + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> > true, may_reduce_num, ctx,
> > - notify, callback, name, dma_dev);
> > + notify, callback, name, &mapping_token);
> > if (!vq) {
> > err = -ENOMEM;
> > goto error_new_virtqueue;
> > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > index addbc209275a..37029df94aaf 100644
> > --- a/include/linux/virtio.h
> > +++ b/include/linux/virtio.h
> > @@ -40,6 +40,13 @@ struct virtqueue {
> > void *priv;
> > };
> >
> > +union vring_mapping_token {
> > + /* Device that performs DMA */
> > + struct device *dma_dev;
> > + /* Transport specific token used for doing map */
> > + void *opaque;
>
> Please just declare whatever structure you want it to be.
>
The type would be backend-specific in the future. HW vdpa will not
have the same type here as VDUSE, and they contain backend-specific
information.
If we want to be 100% type safe we could declare an empty or small
struct and make the backend "inherit" (as "make the empty struct a
member of the backend struct") at the backend so we can cast them with
container_of or similar. Would that work?
> > +};
> > +
> > int virtqueue_add_outbuf(struct virtqueue *vq,
> > struct scatterlist sg[], unsigned int num,
> > void *data,
> > diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> > index 9b33df741b63..fd997178da2a 100644
> > --- a/include/linux/virtio_ring.h
> > +++ b/include/linux/virtio_ring.h
> > @@ -3,6 +3,7 @@
> > #define _LINUX_VIRTIO_RING_H
> >
> > #include <asm/barrier.h>
> > +#include <linux/virtio.h>
> > #include <linux/irqreturn.h>
> > #include <uapi/linux/virtio_ring.h>
> >
> > @@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
> >
> > /*
> > * Creates a virtqueue and allocates the descriptor ring with per
> > - * virtqueue DMA device.
> > + * virtqueue mapping operations.
> > */
> > -struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> > +struct virtqueue *vring_create_virtqueue_map(unsigned int index,
> > unsigned int num,
> > unsigned int vring_align,
> > struct virtio_device *vdev,
> > @@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> > bool (*notify)(struct virtqueue *vq),
> > void (*callback)(struct virtqueue *vq),
> > const char *name,
> > - struct device *dma_dev);
> > + union vring_mapping_token *mapping_token);
> >
> > /*
> > * Creates a virtqueue with a standard layout but a caller-allocated
> > --
> > 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API
2025-08-13 9:02 ` Eugenio Perez Martin
@ 2025-08-14 3:33 ` Jason Wang
2025-08-14 6:42 ` Eugenio Perez Martin
0 siblings, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-14 3:33 UTC (permalink / raw)
To: Eugenio Perez Martin; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 5:03 PM Eugenio Perez Martin
<eperezma@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
> >
> > Lacking the support of device specific mapping supported in virtio,
> > VDUSE must trick the DMA API in order to make virtio-vdpa transport
> > work. This is done by advertising vDPA device as dma device with a
> > VDUSE specific dma_ops even if it doesn't do DMA at all.
> >
> > This will be fixed by this patch. Thanks to the new mapping operations
> > support by virtio and vDPA. VDUSE can simply switch to advertise its
> > specific mappings operations to virtio via virtio-vdpa then DMA API is
> > not needed for VDUSE any more and iova domain could be used as the
> > mapping token instead.
> >
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> > drivers/vdpa/Kconfig | 8 +--
> > drivers/vdpa/vdpa_user/iova_domain.c | 2 +-
> > drivers/vdpa/vdpa_user/iova_domain.h | 2 +-
> > drivers/vdpa/vdpa_user/vduse_dev.c | 75 ++++++++++++++--------------
> > 4 files changed, 41 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
> > index 559fb9d3271f..857cf288c876 100644
> > --- a/drivers/vdpa/Kconfig
> > +++ b/drivers/vdpa/Kconfig
> > @@ -34,13 +34,7 @@ config VDPA_SIM_BLOCK
> >
> > config VDPA_USER
> > tristate "VDUSE (vDPA Device in Userspace) support"
> > - depends on EVENTFD && MMU && HAS_DMA
> > - #
> > - # This driver incorrectly tries to override the dma_ops. It should
> > - # never have done that, but for now keep it working on architectures
> > - # that use dma ops
> > - #
> > - depends on ARCH_HAS_DMA_OPS
> > + depends on EVENTFD && MMU
> > select VHOST_IOTLB
> > select IOMMU_IOVA
> > help
> > diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
> > index 58116f89d8da..ccaed24b7ef8 100644
> > --- a/drivers/vdpa/vdpa_user/iova_domain.c
> > +++ b/drivers/vdpa/vdpa_user/iova_domain.c
> > @@ -447,7 +447,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
> >
> > void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> > size_t size, dma_addr_t *dma_addr,
> > - gfp_t flag, unsigned long attrs)
> > + gfp_t flag)
> > {
> > struct iova_domain *iovad = &domain->consistent_iovad;
> > unsigned long limit = domain->iova_limit;
> > diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h
> > index 7f3f0928ec78..1f3c30be272a 100644
> > --- a/drivers/vdpa/vdpa_user/iova_domain.h
> > +++ b/drivers/vdpa/vdpa_user/iova_domain.h
> > @@ -64,7 +64,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
> >
> > void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> > size_t size, dma_addr_t *dma_addr,
> > - gfp_t flag, unsigned long attrs);
> > + gfp_t flag);
> >
> > void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
> > void *vaddr, dma_addr_t dma_addr,
> > diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> > index f161059d543e..3260edefdf0d 100644
> > --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> > +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> > @@ -88,6 +88,7 @@ struct vduse_dev {
> > struct device *dev;
> > struct vduse_virtqueue **vqs;
> > struct vduse_iova_domain *domain;
> > + struct vduse_iova_domain *dom;
>
> *dom is not used
>
Let me fix that.
> > char *name;
> > struct mutex lock;
> > spinlock_t msg_lock;
> > @@ -814,59 +815,53 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
> > .free = vduse_vdpa_free,
> > };
> >
> > -static void vduse_dev_sync_single_for_device(struct device *dev,
> > +static void vduse_dev_sync_single_for_device(void *token,
> > dma_addr_t dma_addr, size_t size,
> > enum dma_data_direction dir)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
>
> If I add ASID support to VDUSE I'll need to replace the token by a vq
> group representor. Is that ok?
It should be ok.
>
> I think it is as I like how using *domain here makes this patch
> clearer, and adding something else will make this patch harder to
> review.
Yes.
>
> >
> > vduse_domain_sync_single_for_device(domain, dma_addr, size, dir);
> > }
> >
> > -static void vduse_dev_sync_single_for_cpu(struct device *dev,
> > +static void vduse_dev_sync_single_for_cpu(void *token,
> > dma_addr_t dma_addr, size_t size,
> > enum dma_data_direction dir)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> >
> > vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
> > }
> >
> > -static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
> > +static dma_addr_t vduse_dev_map_page(void *token, struct page *page,
> > unsigned long offset, size_t size,
> > enum dma_data_direction dir,
> > unsigned long attrs)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> >
> > return vduse_domain_map_page(domain, page, offset, size, dir, attrs);
> > }
> >
> > -static void vduse_dev_unmap_page(struct device *dev, dma_addr_t dma_addr,
> > +static void vduse_dev_unmap_page(void *token, dma_addr_t dma_addr,
> > size_t size, enum dma_data_direction dir,
> > unsigned long attrs)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> >
> > return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs);
> > }
> >
> > -static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> > - dma_addr_t *dma_addr, gfp_t flag,
> > - unsigned long attrs)
> > +static void *vduse_dev_alloc_coherent(void *token, size_t size,
> > + dma_addr_t *dma_addr, gfp_t flag)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> > unsigned long iova;
> > void *addr;
> >
> > *dma_addr = DMA_MAPPING_ERROR;
> > addr = vduse_domain_alloc_coherent(domain, size,
> > - (dma_addr_t *)&iova, flag, attrs);
> > + (dma_addr_t *)&iova, flag);
> > if (!addr)
> > return NULL;
> >
> > @@ -875,31 +870,45 @@ static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> > return addr;
> > }
> >
> > -static void vduse_dev_free_coherent(struct device *dev, size_t size,
> > - void *vaddr, dma_addr_t dma_addr,
> > - unsigned long attrs)
> > +static void vduse_dev_free_coherent(void *token, size_t size,
> > + void *vaddr, dma_addr_t dma_addr,
> > + unsigned long attrs)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> >
> > vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs);
> > }
> >
> > -static size_t vduse_dev_max_mapping_size(struct device *dev)
> > +static bool vduse_dev_need_sync(void *token, dma_addr_t dma_addr)
> > {
> > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > - struct vduse_iova_domain *domain = vdev->domain;
> > + struct vduse_iova_domain *domain = token;
> > +
> > + return dma_addr < domain->bounce_size;
> > +}
> > +
> > +static int vduse_dev_mapping_error(void *token, dma_addr_t dma_addr)
> > +{
> > + if (unlikely(dma_addr == DMA_MAPPING_ERROR))
> > + return -ENOMEM;
> > + return 0;
> > +}
> > +
> > +static size_t vduse_dev_max_mapping_size(void *token)
> > +{
> > + struct vduse_iova_domain *domain = token;
> >
> > return domain->bounce_size;
> > }
> >
> > -static const struct dma_map_ops vduse_dev_dma_ops = {
> > +static const struct virtio_map_ops vduse_map_ops = {
> > .sync_single_for_device = vduse_dev_sync_single_for_device,
> > .sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
> > .map_page = vduse_dev_map_page,
> > .unmap_page = vduse_dev_unmap_page,
> > .alloc = vduse_dev_alloc_coherent,
> > .free = vduse_dev_free_coherent,
> > + .need_sync = vduse_dev_need_sync,
> > + .mapping_error = vduse_dev_mapping_error,
>
> I think that adding these functions here is problematic,
>
> In the case of mapping error vring_mapping_error only checks for
> vdev->map, not for vdev->map->mapping_error:
>
> static int vring_mapping_error(const struct vring_virtqueue *vq,
> dma_addr_t addr)
> {
> struct virtio_device *vdev = vq->vq.vdev;
>
> if (!vq->use_map_api)
> return 0;
>
> if (vdev->map)
> return vdev->map->mapping_error(vring_mapping_token(vq), addr);
> else
> return dma_mapping_error(vring_dma_dev(vq), addr);
> }
>
> So we either add the check for the member or we define them from the beginning.
I'm not sure I will get here. I can add a comment to explain that all
map ops are mandated not optional.
Thanks
>
> > .max_mapping_size = vduse_dev_max_mapping_size,
> > };
> >
> > @@ -2003,27 +2012,18 @@ static struct vduse_mgmt_dev *vduse_mgmt;
> > static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
> > {
> > struct vduse_vdpa *vdev;
> > - int ret;
> >
> > if (dev->vdev)
> > return -EEXIST;
> >
> > vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
> > - &vduse_vdpa_config_ops, NULL,
> > + &vduse_vdpa_config_ops, &vduse_map_ops,
> > 1, 1, name, true);
> > if (IS_ERR(vdev))
> > return PTR_ERR(vdev);
> >
> > dev->vdev = vdev;
> > vdev->dev = dev;
> > - vdev->vdpa.dev.dma_mask = &vdev->vdpa.dev.coherent_dma_mask;
> > - ret = dma_set_mask_and_coherent(&vdev->vdpa.dev, DMA_BIT_MASK(64));
> > - if (ret) {
> > - put_device(&vdev->vdpa.dev);
> > - return ret;
> > - }
> > - set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
> > - vdev->vdpa.mapping_token.dma_dev = &vdev->vdpa.dev;
> > vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
> >
> > return 0;
> > @@ -2056,6 +2056,7 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
> > return -ENOMEM;
> > }
> >
> > + dev->vdev->vdpa.mapping_token.token = dev->domain;
> > ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num);
> > if (ret) {
> > put_device(&dev->vdev->vdpa.dev);
> > --
> > 2.31.1
> >
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 8:55 ` Michael S. Tsirkin
2025-08-13 9:13 ` Eugenio Perez Martin
@ 2025-08-14 3:36 ` Jason Wang
2025-08-14 10:42 ` Michael S. Tsirkin
1 sibling, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-14 3:36 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 4:55 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> > Following patch will introduce the mapping operations for virtio
> > device. In order to achieve this, besides the dma device, virtio core
> > needs to support a transport or device specific mapping token as well.
> > So this patch introduces a union container of a dma device and opaque
> > mapping token. The idea is the allow the transport layer to pass
> > device specific mapping token which will be used as a parameter for
> > the virtio mapping operations. For the transport or device that is
> > using DMA, dma device is still being used.
> >
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> > drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> > drivers/virtio/virtio_vdpa.c | 6 +-
> > include/linux/virtio.h | 7 +++
> > include/linux/virtio_ring.h | 7 ++-
> > 4 files changed, 72 insertions(+), 58 deletions(-)
> >
> > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > index 482a268af851..fb1d407d5f1b 100644
> > --- a/drivers/virtio/virtio_ring.c
> > +++ b/drivers/virtio/virtio_ring.c
> > @@ -210,8 +210,7 @@ struct vring_virtqueue {
> > /* DMA, allocation, and size information */
> > bool we_own_ring;
> >
> > - /* Device used for doing DMA */
> > - struct device *dma_dev;
> > + union vring_mapping_token mapping_token;
> >
> > #ifdef DEBUG
> > /* They're supposed to lock for us. */
> > @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
> >
> > static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> > dma_addr_t *dma_handle, gfp_t flag,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
>
> Why are you passing it by pointer? It's just an 8 bit value, pass it
> as is.
Sure.
>
>
> > {
> > if (vring_use_map_api(vdev)) {
> > - return dma_alloc_coherent(dma_dev, size,
> > + return dma_alloc_coherent(mapping_token->dma_dev, size,
> > dma_handle, flag);
> > } else {
> > void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> > @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> >
> > static void vring_free_queue(struct virtio_device *vdev, size_t size,
> > void *queue, dma_addr_t dma_handle,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > if (vring_use_map_api(vdev))
> > - dma_free_coherent(dma_dev, size, queue, dma_handle);
> > + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> > else
> > free_pages_exact(queue, PAGE_ALIGN(size));
> > }
> >
> > /*
> > - * The DMA ops on various arches are rather gnarly right now, and
> > - * making all of the arch DMA ops work on the vring device itself
> > + * The map ops on various arches are rather gnarly right now, and
>
>
> how does this make sense?
Let me fix that.
>
> > + * making all of the arch map ops work on the vring device itself
> > * is a mess.
> > */
> > static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> > {
> > - return vq->dma_dev;
> > + return vq->mapping_token.dma_dev;
> > }
> >
> > /* Map one sg entry. */
> > @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> > }
> >
> > static void vring_free_split(struct vring_virtqueue_split *vring_split,
> > - struct virtio_device *vdev, struct device *dma_dev)
> > + struct virtio_device *vdev,
> > + union vring_mapping_token *mapping_token)
> > {
> > vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> > vring_split->vring.desc,
> > vring_split->queue_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > kfree(vring_split->desc_state);
> > kfree(vring_split->desc_extra);
> > @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > u32 num,
> > unsigned int vring_align,
> > bool may_reduce_num,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > void *queue = NULL;
> > dma_addr_t dma_addr;
> > @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > &dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (queue)
> > break;
> > if (!may_reduce_num)
> > @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > /* Try to get a single page. You are my only hope! */
> > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > &dma_addr, GFP_KERNEL | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > }
> > if (!queue)
> > return -ENOMEM;
> > @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue *vq;
> > int err;
> > @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > #else
> > vq->broken = false;
> > #endif
> > - vq->dma_dev = dma_dev;
> > + vq->mapping_token = *mapping_token;
> > vq->use_map_api = vring_use_map_api(vdev);
> >
> > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue_split vring_split = {};
> > struct virtqueue *vq;
> > int err;
> >
> > err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> > - may_reduce_num, dma_dev);
> > + may_reduce_num, mapping_token);
> > if (err)
> > return NULL;
> >
> > vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > if (!vq) {
> > - vring_free_split(&vring_split, vdev, dma_dev);
> > + vring_free_split(&vring_split, vdev, mapping_token);
> > return NULL;
> > }
> >
> > @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > err = vring_alloc_queue_split(&vring_split, vdev, num,
> > vq->split.vring_align,
> > vq->split.may_reduce_num,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> > if (err)
> > goto err;
> >
> > @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > return 0;
> >
> > err_state_extra:
> > - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> > + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> > err:
> > virtqueue_reinit_split(vq);
> > return -ENOMEM;
> > @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
> >
> > static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> > struct virtio_device *vdev,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > if (vring_packed->vring.desc)
> > vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> > vring_packed->vring.desc,
> > vring_packed->ring_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > if (vring_packed->vring.driver)
> > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > vring_packed->vring.driver,
> > vring_packed->driver_event_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > if (vring_packed->vring.device)
> > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > vring_packed->vring.device,
> > vring_packed->device_event_dma_addr,
> > - dma_dev);
> > + mapping_token);
> >
> > kfree(vring_packed->desc_state);
> > kfree(vring_packed->desc_extra);
> > @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> >
> > static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > struct virtio_device *vdev,
> > - u32 num, struct device *dma_dev)
> > + u32 num, union vring_mapping_token *mapping_token)
> > {
> > struct vring_packed_desc *ring;
> > struct vring_packed_desc_event *driver, *device;
> > @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> > &ring_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!ring)
> > goto err;
> >
> > @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > driver = vring_alloc_queue(vdev, event_size_in_bytes,
> > &driver_event_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!driver)
> > goto err;
> >
> > @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > device = vring_alloc_queue(vdev, event_size_in_bytes,
> > &device_event_dma_addr,
> > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > - dma_dev);
> > + mapping_token);
> > if (!device)
> > goto err;
> >
> > @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > return 0;
> >
> > err:
> > - vring_free_packed(vring_packed, vdev, dma_dev);
> > + vring_free_packed(vring_packed, vdev, mapping_token);
> > return -ENOMEM;
> > }
> >
> > @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue *vq;
> > int err;
> > @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > vq->broken = false;
> > #endif
> > vq->packed_ring = true;
> > - vq->dma_dev = dma_dev;
> > + vq->mapping_token = *mapping_token;
> > vq->use_map_api = vring_use_map_api(vdev);
> >
> > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> > struct vring_virtqueue_packed vring_packed = {};
> > struct virtqueue *vq;
> >
> > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> > + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> > return NULL;
> >
> > vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > if (!vq) {
> > - vring_free_packed(&vring_packed, vdev, dma_dev);
> > + vring_free_packed(&vring_packed, vdev, mapping_token);
> > return NULL;
> > }
> >
> > @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > struct virtio_device *vdev = _vq->vdev;
> > int err;
> >
> > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> > + if (vring_alloc_queue_packed(&vring_packed, vdev,
> > + num, &vq->mapping_token))
> > goto err_ring;
> >
> > err = vring_alloc_state_extra_packed(&vring_packed);
> > @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > return 0;
> >
> > err_state_extra:
> > - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> > + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> > err_ring:
> > virtqueue_reinit_packed(vq);
> > return -ENOMEM;
> > @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> > }
> > EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
> >
> > +
> > /**
> > * virtqueue_dma_dev - get the dma dev
> > * @_vq: the struct virtqueue we're talking about.
>
>
> and this?
Will fix.
>
> > @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> > struct vring_virtqueue *vq = to_vvq(_vq);
> >
> > if (vq->use_map_api)
> > - return vring_dma_dev(vq);
> > + return vq->mapping_token.dma_dev;
> > else
> > return NULL;
> > }
> > @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> > void (*callback)(struct virtqueue *),
> > const char *name)
> > {
> > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > return vring_create_virtqueue_packed(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, vdev->dev.parent);
> > + context, notify, callback, name, &mapping_token);
> >
> > return vring_create_virtqueue_split(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, vdev->dev.parent);
> > + context, notify, callback, name, &mapping_token);
> > }
> > EXPORT_SYMBOL_GPL(vring_create_virtqueue);
> >
> > -struct virtqueue *vring_create_virtqueue_dma(
> > +struct virtqueue *vring_create_virtqueue_map(
> > unsigned int index,
> > unsigned int num,
> > unsigned int vring_align,
> > @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> > bool (*notify)(struct virtqueue *),
> > void (*callback)(struct virtqueue *),
> > const char *name,
> > - struct device *dma_dev)
> > + union vring_mapping_token *mapping_token)
> > {
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > return vring_create_virtqueue_packed(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> >
> > return vring_create_virtqueue_split(index, num, vring_align,
> > vdev, weak_barriers, may_reduce_num,
> > - context, notify, callback, name, dma_dev);
> > + context, notify, callback, name, mapping_token);
> > }
> > -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> > +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
> >
> > /**
> > * virtqueue_resize - resize the vring of vq
> > @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > const char *name)
> > {
> > struct vring_virtqueue_split vring_split = {};
> > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> >
> > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> > struct vring_virtqueue_packed vring_packed = {};
> > @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > return __vring_new_virtqueue_packed(index, &vring_packed,
> > vdev, weak_barriers,
> > context, notify, callback,
> > - name, vdev->dev.parent);
> > + name, &mapping_token);
> > }
> >
> > vring_init(&vring_split.vring, num, pages, vring_align);
> > return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > context, notify, callback, name,
> > - vdev->dev.parent);
> > + &mapping_token);
> > }
> > EXPORT_SYMBOL_GPL(vring_new_virtqueue);
> >
> > @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> > vq->packed.ring_size_in_bytes,
> > vq->packed.vring.desc,
> > vq->packed.ring_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > vring_free_queue(vq->vq.vdev,
> > vq->packed.event_size_in_bytes,
> > vq->packed.vring.driver,
> > vq->packed.driver_event_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > vring_free_queue(vq->vq.vdev,
> > vq->packed.event_size_in_bytes,
> > vq->packed.vring.device,
> > vq->packed.device_event_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> >
> > kfree(vq->packed.desc_state);
> > kfree(vq->packed.desc_extra);
> > @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> > vq->split.queue_size_in_bytes,
> > vq->split.vring.desc,
> > vq->split.queue_dma_addr,
> > - vring_dma_dev(vq));
> > + &vq->mapping_token);
> > }
> > }
> > if (!vq->packed_ring) {
> > diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> > index e25610e3393a..acea98ab08ee 100644
> > --- a/drivers/virtio/virtio_vdpa.c
> > +++ b/drivers/virtio/virtio_vdpa.c
> > @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > struct vdpa_callback cb;
> > struct virtqueue *vq;
> > u64 desc_addr, driver_addr, device_addr;
> > + union vring_mapping_token mapping_token = {0};
> > /* Assume split virtqueue, switch to packed if necessary */
> > struct vdpa_vq_state state = {0};
> > u32 align, max_num, min_num = 1;
> > @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > dma_dev = ops->get_vq_dma_dev(vdpa, index);
> > else
> > dma_dev = vdpa_get_dma_dev(vdpa);
> > - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> > + mapping_token.dma_dev = dma_dev;
> > + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> > true, may_reduce_num, ctx,
> > - notify, callback, name, dma_dev);
> > + notify, callback, name, &mapping_token);
> > if (!vq) {
> > err = -ENOMEM;
> > goto error_new_virtqueue;
> > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > index addbc209275a..37029df94aaf 100644
> > --- a/include/linux/virtio.h
> > +++ b/include/linux/virtio.h
> > @@ -40,6 +40,13 @@ struct virtqueue {
> > void *priv;
> > };
> >
> > +union vring_mapping_token {
> > + /* Device that performs DMA */
> > + struct device *dma_dev;
> > + /* Transport specific token used for doing map */
> > + void *opaque;
>
> Please just declare whatever structure you want it to be.
It's an opaque one and so
1) the virtio core knows nothing about that because it could be
transport or device specific
2) no assumption of the type and usage, it just receive it from the
transport and pass it back when doing the mapping
It should work like page->private etc.
Does this make sense?
Thanks
>
> > +};
> > +
> > int virtqueue_add_outbuf(struct virtqueue *vq,
> > struct scatterlist sg[], unsigned int num,
> > void *data,
> > diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> > index 9b33df741b63..fd997178da2a 100644
> > --- a/include/linux/virtio_ring.h
> > +++ b/include/linux/virtio_ring.h
> > @@ -3,6 +3,7 @@
> > #define _LINUX_VIRTIO_RING_H
> >
> > #include <asm/barrier.h>
> > +#include <linux/virtio.h>
> > #include <linux/irqreturn.h>
> > #include <uapi/linux/virtio_ring.h>
> >
> > @@ -79,9 +80,9 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
> >
> > /*
> > * Creates a virtqueue and allocates the descriptor ring with per
> > - * virtqueue DMA device.
> > + * virtqueue mapping operations.
> > */
> > -struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> > +struct virtqueue *vring_create_virtqueue_map(unsigned int index,
> > unsigned int num,
> > unsigned int vring_align,
> > struct virtio_device *vdev,
> > @@ -91,7 +92,7 @@ struct virtqueue *vring_create_virtqueue_dma(unsigned int index,
> > bool (*notify)(struct virtqueue *vq),
> > void (*callback)(struct virtqueue *vq),
> > const char *name,
> > - struct device *dma_dev);
> > + union vring_mapping_token *mapping_token);
> >
> > /*
> > * Creates a virtqueue with a standard layout but a caller-allocated
> > --
> > 2.31.1
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 8:58 ` Michael S. Tsirkin
@ 2025-08-14 3:37 ` Jason Wang
0 siblings, 0 replies; 32+ messages in thread
From: Jason Wang @ 2025-08-14 3:37 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 4:58 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> > Following patch will introduce the mapping operations for virtio
> > device. In order to achieve this, besides the dma device, virtio core
> > needs to support a transport or device specific mapping token as well.
> > So this patch introduces a union container of a dma device and opaque
> > mapping token. The idea is the allow the transport layer to pass
> > device specific mapping token which will be used as a parameter for
> > the virtio mapping operations. For the transport or device that is
> > using DMA, dma device is still being used.
> >
> > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > ---
> > drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> > drivers/virtio/virtio_vdpa.c | 6 +-
> > include/linux/virtio.h | 7 +++
> > include/linux/virtio_ring.h | 7 ++-
> > 4 files changed, 72 insertions(+), 58 deletions(-)
> >
> > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > index 482a268af851..fb1d407d5f1b 100644
> > --- a/drivers/virtio/virtio_ring.c
> > +++ b/drivers/virtio/virtio_ring.c
> > @@ -210,8 +210,7 @@ struct vring_virtqueue {
> > /* DMA, allocation, and size information */
> > bool we_own_ring;
> >
> > - /* Device used for doing DMA */
> > - struct device *dma_dev;
> > + union vring_mapping_token mapping_token;
>
> For name I don't much like "token". and it's not just
> mapping right? maybe it is just union virtio_dma ?
>
It's not limited to dma, maybe virtio_map? (I'm fine with either).
Thanks
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-13 9:13 ` Eugenio Perez Martin
@ 2025-08-14 3:39 ` Jason Wang
0 siblings, 0 replies; 32+ messages in thread
From: Jason Wang @ 2025-08-14 3:39 UTC (permalink / raw)
To: Eugenio Perez Martin
Cc: Michael S. Tsirkin, xuanzhuo, virtualization, linux-kernel, hch
On Wed, Aug 13, 2025 at 5:14 PM Eugenio Perez Martin
<eperezma@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 10:55 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Wed, Aug 13, 2025 at 01:48:26PM +0800, Jason Wang wrote:
> > > Following patch will introduce the mapping operations for virtio
> > > device. In order to achieve this, besides the dma device, virtio core
> > > needs to support a transport or device specific mapping token as well.
> > > So this patch introduces a union container of a dma device and opaque
> > > mapping token. The idea is the allow the transport layer to pass
> > > device specific mapping token which will be used as a parameter for
> > > the virtio mapping operations. For the transport or device that is
> > > using DMA, dma device is still being used.
> > >
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > > ---
> > > drivers/virtio/virtio_ring.c | 110 ++++++++++++++++++-----------------
> > > drivers/virtio/virtio_vdpa.c | 6 +-
> > > include/linux/virtio.h | 7 +++
> > > include/linux/virtio_ring.h | 7 ++-
> > > 4 files changed, 72 insertions(+), 58 deletions(-)
> > >
> > > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> > > index 482a268af851..fb1d407d5f1b 100644
> > > --- a/drivers/virtio/virtio_ring.c
> > > +++ b/drivers/virtio/virtio_ring.c
> > > @@ -210,8 +210,7 @@ struct vring_virtqueue {
> > > /* DMA, allocation, and size information */
> > > bool we_own_ring;
> > >
> > > - /* Device used for doing DMA */
> > > - struct device *dma_dev;
> > > + union vring_mapping_token mapping_token;
> > >
> > > #ifdef DEBUG
> > > /* They're supposed to lock for us. */
> > > @@ -307,10 +306,10 @@ EXPORT_SYMBOL_GPL(virtio_max_dma_size);
> > >
> > > static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> > > dma_addr_t *dma_handle, gfp_t flag,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> >
> > Why are you passing it by pointer? It's just an 8 bit value, pass it
> > as is.
> >
> >
> > > {
> > > if (vring_use_map_api(vdev)) {
> > > - return dma_alloc_coherent(dma_dev, size,
> > > + return dma_alloc_coherent(mapping_token->dma_dev, size,
> > > dma_handle, flag);
> > > } else {
> > > void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
> > > @@ -341,22 +340,22 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
> > >
> > > static void vring_free_queue(struct virtio_device *vdev, size_t size,
> > > void *queue, dma_addr_t dma_handle,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > if (vring_use_map_api(vdev))
> > > - dma_free_coherent(dma_dev, size, queue, dma_handle);
> > > + dma_free_coherent(mapping_token->dma_dev, size, queue, dma_handle);
> > > else
> > > free_pages_exact(queue, PAGE_ALIGN(size));
> > > }
> > >
> > > /*
> > > - * The DMA ops on various arches are rather gnarly right now, and
> > > - * making all of the arch DMA ops work on the vring device itself
> > > + * The map ops on various arches are rather gnarly right now, and
> >
> >
> > how does this make sense?
> >
> > > + * making all of the arch map ops work on the vring device itself
> > > * is a mess.
> > > */
> > > static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
> > > {
> > > - return vq->dma_dev;
> > > + return vq->mapping_token.dma_dev;
> > > }
> > >
> > > /* Map one sg entry. */
> > > @@ -1056,12 +1055,13 @@ static int vring_alloc_state_extra_split(struct vring_virtqueue_split *vring_spl
> > > }
> > >
> > > static void vring_free_split(struct vring_virtqueue_split *vring_split,
> > > - struct virtio_device *vdev, struct device *dma_dev)
> > > + struct virtio_device *vdev,
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > vring_free_queue(vdev, vring_split->queue_size_in_bytes,
> > > vring_split->vring.desc,
> > > vring_split->queue_dma_addr,
> > > - dma_dev);
> > > + mapping_token);
> > >
> > > kfree(vring_split->desc_state);
> > > kfree(vring_split->desc_extra);
> > > @@ -1072,7 +1072,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > > u32 num,
> > > unsigned int vring_align,
> > > bool may_reduce_num,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > void *queue = NULL;
> > > dma_addr_t dma_addr;
> > > @@ -1088,7 +1088,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > > &dma_addr,
> > > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > > - dma_dev);
> > > + mapping_token);
> > > if (queue)
> > > break;
> > > if (!may_reduce_num)
> > > @@ -1102,7 +1102,7 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
> > > /* Try to get a single page. You are my only hope! */
> > > queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
> > > &dma_addr, GFP_KERNEL | __GFP_ZERO,
> > > - dma_dev);
> > > + mapping_token);
> > > }
> > > if (!queue)
> > > return -ENOMEM;
> > > @@ -1126,7 +1126,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > > bool (*notify)(struct virtqueue *),
> > > void (*callback)(struct virtqueue *),
> > > const char *name,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > struct vring_virtqueue *vq;
> > > int err;
> > > @@ -1149,7 +1149,7 @@ static struct virtqueue *__vring_new_virtqueue_split(unsigned int index,
> > > #else
> > > vq->broken = false;
> > > #endif
> > > - vq->dma_dev = dma_dev;
> > > + vq->mapping_token = *mapping_token;
> > > vq->use_map_api = vring_use_map_api(vdev);
> > >
> > > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > > @@ -1187,21 +1187,21 @@ static struct virtqueue *vring_create_virtqueue_split(
> > > bool (*notify)(struct virtqueue *),
> > > void (*callback)(struct virtqueue *),
> > > const char *name,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > struct vring_virtqueue_split vring_split = {};
> > > struct virtqueue *vq;
> > > int err;
> > >
> > > err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
> > > - may_reduce_num, dma_dev);
> > > + may_reduce_num, mapping_token);
> > > if (err)
> > > return NULL;
> > >
> > > vq = __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > > - context, notify, callback, name, dma_dev);
> > > + context, notify, callback, name, mapping_token);
> > > if (!vq) {
> > > - vring_free_split(&vring_split, vdev, dma_dev);
> > > + vring_free_split(&vring_split, vdev, mapping_token);
> > > return NULL;
> > > }
> > >
> > > @@ -1220,7 +1220,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > > err = vring_alloc_queue_split(&vring_split, vdev, num,
> > > vq->split.vring_align,
> > > vq->split.may_reduce_num,
> > > - vring_dma_dev(vq));
> > > + &vq->mapping_token);
> > > if (err)
> > > goto err;
> > >
> > > @@ -1238,7 +1238,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
> > > return 0;
> > >
> > > err_state_extra:
> > > - vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
> > > + vring_free_split(&vring_split, vdev, &vq->mapping_token);
> > > err:
> > > virtqueue_reinit_split(vq);
> > > return -ENOMEM;
> > > @@ -1947,25 +1947,25 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
> > >
> > > static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> > > struct virtio_device *vdev,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > if (vring_packed->vring.desc)
> > > vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
> > > vring_packed->vring.desc,
> > > vring_packed->ring_dma_addr,
> > > - dma_dev);
> > > + mapping_token);
> > >
> > > if (vring_packed->vring.driver)
> > > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > > vring_packed->vring.driver,
> > > vring_packed->driver_event_dma_addr,
> > > - dma_dev);
> > > + mapping_token);
> > >
> > > if (vring_packed->vring.device)
> > > vring_free_queue(vdev, vring_packed->event_size_in_bytes,
> > > vring_packed->vring.device,
> > > vring_packed->device_event_dma_addr,
> > > - dma_dev);
> > > + mapping_token);
> > >
> > > kfree(vring_packed->desc_state);
> > > kfree(vring_packed->desc_extra);
> > > @@ -1973,7 +1973,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
> > >
> > > static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > > struct virtio_device *vdev,
> > > - u32 num, struct device *dma_dev)
> > > + u32 num, union vring_mapping_token *mapping_token)
> > > {
> > > struct vring_packed_desc *ring;
> > > struct vring_packed_desc_event *driver, *device;
> > > @@ -1985,7 +1985,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > > ring = vring_alloc_queue(vdev, ring_size_in_bytes,
> > > &ring_dma_addr,
> > > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > > - dma_dev);
> > > + mapping_token);
> > > if (!ring)
> > > goto err;
> > >
> > > @@ -1998,7 +1998,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > > driver = vring_alloc_queue(vdev, event_size_in_bytes,
> > > &driver_event_dma_addr,
> > > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > > - dma_dev);
> > > + mapping_token);
> > > if (!driver)
> > > goto err;
> > >
> > > @@ -2009,7 +2009,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > > device = vring_alloc_queue(vdev, event_size_in_bytes,
> > > &device_event_dma_addr,
> > > GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
> > > - dma_dev);
> > > + mapping_token);
> > > if (!device)
> > > goto err;
> > >
> > > @@ -2021,7 +2021,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
> > > return 0;
> > >
> > > err:
> > > - vring_free_packed(vring_packed, vdev, dma_dev);
> > > + vring_free_packed(vring_packed, vdev, mapping_token);
> > > return -ENOMEM;
> > > }
> > >
> > > @@ -2097,7 +2097,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > > bool (*notify)(struct virtqueue *),
> > > void (*callback)(struct virtqueue *),
> > > const char *name,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > struct vring_virtqueue *vq;
> > > int err;
> > > @@ -2120,7 +2120,7 @@ static struct virtqueue *__vring_new_virtqueue_packed(unsigned int index,
> > > vq->broken = false;
> > > #endif
> > > vq->packed_ring = true;
> > > - vq->dma_dev = dma_dev;
> > > + vq->mapping_token = *mapping_token;
> > > vq->use_map_api = vring_use_map_api(vdev);
> > >
> > > vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
> > > @@ -2158,18 +2158,18 @@ static struct virtqueue *vring_create_virtqueue_packed(
> > > bool (*notify)(struct virtqueue *),
> > > void (*callback)(struct virtqueue *),
> > > const char *name,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > > struct vring_virtqueue_packed vring_packed = {};
> > > struct virtqueue *vq;
> > >
> > > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
> > > + if (vring_alloc_queue_packed(&vring_packed, vdev, num, mapping_token))
> > > return NULL;
> > >
> > > vq = __vring_new_virtqueue_packed(index, &vring_packed, vdev, weak_barriers,
> > > - context, notify, callback, name, dma_dev);
> > > + context, notify, callback, name, mapping_token);
> > > if (!vq) {
> > > - vring_free_packed(&vring_packed, vdev, dma_dev);
> > > + vring_free_packed(&vring_packed, vdev, mapping_token);
> > > return NULL;
> > > }
> > >
> > > @@ -2185,7 +2185,8 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > > struct virtio_device *vdev = _vq->vdev;
> > > int err;
> > >
> > > - if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
> > > + if (vring_alloc_queue_packed(&vring_packed, vdev,
> > > + num, &vq->mapping_token))
> > > goto err_ring;
> > >
> > > err = vring_alloc_state_extra_packed(&vring_packed);
> > > @@ -2202,7 +2203,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
> > > return 0;
> > >
> > > err_state_extra:
> > > - vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
> > > + vring_free_packed(&vring_packed, vdev, &vq->mapping_token);
> > > err_ring:
> > > virtqueue_reinit_packed(vq);
> > > return -ENOMEM;
> > > @@ -2423,6 +2424,7 @@ int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
> > > }
> > > EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
> > >
> > > +
> > > /**
> > > * virtqueue_dma_dev - get the dma dev
> > > * @_vq: the struct virtqueue we're talking about.
> >
> >
> > and this?
> >
> > > @@ -2434,7 +2436,7 @@ struct device *virtqueue_dma_dev(struct virtqueue *_vq)
> > > struct vring_virtqueue *vq = to_vvq(_vq);
> > >
> > > if (vq->use_map_api)
> > > - return vring_dma_dev(vq);
> > > + return vq->mapping_token.dma_dev;
> > > else
> > > return NULL;
> > > }
> > > @@ -2719,19 +2721,20 @@ struct virtqueue *vring_create_virtqueue(
> > > void (*callback)(struct virtqueue *),
> > > const char *name)
> > > {
> > > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> > >
> > > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > > return vring_create_virtqueue_packed(index, num, vring_align,
> > > vdev, weak_barriers, may_reduce_num,
> > > - context, notify, callback, name, vdev->dev.parent);
> > > + context, notify, callback, name, &mapping_token);
> > >
> > > return vring_create_virtqueue_split(index, num, vring_align,
> > > vdev, weak_barriers, may_reduce_num,
> > > - context, notify, callback, name, vdev->dev.parent);
> > > + context, notify, callback, name, &mapping_token);
> > > }
> > > EXPORT_SYMBOL_GPL(vring_create_virtqueue);
> > >
> > > -struct virtqueue *vring_create_virtqueue_dma(
> > > +struct virtqueue *vring_create_virtqueue_map(
> > > unsigned int index,
> > > unsigned int num,
> > > unsigned int vring_align,
> > > @@ -2742,19 +2745,19 @@ struct virtqueue *vring_create_virtqueue_dma(
> > > bool (*notify)(struct virtqueue *),
> > > void (*callback)(struct virtqueue *),
> > > const char *name,
> > > - struct device *dma_dev)
> > > + union vring_mapping_token *mapping_token)
> > > {
> > >
> > > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
> > > return vring_create_virtqueue_packed(index, num, vring_align,
> > > vdev, weak_barriers, may_reduce_num,
> > > - context, notify, callback, name, dma_dev);
> > > + context, notify, callback, name, mapping_token);
> > >
> > > return vring_create_virtqueue_split(index, num, vring_align,
> > > vdev, weak_barriers, may_reduce_num,
> > > - context, notify, callback, name, dma_dev);
> > > + context, notify, callback, name, mapping_token);
> > > }
> > > -EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
> > > +EXPORT_SYMBOL_GPL(vring_create_virtqueue_map);
> > >
> > > /**
> > > * virtqueue_resize - resize the vring of vq
> > > @@ -2865,6 +2868,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > > const char *name)
> > > {
> > > struct vring_virtqueue_split vring_split = {};
> > > + union vring_mapping_token mapping_token = {.dma_dev = vdev->dev.parent};
> > >
> > > if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> > > struct vring_virtqueue_packed vring_packed = {};
> > > @@ -2874,13 +2878,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
> > > return __vring_new_virtqueue_packed(index, &vring_packed,
> > > vdev, weak_barriers,
> > > context, notify, callback,
> > > - name, vdev->dev.parent);
> > > + name, &mapping_token);
> > > }
> > >
> > > vring_init(&vring_split.vring, num, pages, vring_align);
> > > return __vring_new_virtqueue_split(index, &vring_split, vdev, weak_barriers,
> > > context, notify, callback, name,
> > > - vdev->dev.parent);
> > > + &mapping_token);
> > > }
> > > EXPORT_SYMBOL_GPL(vring_new_virtqueue);
> > >
> > > @@ -2894,19 +2898,19 @@ static void vring_free(struct virtqueue *_vq)
> > > vq->packed.ring_size_in_bytes,
> > > vq->packed.vring.desc,
> > > vq->packed.ring_dma_addr,
> > > - vring_dma_dev(vq));
> > > + &vq->mapping_token);
> > >
> > > vring_free_queue(vq->vq.vdev,
> > > vq->packed.event_size_in_bytes,
> > > vq->packed.vring.driver,
> > > vq->packed.driver_event_dma_addr,
> > > - vring_dma_dev(vq));
> > > + &vq->mapping_token);
> > >
> > > vring_free_queue(vq->vq.vdev,
> > > vq->packed.event_size_in_bytes,
> > > vq->packed.vring.device,
> > > vq->packed.device_event_dma_addr,
> > > - vring_dma_dev(vq));
> > > + &vq->mapping_token);
> > >
> > > kfree(vq->packed.desc_state);
> > > kfree(vq->packed.desc_extra);
> > > @@ -2915,7 +2919,7 @@ static void vring_free(struct virtqueue *_vq)
> > > vq->split.queue_size_in_bytes,
> > > vq->split.vring.desc,
> > > vq->split.queue_dma_addr,
> > > - vring_dma_dev(vq));
> > > + &vq->mapping_token);
> > > }
> > > }
> > > if (!vq->packed_ring) {
> > > diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
> > > index e25610e3393a..acea98ab08ee 100644
> > > --- a/drivers/virtio/virtio_vdpa.c
> > > +++ b/drivers/virtio/virtio_vdpa.c
> > > @@ -139,6 +139,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > > struct vdpa_callback cb;
> > > struct virtqueue *vq;
> > > u64 desc_addr, driver_addr, device_addr;
> > > + union vring_mapping_token mapping_token = {0};
> > > /* Assume split virtqueue, switch to packed if necessary */
> > > struct vdpa_vq_state state = {0};
> > > u32 align, max_num, min_num = 1;
> > > @@ -185,9 +186,10 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
> > > dma_dev = ops->get_vq_dma_dev(vdpa, index);
> > > else
> > > dma_dev = vdpa_get_dma_dev(vdpa);
> > > - vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
> > > + mapping_token.dma_dev = dma_dev;
> > > + vq = vring_create_virtqueue_map(index, max_num, align, vdev,
> > > true, may_reduce_num, ctx,
> > > - notify, callback, name, dma_dev);
> > > + notify, callback, name, &mapping_token);
> > > if (!vq) {
> > > err = -ENOMEM;
> > > goto error_new_virtqueue;
> > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > index addbc209275a..37029df94aaf 100644
> > > --- a/include/linux/virtio.h
> > > +++ b/include/linux/virtio.h
> > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > void *priv;
> > > };
> > >
> > > +union vring_mapping_token {
> > > + /* Device that performs DMA */
> > > + struct device *dma_dev;
> > > + /* Transport specific token used for doing map */
> > > + void *opaque;
> >
> > Please just declare whatever structure you want it to be.
> >
>
> The type would be backend-specific in the future. HW vdpa will not
> have the same type here as VDUSE, and they contain backend-specific
> information.
Yes.
>
> If we want to be 100% type safe we could declare an empty or small
> struct and make the backend "inherit" (as "make the empty struct a
> member of the backend struct") at the backend so we can cast them with
> container_of or similar. Would that work?
I'm fine with this but I don't see an obvious difference.
Thanks
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API
2025-08-14 3:33 ` Jason Wang
@ 2025-08-14 6:42 ` Eugenio Perez Martin
0 siblings, 0 replies; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-14 6:42 UTC (permalink / raw)
To: Jason Wang; +Cc: mst, xuanzhuo, virtualization, linux-kernel, hch
On Thu, Aug 14, 2025 at 5:33 AM Jason Wang <jasowang@redhat.com> wrote:
>
> On Wed, Aug 13, 2025 at 5:03 PM Eugenio Perez Martin
> <eperezma@redhat.com> wrote:
> >
> > On Wed, Aug 13, 2025 at 7:49 AM Jason Wang <jasowang@redhat.com> wrote:
> > >
> > > Lacking the support of device specific mapping supported in virtio,
> > > VDUSE must trick the DMA API in order to make virtio-vdpa transport
> > > work. This is done by advertising vDPA device as dma device with a
> > > VDUSE specific dma_ops even if it doesn't do DMA at all.
> > >
> > > This will be fixed by this patch. Thanks to the new mapping operations
> > > support by virtio and vDPA. VDUSE can simply switch to advertise its
> > > specific mappings operations to virtio via virtio-vdpa then DMA API is
> > > not needed for VDUSE any more and iova domain could be used as the
> > > mapping token instead.
> > >
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > > ---
> > > drivers/vdpa/Kconfig | 8 +--
> > > drivers/vdpa/vdpa_user/iova_domain.c | 2 +-
> > > drivers/vdpa/vdpa_user/iova_domain.h | 2 +-
> > > drivers/vdpa/vdpa_user/vduse_dev.c | 75 ++++++++++++++--------------
> > > 4 files changed, 41 insertions(+), 46 deletions(-)
> > >
> > > diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
> > > index 559fb9d3271f..857cf288c876 100644
> > > --- a/drivers/vdpa/Kconfig
> > > +++ b/drivers/vdpa/Kconfig
> > > @@ -34,13 +34,7 @@ config VDPA_SIM_BLOCK
> > >
> > > config VDPA_USER
> > > tristate "VDUSE (vDPA Device in Userspace) support"
> > > - depends on EVENTFD && MMU && HAS_DMA
> > > - #
> > > - # This driver incorrectly tries to override the dma_ops. It should
> > > - # never have done that, but for now keep it working on architectures
> > > - # that use dma ops
> > > - #
> > > - depends on ARCH_HAS_DMA_OPS
> > > + depends on EVENTFD && MMU
> > > select VHOST_IOTLB
> > > select IOMMU_IOVA
> > > help
> > > diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
> > > index 58116f89d8da..ccaed24b7ef8 100644
> > > --- a/drivers/vdpa/vdpa_user/iova_domain.c
> > > +++ b/drivers/vdpa/vdpa_user/iova_domain.c
> > > @@ -447,7 +447,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
> > >
> > > void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> > > size_t size, dma_addr_t *dma_addr,
> > > - gfp_t flag, unsigned long attrs)
> > > + gfp_t flag)
> > > {
> > > struct iova_domain *iovad = &domain->consistent_iovad;
> > > unsigned long limit = domain->iova_limit;
> > > diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h
> > > index 7f3f0928ec78..1f3c30be272a 100644
> > > --- a/drivers/vdpa/vdpa_user/iova_domain.h
> > > +++ b/drivers/vdpa/vdpa_user/iova_domain.h
> > > @@ -64,7 +64,7 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
> > >
> > > void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
> > > size_t size, dma_addr_t *dma_addr,
> > > - gfp_t flag, unsigned long attrs);
> > > + gfp_t flag);
> > >
> > > void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
> > > void *vaddr, dma_addr_t dma_addr,
> > > diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> > > index f161059d543e..3260edefdf0d 100644
> > > --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> > > +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> > > @@ -88,6 +88,7 @@ struct vduse_dev {
> > > struct device *dev;
> > > struct vduse_virtqueue **vqs;
> > > struct vduse_iova_domain *domain;
> > > + struct vduse_iova_domain *dom;
> >
> > *dom is not used
> >
>
> Let me fix that.
>
> > > char *name;
> > > struct mutex lock;
> > > spinlock_t msg_lock;
> > > @@ -814,59 +815,53 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
> > > .free = vduse_vdpa_free,
> > > };
> > >
> > > -static void vduse_dev_sync_single_for_device(struct device *dev,
> > > +static void vduse_dev_sync_single_for_device(void *token,
> > > dma_addr_t dma_addr, size_t size,
> > > enum dma_data_direction dir)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> >
> > If I add ASID support to VDUSE I'll need to replace the token by a vq
> > group representor. Is that ok?
>
> It should be ok.
>
> >
> > I think it is as I like how using *domain here makes this patch
> > clearer, and adding something else will make this patch harder to
> > review.
>
> Yes.
>
> >
> > >
> > > vduse_domain_sync_single_for_device(domain, dma_addr, size, dir);
> > > }
> > >
> > > -static void vduse_dev_sync_single_for_cpu(struct device *dev,
> > > +static void vduse_dev_sync_single_for_cpu(void *token,
> > > dma_addr_t dma_addr, size_t size,
> > > enum dma_data_direction dir)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > >
> > > vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
> > > }
> > >
> > > -static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
> > > +static dma_addr_t vduse_dev_map_page(void *token, struct page *page,
> > > unsigned long offset, size_t size,
> > > enum dma_data_direction dir,
> > > unsigned long attrs)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > >
> > > return vduse_domain_map_page(domain, page, offset, size, dir, attrs);
> > > }
> > >
> > > -static void vduse_dev_unmap_page(struct device *dev, dma_addr_t dma_addr,
> > > +static void vduse_dev_unmap_page(void *token, dma_addr_t dma_addr,
> > > size_t size, enum dma_data_direction dir,
> > > unsigned long attrs)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > >
> > > return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs);
> > > }
> > >
> > > -static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> > > - dma_addr_t *dma_addr, gfp_t flag,
> > > - unsigned long attrs)
> > > +static void *vduse_dev_alloc_coherent(void *token, size_t size,
> > > + dma_addr_t *dma_addr, gfp_t flag)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > > unsigned long iova;
> > > void *addr;
> > >
> > > *dma_addr = DMA_MAPPING_ERROR;
> > > addr = vduse_domain_alloc_coherent(domain, size,
> > > - (dma_addr_t *)&iova, flag, attrs);
> > > + (dma_addr_t *)&iova, flag);
> > > if (!addr)
> > > return NULL;
> > >
> > > @@ -875,31 +870,45 @@ static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
> > > return addr;
> > > }
> > >
> > > -static void vduse_dev_free_coherent(struct device *dev, size_t size,
> > > - void *vaddr, dma_addr_t dma_addr,
> > > - unsigned long attrs)
> > > +static void vduse_dev_free_coherent(void *token, size_t size,
> > > + void *vaddr, dma_addr_t dma_addr,
> > > + unsigned long attrs)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > >
> > > vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs);
> > > }
> > >
> > > -static size_t vduse_dev_max_mapping_size(struct device *dev)
> > > +static bool vduse_dev_need_sync(void *token, dma_addr_t dma_addr)
> > > {
> > > - struct vduse_dev *vdev = dev_to_vduse(dev);
> > > - struct vduse_iova_domain *domain = vdev->domain;
> > > + struct vduse_iova_domain *domain = token;
> > > +
> > > + return dma_addr < domain->bounce_size;
> > > +}
> > > +
> > > +static int vduse_dev_mapping_error(void *token, dma_addr_t dma_addr)
> > > +{
> > > + if (unlikely(dma_addr == DMA_MAPPING_ERROR))
> > > + return -ENOMEM;
> > > + return 0;
> > > +}
> > > +
> > > +static size_t vduse_dev_max_mapping_size(void *token)
> > > +{
> > > + struct vduse_iova_domain *domain = token;
> > >
> > > return domain->bounce_size;
> > > }
> > >
> > > -static const struct dma_map_ops vduse_dev_dma_ops = {
> > > +static const struct virtio_map_ops vduse_map_ops = {
> > > .sync_single_for_device = vduse_dev_sync_single_for_device,
> > > .sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
> > > .map_page = vduse_dev_map_page,
> > > .unmap_page = vduse_dev_unmap_page,
> > > .alloc = vduse_dev_alloc_coherent,
> > > .free = vduse_dev_free_coherent,
> > > + .need_sync = vduse_dev_need_sync,
> > > + .mapping_error = vduse_dev_mapping_error,
> >
> > I think that adding these functions here is problematic,
> >
> > In the case of mapping error vring_mapping_error only checks for
> > vdev->map, not for vdev->map->mapping_error:
> >
> > static int vring_mapping_error(const struct vring_virtqueue *vq,
> > dma_addr_t addr)
> > {
> > struct virtio_device *vdev = vq->vq.vdev;
> >
> > if (!vq->use_map_api)
> > return 0;
> >
> > if (vdev->map)
> > return vdev->map->mapping_error(vring_mapping_token(vq), addr);
> > else
> > return dma_mapping_error(vring_dma_dev(vq), addr);
> > }
> >
> > So we either add the check for the member or we define them from the beginning.
>
> I'm not sure I will get here. I can add a comment to explain that all
> map ops are mandated not optional.
>
Ok I thought there was a possibility for virtio core to try calling
vdev->map->mapping_error in previous patches. Now I see that
vduse_map_ops is actually created in this patch, so that's not
possible. My bad!
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-14 3:36 ` Jason Wang
@ 2025-08-14 10:42 ` Michael S. Tsirkin
2025-08-15 1:02 ` Jason Wang
2025-08-18 9:09 ` Eugenio Perez Martin
0 siblings, 2 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2025-08-14 10:42 UTC (permalink / raw)
To: Jason Wang; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Thu, Aug 14, 2025 at 11:36:22AM +0800, Jason Wang wrote:
> > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > index addbc209275a..37029df94aaf 100644
> > > --- a/include/linux/virtio.h
> > > +++ b/include/linux/virtio.h
> > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > void *priv;
> > > };
> > >
> > > +union vring_mapping_token {
> > > + /* Device that performs DMA */
> > > + struct device *dma_dev;
> > > + /* Transport specific token used for doing map */
> > > + void *opaque;
> >
> > Please just declare whatever structure you want it to be.
>
> It's an opaque one and so
>
> 1) the virtio core knows nothing about that because it could be
> transport or device specific
> 2) no assumption of the type and usage, it just receive it from the
> transport and pass it back when doing the mapping
>
> It should work like page->private etc.
>
> Does this make sense?
>
> Thanks
I fully expect most devices simply to use DMA here and no weird
tricks. vduse is the weird one, but I don't see us making it
grow much beyond that.
So I think for now we can just make it vduse_iova_domain *. If we see
it's getting out of hand with too many types, we can think of solutions.
--
MST
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-14 10:42 ` Michael S. Tsirkin
@ 2025-08-15 1:02 ` Jason Wang
2025-08-15 10:04 ` Michael S. Tsirkin
2025-08-18 9:09 ` Eugenio Perez Martin
1 sibling, 1 reply; 32+ messages in thread
From: Jason Wang @ 2025-08-15 1:02 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Thu, Aug 14, 2025 at 6:42 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Thu, Aug 14, 2025 at 11:36:22AM +0800, Jason Wang wrote:
> > > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > > index addbc209275a..37029df94aaf 100644
> > > > --- a/include/linux/virtio.h
> > > > +++ b/include/linux/virtio.h
> > > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > > void *priv;
> > > > };
> > > >
> > > > +union vring_mapping_token {
> > > > + /* Device that performs DMA */
> > > > + struct device *dma_dev;
> > > > + /* Transport specific token used for doing map */
> > > > + void *opaque;
> > >
> > > Please just declare whatever structure you want it to be.
> >
> > It's an opaque one and so
> >
> > 1) the virtio core knows nothing about that because it could be
> > transport or device specific
> > 2) no assumption of the type and usage, it just receive it from the
> > transport and pass it back when doing the mapping
> >
> > It should work like page->private etc.
> >
> > Does this make sense?
> >
> > Thanks
>
> I fully expect most devices simply to use DMA here and no weird
> tricks. vduse is the weird one, but I don't see us making it
> grow much beyond that.
>
> So I think for now we can just make it vduse_iova_domain *.
It requires exporting VDUSE's internal data structure to the virtio
layer which is a kind of layer violation. And the iova domain will be
soon replaced by virtqueue group in Eungeio's series that support
multiple address spaces
> If we see
> it's getting out of hand with too many types, we can think of solutions.
Considering we've already at it, I think it's better to have a
solution now if it's not complicated:
I can think of two kind of solutions:
1) Stick to the current void * pointer which is simple and straightforward
2) Eugenio's suggestion of having a virtio_map_head and let the
transport/device get the container struct which is the real token.
E.g
struct vduse_iova_domain {
struct virtio_map_head map;
......
};
If you don't like void *, can we go fo 2)?
Thanks
>
> --
> MST
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-15 1:02 ` Jason Wang
@ 2025-08-15 10:04 ` Michael S. Tsirkin
0 siblings, 0 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2025-08-15 10:04 UTC (permalink / raw)
To: Jason Wang; +Cc: xuanzhuo, eperezma, virtualization, linux-kernel, hch
On Fri, Aug 15, 2025 at 09:02:09AM +0800, Jason Wang wrote:
> On Thu, Aug 14, 2025 at 6:42 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Thu, Aug 14, 2025 at 11:36:22AM +0800, Jason Wang wrote:
> > > > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > > > index addbc209275a..37029df94aaf 100644
> > > > > --- a/include/linux/virtio.h
> > > > > +++ b/include/linux/virtio.h
> > > > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > > > void *priv;
> > > > > };
> > > > >
> > > > > +union vring_mapping_token {
> > > > > + /* Device that performs DMA */
> > > > > + struct device *dma_dev;
> > > > > + /* Transport specific token used for doing map */
> > > > > + void *opaque;
> > > >
> > > > Please just declare whatever structure you want it to be.
> > >
> > > It's an opaque one and so
> > >
> > > 1) the virtio core knows nothing about that because it could be
> > > transport or device specific
> > > 2) no assumption of the type and usage, it just receive it from the
> > > transport and pass it back when doing the mapping
> > >
> > > It should work like page->private etc.
> > >
> > > Does this make sense?
> > >
> > > Thanks
> >
> > I fully expect most devices simply to use DMA here and no weird
> > tricks. vduse is the weird one, but I don't see us making it
> > grow much beyond that.
> >
> > So I think for now we can just make it vduse_iova_domain *.
>
> It requires exporting VDUSE's internal data structure to the virtio
> layer which is a kind of layer violation.
It's just a forward declaration. You do not need the structure.
> And the iova domain will be
> soon replaced by virtqueue group in Eungeio's series that support
> multiple address spaces
>
> > If we see
> > it's getting out of hand with too many types, we can think of solutions.
>
> Considering we've already at it, I think it's better to have a
> solution now if it's not complicated:
>
> I can think of two kind of solutions:
>
> 1) Stick to the current void * pointer which is simple and straightforward
> 2) Eugenio's suggestion of having a virtio_map_head and let the
> transport/device get the container struct which is the real token.
>
> E.g
>
> struct vduse_iova_domain {
> struct virtio_map_head map;
> ......
> };
>
> If you don't like void *, can we go fo 2)?
>
> Thanks
>
>
> >
> > --
> > MST
> >
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-14 10:42 ` Michael S. Tsirkin
2025-08-15 1:02 ` Jason Wang
@ 2025-08-18 9:09 ` Eugenio Perez Martin
2025-08-18 12:02 ` Michael S. Tsirkin
1 sibling, 1 reply; 32+ messages in thread
From: Eugenio Perez Martin @ 2025-08-18 9:09 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Jason Wang, xuanzhuo, virtualization, linux-kernel, hch
On Thu, Aug 14, 2025 at 12:42 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Thu, Aug 14, 2025 at 11:36:22AM +0800, Jason Wang wrote:
> > > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > > index addbc209275a..37029df94aaf 100644
> > > > --- a/include/linux/virtio.h
> > > > +++ b/include/linux/virtio.h
> > > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > > void *priv;
> > > > };
> > > >
> > > > +union vring_mapping_token {
> > > > + /* Device that performs DMA */
> > > > + struct device *dma_dev;
> > > > + /* Transport specific token used for doing map */
> > > > + void *opaque;
> > >
> > > Please just declare whatever structure you want it to be.
> >
> > It's an opaque one and so
> >
> > 1) the virtio core knows nothing about that because it could be
> > transport or device specific
> > 2) no assumption of the type and usage, it just receive it from the
> > transport and pass it back when doing the mapping
> >
> > It should work like page->private etc.
> >
> > Does this make sense?
> >
> > Thanks
>
> I fully expect most devices simply to use DMA here and no weird
> tricks. vduse is the weird one, but I don't see us making it
> grow much beyond that.
>
> So I think for now we can just make it vduse_iova_domain *. If we see
> it's getting out of hand with too many types, we can think of solutions.
>
I've sent my series of adding ASID to VDUSE, which uses this series'
token on each vq group, on top of this version of the DMA rework.
This patch [1] and the next one are the one that reworks the token to
an empty struct, so virtio can handle it in an opaque way and VDUSE
can convert it back and forth in a type safe way, skipping the void *.
Please let me know if you prefer to import a VDUSE header into the
virtio config header or to make a VDUSE forward declaration instead of
going through the empty struct to preserve layer boundaries.
There is one usage I've not been able to convert though. Jason, could
you take a look? It is marked as TODO in my series. I'm not sure if
that's also an abuse of the void * in the DMA rework to be honest, but
it should be easy to correct.
[1] https://lore.kernel.org/all/20250818085711.3461758-4-eperezma@redhat.com/T/#u
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH V5 4/9] virtio: introduce vring_mapping_token
2025-08-18 9:09 ` Eugenio Perez Martin
@ 2025-08-18 12:02 ` Michael S. Tsirkin
0 siblings, 0 replies; 32+ messages in thread
From: Michael S. Tsirkin @ 2025-08-18 12:02 UTC (permalink / raw)
To: Eugenio Perez Martin
Cc: Jason Wang, xuanzhuo, virtualization, linux-kernel, hch
On Mon, Aug 18, 2025 at 11:09:44AM +0200, Eugenio Perez Martin wrote:
> On Thu, Aug 14, 2025 at 12:42 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Thu, Aug 14, 2025 at 11:36:22AM +0800, Jason Wang wrote:
> > > > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h
> > > > > index addbc209275a..37029df94aaf 100644
> > > > > --- a/include/linux/virtio.h
> > > > > +++ b/include/linux/virtio.h
> > > > > @@ -40,6 +40,13 @@ struct virtqueue {
> > > > > void *priv;
> > > > > };
> > > > >
> > > > > +union vring_mapping_token {
> > > > > + /* Device that performs DMA */
> > > > > + struct device *dma_dev;
> > > > > + /* Transport specific token used for doing map */
> > > > > + void *opaque;
> > > >
> > > > Please just declare whatever structure you want it to be.
> > >
> > > It's an opaque one and so
> > >
> > > 1) the virtio core knows nothing about that because it could be
> > > transport or device specific
> > > 2) no assumption of the type and usage, it just receive it from the
> > > transport and pass it back when doing the mapping
> > >
> > > It should work like page->private etc.
> > >
> > > Does this make sense?
> > >
> > > Thanks
> >
> > I fully expect most devices simply to use DMA here and no weird
> > tricks. vduse is the weird one, but I don't see us making it
> > grow much beyond that.
> >
> > So I think for now we can just make it vduse_iova_domain *. If we see
> > it's getting out of hand with too many types, we can think of solutions.
> >
>
> I've sent my series of adding ASID to VDUSE, which uses this series'
> token on each vq group, on top of this version of the DMA rework.
But then I see it drops it from vduse_iova_domain. So it does not
look like they union is going to keep growing in an unmanageable way.
> This patch [1] and the next one are the one that reworks the token to
> an empty struct, so virtio can handle it in an opaque way and VDUSE
> can convert it back and forth in a type safe way, skipping the void *.
> Please let me know if you prefer to import a VDUSE header into the
> virtio config header or to make a VDUSE forward declaration instead of
> going through the empty struct to preserve layer boundaries.
Personally for now I'd be happier with just a forward declaration.
I just like seeing things at a glance: "it's a union, and
can be one of two types", is better for me than
"it can be anything grep the source to figure out what it is".
And a forward declaration is opaque by design.
> There is one usage I've not been able to convert though. Jason, could
> you take a look? It is marked as TODO in my series. I'm not sure if
> that's also an abuse of the void * in the DMA rework to be honest, but
> it should be easy to correct.
>
> [1] https://lore.kernel.org/all/20250818085711.3461758-4-eperezma@redhat.com/T/#u
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2025-08-18 12:03 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-13 5:48 [PATCH V5 0/9] Refine virtio mapping API Jason Wang
2025-08-13 5:48 ` [PATCH V5 1/9] virtio_ring: constify virtqueue pointer for DMA helpers Jason Wang
2025-08-13 7:14 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 2/9] virtio_ring: switch to use dma_{map|unmap}_page() Jason Wang
2025-08-13 7:15 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 3/9] virtio: rename dma helpers Jason Wang
2025-08-13 7:16 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 4/9] virtio: introduce vring_mapping_token Jason Wang
2025-08-13 7:46 ` Eugenio Perez Martin
2025-08-13 8:55 ` Michael S. Tsirkin
2025-08-13 9:13 ` Eugenio Perez Martin
2025-08-14 3:39 ` Jason Wang
2025-08-14 3:36 ` Jason Wang
2025-08-14 10:42 ` Michael S. Tsirkin
2025-08-15 1:02 ` Jason Wang
2025-08-15 10:04 ` Michael S. Tsirkin
2025-08-18 9:09 ` Eugenio Perez Martin
2025-08-18 12:02 ` Michael S. Tsirkin
2025-08-13 8:58 ` Michael S. Tsirkin
2025-08-14 3:37 ` Jason Wang
2025-08-13 5:48 ` [PATCH V5 5/9] virtio_ring: rename dma_handle to map_handle Jason Wang
2025-08-13 7:47 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 6/9] virtio: introduce map ops in virtio core Jason Wang
2025-08-13 8:40 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 7/9] vdpa: support mapping token Jason Wang
2025-08-13 8:45 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 8/9] vdpa: introduce map ops Jason Wang
2025-08-13 8:46 ` Eugenio Perez Martin
2025-08-13 5:48 ` [PATCH V5 9/9] vduse: switch to use virtio map API instead of DMA API Jason Wang
2025-08-13 9:02 ` Eugenio Perez Martin
2025-08-14 3:33 ` Jason Wang
2025-08-14 6:42 ` Eugenio Perez Martin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).