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