From: Mathieu Poirier <mathieu.poirier@linaro.org>
To: Francesco Valla <francesco@valla.it>
Cc: Bjorn Andersson <andersson@kernel.org>,
Kees Cook <kees@kernel.org>,
"Gustavo A. R. Silva" <gustavoars@kernel.org>,
Marek Szyprowski <m.szyprowski@samsung.com>,
Robin Murphy <robin.murphy@arm.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>,
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: Tue, 22 Sep 2026 09:58:53 -0600 [thread overview]
Message-ID: <arKlvZGqu2nt6Ci0@p14s> (raw)
In-Reply-To: <20260916-remoteproc_virtio_map-v1-6-dac8c5eb4aa9@valla.it>
On Wed, Sep 16, 2026 at 11:10:51PM +0200, 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.
Is this _necessary_ for the imx93 platform you are implementing feature for?
>
> 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);
> +}
> +
> +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;
>
> --
> 2.55.0
>
next prev parent reply other threads:[~2026-09-22 15:58 UTC|newest]
Thread overview: 33+ 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 [this message]
2026-09-22 19:39 ` Francesco Valla
2026-09-23 14:44 ` Mathieu Poirier
2026-09-23 16:05 ` Francesco Valla
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-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=arKlvZGqu2nt6Ci0@p14s \
--to=mathieu.poirier@linaro.org \
--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=peng.fan@nxp.com \
--cc=robh@kernel.org \
--cc=robin.murphy@arm.com \
--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®