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]> --- hw/arm/tegra241-cmdqv.c | 60 +++++++++++++++++++++++++++++++++++++++++ hw/arm/trace-events | 1 + 2 files changed, 61 insertions(+) diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c index 853c548e58..0bba2c1801 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" @@ -736,6 +737,48 @@ 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]; + } + cmdqv->vi_err_map[0] |= 0x1; + 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; @@ -747,6 +790,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); @@ -762,6 +806,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, @@ -780,14 +825,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 c4262bb2be..5afbceee83 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, uint64_t offset0, uint64_t val) "vcmdq[%d] page0 offset0: 0x%"PRIx64" val: 0x%"PRIx64 tegra241_cmdqv_read_vcmdq_page1(int index, uint64_t offset0, uint64_t val) "vcmdq[%d] page1 offset0: 0x%"PRIx64" val: 0x%"PRIx64 tegra241_cmdqv_write_vcmdq_page0(int index, uint64_t offset0, uint64_t val) "vcmdq[%d] page0 offset0: 0x%"PRIx64" val: 0x%"PRIx64 -- 2.43.0
