Lines Matching +full:04 +full:- +full:s390x +full:- +full:all +full:- +full:linux +full:- +full:static
7 * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
8 * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
9 * Pierre Morel <pmorel@linux.vnet.ibm.com>
13 * your option) any later version. See the COPYING file in the top-level
19 #include <linux/vfio.h>
20 #include <linux/vfio_ccw.h>
24 #include "hw/vfio/vfio-common.h"
26 #include "hw/s390x/s390-ccw.h"
27 #include "hw/s390x/vfio-ccw.h"
28 #include "hw/qdev-properties.h"
29 #include "hw/s390x/ccw-device.h"
30 #include "exec/address-spaces.h"
31 #include "qemu/error-report.h"
32 #include "qemu/main-loop.h"
57 static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch, in warn_once_pfch()
60 warn_report_once_cond(&vcdev->warned_orb_pfch, in warn_once_pfch()
61 "vfio-ccw (devno %x.%x.%04x): %s", in warn_once_pfch()
62 sch->cssid, sch->ssid, sch->devno, msg); in warn_once_pfch()
65 static void vfio_ccw_compute_needs_reset(VFIODevice *vdev) in vfio_ccw_compute_needs_reset()
67 vdev->needs_reset = false; in vfio_ccw_compute_needs_reset()
78 static IOInstEnding vfio_ccw_handle_request(SubchDev *sch) in vfio_ccw_handle_request()
80 VFIOCCWDevice *vcdev = VFIO_CCW(sch->driver_data); in vfio_ccw_handle_request()
81 struct ccw_io_region *region = vcdev->io_region; in vfio_ccw_handle_request()
84 if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH) && vcdev->force_orb_pfch) { in vfio_ccw_handle_request()
85 sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH; in vfio_ccw_handle_request()
89 QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB)); in vfio_ccw_handle_request()
90 QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW)); in vfio_ccw_handle_request()
91 QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB)); in vfio_ccw_handle_request()
95 memcpy(region->orb_area, &sch->orb, sizeof(ORB)); in vfio_ccw_handle_request()
96 memcpy(region->scsw_area, &sch->curr_status.scsw, sizeof(SCSW)); in vfio_ccw_handle_request()
99 ret = pwrite(vcdev->vdev.fd, region, in vfio_ccw_handle_request()
100 vcdev->io_region_size, vcdev->io_region_offset); in vfio_ccw_handle_request()
101 if (ret != vcdev->io_region_size) { in vfio_ccw_handle_request()
105 error_report("vfio-ccw: write I/O region failed with errno=%d", errno); in vfio_ccw_handle_request()
106 ret = errno ? -errno : -EFAULT; in vfio_ccw_handle_request()
113 case -EBUSY: in vfio_ccw_handle_request()
115 case -ENODEV: in vfio_ccw_handle_request()
116 case -EACCES: in vfio_ccw_handle_request()
118 case -EFAULT: in vfio_ccw_handle_request()
126 static IOInstEnding vfio_ccw_handle_store(SubchDev *sch) in vfio_ccw_handle_store()
128 VFIOCCWDevice *vcdev = VFIO_CCW(sch->driver_data); in vfio_ccw_handle_store()
129 SCHIB *schib = &sch->curr_status; in vfio_ccw_handle_store()
130 struct ccw_schib_region *region = vcdev->schib_region; in vfio_ccw_handle_store()
140 ret = pread(vcdev->vdev.fd, region, vcdev->schib_region_size, in vfio_ccw_handle_store()
141 vcdev->schib_region_offset); in vfio_ccw_handle_store()
143 if (ret == -1) { in vfio_ccw_handle_store()
149 error_report("vfio-ccw: store region read failed with errno=%d", errno); in vfio_ccw_handle_store()
154 * Selectively copy path-related bits of the SCHIB, in vfio_ccw_handle_store()
157 s = (SCHIB *)region->schib_area; in vfio_ccw_handle_store()
158 schib->pmcw.pnom = s->pmcw.pnom; in vfio_ccw_handle_store()
159 schib->pmcw.lpum = s->pmcw.lpum; in vfio_ccw_handle_store()
160 schib->pmcw.pam = s->pmcw.pam; in vfio_ccw_handle_store()
161 schib->pmcw.pom = s->pmcw.pom; in vfio_ccw_handle_store()
163 if (s->scsw.flags & SCSW_FLAGS_MASK_PNO) { in vfio_ccw_handle_store()
164 schib->scsw.flags |= SCSW_FLAGS_MASK_PNO; in vfio_ccw_handle_store()
170 static int vfio_ccw_handle_clear(SubchDev *sch) in vfio_ccw_handle_clear()
172 VFIOCCWDevice *vcdev = VFIO_CCW(sch->driver_data); in vfio_ccw_handle_clear()
173 struct ccw_cmd_region *region = vcdev->async_cmd_region; in vfio_ccw_handle_clear()
176 if (!vcdev->async_cmd_region) { in vfio_ccw_handle_clear()
178 return -ENOSYS; in vfio_ccw_handle_clear()
182 region->command = VFIO_CCW_ASYNC_CMD_CSCH; in vfio_ccw_handle_clear()
185 ret = pwrite(vcdev->vdev.fd, region, in vfio_ccw_handle_clear()
186 vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset); in vfio_ccw_handle_clear()
187 if (ret != vcdev->async_cmd_region_size) { in vfio_ccw_handle_clear()
191 error_report("vfio-ccw: write cmd region failed with errno=%d", errno); in vfio_ccw_handle_clear()
192 ret = errno ? -errno : -EFAULT; in vfio_ccw_handle_clear()
198 case -ENODEV: in vfio_ccw_handle_clear()
199 case -EACCES: in vfio_ccw_handle_clear()
201 case -EFAULT: in vfio_ccw_handle_clear()
209 static int vfio_ccw_handle_halt(SubchDev *sch) in vfio_ccw_handle_halt()
211 VFIOCCWDevice *vcdev = VFIO_CCW(sch->driver_data); in vfio_ccw_handle_halt()
212 struct ccw_cmd_region *region = vcdev->async_cmd_region; in vfio_ccw_handle_halt()
215 if (!vcdev->async_cmd_region) { in vfio_ccw_handle_halt()
217 return -ENOSYS; in vfio_ccw_handle_halt()
221 region->command = VFIO_CCW_ASYNC_CMD_HSCH; in vfio_ccw_handle_halt()
224 ret = pwrite(vcdev->vdev.fd, region, in vfio_ccw_handle_halt()
225 vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset); in vfio_ccw_handle_halt()
226 if (ret != vcdev->async_cmd_region_size) { in vfio_ccw_handle_halt()
230 error_report("vfio-ccw: write cmd region failed with errno=%d", errno); in vfio_ccw_handle_halt()
231 ret = errno ? -errno : -EFAULT; in vfio_ccw_handle_halt()
237 case -EBUSY: in vfio_ccw_handle_halt()
238 case -ENODEV: in vfio_ccw_handle_halt()
239 case -EACCES: in vfio_ccw_handle_halt()
241 case -EFAULT: in vfio_ccw_handle_halt()
249 static void vfio_ccw_reset(DeviceState *dev) in vfio_ccw_reset()
253 ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); in vfio_ccw_reset()
256 static void vfio_ccw_crw_read(VFIOCCWDevice *vcdev) in vfio_ccw_crw_read()
258 struct ccw_crw_region *region = vcdev->crw_region; in vfio_ccw_crw_read()
265 size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size, in vfio_ccw_crw_read()
266 vcdev->crw_region_offset); in vfio_ccw_crw_read()
268 if (size == -1) { in vfio_ccw_crw_read()
269 error_report("vfio-ccw: Read crw region failed with errno=%d", in vfio_ccw_crw_read()
274 if (region->crw == 0) { in vfio_ccw_crw_read()
279 memcpy(&crw, ®ion->crw, sizeof(CRW)); in vfio_ccw_crw_read()
285 static void vfio_ccw_req_notifier_handler(void *opaque) in vfio_ccw_req_notifier_handler()
290 if (!event_notifier_test_and_clear(&vcdev->req_notifier)) { in vfio_ccw_req_notifier_handler()
296 warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); in vfio_ccw_req_notifier_handler()
300 static void vfio_ccw_crw_notifier_handler(void *opaque) in vfio_ccw_crw_notifier_handler()
304 while (event_notifier_test_and_clear(&vcdev->crw_notifier)) { in vfio_ccw_crw_notifier_handler()
309 static void vfio_ccw_io_notifier_handler(void *opaque) in vfio_ccw_io_notifier_handler()
312 struct ccw_io_region *region = vcdev->io_region; in vfio_ccw_io_notifier_handler()
314 SubchDev *sch = ccw_dev->sch; in vfio_ccw_io_notifier_handler()
315 SCHIB *schib = &sch->curr_status; in vfio_ccw_io_notifier_handler()
321 if (!event_notifier_test_and_clear(&vcdev->io_notifier)) { in vfio_ccw_io_notifier_handler()
325 size = pread(vcdev->vdev.fd, region, vcdev->io_region_size, in vfio_ccw_io_notifier_handler()
326 vcdev->io_region_offset); in vfio_ccw_io_notifier_handler()
327 if (size == -1) { in vfio_ccw_io_notifier_handler()
331 schib->scsw.flags |= SCSW_FLAGS_MASK_CC; in vfio_ccw_io_notifier_handler()
332 schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; in vfio_ccw_io_notifier_handler()
333 schib->scsw.ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); in vfio_ccw_io_notifier_handler()
337 schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; in vfio_ccw_io_notifier_handler()
338 schib->scsw.cstat = SCSW_CSTAT_DATA_CHECK; in vfio_ccw_io_notifier_handler()
339 schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; in vfio_ccw_io_notifier_handler()
340 schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | in vfio_ccw_io_notifier_handler()
345 schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; in vfio_ccw_io_notifier_handler()
346 schib->scsw.cstat = SCSW_CSTAT_PROG_CHECK; in vfio_ccw_io_notifier_handler()
347 schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; in vfio_ccw_io_notifier_handler()
348 schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | in vfio_ccw_io_notifier_handler()
352 } else if (size != vcdev->io_region_size) { in vfio_ccw_io_notifier_handler()
353 /* Information transfer error, generate channel-control check. */ in vfio_ccw_io_notifier_handler()
354 schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; in vfio_ccw_io_notifier_handler()
355 schib->scsw.cstat = SCSW_CSTAT_CHN_CTRL_CHK; in vfio_ccw_io_notifier_handler()
356 schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; in vfio_ccw_io_notifier_handler()
357 schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | in vfio_ccw_io_notifier_handler()
362 memcpy(&irb, region->irb_area, sizeof(IRB)); in vfio_ccw_io_notifier_handler()
365 s = schib->scsw; in vfio_ccw_io_notifier_handler()
367 schib->scsw = s; in vfio_ccw_io_notifier_handler()
370 sch->esw = esw; in vfio_ccw_io_notifier_handler()
373 if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && in vfio_ccw_io_notifier_handler()
374 (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { in vfio_ccw_io_notifier_handler()
375 memcpy(sch->sense_data, irb.ecw, sizeof(irb.ecw)); in vfio_ccw_io_notifier_handler()
382 static bool vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, in vfio_ccw_register_irq_notifier()
386 VFIODevice *vdev = &vcdev->vdev; in vfio_ccw_register_irq_notifier()
395 notifier = &vcdev->io_notifier; in vfio_ccw_register_irq_notifier()
399 notifier = &vcdev->crw_notifier; in vfio_ccw_register_irq_notifier()
403 notifier = &vcdev->req_notifier; in vfio_ccw_register_irq_notifier()
411 if (vdev->num_irqs < irq + 1) { in vfio_ccw_register_irq_notifier()
413 irq, vdev->num_irqs); in vfio_ccw_register_irq_notifier()
419 irq_info->index = irq; in vfio_ccw_register_irq_notifier()
420 irq_info->argsz = argsz; in vfio_ccw_register_irq_notifier()
421 if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, in vfio_ccw_register_irq_notifier()
422 irq_info) < 0 || irq_info->count < 1) { in vfio_ccw_register_irq_notifier()
446 static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, in vfio_ccw_unregister_irq_notifier()
454 notifier = &vcdev->io_notifier; in vfio_ccw_unregister_irq_notifier()
457 notifier = &vcdev->crw_notifier; in vfio_ccw_unregister_irq_notifier()
460 notifier = &vcdev->req_notifier; in vfio_ccw_unregister_irq_notifier()
467 if (!vfio_set_irq_signaling(&vcdev->vdev, irq, 0, in vfio_ccw_unregister_irq_notifier()
468 VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { in vfio_ccw_unregister_irq_notifier()
469 warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); in vfio_ccw_unregister_irq_notifier()
477 static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) in vfio_ccw_get_region()
479 VFIODevice *vdev = &vcdev->vdev; in vfio_ccw_get_region()
484 if (!(vdev->flags & VFIO_DEVICE_FLAGS_CCW)) { in vfio_ccw_get_region()
485 error_setg(errp, "vfio: Um, this isn't a vfio-ccw device"); in vfio_ccw_get_region()
493 if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) { in vfio_ccw_get_region()
495 vdev->num_regions, VFIO_CCW_CONFIG_REGION_INDEX + 1); in vfio_ccw_get_region()
501 error_setg_errno(errp, -ret, "vfio: Error getting config info"); in vfio_ccw_get_region()
505 vcdev->io_region_size = info->size; in vfio_ccw_get_region()
506 if (sizeof(*vcdev->io_region) != vcdev->io_region_size) { in vfio_ccw_get_region()
511 vcdev->io_region_offset = info->offset; in vfio_ccw_get_region()
512 vcdev->io_region = g_malloc0(info->size); in vfio_ccw_get_region()
519 vcdev->async_cmd_region_size = info->size; in vfio_ccw_get_region()
520 if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) { in vfio_ccw_get_region()
524 vcdev->async_cmd_region_offset = info->offset; in vfio_ccw_get_region()
525 vcdev->async_cmd_region = g_malloc0(info->size); in vfio_ccw_get_region()
532 vcdev->schib_region_size = info->size; in vfio_ccw_get_region()
533 if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) { in vfio_ccw_get_region()
537 vcdev->schib_region_offset = info->offset; in vfio_ccw_get_region()
538 vcdev->schib_region = g_malloc(info->size); in vfio_ccw_get_region()
546 vcdev->crw_region_size = info->size; in vfio_ccw_get_region()
547 if (sizeof(*vcdev->crw_region) != vcdev->crw_region_size) { in vfio_ccw_get_region()
551 vcdev->crw_region_offset = info->offset; in vfio_ccw_get_region()
552 vcdev->crw_region = g_malloc(info->size); in vfio_ccw_get_region()
559 g_free(vcdev->crw_region); in vfio_ccw_get_region()
560 g_free(vcdev->schib_region); in vfio_ccw_get_region()
561 g_free(vcdev->async_cmd_region); in vfio_ccw_get_region()
562 g_free(vcdev->io_region); in vfio_ccw_get_region()
567 static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) in vfio_ccw_put_region()
569 g_free(vcdev->crw_region); in vfio_ccw_put_region()
570 g_free(vcdev->schib_region); in vfio_ccw_put_region()
571 g_free(vcdev->async_cmd_region); in vfio_ccw_put_region()
572 g_free(vcdev->io_region); in vfio_ccw_put_region()
575 static void vfio_ccw_realize(DeviceState *dev, Error **errp) in vfio_ccw_realize()
580 VFIODevice *vbasedev = &vcdev->vdev; in vfio_ccw_realize()
584 if (cdc->realize) { in vfio_ccw_realize()
585 if (!cdc->realize(cdev, vcdev->vdev.sysfsdev, errp)) { in vfio_ccw_realize()
594 if (!vfio_attach_device(cdev->mdevid, vbasedev, in vfio_ccw_realize()
607 if (vcdev->crw_region) { in vfio_ccw_realize()
633 g_free(vbasedev->name); in vfio_ccw_realize()
635 if (cdc->unrealize) { in vfio_ccw_realize()
636 cdc->unrealize(cdev); in vfio_ccw_realize()
640 static void vfio_ccw_unrealize(DeviceState *dev) in vfio_ccw_unrealize()
650 vfio_detach_device(&vcdev->vdev); in vfio_ccw_unrealize()
651 g_free(vcdev->vdev.name); in vfio_ccw_unrealize()
653 if (cdc->unrealize) { in vfio_ccw_unrealize()
654 cdc->unrealize(cdev); in vfio_ccw_unrealize()
658 static Property vfio_ccw_properties[] = {
660 DEFINE_PROP_BOOL("force-orb-pfch", VFIOCCWDevice, force_orb_pfch, false),
669 static const VMStateDescription vfio_ccw_vmstate = {
670 .name = "vfio-ccw",
674 static void vfio_ccw_instance_init(Object *obj) in vfio_ccw_instance_init()
677 VFIODevice *vbasedev = &vcdev->vdev; in vfio_ccw_instance_init()
680 vbasedev->mdev = true; in vfio_ccw_instance_init()
683 * All vfio-ccw devices are believed to operate in a way compatible with in vfio_ccw_instance_init()
695 static void vfio_ccw_set_fd(Object *obj, const char *str, Error **errp) in vfio_ccw_set_fd()
697 vfio_device_set_fd(&VFIO_CCW(obj)->vdev, str, errp); in vfio_ccw_set_fd()
701 static void vfio_ccw_class_init(ObjectClass *klass, void *data) in vfio_ccw_class_init()
710 dc->vmsd = &vfio_ccw_vmstate; in vfio_ccw_class_init()
711 dc->desc = "VFIO-based subchannel assignment"; in vfio_ccw_class_init()
712 set_bit(DEVICE_CATEGORY_MISC, dc->categories); in vfio_ccw_class_init()
713 dc->realize = vfio_ccw_realize; in vfio_ccw_class_init()
714 dc->unrealize = vfio_ccw_unrealize; in vfio_ccw_class_init()
717 cdc->handle_request = vfio_ccw_handle_request; in vfio_ccw_class_init()
718 cdc->handle_halt = vfio_ccw_handle_halt; in vfio_ccw_class_init()
719 cdc->handle_clear = vfio_ccw_handle_clear; in vfio_ccw_class_init()
720 cdc->handle_store = vfio_ccw_handle_store; in vfio_ccw_class_init()
723 static const TypeInfo vfio_ccw_info = {
731 static void register_vfio_ccw_type(void) in register_vfio_ccw_type()