blob: c2f853a3b3dd3d2d4d7251a4af24f984aa7fd814 [file] [log] [blame]
Antonios Motakisde49fc02015-03-16 14:08:42 -06001/*
2 * Copyright (C) 2013 - Virtual Open Systems
3 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/device.h>
16#include <linux/iommu.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/slab.h>
20#include <linux/types.h>
Antonios Motakis2e8567b2015-03-16 14:08:46 -060021#include <linux/uaccess.h>
Antonios Motakisde49fc02015-03-16 14:08:42 -060022#include <linux/vfio.h>
23
24#include "vfio_platform_private.h"
25
26static void vfio_platform_release(void *device_data)
27{
28 module_put(THIS_MODULE);
29}
30
31static int vfio_platform_open(void *device_data)
32{
33 if (!try_module_get(THIS_MODULE))
34 return -ENODEV;
35
36 return 0;
37}
38
39static long vfio_platform_ioctl(void *device_data,
40 unsigned int cmd, unsigned long arg)
41{
Antonios Motakis2e8567b2015-03-16 14:08:46 -060042 struct vfio_platform_device *vdev = device_data;
43 unsigned long minsz;
Antonios Motakisde49fc02015-03-16 14:08:42 -060044
Antonios Motakis2e8567b2015-03-16 14:08:46 -060045 if (cmd == VFIO_DEVICE_GET_INFO) {
46 struct vfio_device_info info;
47
48 minsz = offsetofend(struct vfio_device_info, num_irqs);
49
50 if (copy_from_user(&info, (void __user *)arg, minsz))
51 return -EFAULT;
52
53 if (info.argsz < minsz)
54 return -EINVAL;
55
56 info.flags = vdev->flags;
57 info.num_regions = 0;
58 info.num_irqs = 0;
59
60 return copy_to_user((void __user *)arg, &info, minsz);
61
62 } else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
Antonios Motakisde49fc02015-03-16 14:08:42 -060063 return -EINVAL;
64
65 else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
66 return -EINVAL;
67
68 else if (cmd == VFIO_DEVICE_SET_IRQS)
69 return -EINVAL;
70
71 else if (cmd == VFIO_DEVICE_RESET)
72 return -EINVAL;
73
74 return -ENOTTY;
75}
76
77static ssize_t vfio_platform_read(void *device_data, char __user *buf,
78 size_t count, loff_t *ppos)
79{
80 return -EINVAL;
81}
82
83static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
84 size_t count, loff_t *ppos)
85{
86 return -EINVAL;
87}
88
89static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
90{
91 return -EINVAL;
92}
93
94static const struct vfio_device_ops vfio_platform_ops = {
95 .name = "vfio-platform",
96 .open = vfio_platform_open,
97 .release = vfio_platform_release,
98 .ioctl = vfio_platform_ioctl,
99 .read = vfio_platform_read,
100 .write = vfio_platform_write,
101 .mmap = vfio_platform_mmap,
102};
103
104int vfio_platform_probe_common(struct vfio_platform_device *vdev,
105 struct device *dev)
106{
107 struct iommu_group *group;
108 int ret;
109
110 if (!vdev)
111 return -EINVAL;
112
113 group = iommu_group_get(dev);
114 if (!group) {
115 pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
116 return -EINVAL;
117 }
118
119 ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
120 if (ret) {
121 iommu_group_put(group);
122 return ret;
123 }
124
125 return 0;
126}
127EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
128
129struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
130{
131 struct vfio_platform_device *vdev;
132
133 vdev = vfio_del_group_dev(dev);
134 if (vdev)
135 iommu_group_put(dev->iommu_group);
136
137 return vdev;
138}
139EXPORT_SYMBOL_GPL(vfio_platform_remove_common);