@samitouri / QOSamiQemu / commits / 46f0d48393

hw/arm/smmuv3-accel: Allocate vEVENTQ for accelerated SMMUv3 devices

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. Allocate a vEVENTQ only when both of the following conditions are met: 1) The guest SMMUv3 driver has set EVENTQEN = 1 in SMMU_CR0. 2) A vIOMMU exists (created when the first VFIO device is attached). These two conditions may occur in any order. In the cold-plug case, the vIOMMU already exists before the guest driver probes. When the guest sets EVENTQEN = 1 during driver probe, the vEVENTQ is allocated at that point. With hot-plug, the VFIO device may be attached either before or after the guest sets EVENTQEN. If the vIOMMU is created first, allocation is deferred until EVENTQEN = 1. If EVENTQEN is already set, allocation happens when the vIOMMU is created. In all cases, allocation is triggered when the second required condition becomes true. 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> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Tested-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Message-id: 20260226084456.112142-4-skolothumtho@nvidia.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Nicolin Chen committed Mar 6, 2026 at 09:01 UTC 46f0d48393529cfa3659012971c20f6808eb3b78
3 files changed +71 -2
hw/arm/smmuv3-accel.c
+59 -2
@@ -390,6 +390,19 @@ bool smmuv3_accel_issue_inv_cmd(SMMUv3State *bs, void *cmd, SMMUDevice *sdev,
390 sizeof(Cmd), &entry_num, cmd, errp);
391 }
392
393 +static void smmuv3_accel_free_veventq(SMMUv3AccelState *accel)
394 +{
395 + IOMMUFDVeventq *veventq = accel->veventq;
396 +
397 + if (!veventq) {
398 + return;
399 + }
400 + close(veventq->veventq_fd);
401 + iommufd_backend_free_id(accel->viommu->iommufd, veventq->veventq_id);
402 + g_free(veventq);
403 + accel->veventq = NULL;
404 +}
405 +
406 static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
407 {
408 IOMMUFDViommu *viommu = accel->viommu;
@@ -397,6 +410,7 @@ static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
410 if (!viommu) {
411 return;
412 }
413 + smmuv3_accel_free_veventq(accel);
414 iommufd_backend_free_id(viommu->iommufd, accel->bypass_hwpt_id);
415 iommufd_backend_free_id(viommu->iommufd, accel->abort_hwpt_id);
416 iommufd_backend_free_id(viommu->iommufd, accel->viommu->viommu_id);
@@ -404,6 +418,41 @@ static void smmuv3_accel_free_viommu(SMMUv3AccelState *accel)
418 accel->viommu = NULL;
419 }
420
421 +bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp)
422 +{
423 + SMMUv3AccelState *accel = s->s_accel;
424 + IOMMUFDVeventq *veventq;
425 + uint32_t veventq_id;
426 + uint32_t veventq_fd;
427 +
428 + if (!accel || !accel->viommu) {
429 + return true;
430 + }
431 +
432 + if (accel->veventq) {
433 + return true;
434 + }
435 +
436 + if (!smmuv3_eventq_enabled(s)) {
437 + return true;
438 + }
439 +
440 + if (!iommufd_backend_alloc_veventq(accel->viommu->iommufd,
441 + accel->viommu->viommu_id,
442 + IOMMU_VEVENTQ_TYPE_ARM_SMMUV3,
443 + 1 << s->eventq.log2size, &veventq_id,
444 + &veventq_fd, errp)) {
445 + return false;
446 + }
447 +
448 + veventq = g_new0(IOMMUFDVeventq, 1);
449 + veventq->veventq_id = veventq_id;
450 + veventq->veventq_fd = veventq_fd;
451 + veventq->viommu = accel->viommu;
452 + accel->veventq = veventq;
453 + return true;
454 +}
455 +
456 static bool
457 smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
458 Error **errp)
@@ -429,6 +478,7 @@ smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
478 viommu->viommu_id = viommu_id;
479 viommu->s2_hwpt_id = s2_hwpt_id;
480 viommu->iommufd = idev->iommufd;
481 + accel->viommu = viommu;
482
483 /*
484 * 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,
498 goto free_abort_hwpt;
499 }
500
501 + /* Allocate a vEVENTQ if guest has enabled event queue */
502 + if (!smmuv3_accel_alloc_veventq(s, errp)) {
503 + goto free_bypass_hwpt;
504 + }
505 +
506 /* Attach a HWPT based on SMMUv3 GBPA.ABORT value */
507 hwpt_id = smmuv3_accel_gbpa_hwpt(s, accel);
508 if (!host_iommu_device_iommufd_attach_hwpt(idev, hwpt_id, errp)) {
454 - goto free_bypass_hwpt;
509 + goto free_veventq;
510 }
456 - accel->viommu = viommu;
511 return true;
512
513 +free_veventq:
514 + smmuv3_accel_free_veventq(accel);
515 free_bypass_hwpt:
516 iommufd_backend_free_id(idev->iommufd, accel->bypass_hwpt_id);
517 free_abort_hwpt:
@@ -463,6 +519,7 @@ free_abort_hwpt:
519 free_viommu:
520 iommufd_backend_free_id(idev->iommufd, viommu->viommu_id);
521 g_free(viommu);
522 + accel->viommu = NULL;
523 return false;
524 }
525
hw/arm/smmuv3-accel.h
+6
@@ -22,6 +22,7 @@
22 */
23 typedef struct SMMUv3AccelState {
24 IOMMUFDViommu *viommu;
25 + IOMMUFDVeventq *veventq;
26 uint32_t bypass_hwpt_id;
27 uint32_t abort_hwpt_id;
28 QLIST_HEAD(, SMMUv3AccelDevice) device_list;
@@ -50,6 +51,7 @@ bool smmuv3_accel_attach_gbpa_hwpt(SMMUv3State *s, Error **errp);
51 bool smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev,
52 Error **errp);
53 void smmuv3_accel_idr_override(SMMUv3State *s);
54 +bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp);
55 void smmuv3_accel_reset(SMMUv3State *s);
56 #else
57 static inline void smmuv3_accel_init(SMMUv3State *s)
@@ -80,6 +82,10 @@ smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev,
82 static inline void smmuv3_accel_idr_override(SMMUv3State *s)
83 {
84 }
85 +static inline bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp)
86 +{
87 + return true;
88 +}
89 static inline void smmuv3_accel_reset(SMMUv3State *s)
90 {
91 }
hw/arm/smmuv3.c
+6
@@ -1605,6 +1605,12 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
1605 s->cr0ack = data & ~SMMU_CR0_RESERVED;
1606 /* in case the command queue has been enabled */
1607 smmuv3_cmdq_consume(s, &local_err);
1608 + if (local_err) {
1609 + error_report_err(local_err);
1610 + local_err = NULL;
1611 + }
1612 + /* Allocate vEVENTQ if EVENTQ is enabled and a vIOMMU is available */
1613 + smmuv3_accel_alloc_veventq(s, &local_err);
1614 break;
1615 case A_CR1:
1616 s->cr[1] = data;