On 6/1/26 1:42 PM, Shameer Kolothum wrote:
> 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 <[email protected]>
> Signed-off-by: Shameer Kolothum <[email protected]>
Reviewed-by: Eric Auger <[email protected]>
Eric
> ---
> hw/arm/tegra241-cmdqv.c | 63 +++++++++++++++++++++++++++++++++++++++++
> hw/arm/trace-events | 1 +
> 2 files changed, 64 insertions(+)
>
> diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c
> index cdd4fa4f1a..d8b36164a1 100644
> --- a/hw/arm/tegra241-cmdqv.c
> +++ b/hw/arm/tegra241-cmdqv.c
> @@ -14,6 +14,7 @@
>
> #include "hw/arm/smmuv3.h"
> #include "hw/arm/smmuv3-common.h"
> +#include "hw/core/irq.h"
> #include "smmuv3-accel.h"
> #include "tegra241-cmdqv.h"
> #include "trace.h"
> @@ -751,6 +752,51 @@ out:
> trace_tegra241_cmdqv_write_mmio(offset, value, size);
> }
>
> +static void tegra241_cmdqv_event_read(void *opaque)
> +{
> + Tegra241CMDQV *cmdqv = opaque;
> + IOMMUFDVeventq *veventq = cmdqv->veventq;
> + struct {
> + struct iommufd_vevent_header hdr;
> + struct iommu_vevent_tegra241_cmdqv vevent;
> + } buf;
> + Error *local_err = NULL;
> +
> + if (!smmuv3_accel_event_read_validate(veventq,
> + IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV,
> + &buf, sizeof(buf), &local_err)) {
> + warn_report_err_once(local_err);
> + return;
> + }
> +
> + if (buf.vevent.lvcmdq_err_map[0] || buf.vevent.lvcmdq_err_map[1]) {
> + cmdqv->vintf_cmdq_err_map[0] =
> + extract64(buf.vevent.lvcmdq_err_map[0], 0, 32);
> + cmdqv->vintf_cmdq_err_map[1] =
> + extract64(buf.vevent.lvcmdq_err_map[0], 32, 32);
> + cmdqv->vintf_cmdq_err_map[2] =
> + extract64(buf.vevent.lvcmdq_err_map[1], 0, 32);
> + cmdqv->vintf_cmdq_err_map[3] =
> + extract64(buf.vevent.lvcmdq_err_map[1], 32, 32);
> + /*
> + * CMDQV_CMDQ_ERR_MAP and VINTF0_LVCMDQ_ERR_MAP are distinct
> + * registers (different MMIO offsets). With only VINTF0 exposed
> + * they carry the same data, so mirror.
> + */
> + for (int i = 0; i < 4; i++) {
> + cmdqv->cmdq_err_map[i] = cmdqv->vintf_cmdq_err_map[i];
> + }
> + /* Set the VINTF0 bit in VI_ERR_MAP_0 (only VINTF0 is exposed). */
> + cmdqv->vi_err_map[0] |= BIT(0);
> + if (!(cmdqv->vi_int_mask[0] & BIT(0))) {
> + qemu_irq_pulse(cmdqv->irq);
> + }
> + trace_tegra241_cmdqv_err_map(
> + cmdqv->vintf_cmdq_err_map[3], cmdqv->vintf_cmdq_err_map[2],
> + cmdqv->vintf_cmdq_err_map[1], cmdqv->vintf_cmdq_err_map[0]);
> + }
> +}
> +
> static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
> {
> SMMUv3AccelState *accel = s->s_accel;
> @@ -762,6 +808,7 @@ static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
> return;
> }
> if (veventq) {
> + qemu_set_fd_handler(veventq->veventq_fd, NULL, NULL, NULL);
> close(veventq->veventq_fd);
> iommufd_backend_free_id(viommu->iommufd, veventq->veventq_id);
> g_free(veventq);
> @@ -777,6 +824,7 @@ tegra241_cmdqv_alloc_viommu(SMMUv3State *s,
> HostIOMMUDeviceIOMMUFD *idev,
> Tegra241CMDQV *cmdqv = s->s_accel->cmdqv;
> uint32_t viommu_id, veventq_id, veventq_fd;
> IOMMUFDVeventq *veventq;
> + int flags;
>
> if (!iommufd_backend_alloc_viommu(idev->iommufd, idev->devid,
> IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV,
> @@ -795,14 +843,29 @@ tegra241_cmdqv_alloc_viommu(SMMUv3State *s,
> HostIOMMUDeviceIOMMUFD *idev,
> goto free_viommu;
> }
>
> + flags = fcntl(veventq_fd, F_GETFL);
> + if (flags < 0) {
> + error_setg(errp, "Failed to get flags for vEVENTQ fd");
> + goto free_veventq;
> + }
> + if (fcntl(veventq_fd, F_SETFL, O_NONBLOCK | flags) < 0) {
> + error_setg(errp, "Failed to set O_NONBLOCK on vEVENTQ fd");
> + goto free_veventq;
> + }
> +
> veventq = g_new(IOMMUFDVeventq, 1);
> veventq->veventq_id = veventq_id;
> veventq->veventq_fd = veventq_fd;
> cmdqv->veventq = veventq;
>
> + /* Set up event handler for veventq fd */
> + qemu_set_fd_handler(veventq_fd, tegra241_cmdqv_event_read, NULL, cmdqv);
> *out_viommu_id = viommu_id;
> return true;
>
> +free_veventq:
> + close(veventq_fd);
> + iommufd_backend_free_id(idev->iommufd, veventq_id);
> free_viommu:
> iommufd_backend_free_id(idev->iommufd, viommu_id);
> return false;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index d76f408d8a..115f1add9d 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -75,6 +75,7 @@ smmuv3_accel_install_ste(uint32_t vsid, const char * type,
> uint32_t hwpt_id) "vS
> # tegra241-cmdqv
> tegra241_cmdqv_read_mmio(uint64_t offset, uint64_t val, unsigned size)
> "offset: 0x%"PRIx64" val: 0x%"PRIx64" size: 0x%x"
> tegra241_cmdqv_write_mmio(uint64_t offset, uint64_t val, unsigned size)
> "offset: 0x%"PRIx64" val: 0x%"PRIx64" size: 0x%x"
> +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"
> tegra241_cmdqv_read_vcmdq_page0(int index, const char *aperture, uint64_t
> offset0, uint64_t val) "vcmdq[%d] %s page0 offset0: 0x%"PRIx64" val:
> 0x%"PRIx64
> tegra241_cmdqv_read_vcmdq_page1(int index, const char *aperture, uint64_t
> offset0, uint64_t val) "vcmdq[%d] %s page1 offset0: 0x%"PRIx64" val:
> 0x%"PRIx64
> tegra241_cmdqv_write_vcmdq_page0(int index, const char *aperture, uint64_t
> offset0, uint64_t val) "vcmdq[%d] %s page0 offset0: 0x%"PRIx64" val:
> 0x%"PRIx64