linux/drivers/s390/cio/vfio_ccw_chp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Channel path related status regions for vfio_ccw
   4 *
   5 * Copyright IBM Corp. 2020
   6 *
   7 * Author(s): Farhan Ali <alifm@linux.ibm.com>
   8 *            Eric Farman <farman@linux.ibm.com>
   9 */
  10
  11#include <linux/slab.h>
  12#include <linux/vfio.h>
  13#include "vfio_ccw_private.h"
  14
  15static ssize_t vfio_ccw_schib_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_schib_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
  30        if (cio_update_schib(private->sch)) {
  31                ret = -ENODEV;
  32                goto out;
  33        }
  34
  35        memcpy(region, &private->sch->schib, sizeof(*region));
  36
  37        if (copy_to_user(buf, (void *)region + pos, count)) {
  38                ret = -EFAULT;
  39                goto out;
  40        }
  41
  42        ret = count;
  43
  44out:
  45        mutex_unlock(&private->io_mutex);
  46        return ret;
  47}
  48
  49static ssize_t vfio_ccw_schib_region_write(struct vfio_ccw_private *private,
  50                                           const char __user *buf, size_t count,
  51                                           loff_t *ppos)
  52{
  53        return -EINVAL;
  54}
  55
  56
  57static void vfio_ccw_schib_region_release(struct vfio_ccw_private *private,
  58                                          struct vfio_ccw_region *region)
  59{
  60
  61}
  62
  63static const struct vfio_ccw_regops vfio_ccw_schib_region_ops = {
  64        .read = vfio_ccw_schib_region_read,
  65        .write = vfio_ccw_schib_region_write,
  66        .release = vfio_ccw_schib_region_release,
  67};
  68
  69int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private)
  70{
  71        return vfio_ccw_register_dev_region(private,
  72                                            VFIO_REGION_SUBTYPE_CCW_SCHIB,
  73                                            &vfio_ccw_schib_region_ops,
  74                                            sizeof(struct ccw_schib_region),
  75                                            VFIO_REGION_INFO_FLAG_READ,
  76                                            private->schib_region);
  77}
  78
  79static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
  80                                        char __user *buf, size_t count,
  81                                        loff_t *ppos)
  82{
  83        unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
  84        loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
  85        struct ccw_crw_region *region;
  86        struct vfio_ccw_crw *crw;
  87        int ret;
  88
  89        if (pos + count > sizeof(*region))
  90                return -EINVAL;
  91
  92        crw = list_first_entry_or_null(&private->crw,
  93                                       struct vfio_ccw_crw, next);
  94
  95        if (crw)
  96                list_del(&crw->next);
  97
  98        mutex_lock(&private->io_mutex);
  99        region = private->region[i].data;
 100
 101        if (crw)
 102                memcpy(&region->crw, &crw->crw, sizeof(region->crw));
 103
 104        if (copy_to_user(buf, (void *)region + pos, count))
 105                ret = -EFAULT;
 106        else
 107                ret = count;
 108
 109        region->crw = 0;
 110
 111        mutex_unlock(&private->io_mutex);
 112
 113        kfree(crw);
 114
 115        /* Notify the guest if more CRWs are on our queue */
 116        if (!list_empty(&private->crw) && private->crw_trigger)
 117                eventfd_signal(private->crw_trigger, 1);
 118
 119        return ret;
 120}
 121
 122static ssize_t vfio_ccw_crw_region_write(struct vfio_ccw_private *private,
 123                                         const char __user *buf, size_t count,
 124                                         loff_t *ppos)
 125{
 126        return -EINVAL;
 127}
 128
 129static void vfio_ccw_crw_region_release(struct vfio_ccw_private *private,
 130                                        struct vfio_ccw_region *region)
 131{
 132
 133}
 134
 135static const struct vfio_ccw_regops vfio_ccw_crw_region_ops = {
 136        .read = vfio_ccw_crw_region_read,
 137        .write = vfio_ccw_crw_region_write,
 138        .release = vfio_ccw_crw_region_release,
 139};
 140
 141int vfio_ccw_register_crw_dev_regions(struct vfio_ccw_private *private)
 142{
 143        return vfio_ccw_register_dev_region(private,
 144                                            VFIO_REGION_SUBTYPE_CCW_CRW,
 145                                            &vfio_ccw_crw_region_ops,
 146                                            sizeof(struct ccw_crw_region),
 147                                            VFIO_REGION_INFO_FLAG_READ,
 148                                            private->crw_region);
 149}
 150