xref: /openbmc/linux/drivers/vfio/group.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
19eefba80SYi Liu // SPDX-License-Identifier: GPL-2.0-only
29eefba80SYi Liu /*
39eefba80SYi Liu  * VFIO core
49eefba80SYi Liu  *
59eefba80SYi Liu  * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
69eefba80SYi Liu  *     Author: Alex Williamson <alex.williamson@redhat.com>
79eefba80SYi Liu  *
89eefba80SYi Liu  * Derived from original vfio:
99eefba80SYi Liu  * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
109eefba80SYi Liu  * Author: Tom Lyon, pugs@cisco.com
119eefba80SYi Liu  */
129eefba80SYi Liu 
139eefba80SYi Liu #include <linux/vfio.h>
149eefba80SYi Liu #include <linux/iommufd.h>
159eefba80SYi Liu #include <linux/anon_inodes.h>
169eefba80SYi Liu #include "vfio.h"
179eefba80SYi Liu 
189eefba80SYi Liu static struct vfio {
199eefba80SYi Liu 	struct class			*class;
209eefba80SYi Liu 	struct list_head		group_list;
219eefba80SYi Liu 	struct mutex			group_lock; /* locks group_list */
229eefba80SYi Liu 	struct ida			group_ida;
239eefba80SYi Liu 	dev_t				group_devt;
249eefba80SYi Liu } vfio;
259eefba80SYi Liu 
vfio_device_get_from_name(struct vfio_group * group,char * buf)269eefba80SYi Liu static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,
279eefba80SYi Liu 						     char *buf)
289eefba80SYi Liu {
299eefba80SYi Liu 	struct vfio_device *it, *device = ERR_PTR(-ENODEV);
309eefba80SYi Liu 
319eefba80SYi Liu 	mutex_lock(&group->device_lock);
329eefba80SYi Liu 	list_for_each_entry(it, &group->device_list, group_next) {
339eefba80SYi Liu 		int ret;
349eefba80SYi Liu 
359eefba80SYi Liu 		if (it->ops->match) {
369eefba80SYi Liu 			ret = it->ops->match(it, buf);
379eefba80SYi Liu 			if (ret < 0) {
389eefba80SYi Liu 				device = ERR_PTR(ret);
399eefba80SYi Liu 				break;
409eefba80SYi Liu 			}
419eefba80SYi Liu 		} else {
429eefba80SYi Liu 			ret = !strcmp(dev_name(it->dev), buf);
439eefba80SYi Liu 		}
449eefba80SYi Liu 
459eefba80SYi Liu 		if (ret && vfio_device_try_get_registration(it)) {
469eefba80SYi Liu 			device = it;
479eefba80SYi Liu 			break;
489eefba80SYi Liu 		}
499eefba80SYi Liu 	}
509eefba80SYi Liu 	mutex_unlock(&group->device_lock);
519eefba80SYi Liu 
529eefba80SYi Liu 	return device;
539eefba80SYi Liu }
549eefba80SYi Liu 
559eefba80SYi Liu /*
569eefba80SYi Liu  * VFIO Group fd, /dev/vfio/$GROUP
579eefba80SYi Liu  */
vfio_group_has_iommu(struct vfio_group * group)589eefba80SYi Liu static bool vfio_group_has_iommu(struct vfio_group *group)
599eefba80SYi Liu {
609eefba80SYi Liu 	lockdep_assert_held(&group->group_lock);
619eefba80SYi Liu 	/*
629eefba80SYi Liu 	 * There can only be users if there is a container, and if there is a
639eefba80SYi Liu 	 * container there must be users.
649eefba80SYi Liu 	 */
659eefba80SYi Liu 	WARN_ON(!group->container != !group->container_users);
669eefba80SYi Liu 
679eefba80SYi Liu 	return group->container || group->iommufd;
689eefba80SYi Liu }
699eefba80SYi Liu 
709eefba80SYi Liu /*
719eefba80SYi Liu  * VFIO_GROUP_UNSET_CONTAINER should fail if there are other users or
729eefba80SYi Liu  * if there was no container to unset.  Since the ioctl is called on
739eefba80SYi Liu  * the group, we know that still exists, therefore the only valid
749eefba80SYi Liu  * transition here is 1->0.
759eefba80SYi Liu  */
vfio_group_ioctl_unset_container(struct vfio_group * group)769eefba80SYi Liu static int vfio_group_ioctl_unset_container(struct vfio_group *group)
779eefba80SYi Liu {
789eefba80SYi Liu 	int ret = 0;
799eefba80SYi Liu 
809eefba80SYi Liu 	mutex_lock(&group->group_lock);
819eefba80SYi Liu 	if (!vfio_group_has_iommu(group)) {
829eefba80SYi Liu 		ret = -EINVAL;
839eefba80SYi Liu 		goto out_unlock;
849eefba80SYi Liu 	}
859eefba80SYi Liu 	if (group->container) {
869eefba80SYi Liu 		if (group->container_users != 1) {
879eefba80SYi Liu 			ret = -EBUSY;
889eefba80SYi Liu 			goto out_unlock;
899eefba80SYi Liu 		}
909eefba80SYi Liu 		vfio_group_detach_container(group);
919eefba80SYi Liu 	}
929eefba80SYi Liu 	if (group->iommufd) {
939eefba80SYi Liu 		iommufd_ctx_put(group->iommufd);
949eefba80SYi Liu 		group->iommufd = NULL;
959eefba80SYi Liu 	}
969eefba80SYi Liu 
979eefba80SYi Liu out_unlock:
989eefba80SYi Liu 	mutex_unlock(&group->group_lock);
999eefba80SYi Liu 	return ret;
1009eefba80SYi Liu }
1019eefba80SYi Liu 
vfio_group_ioctl_set_container(struct vfio_group * group,int __user * arg)1029eefba80SYi Liu static int vfio_group_ioctl_set_container(struct vfio_group *group,
1039eefba80SYi Liu 					  int __user *arg)
1049eefba80SYi Liu {
1059eefba80SYi Liu 	struct vfio_container *container;
1069eefba80SYi Liu 	struct iommufd_ctx *iommufd;
1079eefba80SYi Liu 	struct fd f;
1089eefba80SYi Liu 	int ret;
1099eefba80SYi Liu 	int fd;
1109eefba80SYi Liu 
1119eefba80SYi Liu 	if (get_user(fd, arg))
1129eefba80SYi Liu 		return -EFAULT;
1139eefba80SYi Liu 
1149eefba80SYi Liu 	f = fdget(fd);
1159eefba80SYi Liu 	if (!f.file)
1169eefba80SYi Liu 		return -EBADF;
1179eefba80SYi Liu 
1189eefba80SYi Liu 	mutex_lock(&group->group_lock);
1199eefba80SYi Liu 	if (vfio_group_has_iommu(group)) {
1209eefba80SYi Liu 		ret = -EINVAL;
1219eefba80SYi Liu 		goto out_unlock;
1229eefba80SYi Liu 	}
1239eefba80SYi Liu 	if (!group->iommu_group) {
1249eefba80SYi Liu 		ret = -ENODEV;
1259eefba80SYi Liu 		goto out_unlock;
1269eefba80SYi Liu 	}
1279eefba80SYi Liu 
1289eefba80SYi Liu 	container = vfio_container_from_file(f.file);
1299eefba80SYi Liu 	if (container) {
1309eefba80SYi Liu 		ret = vfio_container_attach_group(container, group);
1319eefba80SYi Liu 		goto out_unlock;
1329eefba80SYi Liu 	}
1339eefba80SYi Liu 
1349eefba80SYi Liu 	iommufd = iommufd_ctx_from_file(f.file);
1359eefba80SYi Liu 	if (!IS_ERR(iommufd)) {
136c9a397ceSJason Gunthorpe 		if (IS_ENABLED(CONFIG_VFIO_NOIOMMU) &&
137c9a397ceSJason Gunthorpe 		    group->type == VFIO_NO_IOMMU)
138c9a397ceSJason Gunthorpe 			ret = iommufd_vfio_compat_set_no_iommu(iommufd);
139c9a397ceSJason Gunthorpe 		else
140c9a397ceSJason Gunthorpe 			ret = iommufd_vfio_compat_ioas_create(iommufd);
1419eefba80SYi Liu 
1429eefba80SYi Liu 		if (ret) {
143d649c34cSYan Zhao 			iommufd_ctx_put(iommufd);
1449eefba80SYi Liu 			goto out_unlock;
1459eefba80SYi Liu 		}
1469eefba80SYi Liu 
1479eefba80SYi Liu 		group->iommufd = iommufd;
1489eefba80SYi Liu 		goto out_unlock;
1499eefba80SYi Liu 	}
1509eefba80SYi Liu 
1519eefba80SYi Liu 	/* The FD passed is not recognized. */
1529eefba80SYi Liu 	ret = -EBADFD;
1539eefba80SYi Liu 
1549eefba80SYi Liu out_unlock:
1559eefba80SYi Liu 	mutex_unlock(&group->group_lock);
1569eefba80SYi Liu 	fdput(f);
1579eefba80SYi Liu 	return ret;
1589eefba80SYi Liu }
1599eefba80SYi Liu 
vfio_device_group_get_kvm_safe(struct vfio_device * device)1602b48f52fSMatthew Rosato static void vfio_device_group_get_kvm_safe(struct vfio_device *device)
1612b48f52fSMatthew Rosato {
1622b48f52fSMatthew Rosato 	spin_lock(&device->group->kvm_ref_lock);
163*5c6de3eaSYi Liu 	vfio_device_get_kvm_safe(device, device->group->kvm);
1642b48f52fSMatthew Rosato 	spin_unlock(&device->group->kvm_ref_lock);
1652b48f52fSMatthew Rosato }
1662b48f52fSMatthew Rosato 
vfio_df_group_open(struct vfio_device_file * df)16705f37e1cSYi Liu static int vfio_df_group_open(struct vfio_device_file *df)
1689eefba80SYi Liu {
16905f37e1cSYi Liu 	struct vfio_device *device = df->device;
1709eefba80SYi Liu 	int ret;
1719eefba80SYi Liu 
1729eefba80SYi Liu 	mutex_lock(&device->group->group_lock);
1739eefba80SYi Liu 	if (!vfio_group_has_iommu(device->group)) {
1749eefba80SYi Liu 		ret = -EINVAL;
1759eefba80SYi Liu 		goto out_unlock;
1769eefba80SYi Liu 	}
1779eefba80SYi Liu 
1782b48f52fSMatthew Rosato 	mutex_lock(&device->dev_set->lock);
1792b48f52fSMatthew Rosato 
1809eefba80SYi Liu 	/*
1812b48f52fSMatthew Rosato 	 * Before the first device open, get the KVM pointer currently
1822b48f52fSMatthew Rosato 	 * associated with the group (if there is one) and obtain a reference
1832b48f52fSMatthew Rosato 	 * now that will be held until the open_count reaches 0 again.  Save
1842b48f52fSMatthew Rosato 	 * the pointer in the device for use by drivers.
1859eefba80SYi Liu 	 */
1862b48f52fSMatthew Rosato 	if (device->open_count == 0)
1872b48f52fSMatthew Rosato 		vfio_device_group_get_kvm_safe(device);
1882b48f52fSMatthew Rosato 
18905f37e1cSYi Liu 	df->iommufd = device->group->iommufd;
1906086efe7SYi Liu 	if (df->iommufd && vfio_device_is_noiommu(device) && device->open_count == 0) {
1916086efe7SYi Liu 		/*
1926086efe7SYi Liu 		 * Require no compat ioas to be assigned to proceed.  The basic
1936086efe7SYi Liu 		 * statement is that the user cannot have done something that
1946086efe7SYi Liu 		 * implies they expected translation to exist
1956086efe7SYi Liu 		 */
1966086efe7SYi Liu 		if (!capable(CAP_SYS_RAWIO) ||
1976086efe7SYi Liu 		    vfio_iommufd_device_has_compat_ioas(device, df->iommufd))
1986086efe7SYi Liu 			ret = -EPERM;
1996086efe7SYi Liu 		else
2006086efe7SYi Liu 			ret = 0;
2016086efe7SYi Liu 		goto out_put_kvm;
2026086efe7SYi Liu 	}
20305f37e1cSYi Liu 
20405f37e1cSYi Liu 	ret = vfio_df_open(df);
2056f240ee6SYi Liu 	if (ret)
20682d93f58SYi Liu 		goto out_put_kvm;
2076f240ee6SYi Liu 
2086f240ee6SYi Liu 	if (df->iommufd && device->open_count == 1) {
2096f240ee6SYi Liu 		ret = vfio_iommufd_compat_attach_ioas(device, df->iommufd);
2106f240ee6SYi Liu 		if (ret)
2116f240ee6SYi Liu 			goto out_close_device;
21282d93f58SYi Liu 	}
2132b48f52fSMatthew Rosato 
21482d93f58SYi Liu 	/*
21582d93f58SYi Liu 	 * Paired with smp_load_acquire() in vfio_device_fops::ioctl/
21682d93f58SYi Liu 	 * read/write/mmap and vfio_file_has_device_access()
21782d93f58SYi Liu 	 */
21882d93f58SYi Liu 	smp_store_release(&df->access_granted, true);
21982d93f58SYi Liu 
2206f240ee6SYi Liu 	mutex_unlock(&device->dev_set->lock);
2216f240ee6SYi Liu 	mutex_unlock(&device->group->group_lock);
2226f240ee6SYi Liu 	return 0;
2236f240ee6SYi Liu 
2246f240ee6SYi Liu out_close_device:
2256f240ee6SYi Liu 	vfio_df_close(df);
22682d93f58SYi Liu out_put_kvm:
2276f240ee6SYi Liu 	df->iommufd = NULL;
2282b48f52fSMatthew Rosato 	if (device->open_count == 0)
2292b48f52fSMatthew Rosato 		vfio_device_put_kvm(device);
2302b48f52fSMatthew Rosato 	mutex_unlock(&device->dev_set->lock);
2319eefba80SYi Liu out_unlock:
2329eefba80SYi Liu 	mutex_unlock(&device->group->group_lock);
2339eefba80SYi Liu 	return ret;
2349eefba80SYi Liu }
2359eefba80SYi Liu 
vfio_df_group_close(struct vfio_device_file * df)23605f37e1cSYi Liu void vfio_df_group_close(struct vfio_device_file *df)
2379eefba80SYi Liu {
23805f37e1cSYi Liu 	struct vfio_device *device = df->device;
23905f37e1cSYi Liu 
2409eefba80SYi Liu 	mutex_lock(&device->group->group_lock);
2412b48f52fSMatthew Rosato 	mutex_lock(&device->dev_set->lock);
2422b48f52fSMatthew Rosato 
24305f37e1cSYi Liu 	vfio_df_close(df);
24405f37e1cSYi Liu 	df->iommufd = NULL;
2452b48f52fSMatthew Rosato 
2462b48f52fSMatthew Rosato 	if (device->open_count == 0)
2472b48f52fSMatthew Rosato 		vfio_device_put_kvm(device);
2482b48f52fSMatthew Rosato 
2492b48f52fSMatthew Rosato 	mutex_unlock(&device->dev_set->lock);
2509eefba80SYi Liu 	mutex_unlock(&device->group->group_lock);
2519eefba80SYi Liu }
2529eefba80SYi Liu 
vfio_device_open_file(struct vfio_device * device)2539eefba80SYi Liu static struct file *vfio_device_open_file(struct vfio_device *device)
2549eefba80SYi Liu {
255b1a3b5c6SYi Liu 	struct vfio_device_file *df;
2569eefba80SYi Liu 	struct file *filep;
2579eefba80SYi Liu 	int ret;
2589eefba80SYi Liu 
259b1a3b5c6SYi Liu 	df = vfio_allocate_device_file(device);
260b1a3b5c6SYi Liu 	if (IS_ERR(df)) {
261b1a3b5c6SYi Liu 		ret = PTR_ERR(df);
262b1a3b5c6SYi Liu 		goto err_out;
263b1a3b5c6SYi Liu 	}
264b1a3b5c6SYi Liu 
265839e692fSYi Liu 	df->group = device->group;
266839e692fSYi Liu 
26705f37e1cSYi Liu 	ret = vfio_df_group_open(df);
2689eefba80SYi Liu 	if (ret)
269b1a3b5c6SYi Liu 		goto err_free;
2709eefba80SYi Liu 
2719eefba80SYi Liu 	/*
2729eefba80SYi Liu 	 * We can't use anon_inode_getfd() because we need to modify
2739eefba80SYi Liu 	 * the f_mode flags directly to allow more than just ioctls
2749eefba80SYi Liu 	 */
2759eefba80SYi Liu 	filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
276b1a3b5c6SYi Liu 				   df, O_RDWR);
2779eefba80SYi Liu 	if (IS_ERR(filep)) {
2789eefba80SYi Liu 		ret = PTR_ERR(filep);
2799eefba80SYi Liu 		goto err_close_device;
2809eefba80SYi Liu 	}
2819eefba80SYi Liu 
2829eefba80SYi Liu 	/*
2839eefba80SYi Liu 	 * TODO: add an anon_inode interface to do this.
2849eefba80SYi Liu 	 * Appears to be missing by lack of need rather than
2859eefba80SYi Liu 	 * explicitly prevented.  Now there's need.
2869eefba80SYi Liu 	 */
2879eefba80SYi Liu 	filep->f_mode |= (FMODE_PREAD | FMODE_PWRITE);
2889eefba80SYi Liu 
2899eefba80SYi Liu 	if (device->group->type == VFIO_NO_IOMMU)
2909eefba80SYi Liu 		dev_warn(device->dev, "vfio-noiommu device opened by user "
2919eefba80SYi Liu 			 "(%s:%d)\n", current->comm, task_pid_nr(current));
2929eefba80SYi Liu 	/*
2939eefba80SYi Liu 	 * On success the ref of device is moved to the file and
2949eefba80SYi Liu 	 * put in vfio_device_fops_release()
2959eefba80SYi Liu 	 */
2969eefba80SYi Liu 	return filep;
2979eefba80SYi Liu 
2989eefba80SYi Liu err_close_device:
29905f37e1cSYi Liu 	vfio_df_group_close(df);
300b1a3b5c6SYi Liu err_free:
301b1a3b5c6SYi Liu 	kfree(df);
3029eefba80SYi Liu err_out:
3039eefba80SYi Liu 	return ERR_PTR(ret);
3049eefba80SYi Liu }
3059eefba80SYi Liu 
vfio_group_ioctl_get_device_fd(struct vfio_group * group,char __user * arg)3069eefba80SYi Liu static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
3079eefba80SYi Liu 					  char __user *arg)
3089eefba80SYi Liu {
3099eefba80SYi Liu 	struct vfio_device *device;
3109eefba80SYi Liu 	struct file *filep;
3119eefba80SYi Liu 	char *buf;
3129eefba80SYi Liu 	int fdno;
3139eefba80SYi Liu 	int ret;
3149eefba80SYi Liu 
3159eefba80SYi Liu 	buf = strndup_user(arg, PAGE_SIZE);
3169eefba80SYi Liu 	if (IS_ERR(buf))
3179eefba80SYi Liu 		return PTR_ERR(buf);
3189eefba80SYi Liu 
3199eefba80SYi Liu 	device = vfio_device_get_from_name(group, buf);
3209eefba80SYi Liu 	kfree(buf);
3219eefba80SYi Liu 	if (IS_ERR(device))
3229eefba80SYi Liu 		return PTR_ERR(device);
3239eefba80SYi Liu 
3249eefba80SYi Liu 	fdno = get_unused_fd_flags(O_CLOEXEC);
3259eefba80SYi Liu 	if (fdno < 0) {
3269eefba80SYi Liu 		ret = fdno;
3279eefba80SYi Liu 		goto err_put_device;
3289eefba80SYi Liu 	}
3299eefba80SYi Liu 
3309eefba80SYi Liu 	filep = vfio_device_open_file(device);
3319eefba80SYi Liu 	if (IS_ERR(filep)) {
3329eefba80SYi Liu 		ret = PTR_ERR(filep);
3339eefba80SYi Liu 		goto err_put_fdno;
3349eefba80SYi Liu 	}
3359eefba80SYi Liu 
3369eefba80SYi Liu 	fd_install(fdno, filep);
3379eefba80SYi Liu 	return fdno;
3389eefba80SYi Liu 
3399eefba80SYi Liu err_put_fdno:
3409eefba80SYi Liu 	put_unused_fd(fdno);
3419eefba80SYi Liu err_put_device:
3429eefba80SYi Liu 	vfio_device_put_registration(device);
3439eefba80SYi Liu 	return ret;
3449eefba80SYi Liu }
3459eefba80SYi Liu 
vfio_group_ioctl_get_status(struct vfio_group * group,struct vfio_group_status __user * arg)3469eefba80SYi Liu static int vfio_group_ioctl_get_status(struct vfio_group *group,
3479eefba80SYi Liu 				       struct vfio_group_status __user *arg)
3489eefba80SYi Liu {
3499eefba80SYi Liu 	unsigned long minsz = offsetofend(struct vfio_group_status, flags);
3509eefba80SYi Liu 	struct vfio_group_status status;
3519eefba80SYi Liu 
3529eefba80SYi Liu 	if (copy_from_user(&status, arg, minsz))
3539eefba80SYi Liu 		return -EFAULT;
3549eefba80SYi Liu 
3559eefba80SYi Liu 	if (status.argsz < minsz)
3569eefba80SYi Liu 		return -EINVAL;
3579eefba80SYi Liu 
3589eefba80SYi Liu 	status.flags = 0;
3599eefba80SYi Liu 
3609eefba80SYi Liu 	mutex_lock(&group->group_lock);
3619eefba80SYi Liu 	if (!group->iommu_group) {
3629eefba80SYi Liu 		mutex_unlock(&group->group_lock);
3639eefba80SYi Liu 		return -ENODEV;
3649eefba80SYi Liu 	}
3659eefba80SYi Liu 
3669eefba80SYi Liu 	/*
3679eefba80SYi Liu 	 * With the container FD the iommu_group_claim_dma_owner() is done
3689eefba80SYi Liu 	 * during SET_CONTAINER but for IOMMFD this is done during
3699eefba80SYi Liu 	 * VFIO_GROUP_GET_DEVICE_FD. Meaning that with iommufd
3709eefba80SYi Liu 	 * VFIO_GROUP_FLAGS_VIABLE could be set but GET_DEVICE_FD will fail due
3719eefba80SYi Liu 	 * to viability.
3729eefba80SYi Liu 	 */
3739eefba80SYi Liu 	if (vfio_group_has_iommu(group))
3749eefba80SYi Liu 		status.flags |= VFIO_GROUP_FLAGS_CONTAINER_SET |
3759eefba80SYi Liu 				VFIO_GROUP_FLAGS_VIABLE;
3769eefba80SYi Liu 	else if (!iommu_group_dma_owner_claimed(group->iommu_group))
3779eefba80SYi Liu 		status.flags |= VFIO_GROUP_FLAGS_VIABLE;
3789eefba80SYi Liu 	mutex_unlock(&group->group_lock);
3799eefba80SYi Liu 
3809eefba80SYi Liu 	if (copy_to_user(arg, &status, minsz))
3819eefba80SYi Liu 		return -EFAULT;
3829eefba80SYi Liu 	return 0;
3839eefba80SYi Liu }
3849eefba80SYi Liu 
vfio_group_fops_unl_ioctl(struct file * filep,unsigned int cmd,unsigned long arg)3859eefba80SYi Liu static long vfio_group_fops_unl_ioctl(struct file *filep,
3869eefba80SYi Liu 				      unsigned int cmd, unsigned long arg)
3879eefba80SYi Liu {
3889eefba80SYi Liu 	struct vfio_group *group = filep->private_data;
3899eefba80SYi Liu 	void __user *uarg = (void __user *)arg;
3909eefba80SYi Liu 
3919eefba80SYi Liu 	switch (cmd) {
3929eefba80SYi Liu 	case VFIO_GROUP_GET_DEVICE_FD:
3939eefba80SYi Liu 		return vfio_group_ioctl_get_device_fd(group, uarg);
3949eefba80SYi Liu 	case VFIO_GROUP_GET_STATUS:
3959eefba80SYi Liu 		return vfio_group_ioctl_get_status(group, uarg);
3969eefba80SYi Liu 	case VFIO_GROUP_SET_CONTAINER:
3979eefba80SYi Liu 		return vfio_group_ioctl_set_container(group, uarg);
3989eefba80SYi Liu 	case VFIO_GROUP_UNSET_CONTAINER:
3999eefba80SYi Liu 		return vfio_group_ioctl_unset_container(group);
4009eefba80SYi Liu 	default:
4019eefba80SYi Liu 		return -ENOTTY;
4029eefba80SYi Liu 	}
4039eefba80SYi Liu }
4049eefba80SYi Liu 
vfio_device_block_group(struct vfio_device * device)405270bf4c0SYi Liu int vfio_device_block_group(struct vfio_device *device)
406270bf4c0SYi Liu {
407270bf4c0SYi Liu 	struct vfio_group *group = device->group;
408270bf4c0SYi Liu 	int ret = 0;
409270bf4c0SYi Liu 
410270bf4c0SYi Liu 	mutex_lock(&group->group_lock);
411270bf4c0SYi Liu 	if (group->opened_file) {
412270bf4c0SYi Liu 		ret = -EBUSY;
413270bf4c0SYi Liu 		goto out_unlock;
414270bf4c0SYi Liu 	}
415270bf4c0SYi Liu 
416270bf4c0SYi Liu 	group->cdev_device_open_cnt++;
417270bf4c0SYi Liu 
418270bf4c0SYi Liu out_unlock:
419270bf4c0SYi Liu 	mutex_unlock(&group->group_lock);
420270bf4c0SYi Liu 	return ret;
421270bf4c0SYi Liu }
422270bf4c0SYi Liu 
vfio_device_unblock_group(struct vfio_device * device)423270bf4c0SYi Liu void vfio_device_unblock_group(struct vfio_device *device)
424270bf4c0SYi Liu {
425270bf4c0SYi Liu 	struct vfio_group *group = device->group;
426270bf4c0SYi Liu 
427270bf4c0SYi Liu 	mutex_lock(&group->group_lock);
428270bf4c0SYi Liu 	group->cdev_device_open_cnt--;
429270bf4c0SYi Liu 	mutex_unlock(&group->group_lock);
430270bf4c0SYi Liu }
431270bf4c0SYi Liu 
vfio_group_fops_open(struct inode * inode,struct file * filep)4329eefba80SYi Liu static int vfio_group_fops_open(struct inode *inode, struct file *filep)
4339eefba80SYi Liu {
4349eefba80SYi Liu 	struct vfio_group *group =
4359eefba80SYi Liu 		container_of(inode->i_cdev, struct vfio_group, cdev);
4369eefba80SYi Liu 	int ret;
4379eefba80SYi Liu 
4389eefba80SYi Liu 	mutex_lock(&group->group_lock);
4399eefba80SYi Liu 
4409eefba80SYi Liu 	/*
4419eefba80SYi Liu 	 * drivers can be zero if this races with vfio_device_remove_group(), it
4429eefba80SYi Liu 	 * will be stable at 0 under the group rwsem
4439eefba80SYi Liu 	 */
4449eefba80SYi Liu 	if (refcount_read(&group->drivers) == 0) {
4459eefba80SYi Liu 		ret = -ENODEV;
4469eefba80SYi Liu 		goto out_unlock;
4479eefba80SYi Liu 	}
4489eefba80SYi Liu 
4499eefba80SYi Liu 	if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) {
4509eefba80SYi Liu 		ret = -EPERM;
4519eefba80SYi Liu 		goto out_unlock;
4529eefba80SYi Liu 	}
4539eefba80SYi Liu 
454270bf4c0SYi Liu 	if (group->cdev_device_open_cnt) {
455270bf4c0SYi Liu 		ret = -EBUSY;
456270bf4c0SYi Liu 		goto out_unlock;
457270bf4c0SYi Liu 	}
458270bf4c0SYi Liu 
4599eefba80SYi Liu 	/*
4609eefba80SYi Liu 	 * Do we need multiple instances of the group open?  Seems not.
4619eefba80SYi Liu 	 */
4629eefba80SYi Liu 	if (group->opened_file) {
4639eefba80SYi Liu 		ret = -EBUSY;
4649eefba80SYi Liu 		goto out_unlock;
4659eefba80SYi Liu 	}
4669eefba80SYi Liu 	group->opened_file = filep;
4679eefba80SYi Liu 	filep->private_data = group;
4689eefba80SYi Liu 	ret = 0;
4699eefba80SYi Liu out_unlock:
4709eefba80SYi Liu 	mutex_unlock(&group->group_lock);
4719eefba80SYi Liu 	return ret;
4729eefba80SYi Liu }
4739eefba80SYi Liu 
vfio_group_fops_release(struct inode * inode,struct file * filep)4749eefba80SYi Liu static int vfio_group_fops_release(struct inode *inode, struct file *filep)
4759eefba80SYi Liu {
4769eefba80SYi Liu 	struct vfio_group *group = filep->private_data;
4779eefba80SYi Liu 
4789eefba80SYi Liu 	filep->private_data = NULL;
4799eefba80SYi Liu 
4809eefba80SYi Liu 	mutex_lock(&group->group_lock);
4819eefba80SYi Liu 	/*
4829eefba80SYi Liu 	 * Device FDs hold a group file reference, therefore the group release
4839eefba80SYi Liu 	 * is only called when there are no open devices.
4849eefba80SYi Liu 	 */
4859eefba80SYi Liu 	WARN_ON(group->notifier.head);
4869eefba80SYi Liu 	if (group->container)
4879eefba80SYi Liu 		vfio_group_detach_container(group);
4889eefba80SYi Liu 	if (group->iommufd) {
4899eefba80SYi Liu 		iommufd_ctx_put(group->iommufd);
4909eefba80SYi Liu 		group->iommufd = NULL;
4919eefba80SYi Liu 	}
4929eefba80SYi Liu 	group->opened_file = NULL;
4939eefba80SYi Liu 	mutex_unlock(&group->group_lock);
4949eefba80SYi Liu 	return 0;
4959eefba80SYi Liu }
4969eefba80SYi Liu 
4979eefba80SYi Liu static const struct file_operations vfio_group_fops = {
4989eefba80SYi Liu 	.owner		= THIS_MODULE,
4999eefba80SYi Liu 	.unlocked_ioctl	= vfio_group_fops_unl_ioctl,
5009eefba80SYi Liu 	.compat_ioctl	= compat_ptr_ioctl,
5019eefba80SYi Liu 	.open		= vfio_group_fops_open,
5029eefba80SYi Liu 	.release	= vfio_group_fops_release,
5039eefba80SYi Liu };
5049eefba80SYi Liu 
5059eefba80SYi Liu /*
5069eefba80SYi Liu  * Group objects - create, release, get, put, search
5079eefba80SYi Liu  */
5089eefba80SYi Liu static struct vfio_group *
vfio_group_find_from_iommu(struct iommu_group * iommu_group)5099eefba80SYi Liu vfio_group_find_from_iommu(struct iommu_group *iommu_group)
5109eefba80SYi Liu {
5119eefba80SYi Liu 	struct vfio_group *group;
5129eefba80SYi Liu 
5139eefba80SYi Liu 	lockdep_assert_held(&vfio.group_lock);
5149eefba80SYi Liu 
5159eefba80SYi Liu 	/*
5169eefba80SYi Liu 	 * group->iommu_group from the vfio.group_list cannot be NULL
5179eefba80SYi Liu 	 * under the vfio.group_lock.
5189eefba80SYi Liu 	 */
5199eefba80SYi Liu 	list_for_each_entry(group, &vfio.group_list, vfio_next) {
5209eefba80SYi Liu 		if (group->iommu_group == iommu_group)
5219eefba80SYi Liu 			return group;
5229eefba80SYi Liu 	}
5239eefba80SYi Liu 	return NULL;
5249eefba80SYi Liu }
5259eefba80SYi Liu 
vfio_group_release(struct device * dev)5269eefba80SYi Liu static void vfio_group_release(struct device *dev)
5279eefba80SYi Liu {
5289eefba80SYi Liu 	struct vfio_group *group = container_of(dev, struct vfio_group, dev);
5299eefba80SYi Liu 
5309eefba80SYi Liu 	mutex_destroy(&group->device_lock);
5319eefba80SYi Liu 	mutex_destroy(&group->group_lock);
5329eefba80SYi Liu 	WARN_ON(group->iommu_group);
533270bf4c0SYi Liu 	WARN_ON(group->cdev_device_open_cnt);
5349eefba80SYi Liu 	ida_free(&vfio.group_ida, MINOR(group->dev.devt));
5359eefba80SYi Liu 	kfree(group);
5369eefba80SYi Liu }
5379eefba80SYi Liu 
vfio_group_alloc(struct iommu_group * iommu_group,enum vfio_group_type type)5389eefba80SYi Liu static struct vfio_group *vfio_group_alloc(struct iommu_group *iommu_group,
5399eefba80SYi Liu 					   enum vfio_group_type type)
5409eefba80SYi Liu {
5419eefba80SYi Liu 	struct vfio_group *group;
5429eefba80SYi Liu 	int minor;
5439eefba80SYi Liu 
5449eefba80SYi Liu 	group = kzalloc(sizeof(*group), GFP_KERNEL);
5459eefba80SYi Liu 	if (!group)
5469eefba80SYi Liu 		return ERR_PTR(-ENOMEM);
5479eefba80SYi Liu 
5489eefba80SYi Liu 	minor = ida_alloc_max(&vfio.group_ida, MINORMASK, GFP_KERNEL);
5499eefba80SYi Liu 	if (minor < 0) {
5509eefba80SYi Liu 		kfree(group);
5519eefba80SYi Liu 		return ERR_PTR(minor);
5529eefba80SYi Liu 	}
5539eefba80SYi Liu 
5549eefba80SYi Liu 	device_initialize(&group->dev);
5559eefba80SYi Liu 	group->dev.devt = MKDEV(MAJOR(vfio.group_devt), minor);
5569eefba80SYi Liu 	group->dev.class = vfio.class;
5579eefba80SYi Liu 	group->dev.release = vfio_group_release;
5589eefba80SYi Liu 	cdev_init(&group->cdev, &vfio_group_fops);
5599eefba80SYi Liu 	group->cdev.owner = THIS_MODULE;
5609eefba80SYi Liu 
5619eefba80SYi Liu 	refcount_set(&group->drivers, 1);
5629eefba80SYi Liu 	mutex_init(&group->group_lock);
5632b48f52fSMatthew Rosato 	spin_lock_init(&group->kvm_ref_lock);
5649eefba80SYi Liu 	INIT_LIST_HEAD(&group->device_list);
5659eefba80SYi Liu 	mutex_init(&group->device_lock);
5669eefba80SYi Liu 	group->iommu_group = iommu_group;
5679eefba80SYi Liu 	/* put in vfio_group_release() */
5689eefba80SYi Liu 	iommu_group_ref_get(iommu_group);
5699eefba80SYi Liu 	group->type = type;
5709eefba80SYi Liu 	BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
5719eefba80SYi Liu 
5729eefba80SYi Liu 	return group;
5739eefba80SYi Liu }
5749eefba80SYi Liu 
vfio_create_group(struct iommu_group * iommu_group,enum vfio_group_type type)5759eefba80SYi Liu static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
5769eefba80SYi Liu 		enum vfio_group_type type)
5779eefba80SYi Liu {
5789eefba80SYi Liu 	struct vfio_group *group;
5799eefba80SYi Liu 	struct vfio_group *ret;
5809eefba80SYi Liu 	int err;
5819eefba80SYi Liu 
5829eefba80SYi Liu 	lockdep_assert_held(&vfio.group_lock);
5839eefba80SYi Liu 
5849eefba80SYi Liu 	group = vfio_group_alloc(iommu_group, type);
5859eefba80SYi Liu 	if (IS_ERR(group))
5869eefba80SYi Liu 		return group;
5879eefba80SYi Liu 
5889eefba80SYi Liu 	err = dev_set_name(&group->dev, "%s%d",
5899eefba80SYi Liu 			   group->type == VFIO_NO_IOMMU ? "noiommu-" : "",
5909eefba80SYi Liu 			   iommu_group_id(iommu_group));
5919eefba80SYi Liu 	if (err) {
5929eefba80SYi Liu 		ret = ERR_PTR(err);
5939eefba80SYi Liu 		goto err_put;
5949eefba80SYi Liu 	}
5959eefba80SYi Liu 
5969eefba80SYi Liu 	err = cdev_device_add(&group->cdev, &group->dev);
5979eefba80SYi Liu 	if (err) {
5989eefba80SYi Liu 		ret = ERR_PTR(err);
5999eefba80SYi Liu 		goto err_put;
6009eefba80SYi Liu 	}
6019eefba80SYi Liu 
6029eefba80SYi Liu 	list_add(&group->vfio_next, &vfio.group_list);
6039eefba80SYi Liu 
6049eefba80SYi Liu 	return group;
6059eefba80SYi Liu 
6069eefba80SYi Liu err_put:
6079eefba80SYi Liu 	put_device(&group->dev);
6089eefba80SYi Liu 	return ret;
6099eefba80SYi Liu }
6109eefba80SYi Liu 
vfio_noiommu_group_alloc(struct device * dev,enum vfio_group_type type)6119eefba80SYi Liu static struct vfio_group *vfio_noiommu_group_alloc(struct device *dev,
6129eefba80SYi Liu 		enum vfio_group_type type)
6139eefba80SYi Liu {
6149eefba80SYi Liu 	struct iommu_group *iommu_group;
6159eefba80SYi Liu 	struct vfio_group *group;
6169eefba80SYi Liu 	int ret;
6179eefba80SYi Liu 
6189eefba80SYi Liu 	iommu_group = iommu_group_alloc();
6199eefba80SYi Liu 	if (IS_ERR(iommu_group))
6209eefba80SYi Liu 		return ERR_CAST(iommu_group);
6219eefba80SYi Liu 
6229eefba80SYi Liu 	ret = iommu_group_set_name(iommu_group, "vfio-noiommu");
6239eefba80SYi Liu 	if (ret)
6249eefba80SYi Liu 		goto out_put_group;
6259eefba80SYi Liu 	ret = iommu_group_add_device(iommu_group, dev);
6269eefba80SYi Liu 	if (ret)
6279eefba80SYi Liu 		goto out_put_group;
6289eefba80SYi Liu 
6299eefba80SYi Liu 	mutex_lock(&vfio.group_lock);
6309eefba80SYi Liu 	group = vfio_create_group(iommu_group, type);
6319eefba80SYi Liu 	mutex_unlock(&vfio.group_lock);
6329eefba80SYi Liu 	if (IS_ERR(group)) {
6339eefba80SYi Liu 		ret = PTR_ERR(group);
6349eefba80SYi Liu 		goto out_remove_device;
6359eefba80SYi Liu 	}
6369eefba80SYi Liu 	iommu_group_put(iommu_group);
6379eefba80SYi Liu 	return group;
6389eefba80SYi Liu 
6399eefba80SYi Liu out_remove_device:
6409eefba80SYi Liu 	iommu_group_remove_device(dev);
6419eefba80SYi Liu out_put_group:
6429eefba80SYi Liu 	iommu_group_put(iommu_group);
6439eefba80SYi Liu 	return ERR_PTR(ret);
6449eefba80SYi Liu }
6459eefba80SYi Liu 
vfio_group_has_device(struct vfio_group * group,struct device * dev)6469eefba80SYi Liu static bool vfio_group_has_device(struct vfio_group *group, struct device *dev)
6479eefba80SYi Liu {
6489eefba80SYi Liu 	struct vfio_device *device;
6499eefba80SYi Liu 
6509eefba80SYi Liu 	mutex_lock(&group->device_lock);
6519eefba80SYi Liu 	list_for_each_entry(device, &group->device_list, group_next) {
6529eefba80SYi Liu 		if (device->dev == dev) {
6539eefba80SYi Liu 			mutex_unlock(&group->device_lock);
6549eefba80SYi Liu 			return true;
6559eefba80SYi Liu 		}
6569eefba80SYi Liu 	}
6579eefba80SYi Liu 	mutex_unlock(&group->device_lock);
6589eefba80SYi Liu 	return false;
6599eefba80SYi Liu }
6609eefba80SYi Liu 
vfio_group_find_or_alloc(struct device * dev)6619eefba80SYi Liu static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
6629eefba80SYi Liu {
6639eefba80SYi Liu 	struct iommu_group *iommu_group;
6649eefba80SYi Liu 	struct vfio_group *group;
6659eefba80SYi Liu 
6669eefba80SYi Liu 	iommu_group = iommu_group_get(dev);
6679eefba80SYi Liu 	if (!iommu_group && vfio_noiommu) {
6689eefba80SYi Liu 		/*
6699eefba80SYi Liu 		 * With noiommu enabled, create an IOMMU group for devices that
6709eefba80SYi Liu 		 * don't already have one, implying no IOMMU hardware/driver
6719eefba80SYi Liu 		 * exists.  Taint the kernel because we're about to give a DMA
6729eefba80SYi Liu 		 * capable device to a user without IOMMU protection.
6739eefba80SYi Liu 		 */
6749eefba80SYi Liu 		group = vfio_noiommu_group_alloc(dev, VFIO_NO_IOMMU);
6759eefba80SYi Liu 		if (!IS_ERR(group)) {
6769eefba80SYi Liu 			add_taint(TAINT_USER, LOCKDEP_STILL_OK);
6779eefba80SYi Liu 			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
6789eefba80SYi Liu 		}
6799eefba80SYi Liu 		return group;
6809eefba80SYi Liu 	}
6819eefba80SYi Liu 
6829eefba80SYi Liu 	if (!iommu_group)
6839eefba80SYi Liu 		return ERR_PTR(-EINVAL);
6849eefba80SYi Liu 
6859eefba80SYi Liu 	mutex_lock(&vfio.group_lock);
6869eefba80SYi Liu 	group = vfio_group_find_from_iommu(iommu_group);
6879eefba80SYi Liu 	if (group) {
6889eefba80SYi Liu 		if (WARN_ON(vfio_group_has_device(group, dev)))
6899eefba80SYi Liu 			group = ERR_PTR(-EINVAL);
6909eefba80SYi Liu 		else
6919eefba80SYi Liu 			refcount_inc(&group->drivers);
6929eefba80SYi Liu 	} else {
6939eefba80SYi Liu 		group = vfio_create_group(iommu_group, VFIO_IOMMU);
6949eefba80SYi Liu 	}
6959eefba80SYi Liu 	mutex_unlock(&vfio.group_lock);
6969eefba80SYi Liu 
6979eefba80SYi Liu 	/* The vfio_group holds a reference to the iommu_group */
6989eefba80SYi Liu 	iommu_group_put(iommu_group);
6999eefba80SYi Liu 	return group;
7009eefba80SYi Liu }
7019eefba80SYi Liu 
vfio_device_set_group(struct vfio_device * device,enum vfio_group_type type)7029eefba80SYi Liu int vfio_device_set_group(struct vfio_device *device,
7039eefba80SYi Liu 			  enum vfio_group_type type)
7049eefba80SYi Liu {
7059eefba80SYi Liu 	struct vfio_group *group;
7069eefba80SYi Liu 
7079eefba80SYi Liu 	if (type == VFIO_IOMMU)
7089eefba80SYi Liu 		group = vfio_group_find_or_alloc(device->dev);
7099eefba80SYi Liu 	else
7109eefba80SYi Liu 		group = vfio_noiommu_group_alloc(device->dev, type);
7119eefba80SYi Liu 
7129eefba80SYi Liu 	if (IS_ERR(group))
7139eefba80SYi Liu 		return PTR_ERR(group);
7149eefba80SYi Liu 
7159eefba80SYi Liu 	/* Our reference on group is moved to the device */
7169eefba80SYi Liu 	device->group = group;
7179eefba80SYi Liu 	return 0;
7189eefba80SYi Liu }
7199eefba80SYi Liu 
vfio_device_remove_group(struct vfio_device * device)7209eefba80SYi Liu void vfio_device_remove_group(struct vfio_device *device)
7219eefba80SYi Liu {
7229eefba80SYi Liu 	struct vfio_group *group = device->group;
7239eefba80SYi Liu 	struct iommu_group *iommu_group;
7249eefba80SYi Liu 
7259eefba80SYi Liu 	if (group->type == VFIO_NO_IOMMU || group->type == VFIO_EMULATED_IOMMU)
7269eefba80SYi Liu 		iommu_group_remove_device(device->dev);
7279eefba80SYi Liu 
7289eefba80SYi Liu 	/* Pairs with vfio_create_group() / vfio_group_get_from_iommu() */
7299eefba80SYi Liu 	if (!refcount_dec_and_mutex_lock(&group->drivers, &vfio.group_lock))
7309eefba80SYi Liu 		return;
7319eefba80SYi Liu 	list_del(&group->vfio_next);
7329eefba80SYi Liu 
7339eefba80SYi Liu 	/*
7349eefba80SYi Liu 	 * We could concurrently probe another driver in the group that might
7359eefba80SYi Liu 	 * race vfio_device_remove_group() with vfio_get_group(), so we have to
7369eefba80SYi Liu 	 * ensure that the sysfs is all cleaned up under lock otherwise the
7379eefba80SYi Liu 	 * cdev_device_add() will fail due to the name aready existing.
7389eefba80SYi Liu 	 */
7399eefba80SYi Liu 	cdev_device_del(&group->cdev, &group->dev);
7409eefba80SYi Liu 
7419eefba80SYi Liu 	mutex_lock(&group->group_lock);
7429eefba80SYi Liu 	/*
7439eefba80SYi Liu 	 * These data structures all have paired operations that can only be
7449eefba80SYi Liu 	 * undone when the caller holds a live reference on the device. Since
7459eefba80SYi Liu 	 * all pairs must be undone these WARN_ON's indicate some caller did not
7469eefba80SYi Liu 	 * properly hold the group reference.
7479eefba80SYi Liu 	 */
7489eefba80SYi Liu 	WARN_ON(!list_empty(&group->device_list));
7499eefba80SYi Liu 	WARN_ON(group->notifier.head);
7509eefba80SYi Liu 
7519eefba80SYi Liu 	/*
7529eefba80SYi Liu 	 * Revoke all users of group->iommu_group. At this point we know there
7539eefba80SYi Liu 	 * are no devices active because we are unplugging the last one. Setting
7549eefba80SYi Liu 	 * iommu_group to NULL blocks all new users.
7559eefba80SYi Liu 	 */
7569eefba80SYi Liu 	if (group->container)
7579eefba80SYi Liu 		vfio_group_detach_container(group);
7589eefba80SYi Liu 	iommu_group = group->iommu_group;
7599eefba80SYi Liu 	group->iommu_group = NULL;
7609eefba80SYi Liu 	mutex_unlock(&group->group_lock);
7619eefba80SYi Liu 	mutex_unlock(&vfio.group_lock);
7629eefba80SYi Liu 
7639eefba80SYi Liu 	iommu_group_put(iommu_group);
7649eefba80SYi Liu 	put_device(&group->dev);
7659eefba80SYi Liu }
7669eefba80SYi Liu 
vfio_device_group_register(struct vfio_device * device)7679eefba80SYi Liu void vfio_device_group_register(struct vfio_device *device)
7689eefba80SYi Liu {
7699eefba80SYi Liu 	mutex_lock(&device->group->device_lock);
7709eefba80SYi Liu 	list_add(&device->group_next, &device->group->device_list);
7719eefba80SYi Liu 	mutex_unlock(&device->group->device_lock);
7729eefba80SYi Liu }
7739eefba80SYi Liu 
vfio_device_group_unregister(struct vfio_device * device)7749eefba80SYi Liu void vfio_device_group_unregister(struct vfio_device *device)
7759eefba80SYi Liu {
7769eefba80SYi Liu 	mutex_lock(&device->group->device_lock);
7779eefba80SYi Liu 	list_del(&device->group_next);
7789eefba80SYi Liu 	mutex_unlock(&device->group->device_lock);
7799eefba80SYi Liu }
7809eefba80SYi Liu 
vfio_device_group_use_iommu(struct vfio_device * device)7819eefba80SYi Liu int vfio_device_group_use_iommu(struct vfio_device *device)
7829eefba80SYi Liu {
7839eefba80SYi Liu 	struct vfio_group *group = device->group;
7849eefba80SYi Liu 	int ret = 0;
7859eefba80SYi Liu 
7869eefba80SYi Liu 	lockdep_assert_held(&group->group_lock);
7879eefba80SYi Liu 
7889eefba80SYi Liu 	if (WARN_ON(!group->container))
7899eefba80SYi Liu 		return -EINVAL;
7909eefba80SYi Liu 
7919eefba80SYi Liu 	ret = vfio_group_use_container(group);
7929eefba80SYi Liu 	if (ret)
7939eefba80SYi Liu 		return ret;
7949eefba80SYi Liu 	vfio_device_container_register(device);
7959eefba80SYi Liu 	return 0;
7969eefba80SYi Liu }
7979eefba80SYi Liu 
vfio_device_group_unuse_iommu(struct vfio_device * device)7989eefba80SYi Liu void vfio_device_group_unuse_iommu(struct vfio_device *device)
7999eefba80SYi Liu {
8009eefba80SYi Liu 	struct vfio_group *group = device->group;
8019eefba80SYi Liu 
8029eefba80SYi Liu 	lockdep_assert_held(&group->group_lock);
8039eefba80SYi Liu 
8049eefba80SYi Liu 	if (WARN_ON(!group->container))
8059eefba80SYi Liu 		return;
8069eefba80SYi Liu 
8079eefba80SYi Liu 	vfio_device_container_unregister(device);
8089eefba80SYi Liu 	vfio_group_unuse_container(group);
8099eefba80SYi Liu }
8109eefba80SYi Liu 
vfio_device_has_container(struct vfio_device * device)8119eefba80SYi Liu bool vfio_device_has_container(struct vfio_device *device)
8129eefba80SYi Liu {
8139eefba80SYi Liu 	return device->group->container;
8149eefba80SYi Liu }
8159eefba80SYi Liu 
vfio_group_from_file(struct file * file)816b1a59be8SYi Liu struct vfio_group *vfio_group_from_file(struct file *file)
817b1a59be8SYi Liu {
818b1a59be8SYi Liu 	struct vfio_group *group = file->private_data;
819b1a59be8SYi Liu 
820b1a59be8SYi Liu 	if (file->f_op != &vfio_group_fops)
821b1a59be8SYi Liu 		return NULL;
822b1a59be8SYi Liu 	return group;
823b1a59be8SYi Liu }
824b1a59be8SYi Liu 
8259eefba80SYi Liu /**
8269eefba80SYi Liu  * vfio_file_iommu_group - Return the struct iommu_group for the vfio group file
8279eefba80SYi Liu  * @file: VFIO group file
8289eefba80SYi Liu  *
8299eefba80SYi Liu  * The returned iommu_group is valid as long as a ref is held on the file. This
8309eefba80SYi Liu  * returns a reference on the group. This function is deprecated, only the SPAPR
8319eefba80SYi Liu  * path in kvm should call it.
8329eefba80SYi Liu  */
vfio_file_iommu_group(struct file * file)8339eefba80SYi Liu struct iommu_group *vfio_file_iommu_group(struct file *file)
8349eefba80SYi Liu {
835b1a59be8SYi Liu 	struct vfio_group *group = vfio_group_from_file(file);
8369eefba80SYi Liu 	struct iommu_group *iommu_group = NULL;
8379eefba80SYi Liu 
8389eefba80SYi Liu 	if (!IS_ENABLED(CONFIG_SPAPR_TCE_IOMMU))
8399eefba80SYi Liu 		return NULL;
8409eefba80SYi Liu 
841b1a59be8SYi Liu 	if (!group)
8429eefba80SYi Liu 		return NULL;
8439eefba80SYi Liu 
8449eefba80SYi Liu 	mutex_lock(&group->group_lock);
8459eefba80SYi Liu 	if (group->iommu_group) {
8469eefba80SYi Liu 		iommu_group = group->iommu_group;
8479eefba80SYi Liu 		iommu_group_ref_get(iommu_group);
8489eefba80SYi Liu 	}
8499eefba80SYi Liu 	mutex_unlock(&group->group_lock);
8509eefba80SYi Liu 	return iommu_group;
8519eefba80SYi Liu }
8529eefba80SYi Liu EXPORT_SYMBOL_GPL(vfio_file_iommu_group);
8539eefba80SYi Liu 
8549eefba80SYi Liu /**
855b1a59be8SYi Liu  * vfio_file_is_group - True if the file is a vfio group file
8569eefba80SYi Liu  * @file: VFIO group file
8579eefba80SYi Liu  */
vfio_file_is_group(struct file * file)8589eefba80SYi Liu bool vfio_file_is_group(struct file *file)
8599eefba80SYi Liu {
860b1a59be8SYi Liu 	return vfio_group_from_file(file);
8619eefba80SYi Liu }
8629eefba80SYi Liu EXPORT_SYMBOL_GPL(vfio_file_is_group);
8639eefba80SYi Liu 
vfio_group_enforced_coherent(struct vfio_group * group)864b1a59be8SYi Liu bool vfio_group_enforced_coherent(struct vfio_group *group)
8659eefba80SYi Liu {
8669eefba80SYi Liu 	struct vfio_device *device;
8679eefba80SYi Liu 	bool ret = true;
8689eefba80SYi Liu 
8699eefba80SYi Liu 	/*
8709eefba80SYi Liu 	 * If the device does not have IOMMU_CAP_ENFORCE_CACHE_COHERENCY then
8719eefba80SYi Liu 	 * any domain later attached to it will also not support it. If the cap
8729eefba80SYi Liu 	 * is set then the iommu_domain eventually attached to the device/group
8739eefba80SYi Liu 	 * must use a domain with enforce_cache_coherency().
8749eefba80SYi Liu 	 */
8759eefba80SYi Liu 	mutex_lock(&group->device_lock);
8769eefba80SYi Liu 	list_for_each_entry(device, &group->device_list, group_next) {
8779eefba80SYi Liu 		if (!device_iommu_capable(device->dev,
8789eefba80SYi Liu 					  IOMMU_CAP_ENFORCE_CACHE_COHERENCY)) {
8799eefba80SYi Liu 			ret = false;
8809eefba80SYi Liu 			break;
8819eefba80SYi Liu 		}
8829eefba80SYi Liu 	}
8839eefba80SYi Liu 	mutex_unlock(&group->device_lock);
8849eefba80SYi Liu 	return ret;
8859eefba80SYi Liu }
8869eefba80SYi Liu 
vfio_group_set_kvm(struct vfio_group * group,struct kvm * kvm)887b1a59be8SYi Liu void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
8889eefba80SYi Liu {
8892b48f52fSMatthew Rosato 	spin_lock(&group->kvm_ref_lock);
8909eefba80SYi Liu 	group->kvm = kvm;
8912b48f52fSMatthew Rosato 	spin_unlock(&group->kvm_ref_lock);
8929eefba80SYi Liu }
8939eefba80SYi Liu 
8949eefba80SYi Liu /**
8959eefba80SYi Liu  * vfio_file_has_dev - True if the VFIO file is a handle for device
8969eefba80SYi Liu  * @file: VFIO file to check
8979eefba80SYi Liu  * @device: Device that must be part of the file
8989eefba80SYi Liu  *
8999eefba80SYi Liu  * Returns true if given file has permission to manipulate the given device.
9009eefba80SYi Liu  */
vfio_file_has_dev(struct file * file,struct vfio_device * device)9019eefba80SYi Liu bool vfio_file_has_dev(struct file *file, struct vfio_device *device)
9029eefba80SYi Liu {
903b1a59be8SYi Liu 	struct vfio_group *group = vfio_group_from_file(file);
9049eefba80SYi Liu 
905b1a59be8SYi Liu 	if (!group)
9069eefba80SYi Liu 		return false;
9079eefba80SYi Liu 
9089eefba80SYi Liu 	return group == device->group;
9099eefba80SYi Liu }
9109eefba80SYi Liu EXPORT_SYMBOL_GPL(vfio_file_has_dev);
9119eefba80SYi Liu 
vfio_devnode(const struct device * dev,umode_t * mode)91271a7507aSLinus Torvalds static char *vfio_devnode(const struct device *dev, umode_t *mode)
9139eefba80SYi Liu {
9149eefba80SYi Liu 	return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev));
9159eefba80SYi Liu }
9169eefba80SYi Liu 
vfio_group_init(void)9179eefba80SYi Liu int __init vfio_group_init(void)
9189eefba80SYi Liu {
9199eefba80SYi Liu 	int ret;
9209eefba80SYi Liu 
9219eefba80SYi Liu 	ida_init(&vfio.group_ida);
9229eefba80SYi Liu 	mutex_init(&vfio.group_lock);
9239eefba80SYi Liu 	INIT_LIST_HEAD(&vfio.group_list);
9249eefba80SYi Liu 
9259eefba80SYi Liu 	ret = vfio_container_init();
9269eefba80SYi Liu 	if (ret)
9279eefba80SYi Liu 		return ret;
9289eefba80SYi Liu 
9299eefba80SYi Liu 	/* /dev/vfio/$GROUP */
9301aaba11dSGreg Kroah-Hartman 	vfio.class = class_create("vfio");
9319eefba80SYi Liu 	if (IS_ERR(vfio.class)) {
9329eefba80SYi Liu 		ret = PTR_ERR(vfio.class);
9339eefba80SYi Liu 		goto err_group_class;
9349eefba80SYi Liu 	}
9359eefba80SYi Liu 
9369eefba80SYi Liu 	vfio.class->devnode = vfio_devnode;
9379eefba80SYi Liu 
9389eefba80SYi Liu 	ret = alloc_chrdev_region(&vfio.group_devt, 0, MINORMASK + 1, "vfio");
9399eefba80SYi Liu 	if (ret)
9409eefba80SYi Liu 		goto err_alloc_chrdev;
9419eefba80SYi Liu 	return 0;
9429eefba80SYi Liu 
9439eefba80SYi Liu err_alloc_chrdev:
9449eefba80SYi Liu 	class_destroy(vfio.class);
9459eefba80SYi Liu 	vfio.class = NULL;
9469eefba80SYi Liu err_group_class:
9479eefba80SYi Liu 	vfio_container_cleanup();
9489eefba80SYi Liu 	return ret;
9499eefba80SYi Liu }
9509eefba80SYi Liu 
vfio_group_cleanup(void)9519eefba80SYi Liu void vfio_group_cleanup(void)
9529eefba80SYi Liu {
9539eefba80SYi Liu 	WARN_ON(!list_empty(&vfio.group_list));
9549eefba80SYi Liu 	ida_destroy(&vfio.group_ida);
9559eefba80SYi Liu 	unregister_chrdev_region(vfio.group_devt, MINORMASK + 1);
9569eefba80SYi Liu 	class_destroy(vfio.class);
9579eefba80SYi Liu 	vfio.class = NULL;
9589eefba80SYi Liu 	vfio_container_cleanup();
9599eefba80SYi Liu }
960