]> Git Repo - qemu.git/blob - hw/vfio/ccw.c
Merge remote-tracking branch 'remotes/kraxel/tags/vga-20180604-pull-request' into...
[qemu.git] / hw / vfio / ccw.c
1 /*
2  * vfio based subchannel assignment support
3  *
4  * Copyright 2017 IBM Corp.
5  * Author(s): Dong Jia Shi <[email protected]>
6  *            Xiao Feng Ren <[email protected]>
7  *            Pierre Morel <[email protected]>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or (at
10  * your option) any later version. See the COPYING file in the top-level
11  * directory.
12  */
13
14 #include "qemu/osdep.h"
15 #include <linux/vfio.h>
16 #include <linux/vfio_ccw.h>
17 #include <sys/ioctl.h>
18
19 #include "qapi/error.h"
20 #include "hw/sysbus.h"
21 #include "hw/vfio/vfio.h"
22 #include "hw/vfio/vfio-common.h"
23 #include "hw/s390x/s390-ccw.h"
24 #include "hw/s390x/ccw-device.h"
25 #include "exec/address-spaces.h"
26 #include "qemu/error-report.h"
27
28 #define TYPE_VFIO_CCW "vfio-ccw"
29 typedef struct VFIOCCWDevice {
30     S390CCWDevice cdev;
31     VFIODevice vdev;
32     uint64_t io_region_size;
33     uint64_t io_region_offset;
34     struct ccw_io_region *io_region;
35     EventNotifier io_notifier;
36 } VFIOCCWDevice;
37
38 static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
39 {
40     vdev->needs_reset = false;
41 }
42
43 /*
44  * We don't need vfio_hot_reset_multi and vfio_eoi operations for
45  * vfio_ccw device now.
46  */
47 struct VFIODeviceOps vfio_ccw_ops = {
48     .vfio_compute_needs_reset = vfio_ccw_compute_needs_reset,
49 };
50
51 static IOInstEnding vfio_ccw_handle_request(SubchDev *sch)
52 {
53     S390CCWDevice *cdev = sch->driver_data;
54     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
55     struct ccw_io_region *region = vcdev->io_region;
56     int ret;
57
58     QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
59     QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW));
60     QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB));
61
62     memset(region, 0, sizeof(*region));
63
64     memcpy(region->orb_area, &sch->orb, sizeof(ORB));
65     memcpy(region->scsw_area, &sch->curr_status.scsw, sizeof(SCSW));
66
67 again:
68     ret = pwrite(vcdev->vdev.fd, region,
69                  vcdev->io_region_size, vcdev->io_region_offset);
70     if (ret != vcdev->io_region_size) {
71         if (errno == EAGAIN) {
72             goto again;
73         }
74         error_report("vfio-ccw: wirte I/O region failed with errno=%d", errno);
75         ret = -errno;
76     } else {
77         ret = region->ret_code;
78     }
79     switch (ret) {
80     case 0:
81         return IOINST_CC_EXPECTED;
82     case -EBUSY:
83         return IOINST_CC_BUSY;
84     case -ENODEV:
85     case -EACCES:
86         return IOINST_CC_NOT_OPERATIONAL;
87     case -EFAULT:
88     default:
89         sch_gen_unit_exception(sch);
90         css_inject_io_interrupt(sch);
91         return IOINST_CC_EXPECTED;
92     }
93 }
94
95 static void vfio_ccw_reset(DeviceState *dev)
96 {
97     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
98     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
99     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
100
101     ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET);
102 }
103
104 static void vfio_ccw_io_notifier_handler(void *opaque)
105 {
106     VFIOCCWDevice *vcdev = opaque;
107     struct ccw_io_region *region = vcdev->io_region;
108     S390CCWDevice *cdev = S390_CCW_DEVICE(vcdev);
109     CcwDevice *ccw_dev = CCW_DEVICE(cdev);
110     SubchDev *sch = ccw_dev->sch;
111     SCSW *s = &sch->curr_status.scsw;
112     PMCW *p = &sch->curr_status.pmcw;
113     IRB irb;
114     int size;
115
116     if (!event_notifier_test_and_clear(&vcdev->io_notifier)) {
117         return;
118     }
119
120     size = pread(vcdev->vdev.fd, region, vcdev->io_region_size,
121                  vcdev->io_region_offset);
122     if (size == -1) {
123         switch (errno) {
124         case ENODEV:
125             /* Generate a deferred cc 3 condition. */
126             s->flags |= SCSW_FLAGS_MASK_CC;
127             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
128             s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
129             goto read_err;
130         case EFAULT:
131             /* Memory problem, generate channel data check. */
132             s->ctrl &= ~SCSW_ACTL_START_PEND;
133             s->cstat = SCSW_CSTAT_DATA_CHECK;
134             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
135             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
136                        SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
137             goto read_err;
138         default:
139             /* Error, generate channel program check. */
140             s->ctrl &= ~SCSW_ACTL_START_PEND;
141             s->cstat = SCSW_CSTAT_PROG_CHECK;
142             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
143             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
144                        SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
145             goto read_err;
146         }
147     } else if (size != vcdev->io_region_size) {
148         /* Information transfer error, generate channel-control check. */
149         s->ctrl &= ~SCSW_ACTL_START_PEND;
150         s->cstat = SCSW_CSTAT_CHN_CTRL_CHK;
151         s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
152         s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
153                    SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
154         goto read_err;
155     }
156
157     memcpy(&irb, region->irb_area, sizeof(IRB));
158
159     /* Update control block via irb. */
160     copy_scsw_to_guest(s, &irb.scsw);
161
162     /* If a uint check is pending, copy sense data. */
163     if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
164         (p->chars & PMCW_CHARS_MASK_CSENSE)) {
165         memcpy(sch->sense_data, irb.ecw, sizeof(irb.ecw));
166     }
167
168 read_err:
169     css_inject_io_interrupt(sch);
170 }
171
172 static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
173 {
174     VFIODevice *vdev = &vcdev->vdev;
175     struct vfio_irq_info *irq_info;
176     struct vfio_irq_set *irq_set;
177     size_t argsz;
178     int32_t *pfd;
179
180     if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
181         error_setg(errp, "vfio: unexpected number of io irqs %u",
182                    vdev->num_irqs);
183         return;
184     }
185
186     argsz = sizeof(*irq_info);
187     irq_info = g_malloc0(argsz);
188     irq_info->index = VFIO_CCW_IO_IRQ_INDEX;
189     irq_info->argsz = argsz;
190     if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
191               irq_info) < 0 || irq_info->count < 1) {
192         error_setg_errno(errp, errno, "vfio: Error getting irq info");
193         goto out_free_info;
194     }
195
196     if (event_notifier_init(&vcdev->io_notifier, 0)) {
197         error_setg_errno(errp, errno,
198                          "vfio: Unable to init event notifier for IO");
199         goto out_free_info;
200     }
201
202     argsz = sizeof(*irq_set) + sizeof(*pfd);
203     irq_set = g_malloc0(argsz);
204     irq_set->argsz = argsz;
205     irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
206                      VFIO_IRQ_SET_ACTION_TRIGGER;
207     irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
208     irq_set->start = 0;
209     irq_set->count = 1;
210     pfd = (int32_t *) &irq_set->data;
211
212     *pfd = event_notifier_get_fd(&vcdev->io_notifier);
213     qemu_set_fd_handler(*pfd, vfio_ccw_io_notifier_handler, NULL, vcdev);
214     if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
215         error_setg(errp, "vfio: Failed to set up io notification");
216         qemu_set_fd_handler(*pfd, NULL, NULL, vcdev);
217         event_notifier_cleanup(&vcdev->io_notifier);
218     }
219
220     g_free(irq_set);
221
222 out_free_info:
223     g_free(irq_info);
224 }
225
226 static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev)
227 {
228     struct vfio_irq_set *irq_set;
229     size_t argsz;
230     int32_t *pfd;
231
232     argsz = sizeof(*irq_set) + sizeof(*pfd);
233     irq_set = g_malloc0(argsz);
234     irq_set->argsz = argsz;
235     irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
236                      VFIO_IRQ_SET_ACTION_TRIGGER;
237     irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
238     irq_set->start = 0;
239     irq_set->count = 1;
240     pfd = (int32_t *) &irq_set->data;
241     *pfd = -1;
242
243     if (ioctl(vcdev->vdev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
244         error_report("vfio: Failed to de-assign device io fd: %m");
245     }
246
247     qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier),
248                         NULL, NULL, vcdev);
249     event_notifier_cleanup(&vcdev->io_notifier);
250
251     g_free(irq_set);
252 }
253
254 static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
255 {
256     VFIODevice *vdev = &vcdev->vdev;
257     struct vfio_region_info *info;
258     int ret;
259
260     /* Sanity check device */
261     if (!(vdev->flags & VFIO_DEVICE_FLAGS_CCW)) {
262         error_setg(errp, "vfio: Um, this isn't a vfio-ccw device");
263         return;
264     }
265
266     if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) {
267         error_setg(errp, "vfio: Unexpected number of the I/O region %u",
268                    vdev->num_regions);
269         return;
270     }
271
272     ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
273     if (ret) {
274         error_setg_errno(errp, -ret, "vfio: Error getting config info");
275         return;
276     }
277
278     vcdev->io_region_size = info->size;
279     if (sizeof(*vcdev->io_region) != vcdev->io_region_size) {
280         error_setg(errp, "vfio: Unexpected size of the I/O region");
281         g_free(info);
282         return;
283     }
284
285     vcdev->io_region_offset = info->offset;
286     vcdev->io_region = g_malloc0(info->size);
287
288     g_free(info);
289 }
290
291 static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
292 {
293     g_free(vcdev->io_region);
294 }
295
296 static void vfio_ccw_put_device(VFIOCCWDevice *vcdev)
297 {
298     g_free(vcdev->vdev.name);
299     vfio_put_base_device(&vcdev->vdev);
300 }
301
302 static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev,
303                                 Error **errp)
304 {
305     char *name = g_strdup_printf("%x.%x.%04x", vcdev->cdev.hostid.cssid,
306                                  vcdev->cdev.hostid.ssid,
307                                  vcdev->cdev.hostid.devid);
308     VFIODevice *vbasedev;
309
310     QLIST_FOREACH(vbasedev, &group->device_list, next) {
311         if (strcmp(vbasedev->name, name) == 0) {
312             error_setg(errp, "vfio: subchannel %s has already been attached",
313                        name);
314             goto out_err;
315         }
316     }
317
318     if (vfio_get_device(group, vcdev->cdev.mdevid, &vcdev->vdev, errp)) {
319         goto out_err;
320     }
321
322     vcdev->vdev.ops = &vfio_ccw_ops;
323     vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW;
324     vcdev->vdev.name = name;
325     vcdev->vdev.dev = &vcdev->cdev.parent_obj.parent_obj;
326
327     return;
328
329 out_err:
330     g_free(name);
331 }
332
333 static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp)
334 {
335     char *tmp, group_path[PATH_MAX];
336     ssize_t len;
337     int groupid;
338
339     tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group",
340                           cdev->hostid.cssid, cdev->hostid.ssid,
341                           cdev->hostid.devid, cdev->mdevid);
342     len = readlink(tmp, group_path, sizeof(group_path));
343     g_free(tmp);
344
345     if (len <= 0 || len >= sizeof(group_path)) {
346         error_setg(errp, "vfio: no iommu_group found");
347         return NULL;
348     }
349
350     group_path[len] = 0;
351
352     if (sscanf(basename(group_path), "%d", &groupid) != 1) {
353         error_setg(errp, "vfio: failed to read %s", group_path);
354         return NULL;
355     }
356
357     return vfio_get_group(groupid, &address_space_memory, errp);
358 }
359
360 static void vfio_ccw_realize(DeviceState *dev, Error **errp)
361 {
362     VFIOGroup *group;
363     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
364     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
365     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
366     S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
367     Error *err = NULL;
368
369     /* Call the class init function for subchannel. */
370     if (cdc->realize) {
371         cdc->realize(cdev, vcdev->vdev.sysfsdev, &err);
372         if (err) {
373             goto out_err_propagate;
374         }
375     }
376
377     group = vfio_ccw_get_group(cdev, &err);
378     if (!group) {
379         goto out_group_err;
380     }
381
382     vfio_ccw_get_device(group, vcdev, &err);
383     if (err) {
384         goto out_device_err;
385     }
386
387     vfio_ccw_get_region(vcdev, &err);
388     if (err) {
389         goto out_region_err;
390     }
391
392     vfio_ccw_register_io_notifier(vcdev, &err);
393     if (err) {
394         goto out_notifier_err;
395     }
396
397     return;
398
399 out_notifier_err:
400     vfio_ccw_put_region(vcdev);
401 out_region_err:
402     vfio_ccw_put_device(vcdev);
403 out_device_err:
404     vfio_put_group(group);
405 out_group_err:
406     if (cdc->unrealize) {
407         cdc->unrealize(cdev, NULL);
408     }
409 out_err_propagate:
410     error_propagate(errp, err);
411 }
412
413 static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
414 {
415     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
416     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
417     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
418     S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
419     VFIOGroup *group = vcdev->vdev.group;
420
421     vfio_ccw_unregister_io_notifier(vcdev);
422     vfio_ccw_put_region(vcdev);
423     vfio_ccw_put_device(vcdev);
424     vfio_put_group(group);
425
426     if (cdc->unrealize) {
427         cdc->unrealize(cdev, errp);
428     }
429 }
430
431 static Property vfio_ccw_properties[] = {
432     DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
433     DEFINE_PROP_END_OF_LIST(),
434 };
435
436 static const VMStateDescription vfio_ccw_vmstate = {
437     .name = TYPE_VFIO_CCW,
438     .unmigratable = 1,
439 };
440
441 static void vfio_ccw_class_init(ObjectClass *klass, void *data)
442 {
443     DeviceClass *dc = DEVICE_CLASS(klass);
444     S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);
445
446     dc->props = vfio_ccw_properties;
447     dc->vmsd = &vfio_ccw_vmstate;
448     dc->desc = "VFIO-based subchannel assignment";
449     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
450     dc->realize = vfio_ccw_realize;
451     dc->unrealize = vfio_ccw_unrealize;
452     dc->reset = vfio_ccw_reset;
453
454     cdc->handle_request = vfio_ccw_handle_request;
455 }
456
457 static const TypeInfo vfio_ccw_info = {
458     .name = TYPE_VFIO_CCW,
459     .parent = TYPE_S390_CCW,
460     .instance_size = sizeof(VFIOCCWDevice),
461     .class_init = vfio_ccw_class_init,
462 };
463
464 static void register_vfio_ccw_type(void)
465 {
466     type_register_static(&vfio_ccw_info);
467 }
468
469 type_init(register_vfio_ccw_type)
This page took 0.049248 seconds and 4 git commands to generate.