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]> --- 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) -- 2.43.0
