On 6/1/26 1:42 PM, Shameer Kolothum wrote:
> When CMDQV is active, the first cold-plugged VFIO device establishes
> the viommu to host SMMUv3 association, and the guest's boot-time CMDQV
> configuration (VINTFs, VCMDQs) is built on top of that association.
>
> Hot-unplugging that device would release the viommu and tear down all
> CMDQV state. Hot-plugging another device behind a different host
> SMMUv3+CMDQV would then re-bind the same vSMMUv3 to new host hardware,
> while the guest keeps using its boot-time configuration and ends up
> issuing commands to the wrong host. Block hot-unplug of the
> establishing device to avoid this; retaining the binding across unplug
> is non-trivial and not required by any current use case.
>
> Also abort at machine_done if cmdqv=on is requested but no cold-plugged
> VFIO device was present to initialize it.
>
> Reviewed-by: Nicolin Chen <[email protected]>
> Signed-off-by: Shameer Kolothum <[email protected]>
Reviewed-by: Eric Auger <[email protected]>
Eric
> ---
> hw/arm/smmuv3-accel.h | 1 +
> hw/arm/smmuv3-accel.c | 18 ++++++++++++++++++
> 2 files changed, 19 insertions(+)
>
> diff --git a/hw/arm/smmuv3-accel.h b/hw/arm/smmuv3-accel.h
> index 5fc85fb89d..dd755c394d 100644
> --- a/hw/arm/smmuv3-accel.h
> +++ b/hw/arm/smmuv3-accel.h
> @@ -84,6 +84,7 @@ typedef struct SMMUv3AccelDevice {
> IOMMUFDVdev *vdev;
> QLIST_ENTRY(SMMUv3AccelDevice) next;
> SMMUv3AccelState *s_accel;
> + Error *unplug_blocker; /* set when CMDQV is active to block hot-unplug */
> } SMMUv3AccelDevice;
>
> bool smmuv3_accel_init(SMMUv3State *s, Error **errp);
> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
> index 9c3bd4413d..80900c2521 100644
> --- a/hw/arm/smmuv3-accel.c
> +++ b/hw/arm/smmuv3-accel.c
> @@ -759,6 +759,18 @@ static bool smmuv3_accel_set_iommu_device(PCIBus *bus,
> void *opaque, int devfn,
> return false;
> }
>
> + /*
> + * CMDQV is active: block hot-unplug of the device that established the
> + * viommu association. Removing it would cause the vIOMMU to host SMMUv3
> + * association be changed via device hot-plug.
> + */
> + if (s->s_accel->cmdqv_ops) {
> + PCIDevice *pdev = pci_find_device(bus, pci_bus_num(bus), devfn);
> + error_setg(&accel_dev->unplug_blocker,
> + "CMDQV is active: removing the device that established
> the "
> + "viommu association would break the guest CMDQV");
> + qdev_add_unplug_blocker(DEVICE(pdev), accel_dev->unplug_blocker);
> + }
> done:
> accel_dev->hiodi = hiodi;
> accel_dev->s_accel = s->s_accel;
> @@ -1082,6 +1094,12 @@ static void smmuv3_accel_machine_done(Notifier
> *notifier, void *data)
> "at least one cold-plugged VFIO device");
> exit(1);
> }
> +
> + if (s->cmdqv == ON_OFF_AUTO_ON && !accel->cmdqv) {
> + error_report("arm-smmuv3 cmdqv=on requires at least one cold-plugged
> "
> + "VFIO device");
> + exit(1);
> + }
> }
>
> bool smmuv3_accel_init(SMMUv3State *s, Error **errp)