vfio queue:

* Minor cleanups
 * Fix for a regression in device reset introduced in 8.2
 * Coverity fixes, including the removal of the iommufd backend mutex
 * Introduced VFIOIOMMUClass, to avoid compiling spapr when !CONFIG_PSERIES
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmWbIrcACgkQUaNDx8/7
 7KFtPRAAxWcH9uh4tjJe4CgL+wXC+JOgviiNaI3AS6KmxdTHXcAvXMNAiGJfTBo4
 y/lJg+PYNgcDWrOqZqp1jj6ulWpO8ekLD9Nxv03e6o3kaArX/o2MtsrndOtWYnG/
 CUrr+/kTNeEw9008OaOca9vuh03xh3AnSwb3DzjHTvpMkj5LTXzuE1mU50DTUkn9
 GZjuN3rqHcdjJ/fXpiS6IgJbxcxLdo2aSykmyuq+TZmGf02lTES94PRef3Btr7Q6
 sKQZpv+A+gcZ8DHDJqfOEzEgu1OSa257q4ic47O1X3CeSyiGTGQ7rVKHtX6bK7xP
 mB9WOVqzzdH/g+kHNG+kVXMCQXZ0qo7VlIkHabYD220RryZBCqMecQ4aKPLFULQE
 e7C5ZaEvb7TLe/EaEQUSFrLCns7Nq6ciurcoAmP0cn2Ef1Sr1luNQVAR9LWRH1pc
 1TeNmHy4nQygT0dQtFBXwNUZfnTuGcKdr43twReiCjX1ViPBU4lrcajVQH4rAuoe
 K/bBak2Kyi1LsFn8AzIwKXZZl83L57EyL+XEW8i5GN1jFSAHFx4ocUq8NQBa//kS
 xei9LV3HEJbAMOQsPO8HEK40mg5WR17s22AUClMqtD2DAQbPUrmcLbZ6Ttq6hTuV
 BqL56JFjbfML5RGjxwF9G8v5mdLmLlNRCGF2KI3NsT7dkMbVh24=
 =zvPi
 -----END PGP SIGNATURE-----

Merge tag 'pull-vfio-20240107' of https://github.com/legoater/qemu into staging

vfio queue:

* Minor cleanups
* Fix for a regression in device reset introduced in 8.2
* Coverity fixes, including the removal of the iommufd backend mutex
* Introduced VFIOIOMMUClass, to avoid compiling spapr when !CONFIG_PSERIES

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmWbIrcACgkQUaNDx8/7
# 7KFtPRAAxWcH9uh4tjJe4CgL+wXC+JOgviiNaI3AS6KmxdTHXcAvXMNAiGJfTBo4
# y/lJg+PYNgcDWrOqZqp1jj6ulWpO8ekLD9Nxv03e6o3kaArX/o2MtsrndOtWYnG/
# CUrr+/kTNeEw9008OaOca9vuh03xh3AnSwb3DzjHTvpMkj5LTXzuE1mU50DTUkn9
# GZjuN3rqHcdjJ/fXpiS6IgJbxcxLdo2aSykmyuq+TZmGf02lTES94PRef3Btr7Q6
# sKQZpv+A+gcZ8DHDJqfOEzEgu1OSa257q4ic47O1X3CeSyiGTGQ7rVKHtX6bK7xP
# mB9WOVqzzdH/g+kHNG+kVXMCQXZ0qo7VlIkHabYD220RryZBCqMecQ4aKPLFULQE
# e7C5ZaEvb7TLe/EaEQUSFrLCns7Nq6ciurcoAmP0cn2Ef1Sr1luNQVAR9LWRH1pc
# 1TeNmHy4nQygT0dQtFBXwNUZfnTuGcKdr43twReiCjX1ViPBU4lrcajVQH4rAuoe
# K/bBak2Kyi1LsFn8AzIwKXZZl83L57EyL+XEW8i5GN1jFSAHFx4ocUq8NQBa//kS
# xei9LV3HEJbAMOQsPO8HEK40mg5WR17s22AUClMqtD2DAQbPUrmcLbZ6Ttq6hTuV
# BqL56JFjbfML5RGjxwF9G8v5mdLmLlNRCGF2KI3NsT7dkMbVh24=
# =zvPi
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 07 Jan 2024 22:16:23 GMT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-vfio-20240107' of https://github.com/legoater/qemu:
  backends/iommufd: Remove mutex
  backends/iommufd: Remove check on number of backend users
  vfio/migration: Add helper function to set state or reset device
  vfio/container: Rename vfio_init_container to vfio_set_iommu
  vfio/iommufd: Remove the use of stat() to check file existence
  hw/vfio: fix iteration over global VFIODevice list
  vfio/container: Replace basename with g_path_get_basename
  vfio/iommufd: Remove CONFIG_IOMMUFD usage
  vfio/spapr: Only compile sPAPR IOMMU support when needed
  vfio/iommufd: Introduce a VFIOIOMMU iommufd QOM interface
  vfio/spapr: Introduce a sPAPR VFIOIOMMU QOM interface
  vfio/container: Intoduce a new VFIOIOMMUClass::setup handler
  vfio/container: Introduce a VFIOIOMMU legacy QOM interface
  vfio/container: Introduce a VFIOIOMMU QOM interface
  vfio/container: Initialize VFIOIOMMUOps under vfio_init_container()
  vfio/container: Introduce vfio_legacy_setup() for further cleanups
  vfio/spapr: Extend VFIOIOMMUOps with a release handler

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-01-08 10:28:42 +00:00
commit ffd454c67e
12 changed files with 222 additions and 151 deletions

View File

@ -29,7 +29,6 @@ static void iommufd_backend_init(Object *obj)
be->fd = -1;
be->users = 0;
be->owned = true;
qemu_mutex_init(&be->lock);
}
static void iommufd_backend_finalize(Object *obj)
@ -52,10 +51,8 @@ static void iommufd_backend_set_fd(Object *obj, const char *str, Error **errp)
error_prepend(errp, "Could not parse remote object fd %s:", str);
return;
}
qemu_mutex_lock(&be->lock);
be->fd = fd;
be->owned = false;
qemu_mutex_unlock(&be->lock);
trace_iommu_backend_set_fd(be->fd);
}
@ -79,12 +76,6 @@ int iommufd_backend_connect(IOMMUFDBackend *be, Error **errp)
{
int fd, ret = 0;
qemu_mutex_lock(&be->lock);
if (be->users == UINT32_MAX) {
error_setg(errp, "too many connections");
ret = -E2BIG;
goto out;
}
if (be->owned && !be->users) {
fd = qemu_open_old("/dev/iommu", O_RDWR);
if (fd < 0) {
@ -98,13 +89,11 @@ int iommufd_backend_connect(IOMMUFDBackend *be, Error **errp)
out:
trace_iommufd_backend_connect(be->fd, be->owned,
be->users, ret);
qemu_mutex_unlock(&be->lock);
return ret;
}
void iommufd_backend_disconnect(IOMMUFDBackend *be)
{
qemu_mutex_lock(&be->lock);
if (!be->users) {
goto out;
}
@ -115,7 +104,6 @@ void iommufd_backend_disconnect(IOMMUFDBackend *be)
}
out:
trace_iommufd_backend_disconnect(be->fd, be->users);
qemu_mutex_unlock(&be->lock);
}
int iommufd_backend_alloc_ioas(IOMMUFDBackend *be, uint32_t *ioas_id,

View File

@ -19,7 +19,6 @@
*/
#include "qemu/osdep.h"
#include CONFIG_DEVICES /* CONFIG_IOMMUFD */
#include <sys/ioctl.h>
#ifdef CONFIG_KVM
#include <linux/kvm.h>
@ -74,7 +73,7 @@ bool vfio_mig_active(void)
return false;
}
QLIST_FOREACH(vbasedev, &vfio_device_list, next) {
QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
if (vbasedev->migration_blocker) {
return false;
}
@ -95,7 +94,7 @@ static bool vfio_multiple_devices_migration_is_supported(void)
unsigned int device_num = 0;
bool all_support_p2p = true;
QLIST_FOREACH(vbasedev, &vfio_device_list, next) {
QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
if (vbasedev->migration) {
device_num++;
@ -1367,13 +1366,13 @@ void vfio_reset_handler(void *opaque)
{
VFIODevice *vbasedev;
QLIST_FOREACH(vbasedev, &vfio_device_list, next) {
QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
if (vbasedev->dev->realized) {
vbasedev->ops->vfio_compute_needs_reset(vbasedev);
}
}
QLIST_FOREACH(vbasedev, &vfio_device_list, next) {
QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) {
if (vbasedev->dev->realized && vbasedev->needs_reset) {
vbasedev->ops->vfio_hot_reset_multi(vbasedev);
}
@ -1503,13 +1502,15 @@ retry:
int vfio_attach_device(char *name, VFIODevice *vbasedev,
AddressSpace *as, Error **errp)
{
const VFIOIOMMUOps *ops = &vfio_legacy_ops;
const VFIOIOMMUClass *ops =
VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY));
#ifdef CONFIG_IOMMUFD
if (vbasedev->iommufd) {
ops = &vfio_iommufd_ops;
ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
}
#endif
assert(ops);
return ops->attach_device(name, vbasedev, as, errp);
}

View File

@ -72,7 +72,7 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
}
void vfio_container_init(VFIOContainerBase *bcontainer, VFIOAddressSpace *space,
const VFIOIOMMUOps *ops)
const VFIOIOMMUClass *ops)
{
bcontainer->ops = ops;
bcontainer->space = space;
@ -99,3 +99,13 @@ void vfio_container_destroy(VFIOContainerBase *bcontainer)
g_list_free_full(bcontainer->iova_ranges, g_free);
}
static const TypeInfo types[] = {
{
.name = TYPE_VFIO_IOMMU,
.parent = TYPE_INTERFACE,
.class_size = sizeof(VFIOIOMMUClass),
},
};
DEFINE_TYPES(types)

View File

@ -369,10 +369,34 @@ static int vfio_get_iommu_type(VFIOContainer *container,
return -EINVAL;
}
static int vfio_init_container(VFIOContainer *container, int group_fd,
Error **errp)
/*
* vfio_get_iommu_ops - get a VFIOIOMMUClass associated with a type
*/
static const VFIOIOMMUClass *vfio_get_iommu_class(int iommu_type, Error **errp)
{
ObjectClass *klass = NULL;
switch (iommu_type) {
case VFIO_TYPE1v2_IOMMU:
case VFIO_TYPE1_IOMMU:
klass = object_class_by_name(TYPE_VFIO_IOMMU_LEGACY);
break;
case VFIO_SPAPR_TCE_v2_IOMMU:
case VFIO_SPAPR_TCE_IOMMU:
klass = object_class_by_name(TYPE_VFIO_IOMMU_SPAPR);
break;
default:
g_assert_not_reached();
};
return VFIO_IOMMU_CLASS(klass);
}
static int vfio_set_iommu(VFIOContainer *container, int group_fd,
VFIOAddressSpace *space, Error **errp)
{
int iommu_type, ret;
const VFIOIOMMUClass *vioc;
iommu_type = vfio_get_iommu_type(container, errp);
if (iommu_type < 0) {
@ -401,6 +425,14 @@ static int vfio_init_container(VFIOContainer *container, int group_fd,
}
container->iommu_type = iommu_type;
vioc = vfio_get_iommu_class(iommu_type, errp);
if (!vioc) {
error_setg(errp, "No available IOMMU models");
return -EINVAL;
}
vfio_container_init(&container->bcontainer, space, vioc);
return 0;
}
@ -474,6 +506,35 @@ static void vfio_get_iommu_info_migration(VFIOContainer *container,
}
}
static int vfio_legacy_setup(VFIOContainerBase *bcontainer, Error **errp)
{
VFIOContainer *container = container_of(bcontainer, VFIOContainer,
bcontainer);
g_autofree struct vfio_iommu_type1_info *info = NULL;
int ret;
ret = vfio_get_iommu_info(container, &info);
if (ret) {
error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info");
return ret;
}
if (info->flags & VFIO_IOMMU_INFO_PGSIZES) {
bcontainer->pgsizes = info->iova_pgsizes;
} else {
bcontainer->pgsizes = qemu_real_host_page_size();
}
if (!vfio_get_info_dma_avail(info, &bcontainer->dma_max_mappings)) {
bcontainer->dma_max_mappings = 65535;
}
vfio_get_info_iova_range(info, bcontainer);
vfio_get_iommu_info_migration(container, info);
return 0;
}
static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
Error **errp)
{
@ -554,9 +615,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
container = g_malloc0(sizeof(*container));
container->fd = fd;
bcontainer = &container->bcontainer;
vfio_container_init(bcontainer, space, &vfio_legacy_ops);
ret = vfio_init_container(container, group->fd, errp);
ret = vfio_set_iommu(container, group->fd, space, errp);
if (ret) {
goto free_container_exit;
}
@ -567,43 +627,11 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
goto free_container_exit;
}
switch (container->iommu_type) {
case VFIO_TYPE1v2_IOMMU:
case VFIO_TYPE1_IOMMU:
{
struct vfio_iommu_type1_info *info;
assert(bcontainer->ops->setup);
ret = vfio_get_iommu_info(container, &info);
if (ret) {
error_setg_errno(errp, -ret, "Failed to get VFIO IOMMU info");
goto enable_discards_exit;
}
if (info->flags & VFIO_IOMMU_INFO_PGSIZES) {
bcontainer->pgsizes = info->iova_pgsizes;
} else {
bcontainer->pgsizes = qemu_real_host_page_size();
}
if (!vfio_get_info_dma_avail(info, &bcontainer->dma_max_mappings)) {
bcontainer->dma_max_mappings = 65535;
}
vfio_get_info_iova_range(info, bcontainer);
vfio_get_iommu_info_migration(container, info);
g_free(info);
break;
}
case VFIO_SPAPR_TCE_v2_IOMMU:
case VFIO_SPAPR_TCE_IOMMU:
{
ret = vfio_spapr_container_init(container, errp);
if (ret) {
goto enable_discards_exit;
}
break;
}
ret = bcontainer->ops->setup(bcontainer, errp);
if (ret) {
goto enable_discards_exit;
}
vfio_kvm_device_add_group(group);
@ -632,9 +660,8 @@ listener_release_exit:
QLIST_REMOVE(bcontainer, next);
vfio_kvm_device_del_group(group);
memory_listener_unregister(&bcontainer->listener);
if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU ||
container->iommu_type == VFIO_SPAPR_TCE_IOMMU) {
vfio_spapr_container_deinit(container);
if (bcontainer->ops->release) {
bcontainer->ops->release(bcontainer);
}
enable_discards_exit:
@ -667,9 +694,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
*/
if (QLIST_EMPTY(&container->group_list)) {
memory_listener_unregister(&bcontainer->listener);
if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU ||
container->iommu_type == VFIO_SPAPR_TCE_IOMMU) {
vfio_spapr_container_deinit(container);
if (bcontainer->ops->release) {
bcontainer->ops->release(bcontainer);
}
}
@ -843,7 +869,8 @@ static void vfio_put_base_device(VFIODevice *vbasedev)
static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp)
{
char *tmp, group_path[PATH_MAX], *group_name;
char *tmp, group_path[PATH_MAX];
g_autofree char *group_name = NULL;
int ret, groupid;
ssize_t len;
@ -859,7 +886,7 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp)
group_path[len] = 0;
group_name = basename(group_path);
group_name = g_path_get_basename(group_path);
if (sscanf(group_name, "%d", &groupid) != 1) {
error_setg_errno(errp, errno, "failed to read %s", group_path);
return -errno;
@ -1093,12 +1120,26 @@ out_single:
return ret;
}
const VFIOIOMMUOps vfio_legacy_ops = {
.dma_map = vfio_legacy_dma_map,
.dma_unmap = vfio_legacy_dma_unmap,
.attach_device = vfio_legacy_attach_device,
.detach_device = vfio_legacy_detach_device,
.set_dirty_page_tracking = vfio_legacy_set_dirty_page_tracking,
.query_dirty_bitmap = vfio_legacy_query_dirty_bitmap,
.pci_hot_reset = vfio_legacy_pci_hot_reset,
static void vfio_iommu_legacy_class_init(ObjectClass *klass, void *data)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
vioc->setup = vfio_legacy_setup;
vioc->dma_map = vfio_legacy_dma_map;
vioc->dma_unmap = vfio_legacy_dma_unmap;
vioc->attach_device = vfio_legacy_attach_device;
vioc->detach_device = vfio_legacy_detach_device;
vioc->set_dirty_page_tracking = vfio_legacy_set_dirty_page_tracking;
vioc->query_dirty_bitmap = vfio_legacy_query_dirty_bitmap;
vioc->pci_hot_reset = vfio_legacy_pci_hot_reset;
};
static const TypeInfo types[] = {
{
.name = TYPE_VFIO_IOMMU_LEGACY,
.parent = TYPE_VFIO_IOMMU,
.class_init = vfio_iommu_legacy_class_init,
},
};
DEFINE_TYPES(types)

View File

@ -121,17 +121,11 @@ static int iommufd_cdev_getfd(const char *sysfs_path, Error **errp)
DIR *dir = NULL;
struct dirent *dent;
gchar *contents;
struct stat st;
gsize length;
int major, minor;
dev_t vfio_devt;
path = g_strdup_printf("%s/vfio-dev", sysfs_path);
if (stat(path, &st) < 0) {
error_setg_errno(errp, errno, "no such host device");
goto out_free_path;
}
dir = opendir(path);
if (!dir) {
error_setg_errno(errp, errno, "couldn't open directory %s", path);
@ -319,6 +313,8 @@ static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
int ret, devfd;
uint32_t ioas_id;
Error *err = NULL;
const VFIOIOMMUClass *iommufd_vioc =
VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
if (vbasedev->fd < 0) {
devfd = iommufd_cdev_getfd(vbasedev->sysfsdev, errp);
@ -340,7 +336,7 @@ static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
/* try to attach to an existing container in this space */
QLIST_FOREACH(bcontainer, &space->containers, next) {
container = container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer);
if (bcontainer->ops != &vfio_iommufd_ops ||
if (bcontainer->ops != iommufd_vioc ||
vbasedev->iommufd != container->be) {
continue;
}
@ -374,7 +370,7 @@ static int iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
container->ioas_id = ioas_id;
bcontainer = &container->bcontainer;
vfio_container_init(bcontainer, space, &vfio_iommufd_ops);
vfio_container_init(bcontainer, space, iommufd_vioc);
QLIST_INSERT_HEAD(&space->containers, bcontainer, next);
ret = iommufd_cdev_attach_container(vbasedev, container, errp);
@ -476,9 +472,11 @@ static void iommufd_cdev_detach(VFIODevice *vbasedev)
static VFIODevice *iommufd_cdev_pci_find_by_devid(__u32 devid)
{
VFIODevice *vbasedev_iter;
const VFIOIOMMUClass *iommufd_vioc =
VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
QLIST_FOREACH(vbasedev_iter, &vfio_device_list, global_next) {
if (vbasedev_iter->bcontainer->ops != &vfio_iommufd_ops) {
if (vbasedev_iter->bcontainer->ops != iommufd_vioc) {
continue;
}
if (devid == vbasedev_iter->devid) {
@ -621,10 +619,23 @@ out_single:
return ret;
}
const VFIOIOMMUOps vfio_iommufd_ops = {
.dma_map = iommufd_cdev_map,
.dma_unmap = iommufd_cdev_unmap,
.attach_device = iommufd_cdev_attach,
.detach_device = iommufd_cdev_detach,
.pci_hot_reset = iommufd_cdev_pci_hot_reset,
static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data)
{
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
vioc->dma_map = iommufd_cdev_map;
vioc->dma_unmap = iommufd_cdev_unmap;
vioc->attach_device = iommufd_cdev_attach;
vioc->detach_device = iommufd_cdev_detach;
vioc->pci_hot_reset = iommufd_cdev_pci_hot_reset;
};
static const TypeInfo types[] = {
{
.name = TYPE_VFIO_IOMMU_IOMMUFD,
.parent = TYPE_VFIO_IOMMU,
.class_init = vfio_iommu_iommufd_class_init,
},
};
DEFINE_TYPES(types)

View File

@ -4,9 +4,9 @@ vfio_ss.add(files(
'common.c',
'container-base.c',
'container.c',
'spapr.c',
'migration.c',
))
vfio_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr.c'))
vfio_ss.add(when: 'CONFIG_IOMMUFD', if_true: files(
'iommufd.c',
))

View File

@ -163,6 +163,19 @@ reset_device:
return ret;
}
/*
* Some device state transitions require resetting the device if they fail.
* This function sets the device in new_state and resets the device if that
* fails. Reset is done by using ERROR as the recover state.
*/
static int
vfio_migration_set_state_or_reset(VFIODevice *vbasedev,
enum vfio_device_mig_state new_state)
{
return vfio_migration_set_state(vbasedev, new_state,
VFIO_DEVICE_STATE_ERROR);
}
static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev,
uint64_t data_size)
{
@ -422,12 +435,7 @@ static void vfio_save_cleanup(void *opaque)
* after migration has completed, so it won't increase downtime.
*/
if (migration->device_state == VFIO_DEVICE_STATE_STOP_COPY) {
/*
* If setting the device in STOP state fails, the device should be
* reset. To do so, use ERROR state as a recover state.
*/
vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP,
VFIO_DEVICE_STATE_ERROR);
vfio_migration_set_state_or_reset(vbasedev, VFIO_DEVICE_STATE_STOP);
}
g_free(migration->data_buffer);
@ -699,12 +707,7 @@ static void vfio_vmstate_change_prepare(void *opaque, bool running,
VFIO_DEVICE_STATE_PRE_COPY_P2P :
VFIO_DEVICE_STATE_RUNNING_P2P;
/*
* If setting the device in new_state fails, the device should be reset.
* To do so, use ERROR state as a recover state.
*/
ret = vfio_migration_set_state(vbasedev, new_state,
VFIO_DEVICE_STATE_ERROR);
ret = vfio_migration_set_state_or_reset(vbasedev, new_state);
if (ret) {
/*
* Migration should be aborted in this case, but vm_state_notify()
@ -736,12 +739,7 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state)
VFIO_DEVICE_STATE_STOP;
}
/*
* If setting the device in new_state fails, the device should be reset.
* To do so, use ERROR state as a recover state.
*/
ret = vfio_migration_set_state(vbasedev, new_state,
VFIO_DEVICE_STATE_ERROR);
ret = vfio_migration_set_state_or_reset(vbasedev, new_state);
if (ret) {
/*
* Migration should be aborted in this case, but vm_state_notify()
@ -770,12 +768,7 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data)
case MIGRATION_STATUS_CANCELLING:
case MIGRATION_STATUS_CANCELLED:
case MIGRATION_STATUS_FAILED:
/*
* If setting the device in RUNNING state fails, the device should
* be reset. To do so, use ERROR state as a recover state.
*/
vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RUNNING,
VFIO_DEVICE_STATE_ERROR);
vfio_migration_set_state_or_reset(vbasedev, VFIO_DEVICE_STATE_RUNNING);
}
}

View File

@ -2488,7 +2488,7 @@ int vfio_pci_get_pci_hot_reset_info(VFIOPCIDevice *vdev,
static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
{
VFIODevice *vbasedev = &vdev->vbasedev;
const VFIOIOMMUOps *ops = vbasedev->bcontainer->ops;
const VFIOIOMMUClass *ops = vbasedev->bcontainer->ops;
return ops->pci_hot_reset(vbasedev, single);
}

View File

@ -440,19 +440,29 @@ vfio_spapr_container_del_section_window(VFIOContainerBase *bcontainer,
}
}
static VFIOIOMMUOps vfio_iommu_spapr_ops;
static void setup_spapr_ops(VFIOContainerBase *bcontainer)
static void vfio_spapr_container_release(VFIOContainerBase *bcontainer)
{
vfio_iommu_spapr_ops = *bcontainer->ops;
vfio_iommu_spapr_ops.add_window = vfio_spapr_container_add_section_window;
vfio_iommu_spapr_ops.del_window = vfio_spapr_container_del_section_window;
bcontainer->ops = &vfio_iommu_spapr_ops;
VFIOContainer *container = container_of(bcontainer, VFIOContainer,
bcontainer);
VFIOSpaprContainer *scontainer = container_of(container, VFIOSpaprContainer,
container);
VFIOHostDMAWindow *hostwin, *next;
if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) {
memory_listener_unregister(&scontainer->prereg_listener);
}
QLIST_FOREACH_SAFE(hostwin, &scontainer->hostwin_list, hostwin_next,
next) {
QLIST_REMOVE(hostwin, hostwin_next);
g_free(hostwin);
}
}
int vfio_spapr_container_init(VFIOContainer *container, Error **errp)
static int vfio_spapr_container_setup(VFIOContainerBase *bcontainer,
Error **errp)
{
VFIOContainerBase *bcontainer = &container->bcontainer;
VFIOContainer *container = container_of(bcontainer, VFIOContainer,
bcontainer);
VFIOSpaprContainer *scontainer = container_of(container, VFIOSpaprContainer,
container);
struct vfio_iommu_spapr_tce_info info;
@ -517,8 +527,6 @@ int vfio_spapr_container_init(VFIOContainer *container, Error **errp)
0x1000);
}
setup_spapr_ops(bcontainer);
return 0;
listener_unregister_exit:
@ -528,18 +536,22 @@ listener_unregister_exit:
return ret;
}
void vfio_spapr_container_deinit(VFIOContainer *container)
static void vfio_iommu_spapr_class_init(ObjectClass *klass, void *data)
{
VFIOSpaprContainer *scontainer = container_of(container, VFIOSpaprContainer,
container);
VFIOHostDMAWindow *hostwin, *next;
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) {
memory_listener_unregister(&scontainer->prereg_listener);
}
QLIST_FOREACH_SAFE(hostwin, &scontainer->hostwin_list, hostwin_next,
next) {
QLIST_REMOVE(hostwin, hostwin_next);
g_free(hostwin);
}
}
vioc->add_window = vfio_spapr_container_add_section_window;
vioc->del_window = vfio_spapr_container_del_section_window;
vioc->release = vfio_spapr_container_release;
vioc->setup = vfio_spapr_container_setup;
};
static const TypeInfo types[] = {
{
.name = TYPE_VFIO_IOMMU_SPAPR,
.parent = TYPE_VFIO_IOMMU_LEGACY,
.class_init = vfio_iommu_spapr_class_init,
},
};
DEFINE_TYPES(types)

View File

@ -210,8 +210,6 @@ typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList;
typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList;
extern VFIOGroupList vfio_group_list;
extern VFIODeviceList vfio_device_list;
extern const VFIOIOMMUOps vfio_legacy_ops;
extern const VFIOIOMMUOps vfio_iommufd_ops;
extern const MemoryListener vfio_memory_listener;
extern int vfio_kvm_device_fd;

View File

@ -16,7 +16,7 @@
#include "exec/memory.h"
typedef struct VFIODevice VFIODevice;
typedef struct VFIOIOMMUOps VFIOIOMMUOps;
typedef struct VFIOIOMMUClass VFIOIOMMUClass;
typedef struct {
unsigned long *bitmap;
@ -34,7 +34,7 @@ typedef struct VFIOAddressSpace {
* This is the base object for vfio container backends
*/
typedef struct VFIOContainerBase {
const VFIOIOMMUOps *ops;
const VFIOIOMMUClass *ops;
VFIOAddressSpace *space;
MemoryListener listener;
Error *error;
@ -88,11 +88,29 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
void vfio_container_init(VFIOContainerBase *bcontainer,
VFIOAddressSpace *space,
const VFIOIOMMUOps *ops);
const VFIOIOMMUClass *ops);
void vfio_container_destroy(VFIOContainerBase *bcontainer);
struct VFIOIOMMUOps {
#define TYPE_VFIO_IOMMU "vfio-iommu"
#define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy"
#define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr"
#define TYPE_VFIO_IOMMU_IOMMUFD TYPE_VFIO_IOMMU "-iommufd"
/*
* VFIOContainerBase is not an abstract QOM object because it felt
* unnecessary to expose all the IOMMU backends to the QEMU machine
* and human interface. However, we can still abstract the IOMMU
* backend handlers using a QOM interface class. This provides more
* flexibility when referencing the various implementations.
*/
DECLARE_CLASS_CHECKERS(VFIOIOMMUClass, VFIO_IOMMU, TYPE_VFIO_IOMMU)
struct VFIOIOMMUClass {
InterfaceClass parent_class;
/* basic feature */
int (*setup)(VFIOContainerBase *bcontainer, Error **errp);
int (*dma_map)(const VFIOContainerBase *bcontainer,
hwaddr iova, ram_addr_t size,
void *vaddr, bool readonly);
@ -117,5 +135,6 @@ struct VFIOIOMMUOps {
Error **errp);
void (*del_window)(VFIOContainerBase *bcontainer,
MemoryRegionSection *section);
void (*release)(VFIOContainerBase *bcontainer);
};
#endif /* HW_VFIO_VFIO_CONTAINER_BASE_H */

View File

@ -2,7 +2,6 @@
#define SYSEMU_IOMMUFD_H
#include "qom/object.h"
#include "qemu/thread.h"
#include "exec/hwaddr.h"
#include "exec/cpu-common.h"
@ -19,7 +18,6 @@ struct IOMMUFDBackend {
/*< protected >*/
int fd; /* /dev/iommu file descriptor */
bool owned; /* is the /dev/iommu opened internally */
QemuMutex lock;
uint32_t users;
/*< public >*/