#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"
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;
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);
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,
goto munmap_page0;
}
+ 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);
munmap_page0:
munmap(cmdqv->vintf_page0, VINTF_PAGE_SIZE);
cmdqv->vintf_page0 = NULL;
# 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, const char *backing, uint64_t offset0, uint64_t val) "vcmdq[%d] %s (%s) 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 offset0: 0x%"PRIx64" val: 0x%"PRIx64
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