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(). Signed-off-by: Shameer Kolothum <[email protected]> --- hw/arm/tegra241-cmdqv.c | 80 +++++++++++++++++++++++++++++++++++++++++ hw/arm/tegra241-cmdqv.h | 2 ++ hw/arm/trace-events | 3 ++ 3 files changed, 85 insertions(+) diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c index 812b027923..5b8a7bdff2 100644 --- a/hw/arm/tegra241-cmdqv.c +++ b/hw/arm/tegra241-cmdqv.c @@ -8,9 +8,12 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/log.h" +#include "trace.h" #include "hw/arm/smmuv3.h" +#include "hw/irq.h" #include "smmuv3-accel.h" #include "tegra241-cmdqv.h" @@ -137,6 +140,79 @@ static uint64_t tegra241_cmdqv_read_vcmdq(Tegra241CMDQV *cmdqv, hwaddr offset, } } +static void tegra241_cmdqv_event_read(void *opaque) +{ + Tegra241CMDQV *cmdqv = opaque; + struct { + struct iommufd_vevent_header hdr; + struct iommu_vevent_tegra241_cmdqv vevent; + } buf; + ssize_t readsz = sizeof(buf); + uint32_t last_seq = cmdqv->last_event_seq; + ssize_t bytes; + + bytes = read(cmdqv->veventq->veventq_fd, &buf, readsz); + if (bytes <= 0) { + if (errno == EAGAIN || errno == EINTR) { + return; + } + error_report("Tegra241 CMDQV: vEVENTQ: read failed (%s)", + strerror(errno)); + return; + } + + if (bytes < readsz) { + error_report("Tegra241 CMDQV: vEVENTQ: incomplete read (%zd/%zd bytes)", + bytes, readsz); + return; + } + + if (buf.hdr.flags & IOMMU_VEVENTQ_FLAG_LOST_EVENTS) { + error_report("Tegra241 CMDQV: vEVENTQ has lost events"); + return; + } + + /* Check sequence in hdr for lost events if any */ + if (cmdqv->event_start) { + uint32_t expected = (last_seq == INT_MAX) ? 0 : last_seq + 1; + + if (buf.hdr.sequence != expected) { + uint32_t delta; + + if (buf.hdr.sequence >= last_seq) { + delta = buf.hdr.sequence - last_seq; + } else { + /* Handle wraparound from INT_MAX */ + delta = (INT_MAX - last_seq) + buf.hdr.sequence + 1; + } + error_report("Tegra241 CMDQV: vEVENTQ: detected lost %u event(s)", + delta - 1); + } + } + + if (buf.vevent.lvcmdq_err_map[0] || buf.vevent.lvcmdq_err_map[1]) { + cmdqv->vintf_cmdq_err_map[0] = + buf.vevent.lvcmdq_err_map[0] & 0xffffffff; + cmdqv->vintf_cmdq_err_map[1] = + (buf.vevent.lvcmdq_err_map[0] >> 32) & 0xffffffff; + cmdqv->vintf_cmdq_err_map[2] = + buf.vevent.lvcmdq_err_map[1] & 0xffffffff; + cmdqv->vintf_cmdq_err_map[3] = + (buf.vevent.lvcmdq_err_map[1] >> 32) & 0xffffffff; + 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]); + } + + cmdqv->last_event_seq = buf.hdr.sequence; + cmdqv->event_start = true; +} + static void tegra241_cmdqv_free_veventq(Tegra241CMDQV *cmdqv) { SMMUv3State *smmu = cmdqv->smmu; @@ -179,6 +255,10 @@ static bool tegra241_cmdqv_alloc_veventq(Tegra241CMDQV *cmdqv, Error **errp) veventq->veventq_fd = veventq_fd; veventq->viommu = viommu; cmdqv->veventq = veventq; + + /* Set up event handler for veventq fd */ + fcntl(veventq_fd, F_SETFL, O_NONBLOCK); + qemu_set_fd_handler(veventq_fd, tegra241_cmdqv_event_read, NULL, cmdqv); return true; } diff --git a/hw/arm/tegra241-cmdqv.h b/hw/arm/tegra241-cmdqv.h index ba7f2a0b1b..97eaef8a72 100644 --- a/hw/arm/tegra241-cmdqv.h +++ b/hw/arm/tegra241-cmdqv.h @@ -25,6 +25,8 @@ typedef struct Tegra241CMDQV { void *vcmdq_page0; IOMMUFDHWqueue *vcmdq[128]; IOMMUFDVeventq *veventq; + uint32_t last_event_seq; + bool event_start; /* Register Cache */ uint32_t config; diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 3457536fb0..76bda0efef 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -72,6 +72,9 @@ smmuv3_accel_unset_iommu_device(int devfn, uint32_t devid) "devfn=0x%x (idev dev smmuv3_accel_translate_ste(uint32_t vsid, uint32_t hwpt_id, uint64_t ste_1, uint64_t ste_0) "vSID=0x%x hwpt_id=0x%x ste=%"PRIx64":%"PRIx64 smmuv3_accel_install_ste(uint32_t vsid, const char * type, uint32_t hwpt_id) "vSID=0x%x ste type=%s hwpt_id=0x%x" +# tegra241-cmdqv +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" + # strongarm.c strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d" strongarm_ssp_read_underrun(void) "SSP rx underrun" -- 2.43.0
