* [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-14 9:13 ` Cédric Le Goater
2024-06-13 9:20 ` [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks Eric Auger
` (5 subsequent siblings)
6 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Store the agent device (VFIO or VDPA) in the host IOMMU device.
This will allow easy access to some of its resources.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
include/sysemu/host_iommu_device.h | 1 +
hw/vfio/container.c | 1 +
hw/vfio/iommufd.c | 2 ++
3 files changed, 4 insertions(+)
diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h
index a57873958b..3e5f058e7b 100644
--- a/include/sysemu/host_iommu_device.h
+++ b/include/sysemu/host_iommu_device.h
@@ -34,6 +34,7 @@ struct HostIOMMUDevice {
Object parent_obj;
char *name;
+ void *agent; /* pointer to agent device, ie. VFIO or VDPA device */
HostIOMMUDeviceCaps caps;
};
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 26e6f7fb4f..b728b978a2 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1145,6 +1145,7 @@ static bool hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
hiod->name = g_strdup(vdev->name);
hiod->caps.aw_bits = vfio_device_get_aw_bits(vdev);
+ hiod->agent = opaque;
return true;
}
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 409ed3dcc9..dbdae1adbb 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -631,6 +631,8 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
struct iommu_hw_info_vtd vtd;
} data;
+ hiod->agent = opaque;
+
if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid,
&type, &data, sizeof(data), errp)) {
return false;
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-13 9:20 ` [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent Eric Auger
@ 2024-06-14 9:13 ` Cédric Le Goater
2024-06-14 10:01 ` Eric Auger
0 siblings, 1 reply; 22+ messages in thread
From: Cédric Le Goater @ 2024-06-14 9:13 UTC (permalink / raw)
To: Eric Auger, eric.auger.pro, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
On 6/13/24 11:20 AM, Eric Auger wrote:
> Store the agent device (VFIO or VDPA) in the host IOMMU device.
> This will allow easy access to some of its resources.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> ---
> include/sysemu/host_iommu_device.h | 1 +
> hw/vfio/container.c | 1 +
> hw/vfio/iommufd.c | 2 ++
> 3 files changed, 4 insertions(+)
>
> diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h
> index a57873958b..3e5f058e7b 100644
> --- a/include/sysemu/host_iommu_device.h
> +++ b/include/sysemu/host_iommu_device.h
> @@ -34,6 +34,7 @@ struct HostIOMMUDevice {
> Object parent_obj;
>
> char *name;
> + void *agent; /* pointer to agent device, ie. VFIO or VDPA device */
> HostIOMMUDeviceCaps caps;
> };
>
> diff --git a/hw/vfio/container.c b/hw/vfio/container.c
> index 26e6f7fb4f..b728b978a2 100644
> --- a/hw/vfio/container.c
> +++ b/hw/vfio/container.c
> @@ -1145,6 +1145,7 @@ static bool hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
>
> hiod->name = g_strdup(vdev->name);
> hiod->caps.aw_bits = vfio_device_get_aw_bits(vdev);
> + hiod->agent = opaque;
>
> return true;
> }
> diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
> index 409ed3dcc9..dbdae1adbb 100644
> --- a/hw/vfio/iommufd.c
> +++ b/hw/vfio/iommufd.c
> @@ -631,6 +631,8 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
> struct iommu_hw_info_vtd vtd;
> } data;
>
> + hiod->agent = opaque;
> +
This opaque pointer could be assigned in vfio_attach_device().
Talking of which, why are we passing a 'VFIODevice *' parameter to
HostIOMMUDeviceClass::realize ? I don't see a good reason
I think a 'VFIOContainerBase *' would be more appropriate since
'HostIOMMUDevice' represents a device on the host which is common
to all VFIO devices.
In that case, HostIOMMUDevice::agent wouldn't need to be opaque
anymore. It could simply be a 'VFIOContainerBase *' and
hiod_legacy_vfio_get_iova_ranges() in patch 3 would grab the
'iova_ranges' from the 'VFIOContainerBase *' directly.
This means some rework :
* vfio_device_get_aw_bits() would use a 'VFIOContainerBase *' instead.
* HostIOMMUDevice::name would be removed. This is just for error messages.
* hiod_iommufd_vfio_realize() would use VFIOIOMMUFDContainer::be.
That said, I think we need the QOMification changes first.
Thanks,
C.
> if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid,
> &type, &data, sizeof(data), errp)) {
> return false;
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-14 9:13 ` Cédric Le Goater
@ 2024-06-14 10:01 ` Eric Auger
2024-06-14 10:04 ` Cédric Le Goater
0 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-14 10:01 UTC (permalink / raw)
To: Cédric Le Goater, eric.auger.pro, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Hi Cédric,
On 6/14/24 11:13, Cédric Le Goater wrote:
> On 6/13/24 11:20 AM, Eric Auger wrote:
>> Store the agent device (VFIO or VDPA) in the host IOMMU device.
>> This will allow easy access to some of its resources.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>> Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
>> ---
>> include/sysemu/host_iommu_device.h | 1 +
>> hw/vfio/container.c | 1 +
>> hw/vfio/iommufd.c | 2 ++
>> 3 files changed, 4 insertions(+)
>>
>> diff --git a/include/sysemu/host_iommu_device.h
>> b/include/sysemu/host_iommu_device.h
>> index a57873958b..3e5f058e7b 100644
>> --- a/include/sysemu/host_iommu_device.h
>> +++ b/include/sysemu/host_iommu_device.h
>> @@ -34,6 +34,7 @@ struct HostIOMMUDevice {
>> Object parent_obj;
>> char *name;
>> + void *agent; /* pointer to agent device, ie. VFIO or VDPA device */
>> HostIOMMUDeviceCaps caps;
>> };
>> diff --git a/hw/vfio/container.c b/hw/vfio/container.c
>> index 26e6f7fb4f..b728b978a2 100644
>> --- a/hw/vfio/container.c
>> +++ b/hw/vfio/container.c
>> @@ -1145,6 +1145,7 @@ static bool
>> hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
>> hiod->name = g_strdup(vdev->name);
>> hiod->caps.aw_bits = vfio_device_get_aw_bits(vdev);
>> + hiod->agent = opaque;
>> return true;
>> }
>> diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
>> index 409ed3dcc9..dbdae1adbb 100644
>> --- a/hw/vfio/iommufd.c
>> +++ b/hw/vfio/iommufd.c
>> @@ -631,6 +631,8 @@ static bool
>> hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
>> struct iommu_hw_info_vtd vtd;
>> } data;
>> + hiod->agent = opaque;
>> +
>
> This opaque pointer could be assigned in vfio_attach_device().
>
> Talking of which, why are we passing a 'VFIODevice *' parameter to
> HostIOMMUDeviceClass::realize ? I don't see a good reason
>
> I think a 'VFIOContainerBase *' would be more appropriate since
> 'HostIOMMUDevice' represents a device on the host which is common
> to all VFIO devices.
>
> In that case, HostIOMMUDevice::agent wouldn't need to be opaque
> anymore. It could simply be a 'VFIOContainerBase *' and
> hiod_legacy_vfio_get_iova_ranges() in patch 3 would grab the
> 'iova_ranges' from the 'VFIOContainerBase *' directly.
>
> This means some rework :
>
> * vfio_device_get_aw_bits() would use a 'VFIOContainerBase *' instead.
> * HostIOMMUDevice::name would be removed. This is just for error
> messages.
> * hiod_iommufd_vfio_realize() would use VFIOIOMMUFDContainer::be.
>
> That said, I think we need the QOMification changes first.
OK I need to review your series first. At the moment I have just
addressed Zhenzhong's comment in v4, just sent.
Thanks
Eric
>
> Thanks,
>
> C.
>
>
>
>
>> if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid,
>> &type, &data,
>> sizeof(data), errp)) {
>> return false;
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-14 10:01 ` Eric Auger
@ 2024-06-14 10:04 ` Cédric Le Goater
2024-06-17 1:25 ` Duan, Zhenzhong
0 siblings, 1 reply; 22+ messages in thread
From: Cédric Le Goater @ 2024-06-14 10:04 UTC (permalink / raw)
To: eric.auger, eric.auger.pro, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
>> Talking of which, why are we passing a 'VFIODevice *' parameter to
>> HostIOMMUDeviceClass::realize ? I don't see a good reason
>>
>> I think a 'VFIOContainerBase *' would be more appropriate since
>> 'HostIOMMUDevice' represents a device on the host which is common
>> to all VFIO devices.
>>
>> In that case, HostIOMMUDevice::agent wouldn't need to be opaque
>> anymore. It could simply be a 'VFIOContainerBase *' and
>> hiod_legacy_vfio_get_iova_ranges() in patch 3 would grab the
>> 'iova_ranges' from the 'VFIOContainerBase *' directly.
>>
>> This means some rework :
>>
>> * vfio_device_get_aw_bits() would use a 'VFIOContainerBase *' instead.
>> * HostIOMMUDevice::name would be removed. This is just for error
>> messages.
>> * hiod_iommufd_vfio_realize() would use VFIOIOMMUFDContainer::be.
>>
>> That said, I think we need the QOMification changes first.
>
> OK I need to review your series first. At the moment I have just
> addressed Zhenzhong's comment in v4, just sent.
Yep. Just take a look at mine. If both of you agree with above
proposal, I can care of it and resend all 3. It's a small change.
Thanks,
C.
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-14 10:04 ` Cédric Le Goater
@ 2024-06-17 1:25 ` Duan, Zhenzhong
2024-06-17 6:23 ` Cédric Le Goater
0 siblings, 1 reply; 22+ messages in thread
From: Duan, Zhenzhong @ 2024-06-17 1:25 UTC (permalink / raw)
To: Cédric Le Goater, eric.auger@redhat.com,
eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org,
peter.maydell@linaro.org, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
Hi Cédric,
>-----Original Message-----
>From: Cédric Le Goater <clg@redhat.com>
>Sent: Friday, June 14, 2024 6:05 PM
>To: eric.auger@redhat.com; eric.auger.pro@gmail.com; qemu-
>devel@nongnu.org; qemu-arm@nongnu.org; mst@redhat.com; jean-
>philippe@linaro.org; peter.maydell@linaro.org; yanghliu@redhat.com; Duan,
>Zhenzhong <zhenzhong.duan@intel.com>
>Cc: alex.williamson@redhat.com; jasowang@redhat.com;
>pbonzini@redhat.com; berrange@redhat.com
>Subject: Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
>
>
>>> Talking of which, why are we passing a 'VFIODevice *' parameter to
>>> HostIOMMUDeviceClass::realize ? I don't see a good reason
>>>
>>> I think a 'VFIOContainerBase *' would be more appropriate since
>>> 'HostIOMMUDevice' represents a device on the host which is common
>>> to all VFIO devices.
>>>
>>> In that case, HostIOMMUDevice::agent wouldn't need to be opaque
>>> anymore. It could simply be a 'VFIOContainerBase *' and
>>> hiod_legacy_vfio_get_iova_ranges() in patch 3 would grab the
>>> 'iova_ranges' from the 'VFIOContainerBase *' directly.
>>>
>>> This means some rework :
>>>
>>> * vfio_device_get_aw_bits() would use a 'VFIOContainerBase *' instead.
>>> * HostIOMMUDevice::name would be removed. This is just for error
>>> messages.
>>> * hiod_iommufd_vfio_realize() would use VFIOIOMMUFDContainer::be.
>>>
>>> That said, I think we need the QOMification changes first.
>>
>> OK I need to review your series first. At the moment I have just
>> addressed Zhenzhong's comment in v4, just sent.
>
>Yep. Just take a look at mine. If both of you agree with above
>proposal, I can care of it and resend all 3. It's a small change.
I would suggest using opaque pointer and VFIODevice for two reasons,
1. in nesting series vIOMMU needs to attach/detaching hwpt which is VFIODevice operations.
See https://github.com/yiliu1765/qemu/commit/3ca559d35adc9840555e361a56708af4c6338b3d
2. If we plan to support VDPA Device in future, the opaque pointer can also point
to an VDPADevice structure.
Thanks
Zhenzhong
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
2024-06-17 1:25 ` Duan, Zhenzhong
@ 2024-06-17 6:23 ` Cédric Le Goater
0 siblings, 0 replies; 22+ messages in thread
From: Cédric Le Goater @ 2024-06-17 6:23 UTC (permalink / raw)
To: Duan, Zhenzhong, eric.auger@redhat.com, eric.auger.pro@gmail.com,
qemu-devel@nongnu.org, qemu-arm@nongnu.org, mst@redhat.com,
jean-philippe@linaro.org, peter.maydell@linaro.org,
yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
On 6/17/24 3:25 AM, Duan, Zhenzhong wrote:
> Hi Cédric,
>
>> -----Original Message-----
>> From: Cédric Le Goater <clg@redhat.com>
>> Sent: Friday, June 14, 2024 6:05 PM
>> To: eric.auger@redhat.com; eric.auger.pro@gmail.com; qemu-
>> devel@nongnu.org; qemu-arm@nongnu.org; mst@redhat.com; jean-
>> philippe@linaro.org; peter.maydell@linaro.org; yanghliu@redhat.com; Duan,
>> Zhenzhong <zhenzhong.duan@intel.com>
>> Cc: alex.williamson@redhat.com; jasowang@redhat.com;
>> pbonzini@redhat.com; berrange@redhat.com
>> Subject: Re: [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent
>>
>>
>>>> Talking of which, why are we passing a 'VFIODevice *' parameter to
>>>> HostIOMMUDeviceClass::realize ? I don't see a good reason
>>>>
>>>> I think a 'VFIOContainerBase *' would be more appropriate since
>>>> 'HostIOMMUDevice' represents a device on the host which is common
>>>> to all VFIO devices.
>>>>
>>>> In that case, HostIOMMUDevice::agent wouldn't need to be opaque
>>>> anymore. It could simply be a 'VFIOContainerBase *' and
>>>> hiod_legacy_vfio_get_iova_ranges() in patch 3 would grab the
>>>> 'iova_ranges' from the 'VFIOContainerBase *' directly.
>>>>
>>>> This means some rework :
>>>>
>>>> * vfio_device_get_aw_bits() would use a 'VFIOContainerBase *' instead.
>>>> * HostIOMMUDevice::name would be removed. This is just for error
>>>> messages.
>>>> * hiod_iommufd_vfio_realize() would use VFIOIOMMUFDContainer::be.
>>>>
>>>> That said, I think we need the QOMification changes first.
>>>
>>> OK I need to review your series first. At the moment I have just
>>> addressed Zhenzhong's comment in v4, just sent.
>>
>> Yep. Just take a look at mine. If both of you agree with above
>> proposal, I can care of it and resend all 3. It's a small change.
>
> I would suggest using opaque pointer and VFIODevice for two reasons,
> 1. in nesting series vIOMMU needs to attach/detaching hwpt which is VFIODevice operations.
> See https://github.com/yiliu1765/qemu/commit/3ca559d35adc9840555e361a56708af4c6338b3d
OK. I realized later on that we needed the device id anyhow.
>
> 2. If we plan to support VDPA Device in future, the opaque pointer can also point
> to an VDPADevice structure.
Thanks,
C.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
2024-06-13 9:20 ` [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-13 9:57 ` Duan, Zhenzhong
2024-06-13 9:20 ` [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges callback Eric Auger
` (4 subsequent siblings)
6 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Implement PCIIOMMUOPs [set|unset]_iommu_device() callbacks.
In set(), a VirtioHostIOMMUDevice is allocated which holds
a reference to the HostIOMMUDevice. This object is stored in a hash
table indexed by PCI BDF. The handle to the Host IOMMU device
will allow to retrieve information related to the physical IOMMU.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v2 -> v3:
- include host_iommu_device.h in virtio-iommu.h header
- introduce hiod_destroy() and fix UAF in
virtio_iommu_unset_iommu_device()
---
include/hw/virtio/virtio-iommu.h | 10 ++++
hw/virtio/virtio-iommu.c | 90 ++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+)
diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h
index 83a52cc446..a5926de947 100644
--- a/include/hw/virtio/virtio-iommu.h
+++ b/include/hw/virtio/virtio-iommu.h
@@ -25,6 +25,7 @@
#include "hw/pci/pci.h"
#include "qom/object.h"
#include "qapi/qapi-types-virtio.h"
+#include "sysemu/host_iommu_device.h"
#define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
#define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-pci"
@@ -45,6 +46,14 @@ typedef struct IOMMUDevice {
bool probe_done;
} IOMMUDevice;
+typedef struct VirtioHostIOMMUDevice {
+ void *viommu;
+ PCIBus *bus;
+ uint8_t devfn;
+ HostIOMMUDevice *dev;
+ QLIST_ENTRY(VirtioHostIOMMUDevice) next;
+} VirtioHostIOMMUDevice;
+
typedef struct IOMMUPciBus {
PCIBus *bus;
IOMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc */
@@ -57,6 +66,7 @@ struct VirtIOIOMMU {
struct virtio_iommu_config config;
uint64_t features;
GHashTable *as_by_busptr;
+ GHashTable *host_iommu_devices;
IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX];
PCIBus *primary_bus;
ReservedRegion *prop_resv_regions;
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 1326c6ec41..db842555c8 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -69,6 +69,11 @@ typedef struct VirtIOIOMMUMapping {
uint32_t flags;
} VirtIOIOMMUMapping;
+struct hiod_key {
+ PCIBus *bus;
+ uint8_t devfn;
+};
+
static inline uint16_t virtio_iommu_get_bdf(IOMMUDevice *dev)
{
return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn);
@@ -462,8 +467,90 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
return &sdev->as;
}
+static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
+{
+ const struct hiod_key *key1 = v1;
+ const struct hiod_key *key2 = v2;
+
+ return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
+}
+
+static guint hiod_hash(gconstpointer v)
+{
+ const struct hiod_key *key = v;
+ guint value = (guint)(uintptr_t)key->bus;
+
+ return (guint)(value << 8 | key->devfn);
+}
+
+static void hiod_destroy(gpointer v)
+{
+ object_unref(v);
+}
+
+static VirtioHostIOMMUDevice *
+get_host_iommu_device(VirtIOIOMMU *viommu, PCIBus *bus, int devfn) {
+ struct hiod_key key = {
+ .bus = bus,
+ .devfn = devfn,
+ };
+
+ return g_hash_table_lookup(viommu->host_iommu_devices, &key);
+}
+
+static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
+ HostIOMMUDevice *hiod, Error **errp)
+{
+ VirtIOIOMMU *viommu = opaque;
+ VirtioHostIOMMUDevice *vhiod;
+ struct hiod_key *new_key;
+
+ assert(hiod);
+
+ vhiod = get_host_iommu_device(viommu, bus, devfn);
+ if (vhiod) {
+ error_setg(errp, "VirtioHostIOMMUDevice already exists");
+ return false;
+ }
+
+ vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
+ vhiod->bus = bus;
+ vhiod->devfn = (uint8_t)devfn;
+ vhiod->viommu = viommu;
+ vhiod->dev = hiod;
+
+ new_key = g_malloc(sizeof(*new_key));
+ new_key->bus = bus;
+ new_key->devfn = devfn;
+
+ object_ref(hiod);
+ g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
+
+ return true;
+}
+
+static void
+virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
+{
+ VirtIOIOMMU *viommu = opaque;
+ VirtioHostIOMMUDevice *vhiod;
+ struct hiod_key key = {
+ .bus = bus,
+ .devfn = devfn,
+ };
+
+ vhiod = g_hash_table_lookup(viommu->host_iommu_devices, &key);
+ if (!vhiod) {
+ return;
+ }
+
+ g_hash_table_remove(viommu->host_iommu_devices, &key);
+}
+
static const PCIIOMMUOps virtio_iommu_ops = {
.get_address_space = virtio_iommu_find_add_as,
+ .set_iommu_device = virtio_iommu_set_iommu_device,
+ .unset_iommu_device = virtio_iommu_unset_iommu_device,
};
static int virtio_iommu_attach(VirtIOIOMMU *s,
@@ -1357,6 +1444,9 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free);
+ s->host_iommu_devices = g_hash_table_new_full(hiod_hash, hiod_equal,
+ g_free, hiod_destroy);
+
if (s->primary_bus) {
pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s);
} else {
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* RE: [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks
2024-06-13 9:20 ` [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks Eric Auger
@ 2024-06-13 9:57 ` Duan, Zhenzhong
2024-06-14 7:35 ` Cédric Le Goater
2024-06-14 7:48 ` Eric Auger
0 siblings, 2 replies; 22+ messages in thread
From: Duan, Zhenzhong @ 2024-06-13 9:57 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,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
>-----Original Message-----
>From: Eric Auger <eric.auger@redhat.com>
>Subject: [PATCH v3 2/7] virtio-iommu: Implement
>set|unset]_iommu_device() callbacks
>
>Implement PCIIOMMUOPs [set|unset]_iommu_device() callbacks.
>In set(), a VirtioHostIOMMUDevice is allocated which holds
>a reference to the HostIOMMUDevice. This object is stored in a hash
>table indexed by PCI BDF. The handle to the Host IOMMU device
>will allow to retrieve information related to the physical IOMMU.
>
>Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
>---
>
>v2 -> v3:
>- include host_iommu_device.h in virtio-iommu.h header
>- introduce hiod_destroy() and fix UAF in
> virtio_iommu_unset_iommu_device()
>---
> include/hw/virtio/virtio-iommu.h | 10 ++++
> hw/virtio/virtio-iommu.c | 90
>++++++++++++++++++++++++++++++++
> 2 files changed, 100 insertions(+)
>
>diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-
>iommu.h
>index 83a52cc446..a5926de947 100644
>--- a/include/hw/virtio/virtio-iommu.h
>+++ b/include/hw/virtio/virtio-iommu.h
>@@ -25,6 +25,7 @@
> #include "hw/pci/pci.h"
> #include "qom/object.h"
> #include "qapi/qapi-types-virtio.h"
>+#include "sysemu/host_iommu_device.h"
>
> #define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
> #define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-pci"
>@@ -45,6 +46,14 @@ typedef struct IOMMUDevice {
> bool probe_done;
> } IOMMUDevice;
>
>+typedef struct VirtioHostIOMMUDevice {
>+ void *viommu;
>+ PCIBus *bus;
>+ uint8_t devfn;
>+ HostIOMMUDevice *dev;
>+ QLIST_ENTRY(VirtioHostIOMMUDevice) next;
>+} VirtioHostIOMMUDevice;
Do you have plan to use the elements in VirtioHostIOMMUDevice?
>+
> typedef struct IOMMUPciBus {
> PCIBus *bus;
> IOMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc
>*/
>@@ -57,6 +66,7 @@ struct VirtIOIOMMU {
> struct virtio_iommu_config config;
> uint64_t features;
> GHashTable *as_by_busptr;
>+ GHashTable *host_iommu_devices;
> IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX];
> PCIBus *primary_bus;
> ReservedRegion *prop_resv_regions;
>diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>index 1326c6ec41..db842555c8 100644
>--- a/hw/virtio/virtio-iommu.c
>+++ b/hw/virtio/virtio-iommu.c
>@@ -69,6 +69,11 @@ typedef struct VirtIOIOMMUMapping {
> uint32_t flags;
> } VirtIOIOMMUMapping;
>
>+struct hiod_key {
>+ PCIBus *bus;
>+ uint8_t devfn;
>+};
>+
> static inline uint16_t virtio_iommu_get_bdf(IOMMUDevice *dev)
> {
> return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn);
>@@ -462,8 +467,90 @@ static AddressSpace
>*virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
> return &sdev->as;
> }
>
>+static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
>+{
>+ const struct hiod_key *key1 = v1;
>+ const struct hiod_key *key2 = v2;
>+
>+ return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
>+}
>+
>+static guint hiod_hash(gconstpointer v)
>+{
>+ const struct hiod_key *key = v;
>+ guint value = (guint)(uintptr_t)key->bus;
>+
>+ return (guint)(value << 8 | key->devfn);
>+}
>+
>+static void hiod_destroy(gpointer v)
>+{
>+ object_unref(v);
This is a bit different from intel_iommu, here v represents VirtioHostIOMMUDevice *.
Thanks
Zhenzhong
>+}
>+
>+static VirtioHostIOMMUDevice *
>+get_host_iommu_device(VirtIOIOMMU *viommu, PCIBus *bus, int devfn) {
>+ struct hiod_key key = {
>+ .bus = bus,
>+ .devfn = devfn,
>+ };
>+
>+ return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>+}
>+
>+static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>int devfn,
>+ HostIOMMUDevice *hiod, Error **errp)
>+{
>+ VirtIOIOMMU *viommu = opaque;
>+ VirtioHostIOMMUDevice *vhiod;
>+ struct hiod_key *new_key;
>+
>+ assert(hiod);
>+
>+ vhiod = get_host_iommu_device(viommu, bus, devfn);
>+ if (vhiod) {
>+ error_setg(errp, "VirtioHostIOMMUDevice already exists");
>+ return false;
>+ }
>+
>+ vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>+ vhiod->bus = bus;
>+ vhiod->devfn = (uint8_t)devfn;
>+ vhiod->viommu = viommu;
>+ vhiod->dev = hiod;
>+
>+ new_key = g_malloc(sizeof(*new_key));
>+ new_key->bus = bus;
>+ new_key->devfn = devfn;
>+
>+ object_ref(hiod);
>+ g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>+
>+ return true;
>+}
>+
>+static void
>+virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
>+{
>+ VirtIOIOMMU *viommu = opaque;
>+ VirtioHostIOMMUDevice *vhiod;
>+ struct hiod_key key = {
>+ .bus = bus,
>+ .devfn = devfn,
>+ };
>+
>+ vhiod = g_hash_table_lookup(viommu->host_iommu_devices, &key);
>+ if (!vhiod) {
>+ return;
>+ }
>+
>+ g_hash_table_remove(viommu->host_iommu_devices, &key);
>+}
>+
> static const PCIIOMMUOps virtio_iommu_ops = {
> .get_address_space = virtio_iommu_find_add_as,
>+ .set_iommu_device = virtio_iommu_set_iommu_device,
>+ .unset_iommu_device = virtio_iommu_unset_iommu_device,
> };
>
> static int virtio_iommu_attach(VirtIOIOMMU *s,
>@@ -1357,6 +1444,9 @@ static void
>virtio_iommu_device_realize(DeviceState *dev, Error **errp)
>
> s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free);
>
>+ s->host_iommu_devices = g_hash_table_new_full(hiod_hash,
>hiod_equal,
>+ g_free, hiod_destroy);
>+
> if (s->primary_bus) {
> pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s);
> } else {
>--
>2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks
2024-06-13 9:57 ` Duan, Zhenzhong
@ 2024-06-14 7:35 ` Cédric Le Goater
2024-06-14 7:48 ` Eric Auger
1 sibling, 0 replies; 22+ messages in thread
From: Cédric Le Goater @ 2024-06-14 7:35 UTC (permalink / raw)
To: Duan, Zhenzhong, Eric Auger, eric.auger.pro@gmail.com,
qemu-devel@nongnu.org, qemu-arm@nongnu.org, mst@redhat.com,
jean-philippe@linaro.org, peter.maydell@linaro.org,
yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
On 6/13/24 11:57 AM, Duan, Zhenzhong wrote:
>
>
>> -----Original Message-----
>> From: Eric Auger <eric.auger@redhat.com>
>> Subject: [PATCH v3 2/7] virtio-iommu: Implement
>> set|unset]_iommu_device() callbacks
>>
>> Implement PCIIOMMUOPs [set|unset]_iommu_device() callbacks.
>> In set(), a VirtioHostIOMMUDevice is allocated which holds
>> a reference to the HostIOMMUDevice. This object is stored in a hash
>> table indexed by PCI BDF. The handle to the Host IOMMU device
>> will allow to retrieve information related to the physical IOMMU.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>>
>> v2 -> v3:
>> - include host_iommu_device.h in virtio-iommu.h header
>> - introduce hiod_destroy() and fix UAF in
>> virtio_iommu_unset_iommu_device()
>> ---
>> include/hw/virtio/virtio-iommu.h | 10 ++++
>> hw/virtio/virtio-iommu.c | 90
>> ++++++++++++++++++++++++++++++++
>> 2 files changed, 100 insertions(+)
>>
>> diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-
>> iommu.h
>> index 83a52cc446..a5926de947 100644
>> --- a/include/hw/virtio/virtio-iommu.h
>> +++ b/include/hw/virtio/virtio-iommu.h
>> @@ -25,6 +25,7 @@
>> #include "hw/pci/pci.h"
>> #include "qom/object.h"
>> #include "qapi/qapi-types-virtio.h"
>> +#include "sysemu/host_iommu_device.h"
>>
>> #define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
>> #define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-pci"
>> @@ -45,6 +46,14 @@ typedef struct IOMMUDevice {
>> bool probe_done;
>> } IOMMUDevice;
>>
>> +typedef struct VirtioHostIOMMUDevice {
>> + void *viommu;
>> + PCIBus *bus;
>> + uint8_t devfn;
>> + HostIOMMUDevice *dev;
>> + QLIST_ENTRY(VirtioHostIOMMUDevice) next;
>> +} VirtioHostIOMMUDevice;
>
> Do you have plan to use the elements in VirtioHostIOMMUDevice?
Indeed.
It would be better to avoid the unused struct definition. If removed,
the new vtd and virtio un/set_iommu_device ops become very similar and
there could be a common shared framework. Some of it could be handled
in the PCI subsystem probably ?
Thanks,
C.
>
>> +
>> typedef struct IOMMUPciBus {
>> PCIBus *bus;
>> IOMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc
>> */
>> @@ -57,6 +66,7 @@ struct VirtIOIOMMU {
>> struct virtio_iommu_config config;
>> uint64_t features;
>> GHashTable *as_by_busptr;
>> + GHashTable *host_iommu_devices;
>> IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX];
>> PCIBus *primary_bus;
>> ReservedRegion *prop_resv_regions;
>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>> index 1326c6ec41..db842555c8 100644
>> --- a/hw/virtio/virtio-iommu.c
>> +++ b/hw/virtio/virtio-iommu.c
>> @@ -69,6 +69,11 @@ typedef struct VirtIOIOMMUMapping {
>> uint32_t flags;
>> } VirtIOIOMMUMapping;
>>
>> +struct hiod_key {
>> + PCIBus *bus;
>> + uint8_t devfn;
>> +};
>> +
>> static inline uint16_t virtio_iommu_get_bdf(IOMMUDevice *dev)
>> {
>> return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn);
>> @@ -462,8 +467,90 @@ static AddressSpace
>> *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
>> return &sdev->as;
>> }
>>
>> +static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
>> +{
>> + const struct hiod_key *key1 = v1;
>> + const struct hiod_key *key2 = v2;
>> +
>> + return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
>> +}
>> +
>> +static guint hiod_hash(gconstpointer v)
>> +{
>> + const struct hiod_key *key = v;
>> + guint value = (guint)(uintptr_t)key->bus;
>> +
>> + return (guint)(value << 8 | key->devfn);
>> +}
>> +
>> +static void hiod_destroy(gpointer v)
>> +{
>> + object_unref(v);
>
> This is a bit different from intel_iommu, here v represents VirtioHostIOMMUDevice *.
>
> Thanks
> Zhenzhong
>
>> +}
>> +
>> +static VirtioHostIOMMUDevice *
>> +get_host_iommu_device(VirtIOIOMMU *viommu, PCIBus *bus, int devfn) {
>> + struct hiod_key key = {
>> + .bus = bus,
>> + .devfn = devfn,
>> + };
>> +
>> + return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>> +}
>> +
>> +static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>> int devfn,
>> + HostIOMMUDevice *hiod, Error **errp)
>> +{
>> + VirtIOIOMMU *viommu = opaque;
>> + VirtioHostIOMMUDevice *vhiod;
>> + struct hiod_key *new_key;
>> +
>> + assert(hiod);
>> +
>> + vhiod = get_host_iommu_device(viommu, bus, devfn);
>> + if (vhiod) {
>> + error_setg(errp, "VirtioHostIOMMUDevice already exists");
>> + return false;
>> + }
>> +
>> + vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>> + vhiod->bus = bus;
>> + vhiod->devfn = (uint8_t)devfn;
>> + vhiod->viommu = viommu;
>> + vhiod->dev = hiod;
>> +
>> + new_key = g_malloc(sizeof(*new_key));
>> + new_key->bus = bus;
>> + new_key->devfn = devfn;
>> +
>> + object_ref(hiod);
>> + g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>> +
>> + return true;
>> +}
>> +
>> +static void
>> +virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
>> +{
>> + VirtIOIOMMU *viommu = opaque;
>> + VirtioHostIOMMUDevice *vhiod;
>> + struct hiod_key key = {
>> + .bus = bus,
>> + .devfn = devfn,
>> + };
>> +
>> + vhiod = g_hash_table_lookup(viommu->host_iommu_devices, &key);
>> + if (!vhiod) {
>> + return;
>> + }
>> +
>> + g_hash_table_remove(viommu->host_iommu_devices, &key);
>> +}
>> +
>> static const PCIIOMMUOps virtio_iommu_ops = {
>> .get_address_space = virtio_iommu_find_add_as,
>> + .set_iommu_device = virtio_iommu_set_iommu_device,
>> + .unset_iommu_device = virtio_iommu_unset_iommu_device,
>> };
>>
>> static int virtio_iommu_attach(VirtIOIOMMU *s,
>> @@ -1357,6 +1444,9 @@ static void
>> virtio_iommu_device_realize(DeviceState *dev, Error **errp)
>>
>> s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free);
>>
>> + s->host_iommu_devices = g_hash_table_new_full(hiod_hash,
>> hiod_equal,
>> + g_free, hiod_destroy);
>> +
>> if (s->primary_bus) {
>> pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s);
>> } else {
>> --
>> 2.41.0
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks
2024-06-13 9:57 ` Duan, Zhenzhong
2024-06-14 7:35 ` Cédric Le Goater
@ 2024-06-14 7:48 ` Eric Auger
1 sibling, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-14 7:48 UTC (permalink / raw)
To: Duan, Zhenzhong, eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
Hi Zhenzhong,
On 6/13/24 11:57, Duan, Zhenzhong wrote:
>
>> -----Original Message-----
>> From: Eric Auger <eric.auger@redhat.com>
>> Subject: [PATCH v3 2/7] virtio-iommu: Implement
>> set|unset]_iommu_device() callbacks
>>
>> Implement PCIIOMMUOPs [set|unset]_iommu_device() callbacks.
>> In set(), a VirtioHostIOMMUDevice is allocated which holds
>> a reference to the HostIOMMUDevice. This object is stored in a hash
>> table indexed by PCI BDF. The handle to the Host IOMMU device
>> will allow to retrieve information related to the physical IOMMU.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>>
>> v2 -> v3:
>> - include host_iommu_device.h in virtio-iommu.h header
>> - introduce hiod_destroy() and fix UAF in
>> virtio_iommu_unset_iommu_device()
>> ---
>> include/hw/virtio/virtio-iommu.h | 10 ++++
>> hw/virtio/virtio-iommu.c | 90
>> ++++++++++++++++++++++++++++++++
>> 2 files changed, 100 insertions(+)
>>
>> diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-
>> iommu.h
>> index 83a52cc446..a5926de947 100644
>> --- a/include/hw/virtio/virtio-iommu.h
>> +++ b/include/hw/virtio/virtio-iommu.h
>> @@ -25,6 +25,7 @@
>> #include "hw/pci/pci.h"
>> #include "qom/object.h"
>> #include "qapi/qapi-types-virtio.h"
>> +#include "sysemu/host_iommu_device.h"
>>
>> #define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
>> #define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-pci"
>> @@ -45,6 +46,14 @@ typedef struct IOMMUDevice {
>> bool probe_done;
>> } IOMMUDevice;
>>
>> +typedef struct VirtioHostIOMMUDevice {
>> + void *viommu;
>> + PCIBus *bus;
>> + uint8_t devfn;
>> + HostIOMMUDevice *dev;
>> + QLIST_ENTRY(VirtioHostIOMMUDevice) next;
>> +} VirtioHostIOMMUDevice;
> Do you have plan to use the elements in VirtioHostIOMMUDevice?
As of now I get rid of this derived object and do something similar as
what you did on vtd.
>
>> +
>> typedef struct IOMMUPciBus {
>> PCIBus *bus;
>> IOMMUDevice *pbdev[]; /* Parent array is sparse, so dynamically alloc
>> */
>> @@ -57,6 +66,7 @@ struct VirtIOIOMMU {
>> struct virtio_iommu_config config;
>> uint64_t features;
>> GHashTable *as_by_busptr;
>> + GHashTable *host_iommu_devices;
>> IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX];
>> PCIBus *primary_bus;
>> ReservedRegion *prop_resv_regions;
>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>> index 1326c6ec41..db842555c8 100644
>> --- a/hw/virtio/virtio-iommu.c
>> +++ b/hw/virtio/virtio-iommu.c
>> @@ -69,6 +69,11 @@ typedef struct VirtIOIOMMUMapping {
>> uint32_t flags;
>> } VirtIOIOMMUMapping;
>>
>> +struct hiod_key {
>> + PCIBus *bus;
>> + uint8_t devfn;
>> +};
>> +
>> static inline uint16_t virtio_iommu_get_bdf(IOMMUDevice *dev)
>> {
>> return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn);
>> @@ -462,8 +467,90 @@ static AddressSpace
>> *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
>> return &sdev->as;
>> }
>>
>> +static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
>> +{
>> + const struct hiod_key *key1 = v1;
>> + const struct hiod_key *key2 = v2;
>> +
>> + return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
>> +}
>> +
>> +static guint hiod_hash(gconstpointer v)
>> +{
>> + const struct hiod_key *key = v;
>> + guint value = (guint)(uintptr_t)key->bus;
>> +
>> + return (guint)(value << 8 | key->devfn);
>> +}
>> +
>> +static void hiod_destroy(gpointer v)
>> +{
>> + object_unref(v);
> This is a bit different from intel_iommu, here v represents VirtioHostIOMMUDevice *.
damned, you are totally right.
Fixed in next version.
Thank you very much!
Eric
>
> Thanks
> Zhenzhong
>
>> +}
>> +
>> +static VirtioHostIOMMUDevice *
>> +get_host_iommu_device(VirtIOIOMMU *viommu, PCIBus *bus, int devfn) {
>> + struct hiod_key key = {
>> + .bus = bus,
>> + .devfn = devfn,
>> + };
>> +
>> + return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>> +}
>> +
>> +static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>> int devfn,
>> + HostIOMMUDevice *hiod, Error **errp)
>> +{
>> + VirtIOIOMMU *viommu = opaque;
>> + VirtioHostIOMMUDevice *vhiod;
>> + struct hiod_key *new_key;
>> +
>> + assert(hiod);
>> +
>> + vhiod = get_host_iommu_device(viommu, bus, devfn);
>> + if (vhiod) {
>> + error_setg(errp, "VirtioHostIOMMUDevice already exists");
>> + return false;
>> + }
>> +
>> + vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>> + vhiod->bus = bus;
>> + vhiod->devfn = (uint8_t)devfn;
>> + vhiod->viommu = viommu;
>> + vhiod->dev = hiod;
>> +
>> + new_key = g_malloc(sizeof(*new_key));
>> + new_key->bus = bus;
>> + new_key->devfn = devfn;
>> +
>> + object_ref(hiod);
>> + g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>> +
>> + return true;
>> +}
>> +
>> +static void
>> +virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
>> +{
>> + VirtIOIOMMU *viommu = opaque;
>> + VirtioHostIOMMUDevice *vhiod;
>> + struct hiod_key key = {
>> + .bus = bus,
>> + .devfn = devfn,
>> + };
>> +
>> + vhiod = g_hash_table_lookup(viommu->host_iommu_devices, &key);
>> + if (!vhiod) {
>> + return;
>> + }
>> +
>> + g_hash_table_remove(viommu->host_iommu_devices, &key);
>> +}
>> +
>> static const PCIIOMMUOps virtio_iommu_ops = {
>> .get_address_space = virtio_iommu_find_add_as,
>> + .set_iommu_device = virtio_iommu_set_iommu_device,
>> + .unset_iommu_device = virtio_iommu_unset_iommu_device,
>> };
>>
>> static int virtio_iommu_attach(VirtIOIOMMU *s,
>> @@ -1357,6 +1444,9 @@ static void
>> virtio_iommu_device_realize(DeviceState *dev, Error **errp)
>>
>> s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free);
>>
>> + s->host_iommu_devices = g_hash_table_new_full(hiod_hash,
>> hiod_equal,
>> + g_free, hiod_destroy);
>> +
>> if (s->primary_bus) {
>> pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s);
>> } else {
>> --
>> 2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges callback
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
2024-06-13 9:20 ` [PATCH v3 1/7] HostIOMMUDevice: Store the VFIO/VDPA agent Eric Auger
2024-06-13 9:20 ` [PATCH v3 2/7] virtio-iommu: Implement set|unset]_iommu_device() callbacks Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-13 10:01 ` Duan, Zhenzhong
2024-06-13 9:20 ` [PATCH v3 4/7] virtio-iommu: Compute host reserved regions Eric Auger
` (3 subsequent siblings)
6 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Introduce a new HostIOMMUDevice callback that allows to
retrieve the usable IOVA ranges.
Implement this callback in the legacy VFIO and IOMMUFD VFIO
host iommu devices. This relies on the VFIODevice agent's
base container iova_ranges resource.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v2 -> v3:
- add g_assert(vdev)
---
include/sysemu/host_iommu_device.h | 8 ++++++++
hw/vfio/container.c | 16 ++++++++++++++++
hw/vfio/iommufd.c | 16 ++++++++++++++++
3 files changed, 40 insertions(+)
diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h
index 3e5f058e7b..40e0fa13ef 100644
--- a/include/sysemu/host_iommu_device.h
+++ b/include/sysemu/host_iommu_device.h
@@ -80,6 +80,14 @@ struct HostIOMMUDeviceClass {
* i.e., HOST_IOMMU_DEVICE_CAP_AW_BITS.
*/
int (*get_cap)(HostIOMMUDevice *hiod, int cap, Error **errp);
+ /**
+ * @get_iova_ranges: Return the list of usable iova_ranges along with
+ * @hiod Host IOMMU device
+ *
+ * @hiod: handle to the host IOMMU device
+ * @errp: error handle
+ */
+ GList* (*get_iova_ranges)(HostIOMMUDevice *hiod, Error **errp);
};
/*
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index b728b978a2..c48749c089 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1164,12 +1164,28 @@ static int hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap,
}
}
+static GList *
+hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
+{
+ VFIODevice *vdev = hiod->agent;
+ GList *l = NULL;
+
+ g_assert(vdev);
+
+ if (vdev->bcontainer) {
+ l = g_list_copy(vdev->bcontainer->iova_ranges);
+ }
+
+ return l;
+}
+
static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
{
HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
hioc->realize = hiod_legacy_vfio_realize;
hioc->get_cap = hiod_legacy_vfio_get_cap;
+ hioc->get_iova_ranges = hiod_legacy_vfio_get_iova_ranges;
};
static const TypeInfo types[] = {
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index dbdae1adbb..e502081c2a 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -645,11 +645,27 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
return true;
}
+static GList *
+hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
+{
+ VFIODevice *vdev = hiod->agent;
+ GList *l = NULL;
+
+ g_assert(vdev);
+
+ if (vdev->bcontainer) {
+ l = g_list_copy(vdev->bcontainer->iova_ranges);
+ }
+
+ return l;
+}
+
static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
{
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
hiodc->realize = hiod_iommufd_vfio_realize;
+ hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges;
};
static const TypeInfo types[] = {
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* RE: [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges callback
2024-06-13 9:20 ` [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges callback Eric Auger
@ 2024-06-13 10:01 ` Duan, Zhenzhong
0 siblings, 0 replies; 22+ messages in thread
From: Duan, Zhenzhong @ 2024-06-13 10:01 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,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
>-----Original Message-----
>From: Eric Auger <eric.auger@redhat.com>
>Subject: [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges
>callback
>
>Introduce a new HostIOMMUDevice callback that allows to
>retrieve the usable IOVA ranges.
>
>Implement this callback in the legacy VFIO and IOMMUFD VFIO
>host iommu devices. This relies on the VFIODevice agent's
>base container iova_ranges resource.
>
>Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Thanks
Zhenzhong
>
>---
>
>v2 -> v3:
>- add g_assert(vdev)
>---
> include/sysemu/host_iommu_device.h | 8 ++++++++
> hw/vfio/container.c | 16 ++++++++++++++++
> hw/vfio/iommufd.c | 16 ++++++++++++++++
> 3 files changed, 40 insertions(+)
>
>diff --git a/include/sysemu/host_iommu_device.h
>b/include/sysemu/host_iommu_device.h
>index 3e5f058e7b..40e0fa13ef 100644
>--- a/include/sysemu/host_iommu_device.h
>+++ b/include/sysemu/host_iommu_device.h
>@@ -80,6 +80,14 @@ struct HostIOMMUDeviceClass {
> * i.e., HOST_IOMMU_DEVICE_CAP_AW_BITS.
> */
> int (*get_cap)(HostIOMMUDevice *hiod, int cap, Error **errp);
>+ /**
>+ * @get_iova_ranges: Return the list of usable iova_ranges along with
>+ * @hiod Host IOMMU device
>+ *
>+ * @hiod: handle to the host IOMMU device
>+ * @errp: error handle
>+ */
>+ GList* (*get_iova_ranges)(HostIOMMUDevice *hiod, Error **errp);
> };
>
> /*
>diff --git a/hw/vfio/container.c b/hw/vfio/container.c
>index b728b978a2..c48749c089 100644
>--- a/hw/vfio/container.c
>+++ b/hw/vfio/container.c
>@@ -1164,12 +1164,28 @@ static int
>hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap,
> }
> }
>
>+static GList *
>+hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
>+{
>+ VFIODevice *vdev = hiod->agent;
>+ GList *l = NULL;
>+
>+ g_assert(vdev);
>+
>+ if (vdev->bcontainer) {
>+ l = g_list_copy(vdev->bcontainer->iova_ranges);
>+ }
>+
>+ return l;
>+}
>+
> static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
> {
> HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
>
> hioc->realize = hiod_legacy_vfio_realize;
> hioc->get_cap = hiod_legacy_vfio_get_cap;
>+ hioc->get_iova_ranges = hiod_legacy_vfio_get_iova_ranges;
> };
>
> static const TypeInfo types[] = {
>diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
>index dbdae1adbb..e502081c2a 100644
>--- a/hw/vfio/iommufd.c
>+++ b/hw/vfio/iommufd.c
>@@ -645,11 +645,27 @@ static bool
>hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
> return true;
> }
>
>+static GList *
>+hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error
>**errp)
>+{
>+ VFIODevice *vdev = hiod->agent;
>+ GList *l = NULL;
>+
>+ g_assert(vdev);
>+
>+ if (vdev->bcontainer) {
>+ l = g_list_copy(vdev->bcontainer->iova_ranges);
>+ }
>+
>+ return l;
>+}
>+
> static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
> {
> HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
>
> hiodc->realize = hiod_iommufd_vfio_realize;
>+ hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges;
> };
>
> static const TypeInfo types[] = {
>--
>2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
` (2 preceding siblings ...)
2024-06-13 9:20 ` [PATCH v3 3/7] HostIOMMUDevice: Introduce get_iova_ranges callback Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-13 10:00 ` Duan, Zhenzhong
2024-06-13 9:20 ` [PATCH v3 5/7] virtio-iommu: Remove the implementation of iommu_set_iova_range Eric Auger
` (2 subsequent siblings)
6 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Compute the host reserved regions in virtio_iommu_set_iommu_device().
The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
The virtio_iommu_set_host_iova_ranges() helper turns usable regions
into complementary reserved regions while testing the inclusion
into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
implementation of virtio_iommu_set_iova_ranges() which will be
removed in subsequent patches. rebuild_resv_regions() is just moved.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
- added g_assert(!sdev->probe_done)
---
hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++---------
1 file changed, 112 insertions(+), 34 deletions(-)
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index db842555c8..04474ebd74 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU *viommu, PCIBus *bus, int devfn) {
return g_hash_table_lookup(viommu->host_iommu_devices, &key);
}
+/**
+ * rebuild_resv_regions: rebuild resv regions with both the
+ * info of host resv ranges and property set resv ranges
+ */
+static int rebuild_resv_regions(IOMMUDevice *sdev)
+{
+ GList *l;
+ int i = 0;
+
+ /* free the existing list and rebuild it from scratch */
+ g_list_free_full(sdev->resv_regions, g_free);
+ sdev->resv_regions = NULL;
+
+ /* First add host reserved regions if any, all tagged as RESERVED */
+ for (l = sdev->host_resv_ranges; l; l = l->next) {
+ ReservedRegion *reg = g_new0(ReservedRegion, 1);
+ Range *r = (Range *)l->data;
+
+ reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
+ range_set_bounds(®->range, range_lob(r), range_upb(r));
+ sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
+ trace_virtio_iommu_host_resv_regions(sdev->iommu_mr.parent_obj.name, i,
+ range_lob(®->range),
+ range_upb(®->range));
+ i++;
+ }
+ /*
+ * then add higher priority reserved regions set by the machine
+ * through properties
+ */
+ add_prop_resv_regions(sdev);
+ return 0;
+}
+
+static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
+ int devfn, GList *iova_ranges,
+ Error **errp)
+{
+ IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
+ IOMMUDevice *sdev;
+ GList *current_ranges;
+ GList *l, *tmp, *new_ranges = NULL;
+ int ret = -EINVAL;
+
+ if (!sbus) {
+ error_report("%s no sbus", __func__);
+ }
+
+ sdev = sbus->pbdev[devfn];
+
+ current_ranges = sdev->host_resv_ranges;
+
+ g_assert(!sdev->probe_done);
+
+ /* check that each new resv region is included in an existing one */
+ if (sdev->host_resv_ranges) {
+ range_inverse_array(iova_ranges,
+ &new_ranges,
+ 0, UINT64_MAX);
+
+ for (tmp = new_ranges; tmp; tmp = tmp->next) {
+ Range *newr = (Range *)tmp->data;
+ bool included = false;
+
+ for (l = current_ranges; l; l = l->next) {
+ Range * r = (Range *)l->data;
+
+ if (range_contains_range(r, newr)) {
+ included = true;
+ break;
+ }
+ }
+ if (!included) {
+ goto error;
+ }
+ }
+ /* all new reserved ranges are included in existing ones */
+ ret = 0;
+ goto out;
+ }
+
+ range_inverse_array(iova_ranges,
+ &sdev->host_resv_ranges,
+ 0, UINT64_MAX);
+ rebuild_resv_regions(sdev);
+
+ return 0;
+error:
+ error_setg(errp, "%s Conflicting host reserved ranges set!",
+ __func__);
+out:
+ g_list_free_full(new_ranges, g_free);
+ return ret;
+}
+
static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
HostIOMMUDevice *hiod, Error **errp)
{
VirtIOIOMMU *viommu = opaque;
VirtioHostIOMMUDevice *vhiod;
+ HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
struct hiod_key *new_key;
+ GList *host_iova_ranges = NULL;
assert(hiod);
@@ -513,6 +610,20 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
return false;
}
+ if (hiodc->get_iova_ranges) {
+ int ret;
+ host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
+ if (!host_iova_ranges) {
+ return true; /* some old kernels may not support that capability */
+ }
+ ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
+ host_iova_ranges, errp);
+ if (ret) {
+ g_list_free_full(host_iova_ranges, g_free);
+ return false;
+ }
+ }
+
vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
vhiod->bus = bus;
vhiod->devfn = (uint8_t)devfn;
@@ -525,6 +636,7 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
object_ref(hiod);
g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
+ g_list_free_full(host_iova_ranges, g_free);
return true;
}
@@ -1246,40 +1358,6 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
return 0;
}
-/**
- * rebuild_resv_regions: rebuild resv regions with both the
- * info of host resv ranges and property set resv ranges
- */
-static int rebuild_resv_regions(IOMMUDevice *sdev)
-{
- GList *l;
- int i = 0;
-
- /* free the existing list and rebuild it from scratch */
- g_list_free_full(sdev->resv_regions, g_free);
- sdev->resv_regions = NULL;
-
- /* First add host reserved regions if any, all tagged as RESERVED */
- for (l = sdev->host_resv_ranges; l; l = l->next) {
- ReservedRegion *reg = g_new0(ReservedRegion, 1);
- Range *r = (Range *)l->data;
-
- reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
- range_set_bounds(®->range, range_lob(r), range_upb(r));
- sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
- trace_virtio_iommu_host_resv_regions(sdev->iommu_mr.parent_obj.name, i,
- range_lob(®->range),
- range_upb(®->range));
- i++;
- }
- /*
- * then add higher priority reserved regions set by the machine
- * through properties
- */
- add_prop_resv_regions(sdev);
- return 0;
-}
-
/**
* virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
*
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* RE: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-13 9:20 ` [PATCH v3 4/7] virtio-iommu: Compute host reserved regions Eric Auger
@ 2024-06-13 10:00 ` Duan, Zhenzhong
2024-06-13 12:08 ` Eric Auger
0 siblings, 1 reply; 22+ messages in thread
From: Duan, Zhenzhong @ 2024-06-13 10:00 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,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
Hi Eric,
>-----Original Message-----
>From: Eric Auger <eric.auger@redhat.com>
>Subject: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>
>Compute the host reserved regions in virtio_iommu_set_iommu_device().
>The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
>The virtio_iommu_set_host_iova_ranges() helper turns usable regions
>into complementary reserved regions while testing the inclusion
>into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
>implementation of virtio_iommu_set_iova_ranges() which will be
>removed in subsequent patches. rebuild_resv_regions() is just moved.
>
>Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
>---
>
>- added g_assert(!sdev->probe_done)
>---
> hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++--------
>-
> 1 file changed, 112 insertions(+), 34 deletions(-)
>
>diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>index db842555c8..04474ebd74 100644
>--- a/hw/virtio/virtio-iommu.c
>+++ b/hw/virtio/virtio-iommu.c
>@@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU
>*viommu, PCIBus *bus, int devfn) {
> return g_hash_table_lookup(viommu->host_iommu_devices, &key);
> }
>
>+/**
>+ * rebuild_resv_regions: rebuild resv regions with both the
>+ * info of host resv ranges and property set resv ranges
>+ */
>+static int rebuild_resv_regions(IOMMUDevice *sdev)
>+{
>+ GList *l;
>+ int i = 0;
>+
>+ /* free the existing list and rebuild it from scratch */
>+ g_list_free_full(sdev->resv_regions, g_free);
>+ sdev->resv_regions = NULL;
>+
>+ /* First add host reserved regions if any, all tagged as RESERVED */
>+ for (l = sdev->host_resv_ranges; l; l = l->next) {
>+ ReservedRegion *reg = g_new0(ReservedRegion, 1);
>+ Range *r = (Range *)l->data;
>+
>+ reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>+ range_set_bounds(®->range, range_lob(r), range_upb(r));
>+ sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
>+ trace_virtio_iommu_host_resv_regions(sdev-
>>iommu_mr.parent_obj.name, i,
>+ range_lob(®->range),
>+ range_upb(®->range));
>+ i++;
>+ }
>+ /*
>+ * then add higher priority reserved regions set by the machine
>+ * through properties
>+ */
>+ add_prop_resv_regions(sdev);
>+ return 0;
>+}
>+
>+static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus
>*bus,
>+ int devfn, GList *iova_ranges,
>+ Error **errp)
>+{
>+ IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
Here the bus/devfn parameters are real device BDF not aliased one,
But used to index s->as_by_busptr which expect aliased bus/devfn.
Do we need a translation of bus/devfn?
Thanks
Zhenzhong
>+ IOMMUDevice *sdev;
>+ GList *current_ranges;
>+ GList *l, *tmp, *new_ranges = NULL;
>+ int ret = -EINVAL;
>+
>+ if (!sbus) {
>+ error_report("%s no sbus", __func__);
>+ }
>+
>+ sdev = sbus->pbdev[devfn];
>+
>+ current_ranges = sdev->host_resv_ranges;
>+
>+ g_assert(!sdev->probe_done);
>+
>+ /* check that each new resv region is included in an existing one */
>+ if (sdev->host_resv_ranges) {
>+ range_inverse_array(iova_ranges,
>+ &new_ranges,
>+ 0, UINT64_MAX);
>+
>+ for (tmp = new_ranges; tmp; tmp = tmp->next) {
>+ Range *newr = (Range *)tmp->data;
>+ bool included = false;
>+
>+ for (l = current_ranges; l; l = l->next) {
>+ Range * r = (Range *)l->data;
>+
>+ if (range_contains_range(r, newr)) {
>+ included = true;
>+ break;
>+ }
>+ }
>+ if (!included) {
>+ goto error;
>+ }
>+ }
>+ /* all new reserved ranges are included in existing ones */
>+ ret = 0;
>+ goto out;
>+ }
>+
>+ range_inverse_array(iova_ranges,
>+ &sdev->host_resv_ranges,
>+ 0, UINT64_MAX);
>+ rebuild_resv_regions(sdev);
>+
>+ return 0;
>+error:
>+ error_setg(errp, "%s Conflicting host reserved ranges set!",
>+ __func__);
>+out:
>+ g_list_free_full(new_ranges, g_free);
>+ return ret;
>+}
>+
> static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>int devfn,
> HostIOMMUDevice *hiod, Error **errp)
> {
> VirtIOIOMMU *viommu = opaque;
> VirtioHostIOMMUDevice *vhiod;
>+ HostIOMMUDeviceClass *hiodc =
>HOST_IOMMU_DEVICE_GET_CLASS(hiod);
> struct hiod_key *new_key;
>+ GList *host_iova_ranges = NULL;
>
> assert(hiod);
>
>@@ -513,6 +610,20 @@ static bool
>virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
> return false;
> }
>
>+ if (hiodc->get_iova_ranges) {
>+ int ret;
>+ host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
>+ if (!host_iova_ranges) {
>+ return true; /* some old kernels may not support that capability */
>+ }
>+ ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
>+ host_iova_ranges, errp);
>+ if (ret) {
>+ g_list_free_full(host_iova_ranges, g_free);
>+ return false;
>+ }
>+ }
>+
> vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
> vhiod->bus = bus;
> vhiod->devfn = (uint8_t)devfn;
>@@ -525,6 +636,7 @@ static bool
>virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>
> object_ref(hiod);
> g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>+ g_list_free_full(host_iova_ranges, g_free);
>
> return true;
> }
>@@ -1246,40 +1358,6 @@ static int
>virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
> return 0;
> }
>
>-/**
>- * rebuild_resv_regions: rebuild resv regions with both the
>- * info of host resv ranges and property set resv ranges
>- */
>-static int rebuild_resv_regions(IOMMUDevice *sdev)
>-{
>- GList *l;
>- int i = 0;
>-
>- /* free the existing list and rebuild it from scratch */
>- g_list_free_full(sdev->resv_regions, g_free);
>- sdev->resv_regions = NULL;
>-
>- /* First add host reserved regions if any, all tagged as RESERVED */
>- for (l = sdev->host_resv_ranges; l; l = l->next) {
>- ReservedRegion *reg = g_new0(ReservedRegion, 1);
>- Range *r = (Range *)l->data;
>-
>- reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>- range_set_bounds(®->range, range_lob(r), range_upb(r));
>- sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
>- trace_virtio_iommu_host_resv_regions(sdev-
>>iommu_mr.parent_obj.name, i,
>- range_lob(®->range),
>- range_upb(®->range));
>- i++;
>- }
>- /*
>- * then add higher priority reserved regions set by the machine
>- * through properties
>- */
>- add_prop_resv_regions(sdev);
>- return 0;
>-}
>-
> /**
> * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
> *
>--
>2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-13 10:00 ` Duan, Zhenzhong
@ 2024-06-13 12:08 ` Eric Auger
2024-06-14 3:05 ` Duan, Zhenzhong
0 siblings, 1 reply; 22+ messages in thread
From: Eric Auger @ 2024-06-13 12:08 UTC (permalink / raw)
To: Duan, Zhenzhong, eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
On 6/13/24 12:00, Duan, Zhenzhong wrote:
> Hi Eric,
>
>> -----Original Message-----
>> From: Eric Auger <eric.auger@redhat.com>
>> Subject: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>
>> Compute the host reserved regions in virtio_iommu_set_iommu_device().
>> The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
>> The virtio_iommu_set_host_iova_ranges() helper turns usable regions
>> into complementary reserved regions while testing the inclusion
>> into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
>> implementation of virtio_iommu_set_iova_ranges() which will be
>> removed in subsequent patches. rebuild_resv_regions() is just moved.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>>
>> - added g_assert(!sdev->probe_done)
>> ---
>> hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++--------
>> -
>> 1 file changed, 112 insertions(+), 34 deletions(-)
>>
>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>> index db842555c8..04474ebd74 100644
>> --- a/hw/virtio/virtio-iommu.c
>> +++ b/hw/virtio/virtio-iommu.c
>> @@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU
>> *viommu, PCIBus *bus, int devfn) {
>> return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>> }
>>
>> +/**
>> + * rebuild_resv_regions: rebuild resv regions with both the
>> + * info of host resv ranges and property set resv ranges
>> + */
>> +static int rebuild_resv_regions(IOMMUDevice *sdev)
>> +{
>> + GList *l;
>> + int i = 0;
>> +
>> + /* free the existing list and rebuild it from scratch */
>> + g_list_free_full(sdev->resv_regions, g_free);
>> + sdev->resv_regions = NULL;
>> +
>> + /* First add host reserved regions if any, all tagged as RESERVED */
>> + for (l = sdev->host_resv_ranges; l; l = l->next) {
>> + ReservedRegion *reg = g_new0(ReservedRegion, 1);
>> + Range *r = (Range *)l->data;
>> +
>> + reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>> + range_set_bounds(®->range, range_lob(r), range_upb(r));
>> + sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
>> + trace_virtio_iommu_host_resv_regions(sdev-
>>> iommu_mr.parent_obj.name, i,
>> + range_lob(®->range),
>> + range_upb(®->range));
>> + i++;
>> + }
>> + /*
>> + * then add higher priority reserved regions set by the machine
>> + * through properties
>> + */
>> + add_prop_resv_regions(sdev);
>> + return 0;
>> +}
>> +
>> +static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus
>> *bus,
>> + int devfn, GList *iova_ranges,
>> + Error **errp)
>> +{
>> + IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
> Here the bus/devfn parameters are real device BDF not aliased one,
> But used to index s->as_by_busptr which expect aliased bus/devfn.
>
> Do we need a translation of bus/devfn?
Hum that's a good point actually. I need to further study that. that's
not easy to translate, is it?
Now I am not totally sure why we don't use the alias as well for
HostIOMMUDevices or at least store the aliased bdf.
Thanks
Eric
>
> Thanks
> Zhenzhong
>
>> + IOMMUDevice *sdev;
>> + GList *current_ranges;
>> + GList *l, *tmp, *new_ranges = NULL;
>> + int ret = -EINVAL;
>> +
>> + if (!sbus) {
>> + error_report("%s no sbus", __func__);
>> + }
>> +
>> + sdev = sbus->pbdev[devfn];
>> +
>> + current_ranges = sdev->host_resv_ranges;
>> +
>> + g_assert(!sdev->probe_done);
>> +
>> + /* check that each new resv region is included in an existing one */
>> + if (sdev->host_resv_ranges) {
>> + range_inverse_array(iova_ranges,
>> + &new_ranges,
>> + 0, UINT64_MAX);
>> +
>> + for (tmp = new_ranges; tmp; tmp = tmp->next) {
>> + Range *newr = (Range *)tmp->data;
>> + bool included = false;
>> +
>> + for (l = current_ranges; l; l = l->next) {
>> + Range * r = (Range *)l->data;
>> +
>> + if (range_contains_range(r, newr)) {
>> + included = true;
>> + break;
>> + }
>> + }
>> + if (!included) {
>> + goto error;
>> + }
>> + }
>> + /* all new reserved ranges are included in existing ones */
>> + ret = 0;
>> + goto out;
>> + }
>> +
>> + range_inverse_array(iova_ranges,
>> + &sdev->host_resv_ranges,
>> + 0, UINT64_MAX);
>> + rebuild_resv_regions(sdev);
>> +
>> + return 0;
>> +error:
>> + error_setg(errp, "%s Conflicting host reserved ranges set!",
>> + __func__);
>> +out:
>> + g_list_free_full(new_ranges, g_free);
>> + return ret;
>> +}
>> +
>> static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>> int devfn,
>> HostIOMMUDevice *hiod, Error **errp)
>> {
>> VirtIOIOMMU *viommu = opaque;
>> VirtioHostIOMMUDevice *vhiod;
>> + HostIOMMUDeviceClass *hiodc =
>> HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>> struct hiod_key *new_key;
>> + GList *host_iova_ranges = NULL;
>>
>> assert(hiod);
>>
>> @@ -513,6 +610,20 @@ static bool
>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>> return false;
>> }
>>
>> + if (hiodc->get_iova_ranges) {
>> + int ret;
>> + host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
>> + if (!host_iova_ranges) {
>> + return true; /* some old kernels may not support that capability */
>> + }
>> + ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
>> + host_iova_ranges, errp);
>> + if (ret) {
>> + g_list_free_full(host_iova_ranges, g_free);
>> + return false;
>> + }
>> + }
>> +
>> vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>> vhiod->bus = bus;
>> vhiod->devfn = (uint8_t)devfn;
>> @@ -525,6 +636,7 @@ static bool
>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>
>> object_ref(hiod);
>> g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>> + g_list_free_full(host_iova_ranges, g_free);
>>
>> return true;
>> }
>> @@ -1246,40 +1358,6 @@ static int
>> virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
>> return 0;
>> }
>>
>> -/**
>> - * rebuild_resv_regions: rebuild resv regions with both the
>> - * info of host resv ranges and property set resv ranges
>> - */
>> -static int rebuild_resv_regions(IOMMUDevice *sdev)
>> -{
>> - GList *l;
>> - int i = 0;
>> -
>> - /* free the existing list and rebuild it from scratch */
>> - g_list_free_full(sdev->resv_regions, g_free);
>> - sdev->resv_regions = NULL;
>> -
>> - /* First add host reserved regions if any, all tagged as RESERVED */
>> - for (l = sdev->host_resv_ranges; l; l = l->next) {
>> - ReservedRegion *reg = g_new0(ReservedRegion, 1);
>> - Range *r = (Range *)l->data;
>> -
>> - reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>> - range_set_bounds(®->range, range_lob(r), range_upb(r));
>> - sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
>> - trace_virtio_iommu_host_resv_regions(sdev-
>>> iommu_mr.parent_obj.name, i,
>> - range_lob(®->range),
>> - range_upb(®->range));
>> - i++;
>> - }
>> - /*
>> - * then add higher priority reserved regions set by the machine
>> - * through properties
>> - */
>> - add_prop_resv_regions(sdev);
>> - return 0;
>> -}
>> -
>> /**
>> * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
>> *
>> --
>> 2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-13 12:08 ` Eric Auger
@ 2024-06-14 3:05 ` Duan, Zhenzhong
2024-06-14 7:56 ` Eric Auger
2024-06-14 9:00 ` Eric Auger
0 siblings, 2 replies; 22+ messages in thread
From: Duan, Zhenzhong @ 2024-06-14 3:05 UTC (permalink / raw)
To: eric.auger@redhat.com, eric.auger.pro@gmail.com,
qemu-devel@nongnu.org, qemu-arm@nongnu.org, mst@redhat.com,
jean-philippe@linaro.org, peter.maydell@linaro.org,
clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
>-----Original Message-----
>From: Eric Auger <eric.auger@redhat.com>
>Subject: Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>
>
>
>On 6/13/24 12:00, Duan, Zhenzhong wrote:
>> Hi Eric,
>>
>>> -----Original Message-----
>>> From: Eric Auger <eric.auger@redhat.com>
>>> Subject: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>>
>>> Compute the host reserved regions in virtio_iommu_set_iommu_device().
>>> The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
>>> The virtio_iommu_set_host_iova_ranges() helper turns usable regions
>>> into complementary reserved regions while testing the inclusion
>>> into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
>>> implementation of virtio_iommu_set_iova_ranges() which will be
>>> removed in subsequent patches. rebuild_resv_regions() is just moved.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>>
>>> - added g_assert(!sdev->probe_done)
>>> ---
>>> hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++----
>----
>>> -
>>> 1 file changed, 112 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>>> index db842555c8..04474ebd74 100644
>>> --- a/hw/virtio/virtio-iommu.c
>>> +++ b/hw/virtio/virtio-iommu.c
>>> @@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU
>>> *viommu, PCIBus *bus, int devfn) {
>>> return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>>> }
>>>
>>> +/**
>>> + * rebuild_resv_regions: rebuild resv regions with both the
>>> + * info of host resv ranges and property set resv ranges
>>> + */
>>> +static int rebuild_resv_regions(IOMMUDevice *sdev)
>>> +{
>>> + GList *l;
>>> + int i = 0;
>>> +
>>> + /* free the existing list and rebuild it from scratch */
>>> + g_list_free_full(sdev->resv_regions, g_free);
>>> + sdev->resv_regions = NULL;
>>> +
>>> + /* First add host reserved regions if any, all tagged as RESERVED */
>>> + for (l = sdev->host_resv_ranges; l; l = l->next) {
>>> + ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>> + Range *r = (Range *)l->data;
>>> +
>>> + reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>> + range_set_bounds(®->range, range_lob(r), range_upb(r));
>>> + sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>reg);
>>> + trace_virtio_iommu_host_resv_regions(sdev-
>>>> iommu_mr.parent_obj.name, i,
>>> + range_lob(®->range),
>>> + range_upb(®->range));
>>> + i++;
>>> + }
>>> + /*
>>> + * then add higher priority reserved regions set by the machine
>>> + * through properties
>>> + */
>>> + add_prop_resv_regions(sdev);
>>> + return 0;
>>> +}
>>> +
>>> +static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus
>>> *bus,
>>> + int devfn, GList *iova_ranges,
>>> + Error **errp)
>>> +{
>>> + IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
>> Here the bus/devfn parameters are real device BDF not aliased one,
>> But used to index s->as_by_busptr which expect aliased bus/devfn.
>>
>> Do we need a translation of bus/devfn?
>
>Hum that's a good point actually. I need to further study that. that's
>not easy to translate, is it?
Yes, may need a path to call into pci_device_get_iommu_bus_devfn().
Maybe a new HostIOMMUDevice callback.
>
>Now I am not totally sure why we don't use the alias as well for
>HostIOMMUDevices or at least store the aliased bdf.
Because we need to store HostIOMMUDevice in vIOMMU in real bdf granularity,
Not aliased bdf granularity. Virtual vtd calls VFIO device uAPI on real device not
the aliased device, i.e., VFIO_DEVICE_[ATTACH|DETACH]_IOMMUFD_PT.
I also have a question, could we define host_resv_ranges in VirtioHostIOMMUDevice
to avoid translation?
Thanks
Zhenzhong
>
>Thanks
>
>Eric
>>
>> Thanks
>> Zhenzhong
>>
>>> + IOMMUDevice *sdev;
>>> + GList *current_ranges;
>>> + GList *l, *tmp, *new_ranges = NULL;
>>> + int ret = -EINVAL;
>>> +
>>> + if (!sbus) {
>>> + error_report("%s no sbus", __func__);
>>> + }
>>> +
>>> + sdev = sbus->pbdev[devfn];
>>> +
>>> + current_ranges = sdev->host_resv_ranges;
>>> +
>>> + g_assert(!sdev->probe_done);
>>> +
>>> + /* check that each new resv region is included in an existing one */
>>> + if (sdev->host_resv_ranges) {
>>> + range_inverse_array(iova_ranges,
>>> + &new_ranges,
>>> + 0, UINT64_MAX);
>>> +
>>> + for (tmp = new_ranges; tmp; tmp = tmp->next) {
>>> + Range *newr = (Range *)tmp->data;
>>> + bool included = false;
>>> +
>>> + for (l = current_ranges; l; l = l->next) {
>>> + Range * r = (Range *)l->data;
>>> +
>>> + if (range_contains_range(r, newr)) {
>>> + included = true;
>>> + break;
>>> + }
>>> + }
>>> + if (!included) {
>>> + goto error;
>>> + }
>>> + }
>>> + /* all new reserved ranges are included in existing ones */
>>> + ret = 0;
>>> + goto out;
>>> + }
>>> +
>>> + range_inverse_array(iova_ranges,
>>> + &sdev->host_resv_ranges,
>>> + 0, UINT64_MAX);
>>> + rebuild_resv_regions(sdev);
>>> +
>>> + return 0;
>>> +error:
>>> + error_setg(errp, "%s Conflicting host reserved ranges set!",
>>> + __func__);
>>> +out:
>>> + g_list_free_full(new_ranges, g_free);
>>> + return ret;
>>> +}
>>> +
>>> static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>>> int devfn,
>>> HostIOMMUDevice *hiod, Error **errp)
>>> {
>>> VirtIOIOMMU *viommu = opaque;
>>> VirtioHostIOMMUDevice *vhiod;
>>> + HostIOMMUDeviceClass *hiodc =
>>> HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>>> struct hiod_key *new_key;
>>> + GList *host_iova_ranges = NULL;
>>>
>>> assert(hiod);
>>>
>>> @@ -513,6 +610,20 @@ static bool
>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>> return false;
>>> }
>>>
>>> + if (hiodc->get_iova_ranges) {
>>> + int ret;
>>> + host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
>>> + if (!host_iova_ranges) {
>>> + return true; /* some old kernels may not support that capability
>*/
>>> + }
>>> + ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
>>> + host_iova_ranges, errp);
>>> + if (ret) {
>>> + g_list_free_full(host_iova_ranges, g_free);
>>> + return false;
>>> + }
>>> + }
>>> +
>>> vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>>> vhiod->bus = bus;
>>> vhiod->devfn = (uint8_t)devfn;
>>> @@ -525,6 +636,7 @@ static bool
>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>>
>>> object_ref(hiod);
>>> g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>>> + g_list_free_full(host_iova_ranges, g_free);
>>>
>>> return true;
>>> }
>>> @@ -1246,40 +1358,6 @@ static int
>>> virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
>>> return 0;
>>> }
>>>
>>> -/**
>>> - * rebuild_resv_regions: rebuild resv regions with both the
>>> - * info of host resv ranges and property set resv ranges
>>> - */
>>> -static int rebuild_resv_regions(IOMMUDevice *sdev)
>>> -{
>>> - GList *l;
>>> - int i = 0;
>>> -
>>> - /* free the existing list and rebuild it from scratch */
>>> - g_list_free_full(sdev->resv_regions, g_free);
>>> - sdev->resv_regions = NULL;
>>> -
>>> - /* First add host reserved regions if any, all tagged as RESERVED */
>>> - for (l = sdev->host_resv_ranges; l; l = l->next) {
>>> - ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>> - Range *r = (Range *)l->data;
>>> -
>>> - reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>> - range_set_bounds(®->range, range_lob(r), range_upb(r));
>>> - sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>reg);
>>> - trace_virtio_iommu_host_resv_regions(sdev-
>>>> iommu_mr.parent_obj.name, i,
>>> - range_lob(®->range),
>>> - range_upb(®->range));
>>> - i++;
>>> - }
>>> - /*
>>> - * then add higher priority reserved regions set by the machine
>>> - * through properties
>>> - */
>>> - add_prop_resv_regions(sdev);
>>> - return 0;
>>> -}
>>> -
>>> /**
>>> * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
>>> *
>>> --
>>> 2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-14 3:05 ` Duan, Zhenzhong
@ 2024-06-14 7:56 ` Eric Auger
2024-06-14 9:00 ` Eric Auger
1 sibling, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-14 7:56 UTC (permalink / raw)
To: Duan, Zhenzhong, eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
On 6/14/24 05:05, Duan, Zhenzhong wrote:
>
>> -----Original Message-----
>> From: Eric Auger <eric.auger@redhat.com>
>> Subject: Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>
>>
>>
>> On 6/13/24 12:00, Duan, Zhenzhong wrote:
>>> Hi Eric,
>>>
>>>> -----Original Message-----
>>>> From: Eric Auger <eric.auger@redhat.com>
>>>> Subject: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>>>
>>>> Compute the host reserved regions in virtio_iommu_set_iommu_device().
>>>> The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
>>>> The virtio_iommu_set_host_iova_ranges() helper turns usable regions
>>>> into complementary reserved regions while testing the inclusion
>>>> into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
>>>> implementation of virtio_iommu_set_iova_ranges() which will be
>>>> removed in subsequent patches. rebuild_resv_regions() is just moved.
>>>>
>>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>>
>>>> ---
>>>>
>>>> - added g_assert(!sdev->probe_done)
>>>> ---
>>>> hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++----
>> ----
>>>> -
>>>> 1 file changed, 112 insertions(+), 34 deletions(-)
>>>>
>>>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>>>> index db842555c8..04474ebd74 100644
>>>> --- a/hw/virtio/virtio-iommu.c
>>>> +++ b/hw/virtio/virtio-iommu.c
>>>> @@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU
>>>> *viommu, PCIBus *bus, int devfn) {
>>>> return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>>>> }
>>>>
>>>> +/**
>>>> + * rebuild_resv_regions: rebuild resv regions with both the
>>>> + * info of host resv ranges and property set resv ranges
>>>> + */
>>>> +static int rebuild_resv_regions(IOMMUDevice *sdev)
>>>> +{
>>>> + GList *l;
>>>> + int i = 0;
>>>> +
>>>> + /* free the existing list and rebuild it from scratch */
>>>> + g_list_free_full(sdev->resv_regions, g_free);
>>>> + sdev->resv_regions = NULL;
>>>> +
>>>> + /* First add host reserved regions if any, all tagged as RESERVED */
>>>> + for (l = sdev->host_resv_ranges; l; l = l->next) {
>>>> + ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>>> + Range *r = (Range *)l->data;
>>>> +
>>>> + reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>>> + range_set_bounds(®->range, range_lob(r), range_upb(r));
>>>> + sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>> reg);
>>>> + trace_virtio_iommu_host_resv_regions(sdev-
>>>>> iommu_mr.parent_obj.name, i,
>>>> + range_lob(®->range),
>>>> + range_upb(®->range));
>>>> + i++;
>>>> + }
>>>> + /*
>>>> + * then add higher priority reserved regions set by the machine
>>>> + * through properties
>>>> + */
>>>> + add_prop_resv_regions(sdev);
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus
>>>> *bus,
>>>> + int devfn, GList *iova_ranges,
>>>> + Error **errp)
>>>> +{
>>>> + IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
>>> Here the bus/devfn parameters are real device BDF not aliased one,
>>> But used to index s->as_by_busptr which expect aliased bus/devfn.
>>>
>>> Do we need a translation of bus/devfn?
>> Hum that's a good point actually. I need to further study that. that's
>> not easy to translate, is it?
> Yes, may need a path to call into pci_device_get_iommu_bus_devfn().
> Maybe a new HostIOMMUDevice callback.
>
>> Now I am not totally sure why we don't use the alias as well for
>> HostIOMMUDevices or at least store the aliased bdf.
> Because we need to store HostIOMMUDevice in vIOMMU in real bdf granularity,
> Not aliased bdf granularity. Virtual vtd calls VFIO device uAPI on real device not
> the aliased device, i.e., VFIO_DEVICE_[ATTACH|DETACH]_IOMMUFD_PT.
>
> I also have a question, could we define host_resv_ranges in VirtioHostIOMMUDevice
> to avoid translation?
well reserved iova regions are rather associated to iommu groups
(associated to the concept of alias bdfs), no? Also potentially emulated
devices could expose some.
Eric
>
> Thanks
> Zhenzhong
>
>> Thanks
>>
>> Eric
>>> Thanks
>>> Zhenzhong
>>>
>>>> + IOMMUDevice *sdev;
>>>> + GList *current_ranges;
>>>> + GList *l, *tmp, *new_ranges = NULL;
>>>> + int ret = -EINVAL;
>>>> +
>>>> + if (!sbus) {
>>>> + error_report("%s no sbus", __func__);
>>>> + }
>>>> +
>>>> + sdev = sbus->pbdev[devfn];
>>>> +
>>>> + current_ranges = sdev->host_resv_ranges;
>>>> +
>>>> + g_assert(!sdev->probe_done);
>>>> +
>>>> + /* check that each new resv region is included in an existing one */
>>>> + if (sdev->host_resv_ranges) {
>>>> + range_inverse_array(iova_ranges,
>>>> + &new_ranges,
>>>> + 0, UINT64_MAX);
>>>> +
>>>> + for (tmp = new_ranges; tmp; tmp = tmp->next) {
>>>> + Range *newr = (Range *)tmp->data;
>>>> + bool included = false;
>>>> +
>>>> + for (l = current_ranges; l; l = l->next) {
>>>> + Range * r = (Range *)l->data;
>>>> +
>>>> + if (range_contains_range(r, newr)) {
>>>> + included = true;
>>>> + break;
>>>> + }
>>>> + }
>>>> + if (!included) {
>>>> + goto error;
>>>> + }
>>>> + }
>>>> + /* all new reserved ranges are included in existing ones */
>>>> + ret = 0;
>>>> + goto out;
>>>> + }
>>>> +
>>>> + range_inverse_array(iova_ranges,
>>>> + &sdev->host_resv_ranges,
>>>> + 0, UINT64_MAX);
>>>> + rebuild_resv_regions(sdev);
>>>> +
>>>> + return 0;
>>>> +error:
>>>> + error_setg(errp, "%s Conflicting host reserved ranges set!",
>>>> + __func__);
>>>> +out:
>>>> + g_list_free_full(new_ranges, g_free);
>>>> + return ret;
>>>> +}
>>>> +
>>>> static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>>>> int devfn,
>>>> HostIOMMUDevice *hiod, Error **errp)
>>>> {
>>>> VirtIOIOMMU *viommu = opaque;
>>>> VirtioHostIOMMUDevice *vhiod;
>>>> + HostIOMMUDeviceClass *hiodc =
>>>> HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>>>> struct hiod_key *new_key;
>>>> + GList *host_iova_ranges = NULL;
>>>>
>>>> assert(hiod);
>>>>
>>>> @@ -513,6 +610,20 @@ static bool
>>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>>> return false;
>>>> }
>>>>
>>>> + if (hiodc->get_iova_ranges) {
>>>> + int ret;
>>>> + host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
>>>> + if (!host_iova_ranges) {
>>>> + return true; /* some old kernels may not support that capability
>> */
>>>> + }
>>>> + ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
>>>> + host_iova_ranges, errp);
>>>> + if (ret) {
>>>> + g_list_free_full(host_iova_ranges, g_free);
>>>> + return false;
>>>> + }
>>>> + }
>>>> +
>>>> vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>>>> vhiod->bus = bus;
>>>> vhiod->devfn = (uint8_t)devfn;
>>>> @@ -525,6 +636,7 @@ static bool
>>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>>>
>>>> object_ref(hiod);
>>>> g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>>>> + g_list_free_full(host_iova_ranges, g_free);
>>>>
>>>> return true;
>>>> }
>>>> @@ -1246,40 +1358,6 @@ static int
>>>> virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
>>>> return 0;
>>>> }
>>>>
>>>> -/**
>>>> - * rebuild_resv_regions: rebuild resv regions with both the
>>>> - * info of host resv ranges and property set resv ranges
>>>> - */
>>>> -static int rebuild_resv_regions(IOMMUDevice *sdev)
>>>> -{
>>>> - GList *l;
>>>> - int i = 0;
>>>> -
>>>> - /* free the existing list and rebuild it from scratch */
>>>> - g_list_free_full(sdev->resv_regions, g_free);
>>>> - sdev->resv_regions = NULL;
>>>> -
>>>> - /* First add host reserved regions if any, all tagged as RESERVED */
>>>> - for (l = sdev->host_resv_ranges; l; l = l->next) {
>>>> - ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>>> - Range *r = (Range *)l->data;
>>>> -
>>>> - reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>>> - range_set_bounds(®->range, range_lob(r), range_upb(r));
>>>> - sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>> reg);
>>>> - trace_virtio_iommu_host_resv_regions(sdev-
>>>>> iommu_mr.parent_obj.name, i,
>>>> - range_lob(®->range),
>>>> - range_upb(®->range));
>>>> - i++;
>>>> - }
>>>> - /*
>>>> - * then add higher priority reserved regions set by the machine
>>>> - * through properties
>>>> - */
>>>> - add_prop_resv_regions(sdev);
>>>> - return 0;
>>>> -}
>>>> -
>>>> /**
>>>> * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
>>>> *
>>>> --
>>>> 2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
2024-06-14 3:05 ` Duan, Zhenzhong
2024-06-14 7:56 ` Eric Auger
@ 2024-06-14 9:00 ` Eric Auger
1 sibling, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-14 9:00 UTC (permalink / raw)
To: Duan, Zhenzhong, eric.auger.pro@gmail.com, qemu-devel@nongnu.org,
qemu-arm@nongnu.org, mst@redhat.com, jean-philippe@linaro.org,
peter.maydell@linaro.org, clg@redhat.com, yanghliu@redhat.com
Cc: alex.williamson@redhat.com, jasowang@redhat.com,
pbonzini@redhat.com, berrange@redhat.com
Hi Zhenzhong,
On 6/14/24 05:05, Duan, Zhenzhong wrote:
>
>> -----Original Message-----
>> From: Eric Auger <eric.auger@redhat.com>
>> Subject: Re: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>
>>
>>
>> On 6/13/24 12:00, Duan, Zhenzhong wrote:
>>> Hi Eric,
>>>
>>>> -----Original Message-----
>>>> From: Eric Auger <eric.auger@redhat.com>
>>>> Subject: [PATCH v3 4/7] virtio-iommu: Compute host reserved regions
>>>>
>>>> Compute the host reserved regions in virtio_iommu_set_iommu_device().
>>>> The usable IOVA regions are retrieved from the HOSTIOMMUDevice.
>>>> The virtio_iommu_set_host_iova_ranges() helper turns usable regions
>>>> into complementary reserved regions while testing the inclusion
>>>> into existing ones. virtio_iommu_set_host_iova_ranges() reuse the
>>>> implementation of virtio_iommu_set_iova_ranges() which will be
>>>> removed in subsequent patches. rebuild_resv_regions() is just moved.
>>>>
>>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>>
>>>> ---
>>>>
>>>> - added g_assert(!sdev->probe_done)
>>>> ---
>>>> hw/virtio/virtio-iommu.c | 146 ++++++++++++++++++++++++++++++----
>> ----
>>>> -
>>>> 1 file changed, 112 insertions(+), 34 deletions(-)
>>>>
>>>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>>>> index db842555c8..04474ebd74 100644
>>>> --- a/hw/virtio/virtio-iommu.c
>>>> +++ b/hw/virtio/virtio-iommu.c
>>>> @@ -498,12 +498,109 @@ get_host_iommu_device(VirtIOIOMMU
>>>> *viommu, PCIBus *bus, int devfn) {
>>>> return g_hash_table_lookup(viommu->host_iommu_devices, &key);
>>>> }
>>>>
>>>> +/**
>>>> + * rebuild_resv_regions: rebuild resv regions with both the
>>>> + * info of host resv ranges and property set resv ranges
>>>> + */
>>>> +static int rebuild_resv_regions(IOMMUDevice *sdev)
>>>> +{
>>>> + GList *l;
>>>> + int i = 0;
>>>> +
>>>> + /* free the existing list and rebuild it from scratch */
>>>> + g_list_free_full(sdev->resv_regions, g_free);
>>>> + sdev->resv_regions = NULL;
>>>> +
>>>> + /* First add host reserved regions if any, all tagged as RESERVED */
>>>> + for (l = sdev->host_resv_ranges; l; l = l->next) {
>>>> + ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>>> + Range *r = (Range *)l->data;
>>>> +
>>>> + reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>>> + range_set_bounds(®->range, range_lob(r), range_upb(r));
>>>> + sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>> reg);
>>>> + trace_virtio_iommu_host_resv_regions(sdev-
>>>>> iommu_mr.parent_obj.name, i,
>>>> + range_lob(®->range),
>>>> + range_upb(®->range));
>>>> + i++;
>>>> + }
>>>> + /*
>>>> + * then add higher priority reserved regions set by the machine
>>>> + * through properties
>>>> + */
>>>> + add_prop_resv_regions(sdev);
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus
>>>> *bus,
>>>> + int devfn, GList *iova_ranges,
>>>> + Error **errp)
>>>> +{
>>>> + IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
>>> Here the bus/devfn parameters are real device BDF not aliased one,
>>> But used to index s->as_by_busptr which expect aliased bus/devfn.
>>>
>>> Do we need a translation of bus/devfn?
>> Hum that's a good point actually. I need to further study that. that's
>> not easy to translate, is it?
> Yes, may need a path to call into pci_device_get_iommu_bus_devfn().
> Maybe a new HostIOMMUDevice callback.
>
>> Now I am not totally sure why we don't use the alias as well for
>> HostIOMMUDevices or at least store the aliased bdf.
> Because we need to store HostIOMMUDevice in vIOMMU in real bdf granularity,
> Not aliased bdf granularity. Virtual vtd calls VFIO device uAPI on real device not
> the aliased device, i.e., VFIO_DEVICE_[ATTACH|DETACH]_IOMMUFD_PT.
>
> I also have a question, could we define host_resv_ranges in VirtioHostIOMMUDevice
> to avoid translation?
I would suggest to pass the aliased info through the set_iommu_device()
and store them in the HostIOMMUDevice. I will submit a patch accordingly
Thanks
Eric
>
> Thanks
> Zhenzhong
>
>> Thanks
>>
>> Eric
>>> Thanks
>>> Zhenzhong
>>>
>>>> + IOMMUDevice *sdev;
>>>> + GList *current_ranges;
>>>> + GList *l, *tmp, *new_ranges = NULL;
>>>> + int ret = -EINVAL;
>>>> +
>>>> + if (!sbus) {
>>>> + error_report("%s no sbus", __func__);
>>>> + }
>>>> +
>>>> + sdev = sbus->pbdev[devfn];
>>>> +
>>>> + current_ranges = sdev->host_resv_ranges;
>>>> +
>>>> + g_assert(!sdev->probe_done);
>>>> +
>>>> + /* check that each new resv region is included in an existing one */
>>>> + if (sdev->host_resv_ranges) {
>>>> + range_inverse_array(iova_ranges,
>>>> + &new_ranges,
>>>> + 0, UINT64_MAX);
>>>> +
>>>> + for (tmp = new_ranges; tmp; tmp = tmp->next) {
>>>> + Range *newr = (Range *)tmp->data;
>>>> + bool included = false;
>>>> +
>>>> + for (l = current_ranges; l; l = l->next) {
>>>> + Range * r = (Range *)l->data;
>>>> +
>>>> + if (range_contains_range(r, newr)) {
>>>> + included = true;
>>>> + break;
>>>> + }
>>>> + }
>>>> + if (!included) {
>>>> + goto error;
>>>> + }
>>>> + }
>>>> + /* all new reserved ranges are included in existing ones */
>>>> + ret = 0;
>>>> + goto out;
>>>> + }
>>>> +
>>>> + range_inverse_array(iova_ranges,
>>>> + &sdev->host_resv_ranges,
>>>> + 0, UINT64_MAX);
>>>> + rebuild_resv_regions(sdev);
>>>> +
>>>> + return 0;
>>>> +error:
>>>> + error_setg(errp, "%s Conflicting host reserved ranges set!",
>>>> + __func__);
>>>> +out:
>>>> + g_list_free_full(new_ranges, g_free);
>>>> + return ret;
>>>> +}
>>>> +
>>>> static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque,
>>>> int devfn,
>>>> HostIOMMUDevice *hiod, Error **errp)
>>>> {
>>>> VirtIOIOMMU *viommu = opaque;
>>>> VirtioHostIOMMUDevice *vhiod;
>>>> + HostIOMMUDeviceClass *hiodc =
>>>> HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>>>> struct hiod_key *new_key;
>>>> + GList *host_iova_ranges = NULL;
>>>>
>>>> assert(hiod);
>>>>
>>>> @@ -513,6 +610,20 @@ static bool
>>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>>> return false;
>>>> }
>>>>
>>>> + if (hiodc->get_iova_ranges) {
>>>> + int ret;
>>>> + host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
>>>> + if (!host_iova_ranges) {
>>>> + return true; /* some old kernels may not support that capability
>> */
>>>> + }
>>>> + ret = virtio_iommu_set_host_iova_ranges(viommu, bus, devfn,
>>>> + host_iova_ranges, errp);
>>>> + if (ret) {
>>>> + g_list_free_full(host_iova_ranges, g_free);
>>>> + return false;
>>>> + }
>>>> + }
>>>> +
>>>> vhiod = g_malloc0(sizeof(VirtioHostIOMMUDevice));
>>>> vhiod->bus = bus;
>>>> vhiod->devfn = (uint8_t)devfn;
>>>> @@ -525,6 +636,7 @@ static bool
>>>> virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
>>>>
>>>> object_ref(hiod);
>>>> g_hash_table_insert(viommu->host_iommu_devices, new_key, vhiod);
>>>> + g_list_free_full(host_iova_ranges, g_free);
>>>>
>>>> return true;
>>>> }
>>>> @@ -1246,40 +1358,6 @@ static int
>>>> virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
>>>> return 0;
>>>> }
>>>>
>>>> -/**
>>>> - * rebuild_resv_regions: rebuild resv regions with both the
>>>> - * info of host resv ranges and property set resv ranges
>>>> - */
>>>> -static int rebuild_resv_regions(IOMMUDevice *sdev)
>>>> -{
>>>> - GList *l;
>>>> - int i = 0;
>>>> -
>>>> - /* free the existing list and rebuild it from scratch */
>>>> - g_list_free_full(sdev->resv_regions, g_free);
>>>> - sdev->resv_regions = NULL;
>>>> -
>>>> - /* First add host reserved regions if any, all tagged as RESERVED */
>>>> - for (l = sdev->host_resv_ranges; l; l = l->next) {
>>>> - ReservedRegion *reg = g_new0(ReservedRegion, 1);
>>>> - Range *r = (Range *)l->data;
>>>> -
>>>> - reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
>>>> - range_set_bounds(®->range, range_lob(r), range_upb(r));
>>>> - sdev->resv_regions = resv_region_list_insert(sdev->resv_regions,
>> reg);
>>>> - trace_virtio_iommu_host_resv_regions(sdev-
>>>>> iommu_mr.parent_obj.name, i,
>>>> - range_lob(®->range),
>>>> - range_upb(®->range));
>>>> - i++;
>>>> - }
>>>> - /*
>>>> - * then add higher priority reserved regions set by the machine
>>>> - * through properties
>>>> - */
>>>> - add_prop_resv_regions(sdev);
>>>> - return 0;
>>>> -}
>>>> -
>>>> /**
>>>> * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
>>>> *
>>>> --
>>>> 2.41.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 5/7] virtio-iommu: Remove the implementation of iommu_set_iova_range
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
` (3 preceding siblings ...)
2024-06-13 9:20 ` [PATCH v3 4/7] virtio-iommu: Compute host reserved regions Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-13 9:20 ` [PATCH v3 6/7] hw/vfio: Remove memory_region_iommu_set_iova_ranges() call Eric Auger
2024-06-13 9:20 ` [PATCH v3 7/7] memory: Remove IOMMU MR iommu_set_iova_range API Eric Auger
6 siblings, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Now that we use PCIIOMMUOps to convey information about usable IOVA
ranges we do not to implement the iommu_set_iova_ranges IOMMU MR
callback.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
hw/virtio/virtio-iommu.c | 67 ----------------------------------------
1 file changed, 67 deletions(-)
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 04474ebd74..22288885f1 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -1358,72 +1358,6 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
return 0;
}
-/**
- * virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
- *
- * The function turns those into reserved ranges. Once some
- * reserved ranges have been set, new reserved regions cannot be
- * added outside of the original ones.
- *
- * @mr: IOMMU MR
- * @iova_ranges: list of usable IOVA ranges
- * @errp: error handle
- */
-static int virtio_iommu_set_iova_ranges(IOMMUMemoryRegion *mr,
- GList *iova_ranges,
- Error **errp)
-{
- IOMMUDevice *sdev = container_of(mr, IOMMUDevice, iommu_mr);
- GList *current_ranges = sdev->host_resv_ranges;
- GList *l, *tmp, *new_ranges = NULL;
- int ret = -EINVAL;
-
- /* check that each new resv region is included in an existing one */
- if (sdev->host_resv_ranges) {
- range_inverse_array(iova_ranges,
- &new_ranges,
- 0, UINT64_MAX);
-
- for (tmp = new_ranges; tmp; tmp = tmp->next) {
- Range *newr = (Range *)tmp->data;
- bool included = false;
-
- for (l = current_ranges; l; l = l->next) {
- Range * r = (Range *)l->data;
-
- if (range_contains_range(r, newr)) {
- included = true;
- break;
- }
- }
- if (!included) {
- goto error;
- }
- }
- /* all new reserved ranges are included in existing ones */
- ret = 0;
- goto out;
- }
-
- if (sdev->probe_done) {
- warn_report("%s: Notified about new host reserved regions after probe",
- mr->parent_obj.name);
- }
-
- range_inverse_array(iova_ranges,
- &sdev->host_resv_ranges,
- 0, UINT64_MAX);
- rebuild_resv_regions(sdev);
-
- return 0;
-error:
- error_setg(errp, "IOMMU mr=%s Conflicting host reserved ranges set!",
- mr->parent_obj.name);
-out:
- g_list_free_full(new_ranges, g_free);
- return ret;
-}
-
static void virtio_iommu_system_reset(void *opaque)
{
VirtIOIOMMU *s = opaque;
@@ -1749,7 +1683,6 @@ static void virtio_iommu_memory_region_class_init(ObjectClass *klass,
imrc->replay = virtio_iommu_replay;
imrc->notify_flag_changed = virtio_iommu_notify_flag_changed;
imrc->iommu_set_page_size_mask = virtio_iommu_set_page_size_mask;
- imrc->iommu_set_iova_ranges = virtio_iommu_set_iova_ranges;
}
static const TypeInfo virtio_iommu_info = {
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 6/7] hw/vfio: Remove memory_region_iommu_set_iova_ranges() call
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
` (4 preceding siblings ...)
2024-06-13 9:20 ` [PATCH v3 5/7] virtio-iommu: Remove the implementation of iommu_set_iova_range Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
2024-06-13 9:20 ` [PATCH v3 7/7] memory: Remove IOMMU MR iommu_set_iova_range API Eric Auger
6 siblings, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
As we have just removed the only implementation of
iommu_set_iova_ranges IOMMU MR callback in the virtio-iommu,
let's remove the call to the memory wrapper. Usable IOVA ranges
are now conveyed through the PCIIOMMUOps in VFIO-PCI.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
hw/vfio/common.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index f20a7b5bba..9e4c0cc95f 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -630,16 +630,6 @@ static void vfio_listener_region_add(MemoryListener *listener,
goto fail;
}
- if (bcontainer->iova_ranges) {
- ret = memory_region_iommu_set_iova_ranges(giommu->iommu_mr,
- bcontainer->iova_ranges,
- &err);
- if (ret) {
- g_free(giommu);
- goto fail;
- }
- }
-
ret = memory_region_register_iommu_notifier(section->mr, &giommu->n,
&err);
if (ret) {
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 7/7] memory: Remove IOMMU MR iommu_set_iova_range API
2024-06-13 9:20 [PATCH v3 0/7] VIRTIO-IOMMU/VFIO: Fix host iommu geometry handling for hotplugged devices Eric Auger
` (5 preceding siblings ...)
2024-06-13 9:20 ` [PATCH v3 6/7] hw/vfio: Remove memory_region_iommu_set_iova_ranges() call Eric Auger
@ 2024-06-13 9:20 ` Eric Auger
6 siblings, 0 replies; 22+ messages in thread
From: Eric Auger @ 2024-06-13 9:20 UTC (permalink / raw)
To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, mst,
jean-philippe, peter.maydell, clg, yanghliu, zhenzhong.duan
Cc: alex.williamson, jasowang, pbonzini, berrange
Since the host IOVA ranges are now passed through the
PCIIOMMUOps set_host_resv_regions and we have removed
the only implementation of iommu_set_iova_range() in
the virtio-iommu and the only call site in vfio/common,
let's retire the IOMMU MR API and its memory wrapper.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
include/exec/memory.h | 32 --------------------------------
system/memory.c | 13 -------------
2 files changed, 45 deletions(-)
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 1be58f694c..ed40f74460 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -530,26 +530,6 @@ struct IOMMUMemoryRegionClass {
int (*iommu_set_page_size_mask)(IOMMUMemoryRegion *iommu,
uint64_t page_size_mask,
Error **errp);
- /**
- * @iommu_set_iova_ranges:
- *
- * Propagate information about the usable IOVA ranges for a given IOMMU
- * memory region. Used for example to propagate host physical device
- * reserved memory region constraints to the virtual IOMMU.
- *
- * Optional method: if this method is not provided, then the default IOVA
- * aperture is used.
- *
- * @iommu: the IOMMUMemoryRegion
- *
- * @iova_ranges: list of ordered IOVA ranges (at least one range)
- *
- * Returns 0 on success, or a negative error. In case of failure, the error
- * object must be created.
- */
- int (*iommu_set_iova_ranges)(IOMMUMemoryRegion *iommu,
- GList *iova_ranges,
- Error **errp);
};
typedef struct RamDiscardListener RamDiscardListener;
@@ -1951,18 +1931,6 @@ int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr,
uint64_t page_size_mask,
Error **errp);
-/**
- * memory_region_iommu_set_iova_ranges - Set the usable IOVA ranges
- * for a given IOMMU MR region
- *
- * @iommu: IOMMU memory region
- * @iova_ranges: list of ordered IOVA ranges (at least one range)
- * @errp: pointer to Error*, to store an error if it happens.
- */
-int memory_region_iommu_set_iova_ranges(IOMMUMemoryRegion *iommu,
- GList *iova_ranges,
- Error **errp);
-
/**
* memory_region_name: get a memory region's name
*
diff --git a/system/memory.c b/system/memory.c
index 74cd73ebc7..336ad5da5f 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1914,19 +1914,6 @@ int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr,
return ret;
}
-int memory_region_iommu_set_iova_ranges(IOMMUMemoryRegion *iommu_mr,
- GList *iova_ranges,
- Error **errp)
-{
- IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
- int ret = 0;
-
- if (imrc->iommu_set_iova_ranges) {
- ret = imrc->iommu_set_iova_ranges(iommu_mr, iova_ranges, errp);
- }
- return ret;
-}
-
int memory_region_register_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n, Error **errp)
{
--
2.41.0
^ permalink raw reply related [flat|nested] 22+ messages in thread