From: Nicolin Chen <nicolinc@nvidia.com>
When the guest enables the Event Queue and a vIOMMU is present, allocate a
vEVENTQ object so that host-side events related to the vIOMMU can be
received and propagated back to the guest.
For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is created
before the guest boots. In this case, the vEVENTQ is allocated when the
guest writes to SMMU_CR0 and sets EVENTQEN = 1.
If no cold-plugged device exists at boot (i.e. no vIOMMU initially), the
vEVENTQ is allocated when a vIOMMU is created, i.e. during the first
device hot-plug.
Errors from command queue consumption and vEVENTQ allocation are reported
independently as the two operations are unrelated.
Event read and propagation will be added in a later patch.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
---
hw/arm/smmuv3-accel.h | 6 +++++
hw/arm/smmuv3-accel.c | 61 +++++++++++++++++++++++++++++++++++++++++--
hw/arm/smmuv3.c | 6 +++++
3 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmuv3-accel.h b/hw/arm/smmuv3-accel.h
index a8a64802ec..dba6c71de5 100644
--- a/hw/arm/smmuv3-accel.h
+++ b/hw/arm/smmuv3-accel.h
@@ -22,6 +22,7 @@
*/
typedef struct SMMUv3AccelState {
IOMMUFDViommu *viommu;
+ IOMMUFDVeventq *veventq;
uint32_t bypass_hwpt_id;
uint32_t abort_hwpt_id;
QLIST_HEAD(, SMMUv3AccelDevice) device_list;
@@ -50,6 +51,7 @@ bool smmuv3_accel_attach_gbpa_hwpt(SMMUv3State *s, Error **errp);
bool smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev,
Error **errp);
void smmuv3_accel_idr_override(SMMUv3State *s);
+bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp);
void smmuv3_accel_reset(SMMUv3State *s);
#else
static inline void smmuv3_accel_init(SMMUv3State *s)
@@ -80,6 +82,10 @@ smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev,
static inline void smmuv3_accel_idr_override(SMMUv3State *s)
{
}
+static inline bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp)
+{
+ return true;
+}
static inline void smmuv3_accel_reset(SMMUv3State *s)
{
}
diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index c19c526fca..f703ea1aac 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -390,6 +390,19 @@ bool smmuv3_accel_issue_inv_cmd(SMMUv3State *bs, void *cmd, SMMUDevice *sdev,
sizeof(Cmd), &entry_num, cmd, errp);
}
+static void smmuv3_accel_free_veventq(SMMUv3AccelState *accel)
+{
+ IOMMUFDVeventq *veventq = accel->veventq;
+
+ if (!veventq) {
+ return;
+ }
+ close(veventq->veventq_fd);
+ iommufd_backend_free_id(accel->viommu->iommufd, veventq->veventq_id);
+ g_free(veventq);
+ accel->veventq = NULL;
+}
+
static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
{
IOMMUFDViommu *viommu = accel->viommu;
@@ -397,6 +410,7 @@ static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
if (!viommu) {
return;
}
+ smmuv3_accel_free_veventq(accel);
iommufd_backend_free_id(viommu->iommufd, accel->bypass_hwpt_id);
iommufd_backend_free_id(viommu->iommufd, accel->abort_hwpt_id);
iommufd_backend_free_id(viommu->iommufd, accel->viommu->viommu_id);
@@ -404,6 +418,41 @@ static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
accel->viommu = NULL;
}
+bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp)
+{
+ SMMUv3AccelState *accel = s->s_accel;
+ IOMMUFDVeventq *veventq;
+ uint32_t veventq_id;
+ uint32_t veventq_fd;
+
+ if (!accel || !accel->viommu) {
+ return true;
+ }
+
+ if (accel->veventq) {
+ return true;
+ }
+
+ if (!smmuv3_eventq_enabled(s)) {
+ return true;
+ }
+
+ if (!iommufd_backend_alloc_veventq(accel->viommu->iommufd,
+ accel->viommu->viommu_id,
+ IOMMU_VEVENTQ_TYPE_ARM_SMMUV3,
+ 1 << s->eventq.log2size, &veventq_id,
+ &veventq_fd, errp)) {
+ return false;
+ }
+
+ veventq = g_new0(IOMMUFDVeventq, 1);
+ veventq->veventq_id = veventq_id;
+ veventq->veventq_fd = veventq_fd;
+ veventq->viommu = accel->viommu;
+ accel->veventq = veventq;
+ return true;
+}
+
static bool
smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
Error **errp)
@@ -429,6 +478,7 @@ smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
viommu->viommu_id = viommu_id;
viommu->s2_hwpt_id = s2_hwpt_id;
viommu->iommufd = idev->iommufd;
+ accel->viommu = viommu;
/*
* Pre-allocate HWPTs for S1 bypass and abort cases. These will be attached
@@ -448,14 +498,20 @@ smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
goto free_abort_hwpt;
}
+ /* Allocate a vEVENTQ if guest has enabled event queue */
+ if (!smmuv3_accel_alloc_veventq(s, errp)) {
+ goto free_bypass_hwpt;
+ }
+
/* Attach a HWPT based on SMMUv3 GBPA.ABORT value */
hwpt_id = smmuv3_accel_gbpa_hwpt(s, accel);
if (!host_iommu_device_iommufd_attach_hwpt(idev, hwpt_id, errp)) {
- goto free_bypass_hwpt;
+ goto free_veventq;
}
- accel->viommu = viommu;
return true;
+free_veventq:
+ smmuv3_accel_free_veventq(accel);
free_bypass_hwpt:
iommufd_backend_free_id(idev->iommufd, accel->bypass_hwpt_id);
free_abort_hwpt:
@@ -463,6 +519,7 @@ free_abort_hwpt:
free_viommu:
iommufd_backend_free_id(idev->iommufd, viommu->viommu_id);
g_free(viommu);
+ accel->viommu = NULL;
return false;
}
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index c08d58c579..5d718da764 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1605,6 +1605,12 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
s->cr0ack = data & ~SMMU_CR0_RESERVED;
/* in case the command queue has been enabled */
smmuv3_cmdq_consume(s, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ local_err = NULL;
+ }
+ /* Allocate vEVENTQ if EVENTQ is enabled and a vIOMMU is available */
+ smmuv3_accel_alloc_veventq(s, &local_err);
break;
case A_CR1:
s->cr[1] = data;
--
2.43.0
On Thu, 19 Feb 2026 09:01:01 +0000 Shameer Kolothum <skolothumtho@nvidia.com> wrote: > From: Nicolin Chen <nicolinc@nvidia.com> > > When the guest enables the Event Queue and a vIOMMU is present, allocate a > vEVENTQ object so that host-side events related to the vIOMMU can be > received and propagated back to the guest. > > For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is created > before the guest boots. In this case, the vEVENTQ is allocated when the > guest writes to SMMU_CR0 and sets EVENTQEN = 1. > > If no cold-plugged device exists at boot (i.e. no vIOMMU initially), the > vEVENTQ is allocated when a vIOMMU is created, i.e. during the first > device hot-plug. Why do it differently? > > Errors from command queue consumption and vEVENTQ allocation are reported > independently as the two operations are unrelated. > > Event read and propagation will be added in a later patch. > > Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> > Reviewed-by: Eric Auger <eric.auger@redhat.com> > Tested-by: Nicolin Chen <nicolinc@nvidia.com> > Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
> -----Original Message----- > From: Jonathan Cameron <jonathan.cameron@huawei.com> > Sent: 24 February 2026 14:29 > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > Krishnakant Jaju <kjaju@nvidia.com> > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > accelerated SMMUv3 devices > > External email: Use caution opening links or attachments > > > On Thu, 19 Feb 2026 09:01:01 +0000 > Shameer Kolothum <skolothumtho@nvidia.com> wrote: > > > From: Nicolin Chen <nicolinc@nvidia.com> > > > > When the guest enables the Event Queue and a vIOMMU is present, > > allocate a vEVENTQ object so that host-side events related to the > > vIOMMU can be received and propagated back to the guest. > > > > For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is > > created before the guest boots. In this case, the vEVENTQ is allocated > > when the guest writes to SMMU_CR0 and sets EVENTQEN = 1. > > > > If no cold-plugged device exists at boot (i.e. no vIOMMU initially), > > the vEVENTQ is allocated when a vIOMMU is created, i.e. during the > > first device hot-plug. > > Why do it differently? This is because a vEVENTQ must be associated with a vIOMMU, and iommufd_backend_alloc_veventq() requires a valid viommu_id. A vIOMMU is only created once at least one vfio-pci device is attached. If the VM boots without any cold-plugged devices, no vIOMMU exists at that point. In that case, the vIOMMU is created during the first device hot-plug, so we allocate the vEVENTQ at that time instead. So, the difference in behaviour simply follows when the vIOMMU becomes available. Hope that is clear now. Thanks, Shameer
On Tue, 24 Feb 2026 14:41:08 +0000 Shameer Kolothum Thodi <skolothumtho@nvidia.com> wrote: > > -----Original Message----- > > From: Jonathan Cameron <jonathan.cameron@huawei.com> > > Sent: 24 February 2026 14:29 > > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > > Krishnakant Jaju <kjaju@nvidia.com> > > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > > accelerated SMMUv3 devices > > > > External email: Use caution opening links or attachments > > > > > > On Thu, 19 Feb 2026 09:01:01 +0000 > > Shameer Kolothum <skolothumtho@nvidia.com> wrote: > > > > > From: Nicolin Chen <nicolinc@nvidia.com> > > > > > > When the guest enables the Event Queue and a vIOMMU is present, > > > allocate a vEVENTQ object so that host-side events related to the > > > vIOMMU can be received and propagated back to the guest. > > > > > > For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is > > > created before the guest boots. In this case, the vEVENTQ is allocated > > > when the guest writes to SMMU_CR0 and sets EVENTQEN = 1. > > > > > > If no cold-plugged device exists at boot (i.e. no vIOMMU initially), > > > the vEVENTQ is allocated when a vIOMMU is created, i.e. during the > > > first device hot-plug. > > > > Why do it differently? > > This is because a vEVENTQ must be associated with a vIOMMU, and > iommufd_backend_alloc_veventq() requires a valid viommu_id. > > A vIOMMU is only created once at least one vfio-pci device is > attached. If the VM boots without any cold-plugged devices, no > vIOMMU exists at that point. > > In that case, the vIOMMU is created during the first device > hot-plug, so we allocate the vEVENTQ at that time instead. > > So, the difference in behaviour simply follows when the vIOMMU > becomes available. > > Hope that is clear now. Ok. So maybe this is just a description thing that was confusing me. The key to my mental model is that both conditions must be met. That is SMMU_CR0 has EVENTQEN = 1 set and there is a VFIO device present. They happen in different orders in the two cases? What guarantees we don't get a hotplug event before the guest has set EVENTQEN = 1? Jonathan > > Thanks, > Shameer
> -----Original Message----- > From: Jonathan Cameron <jonathan.cameron@huawei.com> > Sent: 24 February 2026 15:02 > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > Krishnakant Jaju <kjaju@nvidia.com> > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > accelerated SMMUv3 devices > > External email: Use caution opening links or attachments > > > On Tue, 24 Feb 2026 14:41:08 +0000 > Shameer Kolothum Thodi <skolothumtho@nvidia.com> wrote: > > > > -----Original Message----- > > > From: Jonathan Cameron <jonathan.cameron@huawei.com> > > > Sent: 24 February 2026 14:29 > > > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > > > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > > > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > > > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > > > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > > > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > > > Krishnakant Jaju <kjaju@nvidia.com> > > > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > > > accelerated SMMUv3 devices > > > > > > External email: Use caution opening links or attachments > > > > > > > > > On Thu, 19 Feb 2026 09:01:01 +0000 > > > Shameer Kolothum <skolothumtho@nvidia.com> wrote: > > > > > > > From: Nicolin Chen <nicolinc@nvidia.com> > > > > > > > > When the guest enables the Event Queue and a vIOMMU is present, > > > > allocate a vEVENTQ object so that host-side events related to the > > > > vIOMMU can be received and propagated back to the guest. > > > > > > > > For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is > > > > created before the guest boots. In this case, the vEVENTQ is allocated > > > > when the guest writes to SMMU_CR0 and sets EVENTQEN = 1. > > > > > > > > If no cold-plugged device exists at boot (i.e. no vIOMMU initially), > > > > the vEVENTQ is allocated when a vIOMMU is created, i.e. during the > > > > first device hot-plug. > > > > > > Why do it differently? > > > > This is because a vEVENTQ must be associated with a vIOMMU, and > > iommufd_backend_alloc_veventq() requires a valid viommu_id. > > > > A vIOMMU is only created once at least one vfio-pci device is > > attached. If the VM boots without any cold-plugged devices, no > > vIOMMU exists at that point. > > > > In that case, the vIOMMU is created during the first device > > hot-plug, so we allocate the vEVENTQ at that time instead. > > > > So, the difference in behaviour simply follows when the vIOMMU > > becomes available. > > > > Hope that is clear now. > Ok. So maybe this is just a description thing that was confusing me. > The key to my mental model is that both conditions must be met. That > is SMMU_CR0 has EVENTQEN = 1 set and there is a VFIO device present. > They happen in different orders in the two cases? Yes. And EVENTQEN is set by Guest ARM SMMUv3 driver probe time. > > What guarantees we don't get a hotplug event before the guest has > set EVENTQEN = 1? vEVENTQ needs two things: 1) The guest must set EVENTQEN=1. 2) A vIOMMU must already exist (which happens when a VFIO device is attached). EVENTQEN=1 is set by the guest when the SMMUv3 driver probes. These two things can happen in either order. In the cold-plug case, the vIOMMU already exists before the guest driver probes. So when the guest sets EVENTQEN=1 during driver probe, we allocate the vEVENTQ at that time. In the hot-plug-first case, the first VFIO hotplug creates the vIOMMU, possibly before the guest has loaded the SMMUv3 driver. In that case, we wait until the guest sets EVENTQEN=1 during driver probe, and then allocate the vEVENTQ. So we do not depend on ordering. We just check that both conditions are true, and allocate when the second one becomes true. Thanks, Shameer
On Tue, 24 Feb 2026 15:18:00 +0000 Shameer Kolothum Thodi <skolothumtho@nvidia.com> wrote: > > -----Original Message----- > > From: Jonathan Cameron <jonathan.cameron@huawei.com> > > Sent: 24 February 2026 15:02 > > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > > Krishnakant Jaju <kjaju@nvidia.com> > > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > > accelerated SMMUv3 devices > > > > External email: Use caution opening links or attachments > > > > > > On Tue, 24 Feb 2026 14:41:08 +0000 > > Shameer Kolothum Thodi <skolothumtho@nvidia.com> wrote: > > > > > > -----Original Message----- > > > > From: Jonathan Cameron <jonathan.cameron@huawei.com> > > > > Sent: 24 February 2026 14:29 > > > > To: Shameer Kolothum Thodi <skolothumtho@nvidia.com> > > > > Cc: qemu-arm@nongnu.org; qemu-devel@nongnu.org; > > > > eric.auger@redhat.com; peter.maydell@linaro.org; Nicolin Chen > > > > <nicolinc@nvidia.com>; Nathan Chen <nathanc@nvidia.com>; Matt Ochs > > > > <mochs@nvidia.com>; Jiandi An <jan@nvidia.com>; Jason Gunthorpe > > > > <jgg@nvidia.com>; zhangfei.gao@linaro.org; zhenzhong.duan@intel.com; > > > > Krishnakant Jaju <kjaju@nvidia.com> > > > > Subject: Re: [PATCH v7 3/5] hw/arm/smmuv3-accel: Allocate vEVENTQ for > > > > accelerated SMMUv3 devices > > > > > > > > External email: Use caution opening links or attachments > > > > > > > > > > > > On Thu, 19 Feb 2026 09:01:01 +0000 > > > > Shameer Kolothum <skolothumtho@nvidia.com> wrote: > > > > > > > > > From: Nicolin Chen <nicolinc@nvidia.com> > > > > > > > > > > When the guest enables the Event Queue and a vIOMMU is present, > > > > > allocate a vEVENTQ object so that host-side events related to the > > > > > vIOMMU can be received and propagated back to the guest. > > > > > > > > > > For cold-plugged devices using SMMUv3 acceleration, the vIOMMU is > > > > > created before the guest boots. In this case, the vEVENTQ is allocated > > > > > when the guest writes to SMMU_CR0 and sets EVENTQEN = 1. > > > > > > > > > > If no cold-plugged device exists at boot (i.e. no vIOMMU initially), > > > > > the vEVENTQ is allocated when a vIOMMU is created, i.e. during the > > > > > first device hot-plug. > > > > > > > > Why do it differently? > > > > > > This is because a vEVENTQ must be associated with a vIOMMU, and > > > iommufd_backend_alloc_veventq() requires a valid viommu_id. > > > > > > A vIOMMU is only created once at least one vfio-pci device is > > > attached. If the VM boots without any cold-plugged devices, no > > > vIOMMU exists at that point. > > > > > > In that case, the vIOMMU is created during the first device > > > hot-plug, so we allocate the vEVENTQ at that time instead. > > > > > > So, the difference in behaviour simply follows when the vIOMMU > > > becomes available. > > > > > > Hope that is clear now. > > Ok. So maybe this is just a description thing that was confusing me. > > The key to my mental model is that both conditions must be met. That > > is SMMU_CR0 has EVENTQEN = 1 set and there is a VFIO device present. > > They happen in different orders in the two cases? > > Yes. And EVENTQEN is set by Guest ARM SMMUv3 driver probe time. > > > > > What guarantees we don't get a hotplug event before the guest has > > set EVENTQEN = 1? > > vEVENTQ needs two things: > > 1) The guest must set EVENTQEN=1. > 2) A vIOMMU must already exist (which happens when a VFIO device is attached). > > EVENTQEN=1 is set by the guest when the SMMUv3 driver probes. > > These two things can happen in either order. > > In the cold-plug case, the vIOMMU already exists before the guest driver > probes. So when the guest sets EVENTQEN=1 during driver probe, we > allocate the vEVENTQ at that time. > > In the hot-plug-first case, the first VFIO hotplug creates the vIOMMU, > possibly before the guest has loaded the SMMUv3 driver. In that case, > we wait until the guest sets EVENTQEN=1 during driver probe, and then > allocate the vEVENTQ. > > So we do not depend on ordering. We just check that both conditions > are true, and allocate when the second one becomes true. Perfect. That explanation works for me. If you respin maybe start the explanation with the full conditions that must be met, then break down why they occur in different orders in the cold and hotplug (after we reach a particular point in guest boot) cases. Jonathan > > Thanks, > Shameer >
© 2016 - 2026 Red Hat, Inc.