1
2
3
4
5
6
7
8
9
10#include <linux/vfio.h>
11#include <linux/mdev.h>
12
13#include "vfio_ccw_private.h"
14
15static int vfio_ccw_mdev_reset(struct mdev_device *mdev)
16{
17 struct vfio_ccw_private *private;
18 struct subchannel *sch;
19 int ret;
20
21 private = dev_get_drvdata(mdev_parent_dev(mdev));
22 sch = private->sch;
23
24
25
26
27
28
29
30
31 ret = vfio_ccw_sch_quiesce(sch);
32 if (ret)
33 return ret;
34
35 ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
36 if (!ret)
37 private->state = VFIO_CCW_STATE_IDLE;
38
39 return ret;
40}
41
42static int vfio_ccw_mdev_notifier(struct notifier_block *nb,
43 unsigned long action,
44 void *data)
45{
46 struct vfio_ccw_private *private =
47 container_of(nb, struct vfio_ccw_private, nb);
48
49
50
51
52
53 if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
54 struct vfio_iommu_type1_dma_unmap *unmap = data;
55
56 if (!cp_iova_pinned(&private->cp, unmap->iova))
57 return NOTIFY_OK;
58
59 if (vfio_ccw_mdev_reset(private->mdev))
60 return NOTIFY_BAD;
61
62 cp_free(&private->cp);
63 return NOTIFY_OK;
64 }
65
66 return NOTIFY_DONE;
67}
68
69static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf)
70{
71 return sprintf(buf, "I/O subchannel (Non-QDIO)\n");
72}
73static MDEV_TYPE_ATTR_RO(name);
74
75static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
76 char *buf)
77{
78 return sprintf(buf, "%s\n", VFIO_DEVICE_API_CCW_STRING);
79}
80static MDEV_TYPE_ATTR_RO(device_api);
81
82static ssize_t available_instances_show(struct kobject *kobj,
83 struct device *dev, char *buf)
84{
85 struct vfio_ccw_private *private = dev_get_drvdata(dev);
86
87 return sprintf(buf, "%d\n", atomic_read(&private->avail));
88}
89static MDEV_TYPE_ATTR_RO(available_instances);
90
91static struct attribute *mdev_types_attrs[] = {
92 &mdev_type_attr_name.attr,
93 &mdev_type_attr_device_api.attr,
94 &mdev_type_attr_available_instances.attr,
95 NULL,
96};
97
98static struct attribute_group mdev_type_group = {
99 .name = "io",
100 .attrs = mdev_types_attrs,
101};
102
103static struct attribute_group *mdev_type_groups[] = {
104 &mdev_type_group,
105 NULL,
106};
107
108static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
109{
110 struct vfio_ccw_private *private =
111 dev_get_drvdata(mdev_parent_dev(mdev));
112
113 if (private->state == VFIO_CCW_STATE_NOT_OPER)
114 return -ENODEV;
115
116 if (atomic_dec_if_positive(&private->avail) < 0)
117 return -EPERM;
118
119 private->mdev = mdev;
120 private->state = VFIO_CCW_STATE_IDLE;
121
122 return 0;
123}
124
125static int vfio_ccw_mdev_remove(struct mdev_device *mdev)
126{
127 struct vfio_ccw_private *private =
128 dev_get_drvdata(mdev_parent_dev(mdev));
129
130 if ((private->state != VFIO_CCW_STATE_NOT_OPER) &&
131 (private->state != VFIO_CCW_STATE_STANDBY)) {
132 if (!vfio_ccw_mdev_reset(mdev))
133 private->state = VFIO_CCW_STATE_STANDBY;
134
135 }
136
137 private->mdev = NULL;
138 atomic_inc(&private->avail);
139
140 return 0;
141}
142
143static int vfio_ccw_mdev_open(struct mdev_device *mdev)
144{
145 struct vfio_ccw_private *private =
146 dev_get_drvdata(mdev_parent_dev(mdev));
147 unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
148
149 private->nb.notifier_call = vfio_ccw_mdev_notifier;
150
151 return vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
152 &events, &private->nb);
153}
154
155static void vfio_ccw_mdev_release(struct mdev_device *mdev)
156{
157 struct vfio_ccw_private *private =
158 dev_get_drvdata(mdev_parent_dev(mdev));
159
160 vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
161 &private->nb);
162}
163
164static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev,
165 char __user *buf,
166 size_t count,
167 loff_t *ppos)
168{
169 struct vfio_ccw_private *private;
170 struct ccw_io_region *region;
171
172 if (*ppos + count > sizeof(*region))
173 return -EINVAL;
174
175 private = dev_get_drvdata(mdev_parent_dev(mdev));
176 region = &private->io_region;
177 if (copy_to_user(buf, (void *)region + *ppos, count))
178 return -EFAULT;
179
180 return count;
181}
182
183static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev,
184 const char __user *buf,
185 size_t count,
186 loff_t *ppos)
187{
188 struct vfio_ccw_private *private;
189 struct ccw_io_region *region;
190
191 if (*ppos + count > sizeof(*region))
192 return -EINVAL;
193
194 private = dev_get_drvdata(mdev_parent_dev(mdev));
195 if (private->state != VFIO_CCW_STATE_IDLE)
196 return -EACCES;
197
198 region = &private->io_region;
199 if (copy_from_user((void *)region + *ppos, buf, count))
200 return -EFAULT;
201
202 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ);
203 if (region->ret_code != 0) {
204 private->state = VFIO_CCW_STATE_IDLE;
205 return region->ret_code;
206 }
207
208 return count;
209}
210
211static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info)
212{
213 info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET;
214 info->num_regions = VFIO_CCW_NUM_REGIONS;
215 info->num_irqs = VFIO_CCW_NUM_IRQS;
216
217 return 0;
218}
219
220static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info,
221 u16 *cap_type_id,
222 void **cap_type)
223{
224 switch (info->index) {
225 case VFIO_CCW_CONFIG_REGION_INDEX:
226 info->offset = 0;
227 info->size = sizeof(struct ccw_io_region);
228 info->flags = VFIO_REGION_INFO_FLAG_READ
229 | VFIO_REGION_INFO_FLAG_WRITE;
230 return 0;
231 default:
232 return -EINVAL;
233 }
234}
235
236static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info)
237{
238 if (info->index != VFIO_CCW_IO_IRQ_INDEX)
239 return -EINVAL;
240
241 info->count = 1;
242 info->flags = VFIO_IRQ_INFO_EVENTFD;
243
244 return 0;
245}
246
247static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev,
248 uint32_t flags,
249 void __user *data)
250{
251 struct vfio_ccw_private *private;
252 struct eventfd_ctx **ctx;
253
254 if (!(flags & VFIO_IRQ_SET_ACTION_TRIGGER))
255 return -EINVAL;
256
257 private = dev_get_drvdata(mdev_parent_dev(mdev));
258 ctx = &private->io_trigger;
259
260 switch (flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
261 case VFIO_IRQ_SET_DATA_NONE:
262 {
263 if (*ctx)
264 eventfd_signal(*ctx, 1);
265 return 0;
266 }
267 case VFIO_IRQ_SET_DATA_BOOL:
268 {
269 uint8_t trigger;
270
271 if (get_user(trigger, (uint8_t __user *)data))
272 return -EFAULT;
273
274 if (trigger && *ctx)
275 eventfd_signal(*ctx, 1);
276 return 0;
277 }
278 case VFIO_IRQ_SET_DATA_EVENTFD:
279 {
280 int32_t fd;
281
282 if (get_user(fd, (int32_t __user *)data))
283 return -EFAULT;
284
285 if (fd == -1) {
286 if (*ctx)
287 eventfd_ctx_put(*ctx);
288 *ctx = NULL;
289 } else if (fd >= 0) {
290 struct eventfd_ctx *efdctx;
291
292 efdctx = eventfd_ctx_fdget(fd);
293 if (IS_ERR(efdctx))
294 return PTR_ERR(efdctx);
295
296 if (*ctx)
297 eventfd_ctx_put(*ctx);
298
299 *ctx = efdctx;
300 } else
301 return -EINVAL;
302
303 return 0;
304 }
305 default:
306 return -EINVAL;
307 }
308}
309
310static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
311 unsigned int cmd,
312 unsigned long arg)
313{
314 int ret = 0;
315 unsigned long minsz;
316
317 switch (cmd) {
318 case VFIO_DEVICE_GET_INFO:
319 {
320 struct vfio_device_info info;
321
322 minsz = offsetofend(struct vfio_device_info, num_irqs);
323
324 if (copy_from_user(&info, (void __user *)arg, minsz))
325 return -EFAULT;
326
327 if (info.argsz < minsz)
328 return -EINVAL;
329
330 ret = vfio_ccw_mdev_get_device_info(&info);
331 if (ret)
332 return ret;
333
334 return copy_to_user((void __user *)arg, &info, minsz);
335 }
336 case VFIO_DEVICE_GET_REGION_INFO:
337 {
338 struct vfio_region_info info;
339 u16 cap_type_id = 0;
340 void *cap_type = NULL;
341
342 minsz = offsetofend(struct vfio_region_info, offset);
343
344 if (copy_from_user(&info, (void __user *)arg, minsz))
345 return -EFAULT;
346
347 if (info.argsz < minsz)
348 return -EINVAL;
349
350 ret = vfio_ccw_mdev_get_region_info(&info, &cap_type_id,
351 &cap_type);
352 if (ret)
353 return ret;
354
355 return copy_to_user((void __user *)arg, &info, minsz);
356 }
357 case VFIO_DEVICE_GET_IRQ_INFO:
358 {
359 struct vfio_irq_info info;
360
361 minsz = offsetofend(struct vfio_irq_info, count);
362
363 if (copy_from_user(&info, (void __user *)arg, minsz))
364 return -EFAULT;
365
366 if (info.argsz < minsz || info.index >= VFIO_CCW_NUM_IRQS)
367 return -EINVAL;
368
369 ret = vfio_ccw_mdev_get_irq_info(&info);
370 if (ret)
371 return ret;
372
373 if (info.count == -1)
374 return -EINVAL;
375
376 return copy_to_user((void __user *)arg, &info, minsz);
377 }
378 case VFIO_DEVICE_SET_IRQS:
379 {
380 struct vfio_irq_set hdr;
381 size_t data_size;
382 void __user *data;
383
384 minsz = offsetofend(struct vfio_irq_set, count);
385
386 if (copy_from_user(&hdr, (void __user *)arg, minsz))
387 return -EFAULT;
388
389 ret = vfio_set_irqs_validate_and_prepare(&hdr, 1,
390 VFIO_CCW_NUM_IRQS,
391 &data_size);
392 if (ret)
393 return ret;
394
395 data = (void __user *)(arg + minsz);
396 return vfio_ccw_mdev_set_irqs(mdev, hdr.flags, data);
397 }
398 case VFIO_DEVICE_RESET:
399 return vfio_ccw_mdev_reset(mdev);
400 default:
401 return -ENOTTY;
402 }
403}
404
405static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
406 .owner = THIS_MODULE,
407 .supported_type_groups = mdev_type_groups,
408 .create = vfio_ccw_mdev_create,
409 .remove = vfio_ccw_mdev_remove,
410 .open = vfio_ccw_mdev_open,
411 .release = vfio_ccw_mdev_release,
412 .read = vfio_ccw_mdev_read,
413 .write = vfio_ccw_mdev_write,
414 .ioctl = vfio_ccw_mdev_ioctl,
415};
416
417int vfio_ccw_mdev_reg(struct subchannel *sch)
418{
419 return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops);
420}
421
422void vfio_ccw_mdev_unreg(struct subchannel *sch)
423{
424 mdev_unregister_device(&sch->dev);
425}
426