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:
commit
ffd454c67e
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
))
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 >*/
|
||||
|
Loading…
Reference in New Issue
Block a user