Some vIOMMU such as virtio-iommu use IOVA ranges from host side to
setup reserved ranges for passthrough device, so that guest will not
use an IOVA range beyond host support.
Use an uAPI of IOMMUFD to get IOVA ranges of host side and pass to
vIOMMU just like the legacy backend, if this fails, fallback to
64bit IOVA range.
Also use out_iova_alignment returned from uAPI as pgsizes instead of
qemu_real_host_page_size() as a fallback.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
v6: propagate iommufd_cdev_get_info_iova_range err and print as warning
hw/vfio/iommufd.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 06282d885c..e5bf528e89 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -267,6 +267,53 @@ static int iommufd_cdev_ram_block_discard_disable(bool state)
return ram_block_uncoordinated_discard_disable(state);
}
+static int iommufd_cdev_get_info_iova_range(VFIOIOMMUFDContainer *container,
+ uint32_t ioas_id, Error **errp)
+{
+ VFIOContainerBase *bcontainer = &container->bcontainer;
+ struct iommu_ioas_iova_ranges *info;
+ struct iommu_iova_range *iova_ranges;
+ int ret, sz, fd = container->be->fd;
+
+ info = g_malloc0(sizeof(*info));
+ info->size = sizeof(*info);
+ info->ioas_id = ioas_id;
+
+ ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info);
+ if (ret && errno != EMSGSIZE) {
+ goto error;
+ }
+
+ sz = info->num_iovas * sizeof(struct iommu_iova_range);
+ info = g_realloc(info, sizeof(*info) + sz);
+ info->allowed_iovas = (uintptr_t)(info + 1);
+
+ ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info);
+ if (ret) {
+ goto error;
+ }
+
+ iova_ranges = (struct iommu_iova_range *)(uintptr_t)info->allowed_iovas;
+
+ for (int i = 0; i < info->num_iovas; i++) {
+ Range *range = g_new(Range, 1);
+
+ range_set_bounds(range, iova_ranges[i].start, iova_ranges[i].last);
+ bcontainer->iova_ranges =
+ range_list_insert(bcontainer->iova_ranges, range);
+ }
+ bcontainer->pgsizes = info->out_iova_alignment;
+
+ g_free(info);
+ return 0;
+
+error:
+ ret = -errno;
+ g_free(info);
+ error_setg_errno(errp, errno, "Cannot get IOVA ranges");
+ return ret;
+}
+
static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
AddressSpace *as, Error **errp)
{
@@ -341,7 +388,13 @@ static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
goto err_discard_disable;
}
- bcontainer->pgsizes = qemu_real_host_page_size();
+ ret = iommufd_cdev_get_info_iova_range(container, ioas_id, &err);
+ if (ret) {
+ warn_report_err(err);
+ err = NULL;
+ error_printf("Fallback to default 64bit IOVA range and 4K page size\n");
+ bcontainer->pgsizes = qemu_real_host_page_size();
+ }
bcontainer->listener = vfio_memory_listener;
memory_listener_register(&bcontainer->listener, bcontainer->space->as);
--
2.34.1
On 11/14/23 11:09, Zhenzhong Duan wrote: > Some vIOMMU such as virtio-iommu use IOVA ranges from host side to > setup reserved ranges for passthrough device, so that guest will not > use an IOVA range beyond host support. > > Use an uAPI of IOMMUFD to get IOVA ranges of host side and pass to > vIOMMU just like the legacy backend, if this fails, fallback to > 64bit IOVA range. > > Also use out_iova_alignment returned from uAPI as pgsizes instead of > qemu_real_host_page_size() as a fallback. > > Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> > --- > v6: propagate iommufd_cdev_get_info_iova_range err and print as warning > > hw/vfio/iommufd.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 54 insertions(+), 1 deletion(-) > > diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c > index 06282d885c..e5bf528e89 100644 > --- a/hw/vfio/iommufd.c > +++ b/hw/vfio/iommufd.c > @@ -267,6 +267,53 @@ static int iommufd_cdev_ram_block_discard_disable(bool state) > return ram_block_uncoordinated_discard_disable(state); > } > > +static int iommufd_cdev_get_info_iova_range(VFIOIOMMUFDContainer *container, > + uint32_t ioas_id, Error **errp) > +{ > + VFIOContainerBase *bcontainer = &container->bcontainer; > + struct iommu_ioas_iova_ranges *info; > + struct iommu_iova_range *iova_ranges; > + int ret, sz, fd = container->be->fd; > + > + info = g_malloc0(sizeof(*info)); > + info->size = sizeof(*info); > + info->ioas_id = ioas_id; > + > + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); > + if (ret && errno != EMSGSIZE) { > + goto error; > + } > + > + sz = info->num_iovas * sizeof(struct iommu_iova_range); > + info = g_realloc(info, sizeof(*info) + sz); > + info->allowed_iovas = (uintptr_t)(info + 1); > + > + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); > + if (ret) { > + goto error; > + } > + > + iova_ranges = (struct iommu_iova_range *)(uintptr_t)info->allowed_iovas; > + > + for (int i = 0; i < info->num_iovas; i++) { > + Range *range = g_new(Range, 1); > + > + range_set_bounds(range, iova_ranges[i].start, iova_ranges[i].last); > + bcontainer->iova_ranges = > + range_list_insert(bcontainer->iova_ranges, range); > + } > + bcontainer->pgsizes = info->out_iova_alignment; > + > + g_free(info); > + return 0; > + > +error: > + ret = -errno; > + g_free(info); > + error_setg_errno(errp, errno, "Cannot get IOVA ranges"); > + return ret; > +} > + > static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, > AddressSpace *as, Error **errp) > { > @@ -341,7 +388,13 @@ static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, > goto err_discard_disable; > } > > - bcontainer->pgsizes = qemu_real_host_page_size(); > + ret = iommufd_cdev_get_info_iova_range(container, ioas_id, &err); > + if (ret) { > + warn_report_err(err); > + err = NULL; > + error_printf("Fallback to default 64bit IOVA range and 4K page size\n"); This would be better : error_append_hint(&err, "Fallback to default 64bit IOVA range and 4K page size\n"); warn_report_err(err); I will take care of it if you agree. With that, Reviewed-by: Cédric Le Goater <clg@redhat.com> Thanks, C. > + bcontainer->pgsizes = qemu_real_host_page_size(); > + } > > bcontainer->listener = vfio_memory_listener; > memory_listener_register(&bcontainer->listener, bcontainer->space->as);
On 11/14/23 14:46, Cédric Le Goater wrote: > On 11/14/23 11:09, Zhenzhong Duan wrote: >> Some vIOMMU such as virtio-iommu use IOVA ranges from host side to >> setup reserved ranges for passthrough device, so that guest will not >> use an IOVA range beyond host support. >> >> Use an uAPI of IOMMUFD to get IOVA ranges of host side and pass to >> vIOMMU just like the legacy backend, if this fails, fallback to >> 64bit IOVA range. >> >> Also use out_iova_alignment returned from uAPI as pgsizes instead of >> qemu_real_host_page_size() as a fallback. >> >> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> >> --- >> v6: propagate iommufd_cdev_get_info_iova_range err and print as warning >> >> hw/vfio/iommufd.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> 1 file changed, 54 insertions(+), 1 deletion(-) >> >> diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c >> index 06282d885c..e5bf528e89 100644 >> --- a/hw/vfio/iommufd.c >> +++ b/hw/vfio/iommufd.c >> @@ -267,6 +267,53 @@ static int >> iommufd_cdev_ram_block_discard_disable(bool state) >> return ram_block_uncoordinated_discard_disable(state); >> } >> +static int iommufd_cdev_get_info_iova_range(VFIOIOMMUFDContainer >> *container, >> + uint32_t ioas_id, Error >> **errp) >> +{ >> + VFIOContainerBase *bcontainer = &container->bcontainer; >> + struct iommu_ioas_iova_ranges *info; >> + struct iommu_iova_range *iova_ranges; >> + int ret, sz, fd = container->be->fd; >> + >> + info = g_malloc0(sizeof(*info)); >> + info->size = sizeof(*info); >> + info->ioas_id = ioas_id; >> + >> + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); >> + if (ret && errno != EMSGSIZE) { >> + goto error; >> + } >> + >> + sz = info->num_iovas * sizeof(struct iommu_iova_range); >> + info = g_realloc(info, sizeof(*info) + sz); >> + info->allowed_iovas = (uintptr_t)(info + 1); >> + >> + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); >> + if (ret) { >> + goto error; >> + } >> + >> + iova_ranges = (struct iommu_iova_range >> *)(uintptr_t)info->allowed_iovas; >> + >> + for (int i = 0; i < info->num_iovas; i++) { >> + Range *range = g_new(Range, 1); >> + >> + range_set_bounds(range, iova_ranges[i].start, >> iova_ranges[i].last); >> + bcontainer->iova_ranges = >> + range_list_insert(bcontainer->iova_ranges, range); >> + } >> + bcontainer->pgsizes = info->out_iova_alignment; >> + >> + g_free(info); >> + return 0; >> + >> +error: >> + ret = -errno; >> + g_free(info); >> + error_setg_errno(errp, errno, "Cannot get IOVA ranges"); >> + return ret; >> +} >> + >> static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, >> AddressSpace *as, Error **errp) >> { >> @@ -341,7 +388,13 @@ static int iommufd_cdev_attach(const char *name, >> VFIODevice *vbasedev, >> goto err_discard_disable; >> } >> - bcontainer->pgsizes = qemu_real_host_page_size(); >> + ret = iommufd_cdev_get_info_iova_range(container, ioas_id, &err); >> + if (ret) { >> + warn_report_err(err); >> + err = NULL; >> + error_printf("Fallback to default 64bit IOVA range and 4K >> page size\n"); > > This would be better : > > error_append_hint(&err, > "Fallback to default 64bit IOVA range and 4K page > size\n"); > warn_report_err(err); > > I will take care of it if you agree. With that, > > Reviewed-by: Cédric Le Goater <clg@redhat.com> With Cédric's suggestion, Reviewed-by: Eric Auger <eric.auger@redhat.com> Eric > > Thanks, > > C. > > >> + bcontainer->pgsizes = qemu_real_host_page_size(); >> + } >> bcontainer->listener = vfio_memory_listener; >> memory_listener_register(&bcontainer->listener, >> bcontainer->space->as); >
>-----Original Message----- >From: Cédric Le Goater <clg@redhat.com> >Sent: Tuesday, November 14, 2023 9:46 PM >Subject: Re: [PATCH v6 06/21] vfio/iommufd: Add support for iova_ranges and >pgsizes > >On 11/14/23 11:09, Zhenzhong Duan wrote: >> Some vIOMMU such as virtio-iommu use IOVA ranges from host side to >> setup reserved ranges for passthrough device, so that guest will not >> use an IOVA range beyond host support. >> >> Use an uAPI of IOMMUFD to get IOVA ranges of host side and pass to >> vIOMMU just like the legacy backend, if this fails, fallback to >> 64bit IOVA range. >> >> Also use out_iova_alignment returned from uAPI as pgsizes instead of >> qemu_real_host_page_size() as a fallback. >> >> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> >> --- >> v6: propagate iommufd_cdev_get_info_iova_range err and print as warning >> >> hw/vfio/iommufd.c | 55 >++++++++++++++++++++++++++++++++++++++++++++++- >> 1 file changed, 54 insertions(+), 1 deletion(-) >> >> diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c >> index 06282d885c..e5bf528e89 100644 >> --- a/hw/vfio/iommufd.c >> +++ b/hw/vfio/iommufd.c >> @@ -267,6 +267,53 @@ static int >iommufd_cdev_ram_block_discard_disable(bool state) >> return ram_block_uncoordinated_discard_disable(state); >> } >> >> +static int iommufd_cdev_get_info_iova_range(VFIOIOMMUFDContainer >*container, >> + uint32_t ioas_id, Error **errp) >> +{ >> + VFIOContainerBase *bcontainer = &container->bcontainer; >> + struct iommu_ioas_iova_ranges *info; >> + struct iommu_iova_range *iova_ranges; >> + int ret, sz, fd = container->be->fd; >> + >> + info = g_malloc0(sizeof(*info)); >> + info->size = sizeof(*info); >> + info->ioas_id = ioas_id; >> + >> + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); >> + if (ret && errno != EMSGSIZE) { >> + goto error; >> + } >> + >> + sz = info->num_iovas * sizeof(struct iommu_iova_range); >> + info = g_realloc(info, sizeof(*info) + sz); >> + info->allowed_iovas = (uintptr_t)(info + 1); >> + >> + ret = ioctl(fd, IOMMU_IOAS_IOVA_RANGES, info); >> + if (ret) { >> + goto error; >> + } >> + >> + iova_ranges = (struct iommu_iova_range *)(uintptr_t)info->allowed_iovas; >> + >> + for (int i = 0; i < info->num_iovas; i++) { >> + Range *range = g_new(Range, 1); >> + >> + range_set_bounds(range, iova_ranges[i].start, iova_ranges[i].last); >> + bcontainer->iova_ranges = >> + range_list_insert(bcontainer->iova_ranges, range); >> + } >> + bcontainer->pgsizes = info->out_iova_alignment; >> + >> + g_free(info); >> + return 0; >> + >> +error: >> + ret = -errno; >> + g_free(info); >> + error_setg_errno(errp, errno, "Cannot get IOVA ranges"); >> + return ret; >> +} >> + >> static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, >> AddressSpace *as, Error **errp) >> { >> @@ -341,7 +388,13 @@ static int iommufd_cdev_attach(const char *name, >VFIODevice *vbasedev, >> goto err_discard_disable; >> } >> >> - bcontainer->pgsizes = qemu_real_host_page_size(); >> + ret = iommufd_cdev_get_info_iova_range(container, ioas_id, &err); >> + if (ret) { >> + warn_report_err(err); >> + err = NULL; >> + error_printf("Fallback to default 64bit IOVA range and 4K page size\n"); > >This would be better : > > error_append_hint(&err, > "Fallback to default 64bit IOVA range and 4K page size\n"); > warn_report_err(err); > >I will take care of it if you agree. With that, Sure, thanks BRs Zhenzhong > >Reviewed-by: Cédric Le Goater <clg@redhat.com> > >Thanks, > >C. > > >> + bcontainer->pgsizes = qemu_real_host_page_size(); >> + } >> >> bcontainer->listener = vfio_memory_listener; >> memory_listener_register(&bcontainer->listener, bcontainer->space->as);
© 2016 - 2024 Red Hat, Inc.