This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 32ae7ef2d136bcfed47be3cf0f087a258320e4db
Author: Bowen Wang <[email protected]>
AuthorDate: Wed Jun 24 01:00:55 2026 +0800

    drivers/rptun: bounce buffers outside the carveout for virtio map
    
    The remote side can only touch the carveout shared memory, so a buffer
    outside it must be bounced. Add rptun_map_buf(), rptun_unmap_buf() and
    rptun_free_largest(): map allocates a cache-line aligned bounce from the
    carveout heap and copies per direction, unmap copies back and frees,
    and free_largest reports the largest mappable size after the memalign
    overhead. Cache maintenance is gated by CONFIG_OPENAMP_CACHE to match
    the vring path.
    
    Signed-off-by: Bowen Wang <[email protected]>
---
 drivers/rptun/rptun.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 145 insertions(+), 2 deletions(-)

diff --git a/drivers/rptun/rptun.c b/drivers/rptun/rptun.c
index cfcf22602d5..5ed0a5077e0 100644
--- a/drivers/rptun/rptun.c
+++ b/drivers/rptun/rptun.c
@@ -128,6 +128,13 @@ static metal_phys_addr_t rptun_da_to_pa(FAR struct 
rptun_dev_s *dev,
 static FAR void *rptun_alloc_buf(FAR struct virtio_device *vdev,
                                  size_t size, size_t align);
 static void rptun_free_buf(FAR struct virtio_device *vdev, FAR void *buf);
+static size_t rptun_free_largest(FAR struct virtio_device *vdev);
+static FAR void *rptun_map_buf(FAR struct virtio_device *vdev,
+                               FAR void *buf, size_t len,
+                               enum virtio_dma_map dir);
+static void rptun_unmap_buf(FAR struct virtio_device *vdev,
+                            FAR void *buf, size_t len,
+                            enum virtio_dma_map dir, FAR void *mapped);
 
 static void rptun_send_command(FAR struct rptun_priv_s *priv,
                                uint32_t cmd, bool wait);
@@ -170,8 +177,11 @@ static const struct image_store_ops g_rptun_store_ops =
 
 static const struct virtio_memory_ops g_rptun_mmops =
 {
-  .alloc = rptun_alloc_buf,
-  .free  = rptun_free_buf,
+  .alloc        = rptun_alloc_buf,
+  .free         = rptun_free_buf,
+  .free_largest = rptun_free_largest,
+  .map          = rptun_map_buf,
+  .unmap        = rptun_unmap_buf,
 };
 
 static struct metal_list g_rptun_priv = METAL_INIT_LIST(g_rptun_priv);
@@ -308,6 +318,139 @@ static void rptun_free_buf(FAR struct virtio_device 
*vdev, FAR void *buf)
   mm_free(carveout->heap, buf);
 }
 
+/****************************************************************************
+ * Name: rptun_map_align
+ *
+ * Description:
+ *   Return the alignment used for bounce buffers. Use the dcache line size
+ *   so a bounce buffer never shares a cache line with a neighbour (avoids
+ *   clobbering adjacent data on invalidate). Fall back to MM_ALIGN when the
+ *   arch has no dcache, so the value is never zero.
+ *
+ ****************************************************************************/
+
+static inline_function size_t rptun_map_align(void)
+{
+  size_t linesize = up_get_dcache_linesize();
+
+  return linesize > MM_ALIGN ? linesize : MM_ALIGN;
+}
+
+/****************************************************************************
+ * Name: rptun_free_largest
+ *
+ * Description:
+ *   Return the largest buffer a single rptun_map_buf call can satisfy.
+ *   mm_heapfree_largest gives the largest mm_malloc allocation; subtract the
+ *   extra space mm_memalign consumes for alignment so a map of the returned
+ *   size is guaranteed to succeed.
+ *
+ ****************************************************************************/
+
+static size_t rptun_free_largest(FAR struct virtio_device *vdev)
+{
+  FAR struct rptun_carveout_s *carveout =
+    (FAR struct rptun_carveout_s *)vdev->mm_priv;
+  size_t align = rptun_map_align();
+  size_t largest = mm_heapfree_largest(carveout->heap);
+
+  /* mm_memalign over-allocates by up to 2 * align to find an aligned point,
+   * and map rounds len up to align. Reserve 3 * align to stay safe.
+   */
+
+  size_t overhead = 3 * align;
+
+  return largest > overhead ? largest - overhead : 0;
+}
+
+/****************************************************************************
+ * Name: rptun_map_buf
+ *
+ * Description:
+ *   Map a buffer so the remote side can access it. The remote can only
+ *   touch the carveout shared memory, so a buffer outside the carveout is
+ *   bounced through a buffer allocated from the carveout heap. Returns NULL
+ *   when the carveout heap cannot satisfy the allocation; the caller may
+ *   query rptun_free_largest and retry with a smaller length.
+ *
+ ****************************************************************************/
+
+static FAR void *rptun_map_buf(FAR struct virtio_device *vdev,
+                               FAR void *buf, size_t len,
+                               enum virtio_dma_map dir)
+{
+  FAR struct rptun_carveout_s *carveout =
+    (FAR struct rptun_carveout_s *)vdev->mm_priv;
+  size_t align = rptun_map_align();
+  FAR void *bounce;
+  size_t maplen;
+
+  /* Already inside the carveout heap: the remote can access it directly. */
+
+  if (mm_heapmember(carveout->heap, buf))
+    {
+      return buf;
+    }
+
+  maplen = ALIGN_UP(len, align);
+  bounce = mm_memalign(carveout->heap, align, maplen);
+  if (bounce == NULL)
+    {
+      /* Out of shared memory: the caller decides whether to query
+       * rptun_free_largest and retry with a smaller length.
+       */
+
+      return NULL;
+    }
+
+  if (dir != VIRTIO_DMA_FROM_DEVICE)
+    {
+      memcpy(bounce, buf, len);
+    }
+
+  /* Flush for every direction: a dirty line left by an earlier user of
+   * this carveout block must not be written back over the peer's data.
+   */
+
+  RPTUN_FLUSH(bounce, maplen);
+  return bounce;
+}
+
+/****************************************************************************
+ * Name: rptun_unmap_buf
+ *
+ * Description:
+ *   Release a buffer mapped by rptun_map_buf, copying the device-written
+ *   data back to the original buffer when the direction requires it. Pass
+ *   the same direction that was given to rptun_map_buf.
+ *
+ ****************************************************************************/
+
+static void rptun_unmap_buf(FAR struct virtio_device *vdev,
+                            FAR void *buf, size_t len,
+                            enum virtio_dma_map dir, FAR void *mapped)
+{
+  FAR struct rptun_carveout_s *carveout =
+    (FAR struct rptun_carveout_s *)vdev->mm_priv;
+
+  /* Not bounced (buffer was already inside the carveout): nothing to do. */
+
+  if (mapped == buf)
+    {
+      return;
+    }
+
+  if (dir != VIRTIO_DMA_TO_DEVICE)
+    {
+      /* Device wrote data: drop stale cache lines, then copy it back. */
+
+      RPTUN_INVALIDATE(mapped, ALIGN_UP(len, rptun_map_align()));
+      memcpy(buf, mapped, len);
+    }
+
+  mm_free(carveout->heap, mapped);
+}
+
 /****************************************************************************
  * Name: rptun_init_carveout
  ****************************************************************************/

Reply via email to