@samitouri / QOSamiQemu / commits / 5965b81ce2

hw/arm/tegra241-cmdqv: Use mmap'd host VINTF page0 for virtual VINTF page0

Install the mmap'd host VINTF page0 as a RAM-device MemoryRegion backing the guest's virtual VINTF Page 0 aperture (guest MMIO offset 0x30000) when VINTF is enabled, and remove it on VINTF disable or reset. This eliminates QEMU trapping for hot-path CONS/PROD index updates via that aperture. After this patch, the two VCMDQ Page 0 apertures use different access paths: the direct aperture (0x10000) remains QEMU-trapped, while the VINTF aperture (0x30000) is a guest-direct RAM mapping. The direct aperture is intentionally kept trapped (not aliased to the host VINTF mmap) so that writes to an unallocated VCMDQ remain well-defined. The CMDQV architecture allows software to program a VCMDQ through the direct aperture without first allocating it to a VINTF; aliasing would route those writes to unallocated logical slots in the VINTF page, where the hardware silently drops them. Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Tested-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260609112552.378999-22-skolothumtho@nvidia.com Co-developed-by: Shameer Kolothum <skolothumtho@nvidia.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Nicolin Chen committed Jun 9, 2026 at 12:25 UTC 5965b81ce2835de49ba4eb36c386e72be5ff1ba8
2 files changed +38
hw/arm/tegra241-cmdqv.c
+37
@@ -26,6 +26,40 @@ static void tegra241_cmdqv_reset_vcmdq_cache(Tegra241CMDQV *cmdqv, int index)
26 cmdqv->vcmdq_gerrorn[index] = 0;
27 }
28
29 +static void tegra241_cmdqv_guest_unmap_vintf_page0(Tegra241CMDQV *cmdqv)
30 +{
31 + if (!cmdqv->mr_vintf_page0) {
32 + return;
33 + }
34 +
35 + memory_region_del_subregion(&cmdqv->mmio_cmdqv, cmdqv->mr_vintf_page0);
36 + object_unparent(OBJECT(cmdqv->mr_vintf_page0));
37 + g_free(cmdqv->mr_vintf_page0);
38 + cmdqv->mr_vintf_page0 = NULL;
39 +}
40 +
41 +static void tegra241_cmdqv_guest_map_vintf_page0(Tegra241CMDQV *cmdqv)
42 +{
43 + char *name;
44 +
45 + if (cmdqv->mr_vintf_page0) {
46 + return;
47 + }
48 +
49 + name = g_strdup_printf("%s vintf-page0",
50 + memory_region_name(&cmdqv->mmio_cmdqv));
51 + cmdqv->mr_vintf_page0 = g_malloc0(sizeof(*cmdqv->mr_vintf_page0));
52 + memory_region_init_ram_device_ptr(cmdqv->mr_vintf_page0,
53 + memory_region_owner(&cmdqv->mmio_cmdqv),
54 + name, VINTF_PAGE_SIZE,
55 + cmdqv->vintf_page0);
56 + memory_region_set_skip_iommu_map(cmdqv->mr_vintf_page0, true);
57 + memory_region_add_subregion_overlap(&cmdqv->mmio_cmdqv,
58 + CMDQV_VINTF_PAGE0_BASE,
59 + cmdqv->mr_vintf_page0, 1);
60 + g_free(name);
61 +}
62 +
63 static void tegra241_cmdqv_free_vcmdq(Tegra241CMDQV *cmdqv, int index)
64 {
65 IOMMUFDViommu *viommu = cmdqv->s_accel->viommu;
@@ -430,7 +464,9 @@ static void tegra241_cmdqv_config_vintf_write(Tegra241CMDQV *cmdqv,
464 * enabled need their hw_queue allocated now.
465 */
466 tegra241_cmdqv_setup_all_vcmdq(cmdqv, errp);
467 + tegra241_cmdqv_guest_map_vintf_page0(cmdqv);
468 } else {
469 + tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
470 tegra241_cmdqv_free_all_vcmdq(cmdqv);
471 cmdqv->vintf_status &= ~R_VINTF0_STATUS_ENABLE_OK_MASK;
472 }
@@ -772,6 +808,7 @@ static void tegra241_cmdqv_reset(SMMUv3State *s)
808 return;
809 }
810
811 + tegra241_cmdqv_guest_unmap_vintf_page0(cmdqv);
812 tegra241_cmdqv_free_all_vcmdq(cmdqv);
813 }
814
hw/arm/tegra241-cmdqv.h
+1
@@ -49,6 +49,7 @@ typedef struct Tegra241CMDQV {
49 IOMMUFDVeventq *veventq;
50 IOMMUFDHWqueue *vcmdq[TEGRA241_CMDQV_MAX_CMDQ];
51 void *vintf_page0;
52 + MemoryRegion *mr_vintf_page0;
53
54 /* CMDQ-V Config page register cache */
55 uint32_t config;