From: Nicolin Chen <nicolinc@nvidia.com>
Add support for allocating IOMMUFD hardware queues when VCMDQ base
registers are programmed by the guest.
When a VCMDQ BASE register is written with a valid RAM-backed address,
allocate a corresponding IOMMUFD hardware queue for the CMDQV device.
Any previously allocated queue for the VCMDQ is freed before reallocation.
Writes with invalid addresses (e.g. during reset) are ignored.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
---
hw/arm/tegra241-cmdqv.c | 51 ++++++++++++++++++++++++++++++++++++++---
hw/arm/tegra241-cmdqv.h | 1 +
2 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c
index 71f9a43bce..57f47a4997 100644
--- a/hw/arm/tegra241-cmdqv.c
+++ b/hw/arm/tegra241-cmdqv.c
@@ -170,6 +170,45 @@ static uint64_t tegra241_cmdqv_read(void *opaque, hwaddr offset, unsigned size)
}
}
+static bool tegra241_cmdqv_setup_vcmdq(Tegra241CMDQV *cmdqv, int index,
+ Error **errp)
+{
+ SMMUv3AccelState *accel = cmdqv->s_accel;
+ uint64_t base_mask = (uint64_t)R_VCMDQ0_BASE_L_ADDR_MASK |
+ (uint64_t)R_VCMDQ0_BASE_H_ADDR_MASK << 32;
+ uint64_t addr = cmdqv->vcmdq_base[index] & base_mask;
+ uint64_t log2 = cmdqv->vcmdq_base[index] & R_VCMDQ0_BASE_L_LOG2SIZE_MASK;
+ uint64_t size = 1ULL << (log2 + 4);
+ IOMMUFDHWqueue *vcmdq = cmdqv->vcmdq[index];
+ IOMMUFDViommu *viommu = accel->viommu;
+ IOMMUFDHWqueue *hw_queue;
+ uint32_t hw_queue_id;
+
+ /* Ignore any invalid address. This may come as part of reset etc */
+ if (!address_space_is_ram(&address_space_memory, addr)) {
+ return true;
+ }
+
+ if (vcmdq) {
+ iommufd_backend_free_id(viommu->iommufd, vcmdq->hw_queue_id);
+ cmdqv->vcmdq[index] = NULL;
+ g_free(vcmdq);
+ }
+
+ if (!iommufd_backend_alloc_hw_queue(viommu->iommufd, viommu->viommu_id,
+ IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV,
+ index, addr, size, &hw_queue_id,
+ errp)) {
+ return false;
+ }
+ hw_queue = g_new(IOMMUFDHWqueue, 1);
+ hw_queue->hw_queue_id = hw_queue_id;
+ hw_queue->viommu = viommu;
+ cmdqv->vcmdq[index] = hw_queue;
+
+ return true;
+}
+
/*
* Write a VCMDQ register using VCMDQ0_* offsets.
*
@@ -178,7 +217,7 @@ static uint64_t tegra241_cmdqv_read(void *opaque, hwaddr offset, unsigned size)
*/
static void
tegra241_cmdqv_write_vcmdq(Tegra241CMDQV *cmdqv, hwaddr offset0, int index,
- uint64_t value, unsigned size)
+ uint64_t value, unsigned size, Error **errp)
{
switch (offset0) {
@@ -207,11 +246,13 @@ tegra241_cmdqv_write_vcmdq(Tegra241CMDQV *cmdqv, hwaddr offset0, int index,
(cmdqv->vcmdq_base[index] & 0xffffffff00000000ULL) |
(value & 0xffffffffULL);
}
+ tegra241_cmdqv_setup_vcmdq(cmdqv, index, errp);
return;
case A_VCMDQ0_BASE_H:
cmdqv->vcmdq_base[index] =
(cmdqv->vcmdq_base[index] & 0xffffffffULL) |
((uint64_t)value << 32);
+ tegra241_cmdqv_setup_vcmdq(cmdqv, index, errp);
return;
case A_VCMDQ0_CONS_INDX_BASE_DRAM_L:
if (size == 8) {
@@ -303,7 +344,7 @@ static void tegra241_cmdqv_write(void *opaque, hwaddr offset, uint64_t value,
case A_VCMDQ0_CONS_INDX ... A_VCMDQ127_GERRORN:
index = (offset - 0x10000) / 0x80;
tegra241_cmdqv_write_vcmdq(cmdqv, offset - 0x80 * index, index, value,
- size);
+ size, &local_err);
break;
case A_VI_VCMDQ0_BASE_L ... A_VI_VCMDQ127_CONS_INDX_BASE_DRAM_H:
/* Same decoding as read() case: See comments above */
@@ -312,12 +353,16 @@ static void tegra241_cmdqv_write(void *opaque, hwaddr offset, uint64_t value,
case A_VCMDQ0_BASE_L ... A_VCMDQ127_CONS_INDX_BASE_DRAM_H:
index = (offset - 0x20000) / 0x80;
tegra241_cmdqv_write_vcmdq(cmdqv, offset - 0x80 * index, index, value,
- size);
+ size, &local_err);
break;
default:
qemu_log_mask(LOG_UNIMP, "%s unhandled write access at 0x%" PRIx64 "\n",
__func__, offset);
}
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
}
static void tegra241_cmdqv_free_veventq(SMMUv3State *s)
diff --git a/hw/arm/tegra241-cmdqv.h b/hw/arm/tegra241-cmdqv.h
index 1bc03c4f97..2f4a8ab35f 100644
--- a/hw/arm/tegra241-cmdqv.h
+++ b/hw/arm/tegra241-cmdqv.h
@@ -31,6 +31,7 @@ typedef struct Tegra241CMDQV {
MemoryRegion mmio_cmdqv;
qemu_irq irq;
void *vintf_page0;
+ IOMMUFDHWqueue *vcmdq[128];
/* Register Cache */
uint32_t config;
--
2.43.0