xref: /openbmc/linux/virt/kvm/vfio.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ec53500fSAlex Williamson /*
3ec53500fSAlex Williamson  * VFIO-KVM bridge pseudo device
4ec53500fSAlex Williamson  *
5ec53500fSAlex Williamson  * Copyright (C) 2013 Red Hat, Inc.  All rights reserved.
6ec53500fSAlex Williamson  *     Author: Alex Williamson <alex.williamson@redhat.com>
7ec53500fSAlex Williamson  */
8ec53500fSAlex Williamson 
9ec53500fSAlex Williamson #include <linux/errno.h>
10ec53500fSAlex Williamson #include <linux/file.h>
11ec53500fSAlex Williamson #include <linux/kvm_host.h>
12ec53500fSAlex Williamson #include <linux/list.h>
13ec53500fSAlex Williamson #include <linux/module.h>
14ec53500fSAlex Williamson #include <linux/mutex.h>
15ec53500fSAlex Williamson #include <linux/slab.h>
16ec53500fSAlex Williamson #include <linux/uaccess.h>
17ec53500fSAlex Williamson #include <linux/vfio.h>
183c3c29fdSPaolo Bonzini #include "vfio.h"
19ec53500fSAlex Williamson 
20121f80baSAlexey Kardashevskiy #ifdef CONFIG_SPAPR_TCE_IOMMU
21121f80baSAlexey Kardashevskiy #include <asm/kvm_ppc.h>
22121f80baSAlexey Kardashevskiy #endif
23121f80baSAlexey Kardashevskiy 
242f99073aSYi Liu struct kvm_vfio_file {
25ec53500fSAlex Williamson 	struct list_head node;
26d55d9e7aSJason Gunthorpe 	struct file *file;
27819da99aSJason Gunthorpe #ifdef CONFIG_SPAPR_TCE_IOMMU
28819da99aSJason Gunthorpe 	struct iommu_group *iommu_group;
29819da99aSJason Gunthorpe #endif
30ec53500fSAlex Williamson };
31ec53500fSAlex Williamson 
32ec53500fSAlex Williamson struct kvm_vfio {
332f99073aSYi Liu 	struct list_head file_list;
34ec53500fSAlex Williamson 	struct mutex lock;
35e0f0bbc5SAlex Williamson 	bool noncoherent;
36ec53500fSAlex Williamson };
37ec53500fSAlex Williamson 
kvm_vfio_file_set_kvm(struct file * file,struct kvm * kvm)38ba70a89fSJason Gunthorpe static void kvm_vfio_file_set_kvm(struct file *file, struct kvm *kvm)
392fc1bec1SJike Song {
40ba70a89fSJason Gunthorpe 	void (*fn)(struct file *file, struct kvm *kvm);
412fc1bec1SJike Song 
42ba70a89fSJason Gunthorpe 	fn = symbol_get(vfio_file_set_kvm);
432fc1bec1SJike Song 	if (!fn)
442fc1bec1SJike Song 		return;
452fc1bec1SJike Song 
46ba70a89fSJason Gunthorpe 	fn(file, kvm);
472fc1bec1SJike Song 
48ba70a89fSJason Gunthorpe 	symbol_put(vfio_file_set_kvm);
492fc1bec1SJike Song }
502fc1bec1SJike Song 
kvm_vfio_file_enforced_coherent(struct file * file)51a905ad04SJason Gunthorpe static bool kvm_vfio_file_enforced_coherent(struct file *file)
529d830d47SAlex Williamson {
53a905ad04SJason Gunthorpe 	bool (*fn)(struct file *file);
54a905ad04SJason Gunthorpe 	bool ret;
559d830d47SAlex Williamson 
56a905ad04SJason Gunthorpe 	fn = symbol_get(vfio_file_enforced_coherent);
579d830d47SAlex Williamson 	if (!fn)
589d830d47SAlex Williamson 		return false;
599d830d47SAlex Williamson 
60a905ad04SJason Gunthorpe 	ret = fn(file);
619d830d47SAlex Williamson 
62a905ad04SJason Gunthorpe 	symbol_put(vfio_file_enforced_coherent);
639d830d47SAlex Williamson 
64a905ad04SJason Gunthorpe 	return ret;
659d830d47SAlex Williamson }
669d830d47SAlex Williamson 
kvm_vfio_file_is_valid(struct file * file)67b1a59be8SYi Liu static bool kvm_vfio_file_is_valid(struct file *file)
684b22ef04SJason Gunthorpe {
694b22ef04SJason Gunthorpe 	bool (*fn)(struct file *file);
704b22ef04SJason Gunthorpe 	bool ret;
714b22ef04SJason Gunthorpe 
72b1a59be8SYi Liu 	fn = symbol_get(vfio_file_is_valid);
734b22ef04SJason Gunthorpe 	if (!fn)
744b22ef04SJason Gunthorpe 		return false;
754b22ef04SJason Gunthorpe 
764b22ef04SJason Gunthorpe 	ret = fn(file);
774b22ef04SJason Gunthorpe 
78b1a59be8SYi Liu 	symbol_put(vfio_file_is_valid);
794b22ef04SJason Gunthorpe 
804b22ef04SJason Gunthorpe 	return ret;
814b22ef04SJason Gunthorpe }
824b22ef04SJason Gunthorpe 
834b22ef04SJason Gunthorpe #ifdef CONFIG_SPAPR_TCE_IOMMU
kvm_vfio_file_iommu_group(struct file * file)8450d63b5bSJason Gunthorpe static struct iommu_group *kvm_vfio_file_iommu_group(struct file *file)
85121f80baSAlexey Kardashevskiy {
8650d63b5bSJason Gunthorpe 	struct iommu_group *(*fn)(struct file *file);
8750d63b5bSJason Gunthorpe 	struct iommu_group *ret;
88121f80baSAlexey Kardashevskiy 
8950d63b5bSJason Gunthorpe 	fn = symbol_get(vfio_file_iommu_group);
90121f80baSAlexey Kardashevskiy 	if (!fn)
91121f80baSAlexey Kardashevskiy 		return NULL;
92121f80baSAlexey Kardashevskiy 
9350d63b5bSJason Gunthorpe 	ret = fn(file);
9450d63b5bSJason Gunthorpe 
9550d63b5bSJason Gunthorpe 	symbol_put(vfio_file_iommu_group);
9650d63b5bSJason Gunthorpe 
9750d63b5bSJason Gunthorpe 	return ret;
98121f80baSAlexey Kardashevskiy }
99121f80baSAlexey Kardashevskiy 
kvm_spapr_tce_release_vfio_group(struct kvm * kvm,struct kvm_vfio_file * kvf)100121f80baSAlexey Kardashevskiy static void kvm_spapr_tce_release_vfio_group(struct kvm *kvm,
1012f99073aSYi Liu 					     struct kvm_vfio_file *kvf)
102121f80baSAlexey Kardashevskiy {
1032f99073aSYi Liu 	if (WARN_ON_ONCE(!kvf->iommu_group))
104121f80baSAlexey Kardashevskiy 		return;
105121f80baSAlexey Kardashevskiy 
1062f99073aSYi Liu 	kvm_spapr_tce_release_iommu_group(kvm, kvf->iommu_group);
1072f99073aSYi Liu 	iommu_group_put(kvf->iommu_group);
1082f99073aSYi Liu 	kvf->iommu_group = NULL;
109121f80baSAlexey Kardashevskiy }
110121f80baSAlexey Kardashevskiy #endif
111121f80baSAlexey Kardashevskiy 
112e0f0bbc5SAlex Williamson /*
1132f99073aSYi Liu  * Groups/devices can use the same or different IOMMU domains. If the same
1142f99073aSYi Liu  * then adding a new group/device may change the coherency of groups/devices
1152f99073aSYi Liu  * we've previously been told about. We don't want to care about any of
1162f99073aSYi Liu  * that so we retest each group/device and bail as soon as we find one that's
1172f99073aSYi Liu  * noncoherent.  This means we only ever [un]register_noncoherent_dma once
1182f99073aSYi Liu  * for the whole device.
119e0f0bbc5SAlex Williamson  */
kvm_vfio_update_coherency(struct kvm_device * dev)120e0f0bbc5SAlex Williamson static void kvm_vfio_update_coherency(struct kvm_device *dev)
121e0f0bbc5SAlex Williamson {
122e0f0bbc5SAlex Williamson 	struct kvm_vfio *kv = dev->private;
123e0f0bbc5SAlex Williamson 	bool noncoherent = false;
1242f99073aSYi Liu 	struct kvm_vfio_file *kvf;
125e0f0bbc5SAlex Williamson 
1262f99073aSYi Liu 	list_for_each_entry(kvf, &kv->file_list, node) {
1272f99073aSYi Liu 		if (!kvm_vfio_file_enforced_coherent(kvf->file)) {
128e0f0bbc5SAlex Williamson 			noncoherent = true;
129e0f0bbc5SAlex Williamson 			break;
130e0f0bbc5SAlex Williamson 		}
1319d830d47SAlex Williamson 	}
132e0f0bbc5SAlex Williamson 
133e0f0bbc5SAlex Williamson 	if (noncoherent != kv->noncoherent) {
134e0f0bbc5SAlex Williamson 		kv->noncoherent = noncoherent;
135e0f0bbc5SAlex Williamson 
136e0f0bbc5SAlex Williamson 		if (kv->noncoherent)
137e0f0bbc5SAlex Williamson 			kvm_arch_register_noncoherent_dma(dev->kvm);
138e0f0bbc5SAlex Williamson 		else
139e0f0bbc5SAlex Williamson 			kvm_arch_unregister_noncoherent_dma(dev->kvm);
140e0f0bbc5SAlex Williamson 	}
141e0f0bbc5SAlex Williamson }
142e0f0bbc5SAlex Williamson 
kvm_vfio_file_add(struct kvm_device * dev,unsigned int fd)1432f99073aSYi Liu static int kvm_vfio_file_add(struct kvm_device *dev, unsigned int fd)
144ec53500fSAlex Williamson {
145ec53500fSAlex Williamson 	struct kvm_vfio *kv = dev->private;
1462f99073aSYi Liu 	struct kvm_vfio_file *kvf;
147d55d9e7aSJason Gunthorpe 	struct file *filp;
148*73e2f19dSDmitry Torokhov 	int ret = 0;
149ec53500fSAlex Williamson 
150d55d9e7aSJason Gunthorpe 	filp = fget(fd);
151d55d9e7aSJason Gunthorpe 	if (!filp)
152ec53500fSAlex Williamson 		return -EBADF;
153ec53500fSAlex Williamson 
154b1a59be8SYi Liu 	/* Ensure the FD is a vfio FD. */
155b1a59be8SYi Liu 	if (!kvm_vfio_file_is_valid(filp)) {
1563e5449d5SJason Gunthorpe 		ret = -EINVAL;
157*73e2f19dSDmitry Torokhov 		goto out_fput;
1583e5449d5SJason Gunthorpe 	}
1593e5449d5SJason Gunthorpe 
160ec53500fSAlex Williamson 	mutex_lock(&kv->lock);
161ec53500fSAlex Williamson 
1622f99073aSYi Liu 	list_for_each_entry(kvf, &kv->file_list, node) {
1632f99073aSYi Liu 		if (kvf->file == filp) {
16473b0565fSJason Gunthorpe 			ret = -EEXIST;
165*73e2f19dSDmitry Torokhov 			goto out_unlock;
166ec53500fSAlex Williamson 		}
167ec53500fSAlex Williamson 	}
168ec53500fSAlex Williamson 
1692f99073aSYi Liu 	kvf = kzalloc(sizeof(*kvf), GFP_KERNEL_ACCOUNT);
1702f99073aSYi Liu 	if (!kvf) {
17173b0565fSJason Gunthorpe 		ret = -ENOMEM;
172*73e2f19dSDmitry Torokhov 		goto out_unlock;
173ec53500fSAlex Williamson 	}
174ec53500fSAlex Williamson 
175*73e2f19dSDmitry Torokhov 	kvf->file = get_file(filp);
1762f99073aSYi Liu 	list_add_tail(&kvf->node, &kv->file_list);
177ec53500fSAlex Williamson 
1785544eb9bSPaolo Bonzini 	kvm_arch_start_assignment(dev->kvm);
1799e0f4f29SDmitry Torokhov 	kvm_vfio_file_set_kvm(kvf->file, dev->kvm);
180e0f0bbc5SAlex Williamson 	kvm_vfio_update_coherency(dev);
181e0f0bbc5SAlex Williamson 
182*73e2f19dSDmitry Torokhov out_unlock:
18373b0565fSJason Gunthorpe 	mutex_unlock(&kv->lock);
184*73e2f19dSDmitry Torokhov out_fput:
185d55d9e7aSJason Gunthorpe 	fput(filp);
18673b0565fSJason Gunthorpe 	return ret;
18773b0565fSJason Gunthorpe }
188ec53500fSAlex Williamson 
kvm_vfio_file_del(struct kvm_device * dev,unsigned int fd)1892f99073aSYi Liu static int kvm_vfio_file_del(struct kvm_device *dev, unsigned int fd)
19073b0565fSJason Gunthorpe {
19173b0565fSJason Gunthorpe 	struct kvm_vfio *kv = dev->private;
1922f99073aSYi Liu 	struct kvm_vfio_file *kvf;
19373b0565fSJason Gunthorpe 	struct fd f;
19473b0565fSJason Gunthorpe 	int ret;
195ec53500fSAlex Williamson 
196ec53500fSAlex Williamson 	f = fdget(fd);
197ec53500fSAlex Williamson 	if (!f.file)
198ec53500fSAlex Williamson 		return -EBADF;
199ec53500fSAlex Williamson 
200ec53500fSAlex Williamson 	ret = -ENOENT;
201ec53500fSAlex Williamson 
202ec53500fSAlex Williamson 	mutex_lock(&kv->lock);
203ec53500fSAlex Williamson 
2042f99073aSYi Liu 	list_for_each_entry(kvf, &kv->file_list, node) {
2052f99073aSYi Liu 		if (kvf->file != f.file)
206ec53500fSAlex Williamson 			continue;
207ec53500fSAlex Williamson 
2082f99073aSYi Liu 		list_del(&kvf->node);
209e323369bSAlex Williamson 		kvm_arch_end_assignment(dev->kvm);
210e323369bSAlex Williamson #ifdef CONFIG_SPAPR_TCE_IOMMU
2112f99073aSYi Liu 		kvm_spapr_tce_release_vfio_group(dev->kvm, kvf);
212e323369bSAlex Williamson #endif
2132f99073aSYi Liu 		kvm_vfio_file_set_kvm(kvf->file, NULL);
2142f99073aSYi Liu 		fput(kvf->file);
2152f99073aSYi Liu 		kfree(kvf);
216ec53500fSAlex Williamson 		ret = 0;
217ec53500fSAlex Williamson 		break;
218ec53500fSAlex Williamson 	}
219ec53500fSAlex Williamson 
220*73e2f19dSDmitry Torokhov 	kvm_vfio_update_coherency(dev);
221*73e2f19dSDmitry Torokhov 
222ec53500fSAlex Williamson 	mutex_unlock(&kv->lock);
223ec53500fSAlex Williamson 
2245d6dee80SAlex Williamson 	fdput(f);
225ec53500fSAlex Williamson 
226ec53500fSAlex Williamson 	return ret;
22773b0565fSJason Gunthorpe }
228121f80baSAlexey Kardashevskiy 
229121f80baSAlexey Kardashevskiy #ifdef CONFIG_SPAPR_TCE_IOMMU
kvm_vfio_file_set_spapr_tce(struct kvm_device * dev,void __user * arg)2302f99073aSYi Liu static int kvm_vfio_file_set_spapr_tce(struct kvm_device *dev,
23173b0565fSJason Gunthorpe 				       void __user *arg)
23273b0565fSJason Gunthorpe {
233121f80baSAlexey Kardashevskiy 	struct kvm_vfio_spapr_tce param;
234121f80baSAlexey Kardashevskiy 	struct kvm_vfio *kv = dev->private;
2352f99073aSYi Liu 	struct kvm_vfio_file *kvf;
236121f80baSAlexey Kardashevskiy 	struct fd f;
23773b0565fSJason Gunthorpe 	int ret;
238121f80baSAlexey Kardashevskiy 
23973b0565fSJason Gunthorpe 	if (copy_from_user(&param, arg, sizeof(struct kvm_vfio_spapr_tce)))
240121f80baSAlexey Kardashevskiy 		return -EFAULT;
241121f80baSAlexey Kardashevskiy 
242121f80baSAlexey Kardashevskiy 	f = fdget(param.groupfd);
243121f80baSAlexey Kardashevskiy 	if (!f.file)
244121f80baSAlexey Kardashevskiy 		return -EBADF;
245121f80baSAlexey Kardashevskiy 
246121f80baSAlexey Kardashevskiy 	ret = -ENOENT;
247121f80baSAlexey Kardashevskiy 
248121f80baSAlexey Kardashevskiy 	mutex_lock(&kv->lock);
249121f80baSAlexey Kardashevskiy 
2502f99073aSYi Liu 	list_for_each_entry(kvf, &kv->file_list, node) {
2512f99073aSYi Liu 		if (kvf->file != f.file)
252121f80baSAlexey Kardashevskiy 			continue;
253121f80baSAlexey Kardashevskiy 
2542f99073aSYi Liu 		if (!kvf->iommu_group) {
2552f99073aSYi Liu 			kvf->iommu_group = kvm_vfio_file_iommu_group(kvf->file);
2562f99073aSYi Liu 			if (WARN_ON_ONCE(!kvf->iommu_group)) {
257d55d9e7aSJason Gunthorpe 				ret = -EIO;
258d55d9e7aSJason Gunthorpe 				goto err_fdput;
259d55d9e7aSJason Gunthorpe 			}
260819da99aSJason Gunthorpe 		}
261d55d9e7aSJason Gunthorpe 
26273b0565fSJason Gunthorpe 		ret = kvm_spapr_tce_attach_iommu_group(dev->kvm, param.tablefd,
2632f99073aSYi Liu 						       kvf->iommu_group);
264121f80baSAlexey Kardashevskiy 		break;
265121f80baSAlexey Kardashevskiy 	}
266121f80baSAlexey Kardashevskiy 
267d55d9e7aSJason Gunthorpe err_fdput:
2686b17ca8eSWan Jiabing 	mutex_unlock(&kv->lock);
269d55d9e7aSJason Gunthorpe 	fdput(f);
270121f80baSAlexey Kardashevskiy 	return ret;
271121f80baSAlexey Kardashevskiy }
27273b0565fSJason Gunthorpe #endif
27373b0565fSJason Gunthorpe 
kvm_vfio_set_file(struct kvm_device * dev,long attr,void __user * arg)2742f99073aSYi Liu static int kvm_vfio_set_file(struct kvm_device *dev, long attr,
27573b0565fSJason Gunthorpe 			     void __user *arg)
27673b0565fSJason Gunthorpe {
27773b0565fSJason Gunthorpe 	int32_t __user *argp = arg;
27873b0565fSJason Gunthorpe 	int32_t fd;
27973b0565fSJason Gunthorpe 
28073b0565fSJason Gunthorpe 	switch (attr) {
281dcc31ea6SYi Liu 	case KVM_DEV_VFIO_FILE_ADD:
28273b0565fSJason Gunthorpe 		if (get_user(fd, argp))
28373b0565fSJason Gunthorpe 			return -EFAULT;
2842f99073aSYi Liu 		return kvm_vfio_file_add(dev, fd);
28573b0565fSJason Gunthorpe 
286dcc31ea6SYi Liu 	case KVM_DEV_VFIO_FILE_DEL:
28773b0565fSJason Gunthorpe 		if (get_user(fd, argp))
28873b0565fSJason Gunthorpe 			return -EFAULT;
2892f99073aSYi Liu 		return kvm_vfio_file_del(dev, fd);
29073b0565fSJason Gunthorpe 
29173b0565fSJason Gunthorpe #ifdef CONFIG_SPAPR_TCE_IOMMU
29273b0565fSJason Gunthorpe 	case KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE:
2932f99073aSYi Liu 		return kvm_vfio_file_set_spapr_tce(dev, arg);
29473b0565fSJason Gunthorpe #endif
295ec53500fSAlex Williamson 	}
296ec53500fSAlex Williamson 
297ec53500fSAlex Williamson 	return -ENXIO;
298ec53500fSAlex Williamson }
299ec53500fSAlex Williamson 
kvm_vfio_set_attr(struct kvm_device * dev,struct kvm_device_attr * attr)300ec53500fSAlex Williamson static int kvm_vfio_set_attr(struct kvm_device *dev,
301ec53500fSAlex Williamson 			     struct kvm_device_attr *attr)
302ec53500fSAlex Williamson {
303ec53500fSAlex Williamson 	switch (attr->group) {
304dcc31ea6SYi Liu 	case KVM_DEV_VFIO_FILE:
3052f99073aSYi Liu 		return kvm_vfio_set_file(dev, attr->attr,
30673b0565fSJason Gunthorpe 					 u64_to_user_ptr(attr->addr));
307ec53500fSAlex Williamson 	}
308ec53500fSAlex Williamson 
309ec53500fSAlex Williamson 	return -ENXIO;
310ec53500fSAlex Williamson }
311ec53500fSAlex Williamson 
kvm_vfio_has_attr(struct kvm_device * dev,struct kvm_device_attr * attr)312ec53500fSAlex Williamson static int kvm_vfio_has_attr(struct kvm_device *dev,
313ec53500fSAlex Williamson 			     struct kvm_device_attr *attr)
314ec53500fSAlex Williamson {
315ec53500fSAlex Williamson 	switch (attr->group) {
316dcc31ea6SYi Liu 	case KVM_DEV_VFIO_FILE:
317ec53500fSAlex Williamson 		switch (attr->attr) {
318dcc31ea6SYi Liu 		case KVM_DEV_VFIO_FILE_ADD:
319dcc31ea6SYi Liu 		case KVM_DEV_VFIO_FILE_DEL:
320121f80baSAlexey Kardashevskiy #ifdef CONFIG_SPAPR_TCE_IOMMU
321121f80baSAlexey Kardashevskiy 		case KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE:
322121f80baSAlexey Kardashevskiy #endif
323ec53500fSAlex Williamson 			return 0;
324ec53500fSAlex Williamson 		}
325ec53500fSAlex Williamson 
326ec53500fSAlex Williamson 		break;
327ec53500fSAlex Williamson 	}
328ec53500fSAlex Williamson 
329ec53500fSAlex Williamson 	return -ENXIO;
330ec53500fSAlex Williamson }
331ec53500fSAlex Williamson 
kvm_vfio_release(struct kvm_device * dev)33251cdc8bcSYi Liu static void kvm_vfio_release(struct kvm_device *dev)
333ec53500fSAlex Williamson {
334ec53500fSAlex Williamson 	struct kvm_vfio *kv = dev->private;
3352f99073aSYi Liu 	struct kvm_vfio_file *kvf, *tmp;
336ec53500fSAlex Williamson 
3372f99073aSYi Liu 	list_for_each_entry_safe(kvf, tmp, &kv->file_list, node) {
338121f80baSAlexey Kardashevskiy #ifdef CONFIG_SPAPR_TCE_IOMMU
3392f99073aSYi Liu 		kvm_spapr_tce_release_vfio_group(dev->kvm, kvf);
340121f80baSAlexey Kardashevskiy #endif
3412f99073aSYi Liu 		kvm_vfio_file_set_kvm(kvf->file, NULL);
3422f99073aSYi Liu 		fput(kvf->file);
3432f99073aSYi Liu 		list_del(&kvf->node);
3442f99073aSYi Liu 		kfree(kvf);
3455544eb9bSPaolo Bonzini 		kvm_arch_end_assignment(dev->kvm);
346ec53500fSAlex Williamson 	}
347ec53500fSAlex Williamson 
348e0f0bbc5SAlex Williamson 	kvm_vfio_update_coherency(dev);
349e0f0bbc5SAlex Williamson 
350ec53500fSAlex Williamson 	kfree(kv);
35151cdc8bcSYi Liu 	kfree(dev); /* alloc by kvm_ioctl_create_device, free by .release */
352ec53500fSAlex Williamson }
353ec53500fSAlex Williamson 
35480ce1639SWill Deacon static int kvm_vfio_create(struct kvm_device *dev, u32 type);
35580ce1639SWill Deacon 
35680ce1639SWill Deacon static struct kvm_device_ops kvm_vfio_ops = {
35780ce1639SWill Deacon 	.name = "kvm-vfio",
35880ce1639SWill Deacon 	.create = kvm_vfio_create,
35951cdc8bcSYi Liu 	.release = kvm_vfio_release,
36080ce1639SWill Deacon 	.set_attr = kvm_vfio_set_attr,
36180ce1639SWill Deacon 	.has_attr = kvm_vfio_has_attr,
36280ce1639SWill Deacon };
36380ce1639SWill Deacon 
kvm_vfio_create(struct kvm_device * dev,u32 type)364ec53500fSAlex Williamson static int kvm_vfio_create(struct kvm_device *dev, u32 type)
365ec53500fSAlex Williamson {
366ec53500fSAlex Williamson 	struct kvm_device *tmp;
367ec53500fSAlex Williamson 	struct kvm_vfio *kv;
368ec53500fSAlex Williamson 
369ec53500fSAlex Williamson 	/* Only one VFIO "device" per VM */
370ec53500fSAlex Williamson 	list_for_each_entry(tmp, &dev->kvm->devices, vm_node)
371ec53500fSAlex Williamson 		if (tmp->ops == &kvm_vfio_ops)
372ec53500fSAlex Williamson 			return -EBUSY;
373ec53500fSAlex Williamson 
374b12ce36aSBen Gardon 	kv = kzalloc(sizeof(*kv), GFP_KERNEL_ACCOUNT);
375ec53500fSAlex Williamson 	if (!kv)
376ec53500fSAlex Williamson 		return -ENOMEM;
377ec53500fSAlex Williamson 
3782f99073aSYi Liu 	INIT_LIST_HEAD(&kv->file_list);
379ec53500fSAlex Williamson 	mutex_init(&kv->lock);
380ec53500fSAlex Williamson 
381ec53500fSAlex Williamson 	dev->private = kv;
382ec53500fSAlex Williamson 
383ec53500fSAlex Williamson 	return 0;
384ec53500fSAlex Williamson }
385ec53500fSAlex Williamson 
kvm_vfio_ops_init(void)3863c3c29fdSPaolo Bonzini int kvm_vfio_ops_init(void)
38780ce1639SWill Deacon {
38880ce1639SWill Deacon 	return kvm_register_device_ops(&kvm_vfio_ops, KVM_DEV_TYPE_VFIO);
38980ce1639SWill Deacon }
390571ee1b6SWanpeng Li 
kvm_vfio_ops_exit(void)391571ee1b6SWanpeng Li void kvm_vfio_ops_exit(void)
392571ee1b6SWanpeng Li {
393571ee1b6SWanpeng Li 	kvm_unregister_device_ops(KVM_DEV_TYPE_VFIO);
394571ee1b6SWanpeng Li }
395