2 * vfio based subchannel assignment support
4 * Copyright 2017 IBM Corp.
5 * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
6 * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
7 * Pierre Morel <pmorel@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or(at
10 * your option) any version. See the COPYING file in the top-level
14 #include <linux/vfio.h>
15 #include <linux/vfio_ccw.h>
16 #include <sys/ioctl.h>
18 #include "qemu/osdep.h"
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 "qemu/error-report.h"
27 #define TYPE_VFIO_CCW "vfio-ccw"
28 typedef struct VFIOCCWDevice
{
31 uint64_t io_region_size
;
32 uint64_t io_region_offset
;
33 struct ccw_io_region
*io_region
;
34 EventNotifier io_notifier
;
37 static void vfio_ccw_compute_needs_reset(VFIODevice
*vdev
)
39 vdev
->needs_reset
= false;
43 * We don't need vfio_hot_reset_multi and vfio_eoi operations for
44 * vfio_ccw device now.
46 struct VFIODeviceOps vfio_ccw_ops
= {
47 .vfio_compute_needs_reset
= vfio_ccw_compute_needs_reset
,
50 static int vfio_ccw_handle_request(ORB
*orb
, SCSW
*scsw
, void *data
)
52 S390CCWDevice
*cdev
= data
;
53 VFIOCCWDevice
*vcdev
= DO_UPCAST(VFIOCCWDevice
, cdev
, cdev
);
54 struct ccw_io_region
*region
= vcdev
->io_region
;
57 QEMU_BUILD_BUG_ON(sizeof(region
->orb_area
) != sizeof(ORB
));
58 QEMU_BUILD_BUG_ON(sizeof(region
->scsw_area
) != sizeof(SCSW
));
59 QEMU_BUILD_BUG_ON(sizeof(region
->irb_area
) != sizeof(IRB
));
61 memset(region
, 0, sizeof(*region
));
63 memcpy(region
->orb_area
, orb
, sizeof(ORB
));
64 memcpy(region
->scsw_area
, scsw
, sizeof(SCSW
));
67 ret
= pwrite(vcdev
->vdev
.fd
, region
,
68 vcdev
->io_region_size
, vcdev
->io_region_offset
);
69 if (ret
!= vcdev
->io_region_size
) {
70 if (errno
== EAGAIN
) {
73 error_report("vfio-ccw: wirte I/O region failed with errno=%d", errno
);
77 return region
->ret_code
;
80 static void vfio_ccw_reset(DeviceState
*dev
)
82 CcwDevice
*ccw_dev
= DO_UPCAST(CcwDevice
, parent_obj
, dev
);
83 S390CCWDevice
*cdev
= DO_UPCAST(S390CCWDevice
, parent_obj
, ccw_dev
);
84 VFIOCCWDevice
*vcdev
= DO_UPCAST(VFIOCCWDevice
, cdev
, cdev
);
86 ioctl(vcdev
->vdev
.fd
, VFIO_DEVICE_RESET
);
89 static void vfio_ccw_io_notifier_handler(void *opaque
)
91 VFIOCCWDevice
*vcdev
= opaque
;
92 struct ccw_io_region
*region
= vcdev
->io_region
;
93 S390CCWDevice
*cdev
= S390_CCW_DEVICE(vcdev
);
94 CcwDevice
*ccw_dev
= CCW_DEVICE(cdev
);
95 SubchDev
*sch
= ccw_dev
->sch
;
96 SCSW
*s
= &sch
->curr_status
.scsw
;
97 PMCW
*p
= &sch
->curr_status
.pmcw
;
101 if (!event_notifier_test_and_clear(&vcdev
->io_notifier
)) {
105 size
= pread(vcdev
->vdev
.fd
, region
, vcdev
->io_region_size
,
106 vcdev
->io_region_offset
);
110 /* Generate a deferred cc 3 condition. */
111 s
->flags
|= SCSW_FLAGS_MASK_CC
;
112 s
->ctrl
&= ~SCSW_CTRL_MASK_STCTL
;
113 s
->ctrl
|= (SCSW_STCTL_ALERT
| SCSW_STCTL_STATUS_PEND
);
116 /* Memory problem, generate channel data check. */
117 s
->ctrl
&= ~SCSW_ACTL_START_PEND
;
118 s
->cstat
= SCSW_CSTAT_DATA_CHECK
;
119 s
->ctrl
&= ~SCSW_CTRL_MASK_STCTL
;
120 s
->ctrl
|= SCSW_STCTL_PRIMARY
| SCSW_STCTL_SECONDARY
|
121 SCSW_STCTL_ALERT
| SCSW_STCTL_STATUS_PEND
;
124 /* Error, generate channel program check. */
125 s
->ctrl
&= ~SCSW_ACTL_START_PEND
;
126 s
->cstat
= SCSW_CSTAT_PROG_CHECK
;
127 s
->ctrl
&= ~SCSW_CTRL_MASK_STCTL
;
128 s
->ctrl
|= SCSW_STCTL_PRIMARY
| SCSW_STCTL_SECONDARY
|
129 SCSW_STCTL_ALERT
| SCSW_STCTL_STATUS_PEND
;
132 } else if (size
!= vcdev
->io_region_size
) {
133 /* Information transfer error, generate channel-control check. */
134 s
->ctrl
&= ~SCSW_ACTL_START_PEND
;
135 s
->cstat
= SCSW_CSTAT_CHN_CTRL_CHK
;
136 s
->ctrl
&= ~SCSW_CTRL_MASK_STCTL
;
137 s
->ctrl
|= SCSW_STCTL_PRIMARY
| SCSW_STCTL_SECONDARY
|
138 SCSW_STCTL_ALERT
| SCSW_STCTL_STATUS_PEND
;
142 memcpy(&irb
, region
->irb_area
, sizeof(IRB
));
144 /* Update control block via irb. */
145 copy_scsw_to_guest(s
, &irb
.scsw
);
147 /* If a uint check is pending, copy sense data. */
148 if ((s
->dstat
& SCSW_DSTAT_UNIT_CHECK
) &&
149 (p
->chars
& PMCW_CHARS_MASK_CSENSE
)) {
150 memcpy(sch
->sense_data
, irb
.ecw
, sizeof(irb
.ecw
));
154 css_inject_io_interrupt(sch
);
157 static void vfio_ccw_register_io_notifier(VFIOCCWDevice
*vcdev
, Error
**errp
)
159 VFIODevice
*vdev
= &vcdev
->vdev
;
160 struct vfio_irq_info
*irq_info
;
161 struct vfio_irq_set
*irq_set
;
165 if (vdev
->num_irqs
< VFIO_CCW_IO_IRQ_INDEX
+ 1) {
166 error_setg(errp
, "vfio: unexpected number of io irqs %u",
171 argsz
= sizeof(*irq_set
);
172 irq_info
= g_malloc0(argsz
);
173 irq_info
->index
= VFIO_CCW_IO_IRQ_INDEX
;
174 irq_info
->argsz
= argsz
;
175 if (ioctl(vdev
->fd
, VFIO_DEVICE_GET_IRQ_INFO
,
176 irq_info
) < 0 || irq_info
->count
< 1) {
177 error_setg_errno(errp
, errno
, "vfio: Error getting irq info");
181 if (event_notifier_init(&vcdev
->io_notifier
, 0)) {
182 error_setg_errno(errp
, errno
,
183 "vfio: Unable to init event notifier for IO");
187 argsz
= sizeof(*irq_set
) + sizeof(*pfd
);
188 irq_set
= g_malloc0(argsz
);
189 irq_set
->argsz
= argsz
;
190 irq_set
->flags
= VFIO_IRQ_SET_DATA_EVENTFD
|
191 VFIO_IRQ_SET_ACTION_TRIGGER
;
192 irq_set
->index
= VFIO_CCW_IO_IRQ_INDEX
;
195 pfd
= (int32_t *) &irq_set
->data
;
197 *pfd
= event_notifier_get_fd(&vcdev
->io_notifier
);
198 qemu_set_fd_handler(*pfd
, vfio_ccw_io_notifier_handler
, NULL
, vcdev
);
199 if (ioctl(vdev
->fd
, VFIO_DEVICE_SET_IRQS
, irq_set
)) {
200 error_setg(errp
, "vfio: Failed to set up io notification");
201 qemu_set_fd_handler(*pfd
, NULL
, NULL
, vcdev
);
202 event_notifier_cleanup(&vcdev
->io_notifier
);
211 static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice
*vcdev
)
213 struct vfio_irq_set
*irq_set
;
217 argsz
= sizeof(*irq_set
) + sizeof(*pfd
);
218 irq_set
= g_malloc0(argsz
);
219 irq_set
->argsz
= argsz
;
220 irq_set
->flags
= VFIO_IRQ_SET_DATA_EVENTFD
|
221 VFIO_IRQ_SET_ACTION_TRIGGER
;
222 irq_set
->index
= VFIO_CCW_IO_IRQ_INDEX
;
225 pfd
= (int32_t *) &irq_set
->data
;
228 if (ioctl(vcdev
->vdev
.fd
, VFIO_DEVICE_SET_IRQS
, irq_set
)) {
229 error_report("vfio: Failed to de-assign device io fd: %m");
232 qemu_set_fd_handler(event_notifier_get_fd(&vcdev
->io_notifier
),
234 event_notifier_cleanup(&vcdev
->io_notifier
);
239 static void vfio_ccw_get_region(VFIOCCWDevice
*vcdev
, Error
**errp
)
241 VFIODevice
*vdev
= &vcdev
->vdev
;
242 struct vfio_region_info
*info
;
245 /* Sanity check device */
246 if (!(vdev
->flags
& VFIO_DEVICE_FLAGS_CCW
)) {
247 error_setg(errp
, "vfio: Um, this isn't a vfio-ccw device");
251 if (vdev
->num_regions
< VFIO_CCW_CONFIG_REGION_INDEX
+ 1) {
252 error_setg(errp
, "vfio: Unexpected number of the I/O region %u",
257 ret
= vfio_get_region_info(vdev
, VFIO_CCW_CONFIG_REGION_INDEX
, &info
);
259 error_setg_errno(errp
, -ret
, "vfio: Error getting config info");
263 vcdev
->io_region_size
= info
->size
;
264 if (sizeof(*vcdev
->io_region
) != vcdev
->io_region_size
) {
265 error_setg(errp
, "vfio: Unexpected size of the I/O region");
270 vcdev
->io_region_offset
= info
->offset
;
271 vcdev
->io_region
= g_malloc0(info
->size
);
276 static void vfio_ccw_put_region(VFIOCCWDevice
*vcdev
)
278 g_free(vcdev
->io_region
);
281 static void vfio_put_device(VFIOCCWDevice
*vcdev
)
283 g_free(vcdev
->vdev
.name
);
284 vfio_put_base_device(&vcdev
->vdev
);
287 static VFIOGroup
*vfio_ccw_get_group(S390CCWDevice
*cdev
, Error
**errp
)
289 char *tmp
, group_path
[PATH_MAX
];
293 tmp
= g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group",
294 cdev
->hostid
.cssid
, cdev
->hostid
.ssid
,
295 cdev
->hostid
.devid
, cdev
->mdevid
);
296 len
= readlink(tmp
, group_path
, sizeof(group_path
));
299 if (len
<= 0 || len
>= sizeof(group_path
)) {
300 error_setg(errp
, "vfio: no iommu_group found");
306 if (sscanf(basename(group_path
), "%d", &groupid
) != 1) {
307 error_setg(errp
, "vfio: failed to read %s", group_path
);
311 return vfio_get_group(groupid
, &address_space_memory
, errp
);
314 static void vfio_ccw_realize(DeviceState
*dev
, Error
**errp
)
316 VFIODevice
*vbasedev
;
318 CcwDevice
*ccw_dev
= DO_UPCAST(CcwDevice
, parent_obj
, dev
);
319 S390CCWDevice
*cdev
= DO_UPCAST(S390CCWDevice
, parent_obj
, ccw_dev
);
320 VFIOCCWDevice
*vcdev
= DO_UPCAST(VFIOCCWDevice
, cdev
, cdev
);
321 S390CCWDeviceClass
*cdc
= S390_CCW_DEVICE_GET_CLASS(cdev
);
324 /* Call the class init function for subchannel. */
326 cdc
->realize(cdev
, vcdev
->vdev
.sysfsdev
, &err
);
328 goto out_err_propagate
;
332 group
= vfio_ccw_get_group(cdev
, &err
);
337 vcdev
->vdev
.ops
= &vfio_ccw_ops
;
338 vcdev
->vdev
.type
= VFIO_DEVICE_TYPE_CCW
;
339 vcdev
->vdev
.name
= g_strdup_printf("%x.%x.%04x", cdev
->hostid
.cssid
,
340 cdev
->hostid
.ssid
, cdev
->hostid
.devid
);
341 QLIST_FOREACH(vbasedev
, &group
->device_list
, next
) {
342 if (strcmp(vbasedev
->name
, vcdev
->vdev
.name
) == 0) {
343 error_setg(&err
, "vfio: subchannel %s has already been attached",
349 if (vfio_get_device(group
, cdev
->mdevid
, &vcdev
->vdev
, &err
)) {
353 vfio_ccw_get_region(vcdev
, &err
);
358 vfio_ccw_register_io_notifier(vcdev
, &err
);
360 goto out_notifier_err
;
366 vfio_ccw_put_region(vcdev
);
368 vfio_put_device(vcdev
);
370 vfio_put_group(group
);
372 if (cdc
->unrealize
) {
373 cdc
->unrealize(cdev
, NULL
);
376 error_propagate(errp
, err
);
379 static void vfio_ccw_unrealize(DeviceState
*dev
, Error
**errp
)
381 CcwDevice
*ccw_dev
= DO_UPCAST(CcwDevice
, parent_obj
, dev
);
382 S390CCWDevice
*cdev
= DO_UPCAST(S390CCWDevice
, parent_obj
, ccw_dev
);
383 VFIOCCWDevice
*vcdev
= DO_UPCAST(VFIOCCWDevice
, cdev
, cdev
);
384 S390CCWDeviceClass
*cdc
= S390_CCW_DEVICE_GET_CLASS(cdev
);
385 VFIOGroup
*group
= vcdev
->vdev
.group
;
387 vfio_ccw_unregister_io_notifier(vcdev
);
388 vfio_ccw_put_region(vcdev
);
389 vfio_put_device(vcdev
);
390 vfio_put_group(group
);
392 if (cdc
->unrealize
) {
393 cdc
->unrealize(cdev
, errp
);
397 static Property vfio_ccw_properties
[] = {
398 DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice
, vdev
.sysfsdev
),
399 DEFINE_PROP_END_OF_LIST(),
402 static const VMStateDescription vfio_ccw_vmstate
= {
403 .name
= TYPE_VFIO_CCW
,
407 static void vfio_ccw_class_init(ObjectClass
*klass
, void *data
)
409 DeviceClass
*dc
= DEVICE_CLASS(klass
);
410 S390CCWDeviceClass
*cdc
= S390_CCW_DEVICE_CLASS(klass
);
412 dc
->props
= vfio_ccw_properties
;
413 dc
->vmsd
= &vfio_ccw_vmstate
;
414 dc
->desc
= "VFIO-based subchannel assignment";
415 dc
->realize
= vfio_ccw_realize
;
416 dc
->unrealize
= vfio_ccw_unrealize
;
417 dc
->reset
= vfio_ccw_reset
;
419 cdc
->handle_request
= vfio_ccw_handle_request
;
422 static const TypeInfo vfio_ccw_info
= {
423 .name
= TYPE_VFIO_CCW
,
424 .parent
= TYPE_S390_CCW
,
425 .instance_size
= sizeof(VFIOCCWDevice
),
426 .class_init
= vfio_ccw_class_init
,
429 static void register_vfio_ccw_type(void)
431 type_register_static(&vfio_ccw_info
);
434 type_init(register_vfio_ccw_type
)