From: Nicolin Chen <nicolinc@nvidia.com>
Tegra241 CMDQV extends SMMUv3 with support for virtual command queues
(VCMDQs) exposed via a CMDQV MMIO region. The CMDQV MMIO space is split
into 64KB pages:
0x00000: Global CMDQV registers
0x10000: Global VCMDQ registers, Page0
0x20000: Global VCMDQ registers, Page1
0x30000: VINTF0 logical VCMDQ registers, Page0
0x40000: VINTF0 logical VCMDQ registers, Page1
This patch wires up the Tegra241 CMDQV init callback and allocates
vendor-specific CMDQV state. The state pointer is stored in
SMMUv3AccelState for use by subsequent CMDQV operations.
The CMDQV MMIO region and a dedicated IRQ line are registered with the
SMMUv3 device. The MMIO read/write handlers are currently stubs and will
be implemented in later patches.
The CMDQV interrupt is edge-triggered and indicates VCMDQ or VINTF
error conditions. This patch only registers the IRQ line. Interrupt
generation and propagation to the guest will be added in a subsequent
patch.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
---
hw/arm/smmuv3-accel.h | 1 +
hw/arm/tegra241-cmdqv.h | 18 ++++++++++++++++++
hw/arm/tegra241-cmdqv.c | 30 ++++++++++++++++++++++++++++--
3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmuv3-accel.h b/hw/arm/smmuv3-accel.h
index 5bdd01afb5..7d6e4c6b76 100644
--- a/hw/arm/smmuv3-accel.h
+++ b/hw/arm/smmuv3-accel.h
@@ -42,6 +42,7 @@ typedef struct SMMUv3AccelState {
uint32_t abort_hwpt_id;
QLIST_HEAD(, SMMUv3AccelDevice) device_list;
const SMMUv3AccelCmdqvOps *cmdqv_ops;
+ void *cmdqv; /* vendor specific CMDQV state */
} SMMUv3AccelState;
typedef struct SMMUS1Hwpt {
diff --git a/hw/arm/tegra241-cmdqv.h b/hw/arm/tegra241-cmdqv.h
index 312064a081..46aa9e8a9f 100644
--- a/hw/arm/tegra241-cmdqv.h
+++ b/hw/arm/tegra241-cmdqv.h
@@ -15,6 +15,24 @@
#define TEGRA241_CMDQV_MAX_CMDQ (1U << TEGRA241_CMDQV_NUM_CMDQ_LOG2)
#define TEGRA241_CMDQV_NUM_SID_PER_VM_LOG2 4
+/*
+ * Tegra241 CMDQV MMIO layout (64KB pages)
+ *
+ * 0x00000 TEGRA241_CMDQV_CFG (Global CMDQV configuration)
+ * 0x10000 TEGRA241_VCMDQ_PAGE0 (Virtual CMDQ page 0)
+ * 0x20000 TEGRA241_VCMDQ_PAGE1 (Virtual CMDQ page 1)
+ * 0x30000 TEGRA241_VINTF0_PAGE0 (Virtual interface 0, page 0)
+ * 0x40000 TEGRA241_VINTF0_PAGE1 (Virtual interface 0, page 1)
+ */
+#define TEGRA241_CMDQV_IO_LEN 0x50000
+
+typedef struct Tegra241CMDQV {
+ struct iommu_viommu_tegra241_cmdqv cmdqv_data;
+ SMMUv3AccelState *s_accel;
+ MemoryRegion mmio_cmdqv;
+ qemu_irq irq;
+} Tegra241CMDQV;
+
const SMMUv3AccelCmdqvOps *tegra241_cmdqv_get_ops(void);
#endif /* HW_ARM_TEGRA241_CMDQV_H */
diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c
index a270fa7ce4..6959766129 100644
--- a/hw/arm/tegra241-cmdqv.c
+++ b/hw/arm/tegra241-cmdqv.c
@@ -13,6 +13,16 @@
#include "smmuv3-accel.h"
#include "tegra241-cmdqv.h"
+static uint64_t tegra241_cmdqv_read(void *opaque, hwaddr offset, unsigned size)
+{
+ return 0;
+}
+
+static void tegra241_cmdqv_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+}
+
static void tegra241_cmdqv_free_viommu(SMMUv3State *s)
{
}
@@ -29,10 +39,26 @@ static void tegra241_cmdqv_reset(SMMUv3State *s)
{
}
+static const MemoryRegionOps mmio_cmdqv_ops = {
+ .read = tegra241_cmdqv_read,
+ .write = tegra241_cmdqv_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static bool tegra241_cmdqv_init(SMMUv3State *s, Error **errp)
{
- error_setg(errp, "NVIDIA Tegra241 CMDQV is unsupported");
- return false;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(OBJECT(s));
+ SMMUv3AccelState *accel = s->s_accel;
+ Tegra241CMDQV *cmdqv;
+
+ cmdqv = g_new0(Tegra241CMDQV, 1);
+ memory_region_init_io(&cmdqv->mmio_cmdqv, OBJECT(s), &mmio_cmdqv_ops, cmdqv,
+ "tegra241-cmdqv", TEGRA241_CMDQV_IO_LEN);
+ sysbus_init_mmio(sbd, &cmdqv->mmio_cmdqv);
+ sysbus_init_irq(sbd, &cmdqv->irq);
+ cmdqv->s_accel = accel;
+ accel->cmdqv = cmdqv;
+ return true;
}
static bool tegra241_cmdqv_probe(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
--
2.43.0