0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/vfio.h>
0011
0012 #include "vfio_ccw_private.h"
0013
0014 static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
0015 char __user *buf, size_t count,
0016 loff_t *ppos)
0017 {
0018 unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
0019 loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
0020 struct ccw_cmd_region *region;
0021 int ret;
0022
0023 if (pos + count > sizeof(*region))
0024 return -EINVAL;
0025
0026 mutex_lock(&private->io_mutex);
0027 region = private->region[i].data;
0028 if (copy_to_user(buf, (void *)region + pos, count))
0029 ret = -EFAULT;
0030 else
0031 ret = count;
0032 mutex_unlock(&private->io_mutex);
0033 return ret;
0034 }
0035
0036 static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
0037 const char __user *buf, size_t count,
0038 loff_t *ppos)
0039 {
0040 unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
0041 loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
0042 struct ccw_cmd_region *region;
0043 int ret;
0044
0045 if (pos + count > sizeof(*region))
0046 return -EINVAL;
0047
0048 if (!mutex_trylock(&private->io_mutex))
0049 return -EAGAIN;
0050
0051 region = private->region[i].data;
0052 if (copy_from_user((void *)region + pos, buf, count)) {
0053 ret = -EFAULT;
0054 goto out_unlock;
0055 }
0056
0057 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_ASYNC_REQ);
0058
0059 ret = region->ret_code ? region->ret_code : count;
0060
0061 out_unlock:
0062 mutex_unlock(&private->io_mutex);
0063 return ret;
0064 }
0065
0066 static void vfio_ccw_async_region_release(struct vfio_ccw_private *private,
0067 struct vfio_ccw_region *region)
0068 {
0069
0070 }
0071
0072 static const struct vfio_ccw_regops vfio_ccw_async_region_ops = {
0073 .read = vfio_ccw_async_region_read,
0074 .write = vfio_ccw_async_region_write,
0075 .release = vfio_ccw_async_region_release,
0076 };
0077
0078 int vfio_ccw_register_async_dev_regions(struct vfio_ccw_private *private)
0079 {
0080 return vfio_ccw_register_dev_region(private,
0081 VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD,
0082 &vfio_ccw_async_region_ops,
0083 sizeof(struct ccw_cmd_region),
0084 VFIO_REGION_INFO_FLAG_READ |
0085 VFIO_REGION_INFO_FLAG_WRITE,
0086 private->cmd_region);
0087 }