linux/drivers/s390/cio/vfio_ccw_async.c
<<
>>
Prefs
   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#include <linux/mdev.h>
  12
  13#include "vfio_ccw_private.h"
  14
  15static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
  16                                          char __user *buf, size_t count,
  17                                          loff_t *ppos)
  18{
  19        unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
  20        loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
  21        struct ccw_cmd_region *region;
  22        int ret;
  23
  24        if (pos + count > sizeof(*region))
  25                return -EINVAL;
  26
  27        mutex_lock(&private->io_mutex);
  28        region = private->region[i].data;
  29        if (copy_to_user(buf, (void *)region + pos, count))
  30                ret = -EFAULT;
  31        else
  32                ret = count;
  33        mutex_unlock(&private->io_mutex);
  34        return ret;
  35}
  36
  37static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
  38                                           const char __user *buf, size_t count,
  39                                           loff_t *ppos)
  40{
  41        unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
  42        loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
  43        struct ccw_cmd_region *region;
  44        int ret;
  45
  46        if (pos + count > sizeof(*region))
  47                return -EINVAL;
  48
  49        if (!mutex_trylock(&private->io_mutex))
  50                return -EAGAIN;
  51
  52        region = private->region[i].data;
  53        if (copy_from_user((void *)region + pos, buf, count)) {
  54                ret = -EFAULT;
  55                goto out_unlock;
  56        }
  57
  58        vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_ASYNC_REQ);
  59
  60        ret = region->ret_code ? region->ret_code : count;
  61
  62out_unlock:
  63        mutex_unlock(&private->io_mutex);
  64        return ret;
  65}
  66
  67static void vfio_ccw_async_region_release(struct vfio_ccw_private *private,
  68                                          struct vfio_ccw_region *region)
  69{
  70
  71}
  72
  73static const struct vfio_ccw_regops vfio_ccw_async_region_ops = {
  74        .read = vfio_ccw_async_region_read,
  75        .write = vfio_ccw_async_region_write,
  76        .release = vfio_ccw_async_region_release,
  77};
  78
  79int vfio_ccw_register_async_dev_regions(struct vfio_ccw_private *private)
  80{
  81        return vfio_ccw_register_dev_region(private,
  82                                            VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD,
  83                                            &vfio_ccw_async_region_ops,
  84                                            sizeof(struct ccw_cmd_region),
  85                                            VFIO_REGION_INFO_FLAG_READ |
  86                                            VFIO_REGION_INFO_FLAG_WRITE,
  87                                            private->cmd_region);
  88}
  89