1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Async I/O region for vfio_ccw 4 * 5 * Copyright Red Hat, Inc. 2019 6 * 7 * Author(s): Cornelia Huck <cohuck@redhat.com> 8 */ 9 10 #include <linux/vfio.h> 11 12 #include "vfio_ccw_private.h" 13 14 static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private, 15 char __user *buf, size_t count, 16 loff_t *ppos) 17 { 18 unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 19 loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 20 struct ccw_cmd_region *region; 21 int ret; 22 23 if (pos + count > sizeof(*region)) 24 return -EINVAL; 25 26 mutex_lock(&private->io_mutex); 27 region = private->region[i].data; 28 if (copy_to_user(buf, (void *)region + pos, count)) 29 ret = -EFAULT; 30 else 31 ret = count; 32 mutex_unlock(&private->io_mutex); 33 return ret; 34 } 35 36 static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private, 37 const char __user *buf, size_t count, 38 loff_t *ppos) 39 { 40 unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 41 loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 42 struct ccw_cmd_region *region; 43 int ret; 44 45 if (pos + count > sizeof(*region)) 46 return -EINVAL; 47 48 if (!mutex_trylock(&private->io_mutex)) 49 return -EAGAIN; 50 51 region = private->region[i].data; 52 if (copy_from_user((void *)region + pos, buf, count)) { 53 ret = -EFAULT; 54 goto out_unlock; 55 } 56 57 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_ASYNC_REQ); 58 59 ret = region->ret_code ? region->ret_code : count; 60 61 out_unlock: 62 mutex_unlock(&private->io_mutex); 63 return ret; 64 } 65 66 static void vfio_ccw_async_region_release(struct vfio_ccw_private *private, 67 struct vfio_ccw_region *region) 68 { 69 70 } 71 72 static const struct vfio_ccw_regops vfio_ccw_async_region_ops = { 73 .read = vfio_ccw_async_region_read, 74 .write = vfio_ccw_async_region_write, 75 .release = vfio_ccw_async_region_release, 76 }; 77 78 int vfio_ccw_register_async_dev_regions(struct vfio_ccw_private *private) 79 { 80 return vfio_ccw_register_dev_region(private, 81 VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, 82 &vfio_ccw_async_region_ops, 83 sizeof(struct ccw_cmd_region), 84 VFIO_REGION_INFO_FLAG_READ | 85 VFIO_REGION_INFO_FLAG_WRITE, 86 private->cmd_region); 87 } 88