mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Robin Murphy <robin.murphy@arm.com>
To: Francesco Valla <francesco@valla.it>,
	Bjorn Andersson <andersson@kernel.org>,
	Mathieu Poirier <mathieu.poirier@linaro.org>,
	Kees Cook <kees@kernel.org>,
	"Gustavo A. R. Silva" <gustavoars@kernel.org>,
	Marek Szyprowski <m.szyprowski@samsung.com>,
	Mark Brown <broonie@kernel.org>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>, Frank Li <Frank.Li@nxp.com>,
	Peng Fan <peng.fan@nxp.com>,
	Sascha Hauer <s.hauer@pengutronix.de>
Cc: linux-remoteproc@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, virtualization@lists.linux.dev,
	imx@lists.linux.dev, iommu@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH RFC 06/12] remoteproc: virtio: add bounce buffering for data buffers
Date: Fri, 25 Sep 2026 18:03:59 +0100	[thread overview]
Message-ID: <741cd763-8c15-436f-9810-fbbdb78b4eb2@arm.com> (raw)
In-Reply-To: <20260916-remoteproc_virtio_map-v1-6-dac8c5eb4aa9@valla.it>

On 16/09/2026 10:10 pm, Francesco Valla wrote:
> Depending on the driver originating them, data buffers used for virtio
> communication can either:
> 
>    - already be allocated from the coherent memory area that is
>      accessible by the remote processor; this is the case of rpmsg
>      and the rproc flavor of virtio-console;
>    - be allocated from generic kmem, and thus not accessible directly by
>      the remote processor.
> 
> Exploiting the map operations, which are used by the virtio framework
> when VIRTIO_F_ACCESS_PLATFORM is part of a vdev's feature flags, add
> bounce buffering for the second case: when the map() callback is called
> for a buffer, one or more pages of coherent memory are allocated and
> data is copied to them, then they are exposed to the remote processor;
> the data is  then bounced back on unmap().
> 
> The first case is not impacted, since buffers already suitable for
> remote transmission are passed through.
> 
> With the bounce buffering in place, any kind of virtio device can be
> supported through the remoteproc-virtio transport, at least from a
> data exchange standpoint.
> 
> Signed-off-by: Francesco Valla <francesco@valla.it>
> ---
>   drivers/remoteproc/remoteproc_virtio.c | 182 +++++++++++++++++++++++++++++++--
>   include/linux/remoteproc.h             |  14 +++
>   2 files changed, 190 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
> index cfd66d9d1c9e..d21b3b8044df 100644
> --- a/drivers/remoteproc/remoteproc_virtio.c
> +++ b/drivers/remoteproc/remoteproc_virtio.c
> @@ -241,7 +241,14 @@ static void rproc_virtio_reset(struct virtio_device *vdev)
>   	dev_dbg(&vdev->dev, "reset !\n");
>   }
>   
> -/* provide the vdev features as retrieved from the firmware */
> +/* Provide the vdev features as retrieved from the firmware, plus the following
> + * additional ones:
> + *   - VIRTIO_F_VERSION_1 that is required by some non-rpmsg virtio devices
> + *   - VIRTIO_F_ACCESS_PLATFORM to force usage of the map operations
> + */
> +#define RPROC_VIRTIO_STATIC_FEATURES \
> +	((1ULL << VIRTIO_F_VERSION_1) | (1ULL << VIRTIO_F_ACCESS_PLATFORM))
> +
>   static u64 rproc_virtio_get_features(struct virtio_device *vdev)
>   {
>   	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
> @@ -249,7 +256,7 @@ static u64 rproc_virtio_get_features(struct virtio_device *vdev)
>   
>   	rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
>   
> -	return rsc->dfeatures | (1ULL << VIRTIO_F_VERSION_1);
> +	return rsc->dfeatures | RPROC_VIRTIO_STATIC_FEATURES;
>   }
>   
>   static void rproc_transport_features(struct virtio_device *vdev)
> @@ -275,16 +282,16 @@ static int rproc_virtio_finalize_features(struct virtio_device *vdev)
>   	/* Give virtio_rproc a chance to accept features. */
>   	rproc_transport_features(vdev);
>   
> -	/* Make sure we don't have any features > 32 bits except VIRTIO_F_VERSION_1 */
> +	/* Make sure we don't have any features > 32 bits */
>   	if (WARN_ON_ONCE((u32)vdev->features !=
> -			 (vdev->features & ~(1ULL << VIRTIO_F_VERSION_1))))
> +			 (vdev->features & ~RPROC_VIRTIO_STATIC_FEATURES)))
>   		return -1;
>   
>   	/*
>   	 * Remember the finalized features of our vdev, and provide it
>   	 * to the remote processor once it is powered on.
>   	 */
> -	rsc->gfeatures = vdev->features & ~(1ULL << VIRTIO_F_VERSION_1);
> +	rsc->gfeatures = vdev->features & ~RPROC_VIRTIO_STATIC_FEATURES;
>   
>   	return 0;
>   }
> @@ -337,6 +344,151 @@ static const struct virtio_config_ops rproc_virtio_config_ops = {
>   	.set		= rproc_virtio_set,
>   };
>   
> +static inline unsigned int rproc_virtio_bounce_slot(struct device *dma_dev,
> +						    dma_addr_t dma_handle)
> +{
> +	const dma_addr_t dma_base = dma_dev_coherent_base(dma_dev);
> +
> +	return (dma_handle - dma_base) >> PAGE_SHIFT;
> +}
> +
> +static dma_addr_t rproc_virtio_map_page(union virtio_map map, struct page *page,
> +					unsigned long offset, size_t size,
> +					enum dma_data_direction dir,
> +					unsigned long attrs)
> +{
> +	struct device *dev = map.dma_dev;
> +	struct rproc_vdev *rvdev = dev_get_drvdata(dev);
> +	dma_addr_t dma_base = dma_dev_coherent_base(dev);
> +	size_t dma_size = dma_dev_coherent_size(dev);
> +	phys_addr_t paddr = page_to_phys(page) + offset;
> +	void *vaddr = page_to_virt(page) + offset;
> +	struct rproc_map_record *record;
> +	dma_addr_t map_handle;
> +	void *bounce;
> +
> +	// No need to allocate a bounce buffer if the memory to map is already
> +	// part of the device's coherent pool.
> +	if (paddr >= dma_base && paddr < (dma_base + dma_size)) {
> +		// The allocation details will be recorded also in this case,
> +		// indicating that no bounce buffer was allocated.
> +		map_handle = (dma_addr_t)paddr;
> +		bounce = NULL;
> +	} else {
> +		// Allocate bounce buffer from device coherent memory
> +		bounce = dma_alloc_coherent(dev, size, &map_handle, GFP_KERNEL | __GFP_ZERO);
> +		if (!bounce)
> +			return DMA_MAPPING_ERROR;
> +
> +		// Copy data to bounce buffer
> +		memcpy(bounce, vaddr, size);
> +	}
> +
> +	// Save bounce details
> +	record = &rvdev->map_records[rproc_virtio_bounce_slot(dev, map_handle)];
> +
> +	record->original = vaddr;
> +	record->size = size;
> +	record->bounce = bounce;
> +
> +	return map_handle;
> +}
> +
> +static void rproc_virtio_unmap_page(union virtio_map map, dma_addr_t map_handle,
> +				    size_t size, enum dma_data_direction dir,
> +				    unsigned long attrs)
> +{
> +	struct device *dev = map.dma_dev;
> +	struct rproc_vdev *rvdev = dev_get_drvdata(dev);
> +	unsigned int slot = rproc_virtio_bounce_slot(dev, map_handle);
> +	struct rproc_map_record *record = &rvdev->map_records[slot];
> +
> +	WARN_ON(size != record->size);
> +
> +	// If a bounce buffer was used, copy data back to original one
> +	if (record->bounce) {
> +		memcpy(record->original, record->bounce, record->size);
> +
> +		dma_free_coherent(dev, record->size, record->bounce, map_handle);
> +	}
> +
> +	record->original = NULL;
> +	record->size = 0;
> +	record->bounce = NULL;
> +}
> +
> +static void rproc_virtio_sync_single_for_cpu(union virtio_map map,
> +					     dma_addr_t map_handle,
> +					     size_t size,
> +					     enum dma_data_direction dir)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	dma_sync_single_range_for_cpu(dev, (map_handle & PAGE_MASK),
> +				      offset_in_page(map_handle), size, dir);

Also note that this seems massively wrong anyway - it's invalid to call 
dma_sync_* on sometning that hasn't come from the corresponding 
dma_map_* operation; it's defintiely invalid to use any streaming DMA 
operation at all on remapped non-kernel memory; but above all else, this 
clearly *isn't* copying any data from your bounce buffer to the original 
location (or vice verse in for_device), which is what the sync ops would 
actually need to do.

Letting the existing restricted DMA code do all the hard work for you is 
definitely the way to go...

Thanks,
Robin.

> +}
> +
> +static void rproc_virtio_sync_single_for_device(union virtio_map map,
> +						dma_addr_t map_handle,
> +						size_t size,
> +						enum dma_data_direction dir)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	dma_sync_single_range_for_device(dev, (map_handle & PAGE_MASK),
> +					 offset_in_page(map_handle), size, dir);
> +}
> +
> +static void *rproc_virtio_alloc(union virtio_map map, size_t size,
> +				dma_addr_t *map_handle, gfp_t gfp)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	return dma_alloc_coherent(dev, size, map_handle, gfp);
> +}
> +
> +static void rproc_virtio_free(union virtio_map map, size_t size, void *vaddr,
> +			      dma_addr_t map_handle, unsigned long attrs)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	dma_free_coherent(dev, size, vaddr, map_handle);
> +}
> +
> +static bool rproc_virtio_need_sync(union virtio_map map, dma_addr_t map_handle)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	return dma_need_sync(dev, map_handle);
> +}
> +
> +static int rproc_virtio_mapping_error(union virtio_map map, dma_addr_t map_handle)
> +{
> +	if (unlikely(map_handle == DMA_MAPPING_ERROR))
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static inline size_t rproc_virtio_max_mapping_size(union virtio_map map)
> +{
> +	struct device *dev = map.dma_dev;
> +
> +	return dma_dev_coherent_size(dev);
> +}
> +
> +static const struct virtio_map_ops rproc_virtio_map_ops = {
> +	.map_page = rproc_virtio_map_page,
> +	.unmap_page = rproc_virtio_unmap_page,
> +	.sync_single_for_cpu = rproc_virtio_sync_single_for_cpu,
> +	.sync_single_for_device = rproc_virtio_sync_single_for_device,
> +	.alloc = rproc_virtio_alloc,
> +	.free = rproc_virtio_free,
> +	.need_sync = rproc_virtio_need_sync,
> +	.mapping_error = rproc_virtio_mapping_error,
> +	.max_mapping_size = rproc_virtio_max_mapping_size,
> +};
> +
>   /*
>    * This function is called whenever vdev is released, and is responsible
>    * to decrement the remote processor's refcount which was taken when vdev was
> @@ -355,6 +507,8 @@ static void rproc_virtio_dev_release(struct device *dev)
>   	of_reserved_mem_device_release(&rvdev->pdev->dev);
>   	dma_release_coherent_memory(&rvdev->pdev->dev);
>   
> +	kvfree(rvdev->map_records);
> +
>   	put_device(&rvdev->pdev->dev);
>   }
>   
> @@ -429,13 +583,29 @@ static int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
>   		of_reserved_mem_device_init_by_idx(dev, np, 0);
>   	}
>   
> +	/* Allocate one tracking record for each page of the device reserved
> +	 * memory. Contiguous memory is not required for this array, which can
> +	 * also be quite big (depending on the size of the coherent memory), so
> +	 * let's use vmalloc for this allocation.
> +	 */
> +	rvdev->map_records = kvcalloc(dma_dev_coherent_size(dev) >> PAGE_SHIFT,
> +				      sizeof(*rvdev->map_records),
> +				      GFP_KERNEL);
> +	if (!rvdev->map_records) {
> +		dev_err(dev, "failed to allocate memory for map records\n");
> +		return -ENOMEM;
> +	}
> +
>   	/* Allocate virtio device */
>   	vdev = kzalloc_obj(*vdev);
> -	if (!vdev)
> +	if (!vdev) {
> +		kvfree(rvdev->map_records);
>   		return -ENOMEM;
> +	}
>   
>   	vdev->id.device = id;
>   	vdev->config = &rproc_virtio_config_ops;
> +	vdev->map = &rproc_virtio_map_ops;
>   	vdev->dev.parent = dev;
>   	vdev->dev.release = rproc_virtio_dev_release;
>   
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index c3ba51fe9e54..2ff48b505ac0 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -339,10 +339,23 @@ struct rproc_vring {
>   	struct virtqueue *vq;
>   };
>   
> +/**
> + * struct rproc_map_record - remoteproc map record
> + * @original:	original virtual address
> + * @num: allocation size
> + * @bounce: bounce buffer virtual address (NULL if not used)
> + */
> +struct rproc_map_record {
> +	void *original;
> +	size_t size;
> +	void *bounce;
> +};
> +
>   /**
>    * struct rproc_vdev - remoteproc state for a supported virtio device
>    * @subdev: handle for registering the vdev as a rproc subdevice
>    * @pdev: remoteproc virtio platform device
> + * @map_records: array of map records
>    * @id: virtio device id (as in virtio_ids.h)
>    * @node: list node
>    * @rproc: the rproc handle
> @@ -358,6 +371,7 @@ struct rproc_vdev {
>   	unsigned int id;
>   	struct list_head node;
>   	struct rproc *rproc;
> +	struct rproc_map_record *map_records;
>   	u32 rsc_offset;
>   	u32 index;
>   	unsigned int num_vrings;
> 


  parent reply	other threads:[~2026-09-25 17:04 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-16 21:10 [PATCH RFC 00/12] remoteproc: add support for any virtio device Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 01/12] remoteproc: virtio: cleanup rproc_add_virtio_dev error path Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 02/12] remoteproc: virtio: replace commas with semicolons Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 03/12] remoteproc: virtio: support dynamic number of vrings Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 04/12] dma-coherent: add base and size APIs Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 05/12] remoteproc: always report VIRTIO_F_VERSION_1 feature Francesco Valla
2026-09-21 15:47   ` Mathieu Poirier
2026-09-22  6:32     ` Francesco Valla
2026-09-22 15:10       ` Mathieu Poirier
2026-09-16 21:10 ` [PATCH RFC 06/12] remoteproc: virtio: add bounce buffering for data buffers Francesco Valla
2026-09-22 15:58   ` Mathieu Poirier
2026-09-22 19:39     ` Francesco Valla
2026-09-23 14:44       ` Mathieu Poirier
2026-09-23 16:05         ` Francesco Valla
2026-09-25 15:07           ` Mathieu Poirier
2026-09-25 16:48             ` Robin Murphy
2026-09-25 19:05               ` Francesco Valla
2026-09-25 17:03   ` Robin Murphy [this message]
2026-09-16 21:10 ` [PATCH RFC 07/12] dt-bindings: spi: add bindings for spi-virtio Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 08/12] dt-bindings: remoteproc: add remoteproc-virtio Francesco Valla
2026-09-22 15:40   ` Mathieu Poirier
2026-09-22 19:44     ` Francesco Valla
2026-09-23 14:56       ` Mathieu Poirier
2026-09-16 21:10 ` [PATCH RFC 09/12] remoteproc: search for a fwnode during vdev registration Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 10/12] remoteproc: imx_rproc: always use non-blocking mailboxes Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 11/12] dt-bindings: remoteproc: imx-rproc: support virtio Francesco Valla
2026-09-16 21:10 ` [PATCH RFC 12/12] PoC: arm64: dts: imx93-11x11-frdm: add multiple vdevs Francesco Valla
2026-09-22 15:43   ` Mathieu Poirier
2026-09-22 20:19     ` Francesco Valla
2026-09-23 15:48       ` Mathieu Poirier
2026-09-23 18:42         ` Francesco Valla
2026-09-24 15:49           ` Mathieu Poirier
2026-09-25 19:13             ` Francesco Valla
2026-09-25  8:39   ` Alexander Stein
2026-09-25 19:26     ` Francesco Valla
2026-09-18 16:53 ` [PATCH RFC 00/12] remoteproc: add support for any virtio device Mathieu Poirier
2026-09-19  7:33   ` Francesco Valla
2026-09-21  3:31     ` Mathieu Poirier
2026-09-22  6:28       ` Francesco Valla
2026-09-22 13:53         ` Mathieu Poirier
2026-09-23 15:13 ` Robin Murphy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=741cd763-8c15-436f-9810-fbbdb78b4eb2@arm.com \
    --to=robin.murphy@arm.com \
    --cc=Frank.Li@nxp.com \
    --cc=andersson@kernel.org \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=francesco@valla.it \
    --cc=gustavoars@kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=iommu@lists.linux.dev \
    --cc=kees@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-remoteproc@vger.kernel.org \
    --cc=m.szyprowski@samsung.com \
    --cc=mathieu.poirier@linaro.org \
    --cc=peng.fan@nxp.com \
    --cc=robh@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=virtualization@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®