Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Async I/O region for vfio_ccw
0004  *
0005  * Copyright Red Hat, Inc. 2019
0006  *
0007  * Author(s): Cornelia Huck <cohuck@redhat.com>
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 }