Re: [PATCH v5 22/32] hw/arm/tegra241-cmdqv: Map VINTF page0 into guest MMIO space

2026-05-21 Thread Eric Auger



On 5/19/26 12:37 PM, Shameer Kolothum wrote:
> From: Nicolin Chen 
>
> Once a VCMDQ is allocated, map the mmap'd vintf_page0 region directly
> into the guest-visible MMIO space at offset 0x3 as a RAM-backed
> MemoryRegion. This eliminates QEMU trapping for hot-path CONS/PROD
> index updates.
>
> After this patch, the two VCMDQ apertures use different access paths:
> the direct aperture (0x1) remains QEMU-trapped and writes via
> vintf_ptr, while the VI aperture (0x3) is a direct guest RAM
> mapping. Both paths write to the same underlying vintf_page0 memory,
> so no synchronisation between the apertures is needed.

Please further explain the rationale of having 2 separate paths

Eric
>
> The mapping is installed lazily on first successful VCMDQ hardware
> queue allocation and removed when CMDQV or VINTF is disabled.
>
> Signed-off-by: Nicolin Chen 
> Co-developed-by: Shameer Kolothum 
> Signed-off-by: Shameer Kolothum 
> ---
>  hw/arm/tegra241-cmdqv.h |  1 +
>  hw/arm/tegra241-cmdqv.c | 39 +++
>  2 files changed, 40 insertions(+)
>
> diff --git a/hw/arm/tegra241-cmdqv.h b/hw/arm/tegra241-cmdqv.h
> index 7a8cb2ebc7..e9e1933a19 100644
> --- a/hw/arm/tegra241-cmdqv.h
> +++ b/hw/arm/tegra241-cmdqv.h
> @@ -47,6 +47,7 @@ typedef struct Tegra241CMDQV {
>  IOMMUFDVeventq *veventq;
>  IOMMUFDHWqueue *vcmdq[TEGRA241_CMDQV_MAX_CMDQ];
>  void *vintf_page0;
> +MemoryRegion *mr_vintf_page0;
>  
>  /* CMDQ-V Config page register cache */
>  uint32_t config;
> diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c
> index a7e89905df..853c548e58 100644
> --- a/hw/arm/tegra241-cmdqv.c
> +++ b/hw/arm/tegra241-cmdqv.c
> @@ -18,6 +18,40 @@
>  #include "tegra241-cmdqv.h"
>  #include "trace.h"
>  
> +static void tegra241_cmdqv_guest_unmap_vintf_page0(Tegra241CMDQV *cmdqv)
> +{
> +if (!cmdqv->mr_vintf_page0) {
> +return;
> +}
> +
> +memory_region_del_subregion(&cmdqv->mmio_cmdqv, cmdqv->mr_vintf_page0);
> +object_unparent(OBJECT(cmdqv->mr_vintf_page0));
> +g_free(cmdqv->mr_vintf_page0);
> +cmdqv->mr_vintf_page0 = NULL;
> +}
> +
> +static void tegra241_cmdqv_guest_map_vintf_page0(Tegra241CMDQV *cmdqv)
> +{
> +char *name;
> +
> +if (cmdqv->mr_vintf_page0) {
> +return;
> +}
> +
> +name = g_strdup_printf("%s vintf-page0",
> +   memory_region_name(&cmdqv->mmio_cmdqv));
> +cmdqv->mr_vintf_page0 = g_malloc0(sizeof(*cmdqv->mr_vintf_page0));
> +memory_region_init_ram_device_ptr(cmdqv->mr_vintf_page0,
> +  
> memory_region_owner(&cmdqv->mmio_cmdqv),
> +  name, VINTF_PAGE_SIZE,
> +  cmdqv->vintf_page0);
> +memory_region_set_skip_iommu_map(cmdqv->mr_vintf_page0, true);
> +memory_region_add_subregion_overlap(&cmdqv->mmio_cmdqv,
> +CMDQV_VINTF_PAGE0_BASE,
> +cmdqv->mr_vintf_page0, 1);
> +g_free(name);
> +}
> +
>  static void tegra241_cmdqv_free_vcmdq(Tegra241CMDQV *cmdqv, int index)
>  {
>  IOMMUFDViommu *viommu = cmdqv->s_accel->viommu;
> @@ -130,6 +164,9 @@ static bool tegra241_cmdqv_setup_vcmdq(Tegra241CMDQV 
> *cmdqv, int index,
>  /* Pre-alloc cached writes survive the cache-to-hardware transition. */
>  tegra241_cmdqv_sync_vcmdq(cmdqv, index);
>  
> +/* Map the mmap'd VINTF page0 into guest MMIO space. */
> +tegra241_cmdqv_guest_map_vintf_page0(cmdqv);
> +
>  return true;
>  }
>  
> @@ -449,6 +486,7 @@ static void 
> tegra241_cmdqv_config_vintf_write(Tegra241CMDQV *cmdqv,
>  tegra241_cmdqv_setup_all_vcmdq(cmdqv, errp);

I would rather put the     tegra241_cmdqv_guest_map_vintf_page0(cmdqv) here 
to have symetric map/unmap
>  }
>  } else {
> +tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
>  tegra241_cmdqv_free_all_vcmdq(cmdqv);
>  tegra241_cmdqv_munmap_vintf_page0(cmdqv, errp);
>  cmdqv->vintf_status &= ~R_VINTF0_STATUS_ENABLE_OK_MASK;
> @@ -566,6 +604,7 @@ static void tegra241_cmdqv_writel_mmio(Tegra241CMDQV 
> *cmdqv, hwaddr offset,
>   */
>  tegra241_cmdqv_setup_all_vcmdq(cmdqv, &local_err);
same
>  } else {
> +tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
>  tegra241_cmdqv_free_all_vcmdq(cmdqv);
>  cmdqv->status &= ~R_STATUS_CMDQV_ENABLED_MASK;
>  }
Thanks

Eric




[PATCH v5 22/32] hw/arm/tegra241-cmdqv: Map VINTF page0 into guest MMIO space

2026-05-19 Thread Shameer Kolothum
From: Nicolin Chen 

Once a VCMDQ is allocated, map the mmap'd vintf_page0 region directly
into the guest-visible MMIO space at offset 0x3 as a RAM-backed
MemoryRegion. This eliminates QEMU trapping for hot-path CONS/PROD
index updates.

After this patch, the two VCMDQ apertures use different access paths:
the direct aperture (0x1) remains QEMU-trapped and writes via
vintf_ptr, while the VI aperture (0x3) is a direct guest RAM
mapping. Both paths write to the same underlying vintf_page0 memory,
so no synchronisation between the apertures is needed.

The mapping is installed lazily on first successful VCMDQ hardware
queue allocation and removed when CMDQV or VINTF is disabled.

Signed-off-by: Nicolin Chen 
Co-developed-by: Shameer Kolothum 
Signed-off-by: Shameer Kolothum 
---
 hw/arm/tegra241-cmdqv.h |  1 +
 hw/arm/tegra241-cmdqv.c | 39 +++
 2 files changed, 40 insertions(+)

diff --git a/hw/arm/tegra241-cmdqv.h b/hw/arm/tegra241-cmdqv.h
index 7a8cb2ebc7..e9e1933a19 100644
--- a/hw/arm/tegra241-cmdqv.h
+++ b/hw/arm/tegra241-cmdqv.h
@@ -47,6 +47,7 @@ typedef struct Tegra241CMDQV {
 IOMMUFDVeventq *veventq;
 IOMMUFDHWqueue *vcmdq[TEGRA241_CMDQV_MAX_CMDQ];
 void *vintf_page0;
+MemoryRegion *mr_vintf_page0;
 
 /* CMDQ-V Config page register cache */
 uint32_t config;
diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c
index a7e89905df..853c548e58 100644
--- a/hw/arm/tegra241-cmdqv.c
+++ b/hw/arm/tegra241-cmdqv.c
@@ -18,6 +18,40 @@
 #include "tegra241-cmdqv.h"
 #include "trace.h"
 
+static void tegra241_cmdqv_guest_unmap_vintf_page0(Tegra241CMDQV *cmdqv)
+{
+if (!cmdqv->mr_vintf_page0) {
+return;
+}
+
+memory_region_del_subregion(&cmdqv->mmio_cmdqv, cmdqv->mr_vintf_page0);
+object_unparent(OBJECT(cmdqv->mr_vintf_page0));
+g_free(cmdqv->mr_vintf_page0);
+cmdqv->mr_vintf_page0 = NULL;
+}
+
+static void tegra241_cmdqv_guest_map_vintf_page0(Tegra241CMDQV *cmdqv)
+{
+char *name;
+
+if (cmdqv->mr_vintf_page0) {
+return;
+}
+
+name = g_strdup_printf("%s vintf-page0",
+   memory_region_name(&cmdqv->mmio_cmdqv));
+cmdqv->mr_vintf_page0 = g_malloc0(sizeof(*cmdqv->mr_vintf_page0));
+memory_region_init_ram_device_ptr(cmdqv->mr_vintf_page0,
+  memory_region_owner(&cmdqv->mmio_cmdqv),
+  name, VINTF_PAGE_SIZE,
+  cmdqv->vintf_page0);
+memory_region_set_skip_iommu_map(cmdqv->mr_vintf_page0, true);
+memory_region_add_subregion_overlap(&cmdqv->mmio_cmdqv,
+CMDQV_VINTF_PAGE0_BASE,
+cmdqv->mr_vintf_page0, 1);
+g_free(name);
+}
+
 static void tegra241_cmdqv_free_vcmdq(Tegra241CMDQV *cmdqv, int index)
 {
 IOMMUFDViommu *viommu = cmdqv->s_accel->viommu;
@@ -130,6 +164,9 @@ static bool tegra241_cmdqv_setup_vcmdq(Tegra241CMDQV 
*cmdqv, int index,
 /* Pre-alloc cached writes survive the cache-to-hardware transition. */
 tegra241_cmdqv_sync_vcmdq(cmdqv, index);
 
+/* Map the mmap'd VINTF page0 into guest MMIO space. */
+tegra241_cmdqv_guest_map_vintf_page0(cmdqv);
+
 return true;
 }
 
@@ -449,6 +486,7 @@ static void tegra241_cmdqv_config_vintf_write(Tegra241CMDQV 
*cmdqv,
 tegra241_cmdqv_setup_all_vcmdq(cmdqv, errp);
 }
 } else {
+tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
 tegra241_cmdqv_free_all_vcmdq(cmdqv);
 tegra241_cmdqv_munmap_vintf_page0(cmdqv, errp);
 cmdqv->vintf_status &= ~R_VINTF0_STATUS_ENABLE_OK_MASK;
@@ -566,6 +604,7 @@ static void tegra241_cmdqv_writel_mmio(Tegra241CMDQV 
*cmdqv, hwaddr offset,
  */
 tegra241_cmdqv_setup_all_vcmdq(cmdqv, &local_err);
 } else {
+tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
 tegra241_cmdqv_free_all_vcmdq(cmdqv);
 cmdqv->status &= ~R_STATUS_CMDQV_ENABLED_MASK;
 }
-- 
2.43.0