summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2025-08-21 09:46:38 +0300
committerMichael S. Tsirkin <mst@redhat.com>2025-10-01 14:24:43 +0300
commitbee8c7c24b737338216dc0f87d6c47a4abaf609a (patch)
tree538af5ec10b01177535873a5dad9d86e2049d02d /include/linux
parent201e52ffe3349396303f741d098a9d285c52f44e (diff)
downloadlinux-bee8c7c24b737338216dc0f87d6c47a4abaf609a.tar.xz
virtio: introduce map ops in virtio core
This patch introduces map operations for virtio device. Virtio used 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 mapping metadata 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> Message-Id: <20250821064641.5025-7-jasowang@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Tested-by: Lei Yang <leiyang@redhat.com> Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/virtio.h25
-rw-r--r--include/linux/virtio_config.h72
2 files changed, 97 insertions, 0 deletions
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index b4ba1a99e5ab..3386a4a8d06b 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -166,9 +166,11 @@ 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;
VIRTIO_DECLARE_FEATURES(features);
void *priv;
+ union virtio_map vmap;
#ifdef CONFIG_VIRTIO_DEBUG
struct dentry *debugfs_dir;
u64 debugfs_filter_features[VIRTIO_FEATURES_DWORDS];
@@ -267,6 +269,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 virtio_map mapping_token,
+ size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp);
+
+void virtqueue_map_free_coherent(struct virtio_device *vdev,
+ union virtio_map 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 7427b79d6f3d..16001e9f9b39 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -139,6 +139,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
+ * map: metadata for performing mapping
+ * 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
+ * map: device specific mapping map
+ * 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
+ * map: metadata for performing mapping
+ * 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
+ * map: metadata for performing mapping
+ * map_handle: the mapping address to sync
+ * size: the size of the buffer
+ * dir: synchronization direction
+ * @alloc: alloc a coherent buffer mapping
+ * map: metadata for performing mapping
+ * 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
+ * map: metadata for performing mapping
+ * 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
+ * map: metadata for performing mapping
+ * map_handle: the mapped address
+ * Returns: whether the buffer needs synchronization
+ * @mapping_error: if the mapping address is error
+ * map: metadata for performing mapping
+ * map_handle: the mapped address
+ * @max_mapping_size: get the maximum buffer size that can be mapped
+ * map: metadata for performing mapping
+ * Returns: the maximum buffer size that can be mapped
+ */
+struct virtio_map_ops {
+ dma_addr_t (*map_page)(union virtio_map map, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir, unsigned long attrs);
+ void (*unmap_page)(union virtio_map map, dma_addr_t map_handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+ void (*sync_single_for_cpu)(union virtio_map map, dma_addr_t map_handle,
+ size_t size, enum dma_data_direction dir);
+ void (*sync_single_for_device)(union virtio_map map,
+ dma_addr_t map_handle, size_t size,
+ enum dma_data_direction dir);
+ void *(*alloc)(union virtio_map map, size_t size,
+ dma_addr_t *map_handle, gfp_t gfp);
+ void (*free)(union virtio_map map, size_t size, void *vaddr,
+ dma_addr_t map_handle, unsigned long attrs);
+ bool (*need_sync)(union virtio_map map, dma_addr_t map_handle);
+ int (*mapping_error)(union virtio_map map, dma_addr_t map_handle);
+ size_t (*max_mapping_size)(union virtio_map map);
+};
+
/* 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);