hw/arm/smmuv3: Move reset to exit phase

Currently the iommu may be reset before the devices
it protects. For example this happens with virtio-scsi-pci.
when system_reset is issued from qmp monitor: spurious
"virtio: zero sized buffers are not allowed" warnings can
be observed. This happens because outstanding DMA requests
are still happening while the SMMU gets reset.

This can also happen with VFIO devices. In that case
spurious DMA translation faults can be observed on host.

Make sure the SMMU is reset in the 'exit' phase after
all DMA capable devices have been reset during the 'enter'
or 'hold' phase.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>

Message-Id: <20250218182737.76722-4-eric.auger@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Eric Auger 2025-02-18 19:25:33 +01:00 committed by Michael S. Tsirkin
parent 2aaf48bcf2
commit e39e3f8b8d
3 changed files with 18 additions and 6 deletions

View File

@ -924,7 +924,12 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
} }
} }
static void smmu_base_reset_hold(Object *obj, ResetType type) /*
* Make sure the IOMMU is reset in 'exit' phase after
* all outstanding DMA requests have been quiesced during
* the 'enter' or 'hold' reset phases
*/
static void smmu_base_reset_exit(Object *obj, ResetType type)
{ {
SMMUState *s = ARM_SMMU(obj); SMMUState *s = ARM_SMMU(obj);
@ -949,7 +954,7 @@ static void smmu_base_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, smmu_dev_properties); device_class_set_props(dc, smmu_dev_properties);
device_class_set_parent_realize(dc, smmu_base_realize, device_class_set_parent_realize(dc, smmu_base_realize,
&sbc->parent_realize); &sbc->parent_realize);
rc->phases.hold = smmu_base_reset_hold; rc->phases.exit = smmu_base_reset_exit;
} }
static const TypeInfo smmu_base_info = { static const TypeInfo smmu_base_info = {

View File

@ -1870,13 +1870,19 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev)
} }
} }
static void smmu_reset_hold(Object *obj, ResetType type) /*
* Make sure the IOMMU is reset in 'exit' phase after
* all outstanding DMA requests have been quiesced during
* the 'enter' or 'hold' reset phases
*/
static void smmu_reset_exit(Object *obj, ResetType type)
{ {
SMMUv3State *s = ARM_SMMUV3(obj); SMMUv3State *s = ARM_SMMUV3(obj);
SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s); SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s);
if (c->parent_phases.hold) { trace_smmu_reset_exit();
c->parent_phases.hold(obj, type); if (c->parent_phases.exit) {
c->parent_phases.exit(obj, type);
} }
smmuv3_init_regs(s); smmuv3_init_regs(s);
@ -1999,7 +2005,7 @@ static void smmuv3_class_init(ObjectClass *klass, void *data)
SMMUv3Class *c = ARM_SMMUV3_CLASS(klass); SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
dc->vmsd = &vmstate_smmuv3; dc->vmsd = &vmstate_smmuv3;
resettable_class_set_parent_phases(rc, NULL, smmu_reset_hold, NULL, resettable_class_set_parent_phases(rc, NULL, NULL, smmu_reset_exit,
&c->parent_phases); &c->parent_phases);
device_class_set_parent_realize(dc, smmu_realize, device_class_set_parent_realize(dc, smmu_realize,
&c->parent_realize); &c->parent_realize);

View File

@ -56,6 +56,7 @@ smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s" smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d" smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
smmu_reset_exit(void) ""
# strongarm.c # strongarm.c
strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d" strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"