@samitouri / QOSamiQemu / commits / f4ec4767ce

hw/arm/smmuv3-accel: Wire CMDQV ops into accel lifecycle

Add support for selecting and initializing a CMDQV backend based on the cmdqv OnOffAuto property. If set to OFF, CMDQV is not used and the default IOMMUFD-backed allocation path is taken. If set to AUTO, QEMU attempts to probe a CMDQV backend during device setup. If probing succeeds, the selected ops are stored in the accelerated SMMUv3 state and used. If probing fails, QEMU silently falls back to the default path. If set to ON, QEMU requires CMDQV support. Probing is performed during setup and failure results in an error. When a CMDQV backend is active, its callbacks are used for vIOMMU allocation, free, and reset handling. Otherwise, the base implementation is used. The current implementation wires up the Tegra241 CMDQV backend through the generic ops interface. Functional CMDQV behaviour is added in subsequent patches. No functional change. Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Tested-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260609112552.378999-9-skolothumtho@nvidia.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Shameer Kolothum committed Jun 9, 2026 at 12:25 UTC f4ec4767ce0c1fe5b0b1adf5f559ca808c3c2aba
2 files changed +89 -7
hw/arm/smmuv3-accel.c
+87 -7
@@ -19,6 +19,7 @@
19 #include "smmuv3-internal.h"
20 #include "smmuv3-accel.h"
21 #include "system/system.h"
22 +#include "tegra241-cmdqv.h"
23
24 /*
25 * The root region aliases the global system memory, and shared_as_sysmem
@@ -570,6 +571,7 @@ smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *hiodi,
571 Error **errp)
572 {
573 SMMUv3AccelState *accel = s->s_accel;
574 + const SMMUv3AccelCmdqvOps *cmdqv_ops = accel->cmdqv_ops;
575 struct iommu_hwpt_arm_smmuv3 bypass_data = {
576 .ste = { SMMU_STE_CFG_BYPASS | SMMU_STE_VALID, 0x0ULL },
577 };
@@ -580,10 +582,17 @@ smmuv3_accel_alloc_viommu(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *hiodi,
582 uint32_t viommu_id, hwpt_id;
583 IOMMUFDViommu *viommu;
584
583 - if (!iommufd_backend_alloc_viommu(hiodi->iommufd, hiodi->devid,
584 - IOMMU_VIOMMU_TYPE_ARM_SMMUV3, s2_hwpt_id,
585 - NULL, 0, &viommu_id, errp)) {
586 - return false;
585 + if (cmdqv_ops) {
586 + if (!cmdqv_ops->alloc_viommu(s, hiodi, &viommu_id, errp)) {
587 + return false;
588 + }
589 + } else {
590 + if (!iommufd_backend_alloc_viommu(hiodi->iommufd, hiodi->devid,
591 + IOMMU_VIOMMU_TYPE_ARM_SMMUV3,
592 + s2_hwpt_id, NULL, 0, &viommu_id,
593 + errp)) {
594 + return false;
595 + }
596 }
597
598 viommu = g_new0(IOMMUFDViommu, 1);
@@ -629,12 +638,70 @@ free_bypass_hwpt:
638 free_abort_hwpt:
639 iommufd_backend_free_id(hiodi->iommufd, accel->abort_hwpt_id);
640 free_viommu:
632 - iommufd_backend_free_id(hiodi->iommufd, viommu->viommu_id);
641 + if (cmdqv_ops && cmdqv_ops->free_viommu) {
642 + cmdqv_ops->free_viommu(s);
643 + } else {
644 + iommufd_backend_free_id(hiodi->iommufd, viommu->viommu_id);
645 + }
646 g_free(viommu);
647 accel->viommu = NULL;
648 return false;
649 }
650
651 +static const SMMUv3AccelCmdqvOps *
652 +smmuv3_accel_probe_cmdqv(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
653 + Error **errp)
654 +{
655 + const SMMUv3AccelCmdqvOps *ops = tegra241_cmdqv_get_ops();
656 +
657 + if (!ops) {
658 + error_setg(errp, "No CMDQV ops found");
659 + return NULL;
660 + }
661 + g_assert(ops->probe);
662 + g_assert(ops->alloc_viommu);
663 +
664 + if (!ops->probe(s, idev, errp)) {
665 + return NULL;
666 + }
667 + return ops;
668 +}
669 +
670 +static bool
671 +smmuv3_accel_select_cmdqv(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev,
672 + Error **errp)
673 +{
674 + const SMMUv3AccelCmdqvOps *ops = NULL;
675 +
676 + if (s->s_accel->cmdqv_ops) {
677 + return true;
678 + }
679 +
680 + switch (s->cmdqv) {
681 + case ON_OFF_AUTO_OFF:
682 + s->s_accel->cmdqv_ops = NULL;
683 + return true;
684 + case ON_OFF_AUTO_AUTO:
685 + ops = smmuv3_accel_probe_cmdqv(s, idev, NULL);
686 + break;
687 + case ON_OFF_AUTO_ON:
688 + ops = smmuv3_accel_probe_cmdqv(s, idev, errp);
689 + if (!ops) {
690 + error_append_hint(errp, "CMDQV requested but not supported");
691 + return false;
692 + }
693 + break;
694 + default:
695 + g_assert_not_reached();
696 + }
697 +
698 + if (ops && ops->init && !ops->init(s, errp)) {
699 + return false;
700 + }
701 + s->s_accel->cmdqv_ops = ops;
702 + return true;
703 +}
704 +
705 static bool smmuv3_accel_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
706 HostIOMMUDevice *hiod, Error **errp)
707 {
@@ -669,6 +736,10 @@ static bool smmuv3_accel_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
736 goto done;
737 }
738
739 + if (!smmuv3_accel_select_cmdqv(s, hiodi, errp)) {
740 + return false;
741 + }
742 +
743 if (!smmuv3_accel_alloc_viommu(s, hiodi, errp)) {
744 error_append_hint(errp, "Unable to alloc vIOMMU: hiodi devid 0x%x: ",
745 hiodi->devid);
@@ -946,8 +1017,17 @@ bool smmuv3_accel_attach_gbpa_hwpt(SMMUv3State *s, Error **errp)
1017
1018 void smmuv3_accel_reset(SMMUv3State *s)
1019 {
949 - /* Attach a HWPT based on GBPA reset value */
950 - smmuv3_accel_attach_gbpa_hwpt(s, NULL);
1020 + SMMUv3AccelState *accel = s->s_accel;
1021 +
1022 + if (!accel) {
1023 + return;
1024 + }
1025 + /* Attach a HWPT based on GBPA reset value */
1026 + smmuv3_accel_attach_gbpa_hwpt(s, NULL);
1027 +
1028 + if (accel->cmdqv_ops && accel->cmdqv_ops->reset) {
1029 + accel->cmdqv_ops->reset(s);
1030 + }
1031 }
1032
1033 static void smmuv3_accel_as_init(SMMUv3State *s)
include/hw/arm/smmuv3.h
+2
@@ -75,6 +75,8 @@ struct SMMUv3State {
75 OnOffAuto ats;
76 OasMode oas;
77 SsidSizeMode ssidsize;
78 + /* SMMU CMDQV extension */
79 + OnOffAuto cmdqv;
80
81 Notifier machine_done;
82 };