* [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device assignment
2023-07-05 16:51 [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes Eric Auger
@ 2023-07-05 16:51 ` Eric Auger
2023-07-06 9:25 ` Duan, Zhenzhong
2023-07-05 16:51 ` [PATCH v2 2/2] virtio-iommu: Rework the traces in virtio_iommu_set_page_size_mask() Eric Auger
2023-07-07 15:25 ` [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes Jean-Philippe Brucker
2 siblings, 1 reply; 5+ messages in thread
From: Eric Auger @ 2023-07-05 16:51 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, zhenzhong.duan
Cc: alex.williamson, clg, bharat.bhushan, peter.maydell
When running on a 64kB page size host and protecting a VFIO device
with the virtio-iommu, qemu crashes with this kind of message:
qemu-kvm: virtio-iommu page mask 0xfffffffffffff000 is incompatible
with mask 0x20010000
qemu: hardware error: vfio: DMA mapping failed, unable to continue
This is due to the fact the IOMMU MR corresponding to the VFIO device
is enabled very late on domain attach, after the machine init.
The device reports a minimal 64kB page size but it is too late to be
applied. virtio_iommu_set_page_size_mask() fails and this causes
vfio_listener_region_add() to end up with hw_error();
To work around this issue, we transiently enable the IOMMU MR on
machine init to collect the page size requirements and then restore
the bypass state.
Fixes: 90519b9053 ("virtio-iommu: Add bypass mode support to assigned device")
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v1 -> v2:
- check bypass if set before transiently enabling the MRs
---
include/hw/virtio/virtio-iommu.h | 2 ++
hw/virtio/virtio-iommu.c | 31 +++++++++++++++++++++++++++++--
hw/virtio/trace-events | 1 +
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h
index 2ad5ee320b..a93fc5383e 100644
--- a/include/hw/virtio/virtio-iommu.h
+++ b/include/hw/virtio/virtio-iommu.h
@@ -61,6 +61,8 @@ struct VirtIOIOMMU {
QemuRecMutex mutex;
GTree *endpoints;
bool boot_bypass;
+ Notifier machine_done;
+ bool granule_frozen;
};
#endif
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 1bbad23f4a..8d0c5e3f32 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -25,6 +25,7 @@
#include "hw/virtio/virtio.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
+#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "trace.h"
@@ -1106,12 +1107,12 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
}
/*
- * After the machine is finalized, we can't change the mask anymore. If by
+ * Once the granule is frozen we can't change the mask anymore. If by
* chance the hotplugged device supports the same granule, we can still
* accept it. Having a different masks is possible but the guest will use
* sub-optimal block sizes, so warn about it.
*/
- if (phase_check(PHASE_MACHINE_READY)) {
+ if (s->granule_frozen) {
int new_granule = ctz64(new_mask);
int cur_granule = ctz64(cur_mask);
@@ -1146,6 +1147,28 @@ static void virtio_iommu_system_reset(void *opaque)
}
+static void virtio_iommu_freeze_granule(Notifier *notifier, void *data)
+{
+ VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done);
+ int granule;
+
+ if (likely(s->config.bypass)) {
+ /*
+ * Transient IOMMU MR enable to collect page_size_mask requirements
+ * through memory_region_iommu_set_page_size_mask() called by
+ * VFIO region_add() callback
+ */
+ s->config.bypass = false;
+ virtio_iommu_switch_address_space_all(s);
+ /* restore default */
+ s->config.bypass = true;
+ virtio_iommu_switch_address_space_all(s);
+ }
+ s->granule_frozen = true;
+ granule = ctz64(s->config.page_size_mask);
+ trace_virtio_iommu_freeze_granule(BIT(granule));
+}
+
static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -1189,6 +1212,9 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!");
}
+ s->machine_done.notify = virtio_iommu_freeze_granule;
+ qemu_add_machine_init_done_notifier(&s->machine_done);
+
qemu_register_reset(virtio_iommu_system_reset, s);
}
@@ -1198,6 +1224,7 @@ static void virtio_iommu_device_unrealize(DeviceState *dev)
VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
qemu_unregister_reset(virtio_iommu_system_reset, s);
+ qemu_remove_machine_init_done_notifier(&s->machine_done);
g_hash_table_destroy(s->as_by_busptr);
if (s->domains) {
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 8f8d05cf9b..68b752e304 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -131,6 +131,7 @@ virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "m
virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s"
virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s"
virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
+virtio_iommu_freeze_granule(uint64_t page_size_mask) "granule set to 0x%"PRIx64
# virtio-mem.c
virtio_mem_send_response(uint16_t type) "type=%" PRIu16
--
2.38.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* RE: [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device assignment
2023-07-05 16:51 ` [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device assignment Eric Auger
@ 2023-07-06 9:25 ` Duan, Zhenzhong
0 siblings, 0 replies; 5+ messages in thread
From: Duan, Zhenzhong @ 2023-07-06 9:25 UTC (permalink / raw)
To: Eric Auger, eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org
Cc: alex.williamson@redhat.com, clg@redhat.com,
bharat.bhushan@nxp.com, peter.maydell@linaro.org
>-----Original Message-----
>From: Eric Auger <eric.auger@redhat.com>
>Sent: Thursday, July 6, 2023 12:51 AM
>Subject: [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device
>assignment
>
>When running on a 64kB page size host and protecting a VFIO device with the
>virtio-iommu, qemu crashes with this kind of message:
>
>qemu-kvm: virtio-iommu page mask 0xfffffffffffff000 is incompatible with
>mask 0x20010000
>qemu: hardware error: vfio: DMA mapping failed, unable to continue
>
>This is due to the fact the IOMMU MR corresponding to the VFIO device is
>enabled very late on domain attach, after the machine init.
>The device reports a minimal 64kB page size but it is too late to be applied.
>virtio_iommu_set_page_size_mask() fails and this causes
>vfio_listener_region_add() to end up with hw_error();
>
>To work around this issue, we transiently enable the IOMMU MR on machine
>init to collect the page size requirements and then restore the bypass state.
>
>Fixes: 90519b9053 ("virtio-iommu: Add bypass mode support to assigned
>device")
>Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Thanks
Zhenzhong
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] virtio-iommu: Rework the traces in virtio_iommu_set_page_size_mask()
2023-07-05 16:51 [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes Eric Auger
2023-07-05 16:51 ` [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device assignment Eric Auger
@ 2023-07-05 16:51 ` Eric Auger
2023-07-07 15:25 ` [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes Jean-Philippe Brucker
2 siblings, 0 replies; 5+ messages in thread
From: Eric Auger @ 2023-07-05 16:51 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, zhenzhong.duan
Cc: alex.williamson, clg, bharat.bhushan, peter.maydell
The current error messages in virtio_iommu_set_page_size_mask()
sound quite similar for different situations and miss the IOMMU
memory region that causes the issue.
Clarify them and rework the comment.
Also remove the trace when the new page_size_mask is not applied as
the current frozen granule is kept. This message is rather confusing
for the end user and anyway the current granule would have been used
by the driver.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
hw/virtio/virtio-iommu.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 8d0c5e3f32..4b711ddd09 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -1101,29 +1101,24 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
new_mask);
if ((cur_mask & new_mask) == 0) {
- error_setg(errp, "virtio-iommu page mask 0x%"PRIx64
- " is incompatible with mask 0x%"PRIx64, cur_mask, new_mask);
+ error_setg(errp, "virtio-iommu %s reports a page size mask 0x%"PRIx64
+ " incompatible with currently supported mask 0x%"PRIx64,
+ mr->parent_obj.name, new_mask, cur_mask);
return -1;
}
/*
* Once the granule is frozen we can't change the mask anymore. If by
* chance the hotplugged device supports the same granule, we can still
- * accept it. Having a different masks is possible but the guest will use
- * sub-optimal block sizes, so warn about it.
+ * accept it.
*/
if (s->granule_frozen) {
- int new_granule = ctz64(new_mask);
int cur_granule = ctz64(cur_mask);
- if (new_granule != cur_granule) {
- error_setg(errp, "virtio-iommu page mask 0x%"PRIx64
- " is incompatible with mask 0x%"PRIx64, cur_mask,
- new_mask);
+ if (!(BIT(cur_granule) & new_mask)) {
+ error_setg(errp, "virtio-iommu %s does not support frozen granule 0x%"PRIx64,
+ mr->parent_obj.name, BIT(cur_granule));
return -1;
- } else if (new_mask != cur_mask) {
- warn_report("virtio-iommu page mask 0x%"PRIx64
- " does not match 0x%"PRIx64, cur_mask, new_mask);
}
return 0;
}
--
2.38.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes
2023-07-05 16:51 [PATCH v2 0/2] VIRTIO-IOMMU/VFIO page size related fixes Eric Auger
2023-07-05 16:51 ` [PATCH v2 1/2] virtio-iommu: Fix 64kB host page size VFIO device assignment Eric Auger
2023-07-05 16:51 ` [PATCH v2 2/2] virtio-iommu: Rework the traces in virtio_iommu_set_page_size_mask() Eric Auger
@ 2023-07-07 15:25 ` Jean-Philippe Brucker
2 siblings, 0 replies; 5+ messages in thread
From: Jean-Philippe Brucker @ 2023-07-07 15:25 UTC (permalink / raw)
To: Eric Auger
Cc: eric.auger.pro, qemu-devel, qemu-arm, mst, zhenzhong.duan,
alex.williamson, clg, bharat.bhushan, peter.maydell
On Wed, Jul 05, 2023 at 06:51:16PM +0200, Eric Auger wrote:
> When assigning a host device and protecting it with the virtio-iommu we may
> end up with qemu crashing with
>
> qemu-kvm: virtio-iommu page mask 0xfffffffffffff000 is incompatible
> with mask 0x20010000
> qemu: hardware error: vfio: DMA mapping failed, unable to continue
>
> This happens if the host features a 64kB page size and constraints
> the physical IOMMU to use a 64kB page size. By default 4kB granule is used
> by the qemu virtio-iommu device and this latter becomes aware of the 64kB
> requirement too late, after the machine init, when the vfio device domain is
> attached. virtio_iommu_set_page_size_mask() fails and this causes
> vfio_listener_region_add() to end up with hw_error(). Currently the
> granule is global to all domains.
>
> To work around this issue, despite the IOMMU MR may be bypassed, we
> transiently enable it on machine init done to get vfio_listener_region_add
> and virtio_iommu_set_page_size_mask called ealier, before the domain
> attach. That way the page size requirement can be taken into account
> before the guest gets started.
>
> Also get benefit of this series to do some cleanups in some traces
> which may confuse the end user.
For both patches:
Reviewed-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Tested-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
^ permalink raw reply [flat|nested] 5+ messages in thread