@samitouri / QOSamiQemu / commits / 1de52612f3

hw/arm/tegra241-cmdqv: Read and propagate Tegra241 CMDQV errors

Install an event handler on the CMDQV vEVENTQ fd to read and propagate host received CMDQV errors to the guest. The handler runs in QEMU's main loop, using a non-blocking fd registered via qemu_set_fd_handler(). Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Tested-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260609112552.378999-24-skolothumtho@nvidia.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Shameer Kolothum committed Jun 9, 2026 at 12:25 UTC 1de52612f3ff339598b8c19ee5caa563a371a323
2 files changed +64
hw/arm/tegra241-cmdqv.c
+63
@@ -12,6 +12,7 @@
12
13 #include "hw/arm/smmuv3.h"
14 #include "hw/arm/smmuv3-common.h"
15 +#include "hw/core/irq.h"
16 #include "smmuv3-accel.h"
17 #include "tegra241-cmdqv.h"
18 #include "trace.h"
@@ -729,6 +730,51 @@ out:
730 trace_tegra241_cmdqv_write_mmio(offset, value, size);
731 }
732
733 +static void tegra241_cmdqv_event_read(void *opaque)
734 +{
735 + Tegra241CMDQV *cmdqv = opaque;
736 + IOMMUFDVeventq *veventq = cmdqv->veventq;
737 + struct {
738 + struct iommufd_vevent_header hdr;
739 + struct iommu_vevent_tegra241_cmdqv vevent;
740 + } buf;
741 + Error *local_err = NULL;
742 +
743 + if (!smmuv3_accel_event_read_validate(veventq,
744 + IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV,
745 + &buf, sizeof(buf), &local_err)) {
746 + warn_report_err_once(local_err);
747 + return;
748 + }
749 +
750 + if (buf.vevent.lvcmdq_err_map[0] || buf.vevent.lvcmdq_err_map[1]) {
751 + cmdqv->vintf_cmdq_err_map[0] =
752 + extract64(buf.vevent.lvcmdq_err_map[0], 0, 32);
753 + cmdqv->vintf_cmdq_err_map[1] =
754 + extract64(buf.vevent.lvcmdq_err_map[0], 32, 32);
755 + cmdqv->vintf_cmdq_err_map[2] =
756 + extract64(buf.vevent.lvcmdq_err_map[1], 0, 32);
757 + cmdqv->vintf_cmdq_err_map[3] =
758 + extract64(buf.vevent.lvcmdq_err_map[1], 32, 32);
759 + /*
760 + * CMDQV_CMDQ_ERR_MAP and VINTF0_LVCMDQ_ERR_MAP are distinct
761 + * registers (different MMIO offsets). With only VINTF0 exposed
762 + * they carry the same data, so mirror.
763 + */
764 + for (int i = 0; i < 4; i++) {
765 + cmdqv->cmdq_err_map[i] = cmdqv->vintf_cmdq_err_map[i];
766 + }
767 + /* Set the VINTF0 bit in VI_ERR_MAP_0 (only VINTF0 is exposed). */
768 + cmdqv->vi_err_map[0] |= BIT(0);
769 + if (!(cmdqv->vi_int_mask[0] & BIT(0))) {
770 + qemu_irq_pulse(cmdqv->irq);
771 + }
772 + trace_tegra241_cmdqv_err_map(
773 + cmdqv->vintf_cmdq_err_map[3], cmdqv->vintf_cmdq_err_map[2],
774 + cmdqv->vintf_cmdq_err_map[1], cmdqv->vintf_cmdq_err_map[0]);
775 + }
776 +}
777 +
778 static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
779 {
780 SMMUv3AccelState *accel = s->s_accel;
@@ -740,6 +786,7 @@ static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
786 return;
787 }
788 if (veventq) {
789 + qemu_set_fd_handler(veventq->veventq_fd, NULL, NULL, NULL);
790 close(veventq->veventq_fd);
791 iommufd_backend_free_id(viommu->iommufd, veventq->veventq_id);
792 g_free(veventq);
@@ -759,6 +806,7 @@ tegra241_cmdqv_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
806 Tegra241CMDQV *cmdqv = s->s_accel->cmdqv;
807 uint32_t viommu_id, veventq_id, veventq_fd;
808 IOMMUFDVeventq *veventq;
809 + int flags;
810
811 if (!iommufd_backend_alloc_viommu(idev->iommufd, idev->devid,
812 IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV,
@@ -784,14 +832,29 @@ tegra241_cmdqv_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
832 goto munmap_page0;
833 }
834
835 + flags = fcntl(veventq_fd, F_GETFL);
836 + if (flags < 0) {
837 + error_setg(errp, "Failed to get flags for vEVENTQ fd");
838 + goto free_veventq;
839 + }
840 + if (fcntl(veventq_fd, F_SETFL, O_NONBLOCK | flags) < 0) {
841 + error_setg(errp, "Failed to set O_NONBLOCK on vEVENTQ fd");
842 + goto free_veventq;
843 + }
844 +
845 veventq = g_new(IOMMUFDVeventq, 1);
846 veventq->veventq_id = veventq_id;
847 veventq->veventq_fd = veventq_fd;
848 cmdqv->veventq = veventq;
849
850 + /* Set up event handler for veventq fd */
851 + qemu_set_fd_handler(veventq_fd, tegra241_cmdqv_event_read, NULL, cmdqv);
852 *out_viommu_id = viommu_id;
853 return true;
854
855 +free_veventq:
856 + close(veventq_fd);
857 + iommufd_backend_free_id(idev->iommufd, veventq_id);
858 munmap_page0:
859 munmap(cmdqv->vintf_page0, VINTF_PAGE_SIZE);
860 cmdqv->vintf_page0 = NULL;
hw/arm/trace-events
+1
@@ -75,6 +75,7 @@ smmuv3_accel_install_ste(uint32_t vsid, const char * type, uint32_t hwpt_id) "vS
75 # tegra241-cmdqv
76 tegra241_cmdqv_read_mmio(uint64_t offset, uint64_t val, unsigned size) "offset: 0x%"PRIx64" val: 0x%"PRIx64" size: 0x%x"
77 tegra241_cmdqv_write_mmio(uint64_t offset, uint64_t val, unsigned size) "offset: 0x%"PRIx64" val: 0x%"PRIx64" size: 0x%x"
78 +tegra241_cmdqv_err_map(uint32_t map3, uint32_t map2, uint32_t map1, uint32_t map0) "hw irq received. error (hex) maps: %04X:%04X:%04X:%04X"
79 tegra241_cmdqv_read_vcmdq_page0(int index, const char *aperture, const char *backing, uint64_t offset0, uint64_t val) "vcmdq[%d] %s (%s) offset0: 0x%"PRIx64" val: 0x%"PRIx64
80 tegra241_cmdqv_read_vcmdq_page1(int index, const char *aperture, uint64_t offset0, uint64_t val) "vcmdq[%d] %s offset0: 0x%"PRIx64" val: 0x%"PRIx64
81 tegra241_cmdqv_write_vcmdq_page0(int index, const char *aperture, const char *backing, uint64_t offset0, uint64_t val) "vcmdq[%d] %s (%s) offset0: 0x%"PRIx64" val: 0x%"PRIx64