124c98674SFarhan Ali // SPDX-License-Identifier: GPL-2.0 224c98674SFarhan Ali /* 324c98674SFarhan Ali * Channel path related status regions for vfio_ccw 424c98674SFarhan Ali * 524c98674SFarhan Ali * Copyright IBM Corp. 2020 624c98674SFarhan Ali * 724c98674SFarhan Ali * Author(s): Farhan Ali <alifm@linux.ibm.com> 824c98674SFarhan Ali * Eric Farman <farman@linux.ibm.com> 924c98674SFarhan Ali */ 1024c98674SFarhan Ali 11d8ca55adSSean Christopherson #include <linux/slab.h> 1224c98674SFarhan Ali #include <linux/vfio.h> 1324c98674SFarhan Ali #include "vfio_ccw_private.h" 1424c98674SFarhan Ali 1524c98674SFarhan Ali static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private, 1624c98674SFarhan Ali char __user *buf, size_t count, 1724c98674SFarhan Ali loff_t *ppos) 1824c98674SFarhan Ali { 1924c98674SFarhan Ali unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 2024c98674SFarhan Ali loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 2124c98674SFarhan Ali struct ccw_schib_region *region; 2224c98674SFarhan Ali int ret; 2324c98674SFarhan Ali 2424c98674SFarhan Ali if (pos + count > sizeof(*region)) 2524c98674SFarhan Ali return -EINVAL; 2624c98674SFarhan Ali 2724c98674SFarhan Ali mutex_lock(&private->io_mutex); 2824c98674SFarhan Ali region = private->region[i].data; 2924c98674SFarhan Ali 3024c98674SFarhan Ali if (cio_update_schib(private->sch)) { 3124c98674SFarhan Ali ret = -ENODEV; 3224c98674SFarhan Ali goto out; 3324c98674SFarhan Ali } 3424c98674SFarhan Ali 3524c98674SFarhan Ali memcpy(region, &private->sch->schib, sizeof(*region)); 3624c98674SFarhan Ali 3724c98674SFarhan Ali if (copy_to_user(buf, (void *)region + pos, count)) { 3824c98674SFarhan Ali ret = -EFAULT; 3924c98674SFarhan Ali goto out; 4024c98674SFarhan Ali } 4124c98674SFarhan Ali 4224c98674SFarhan Ali ret = count; 4324c98674SFarhan Ali 4424c98674SFarhan Ali out: 4524c98674SFarhan Ali mutex_unlock(&private->io_mutex); 4624c98674SFarhan Ali return ret; 4724c98674SFarhan Ali } 4824c98674SFarhan Ali 4924c98674SFarhan Ali static ssize_t vfio_ccw_schib_region_write(struct vfio_ccw_private *private, 5024c98674SFarhan Ali const char __user *buf, size_t count, 5124c98674SFarhan Ali loff_t *ppos) 5224c98674SFarhan Ali { 5324c98674SFarhan Ali return -EINVAL; 5424c98674SFarhan Ali } 5524c98674SFarhan Ali 5624c98674SFarhan Ali 5724c98674SFarhan Ali static void vfio_ccw_schib_region_release(struct vfio_ccw_private *private, 5824c98674SFarhan Ali struct vfio_ccw_region *region) 5924c98674SFarhan Ali { 6024c98674SFarhan Ali 6124c98674SFarhan Ali } 6224c98674SFarhan Ali 63bfa50e14SVasily Gorbik static const struct vfio_ccw_regops vfio_ccw_schib_region_ops = { 6424c98674SFarhan Ali .read = vfio_ccw_schib_region_read, 6524c98674SFarhan Ali .write = vfio_ccw_schib_region_write, 6624c98674SFarhan Ali .release = vfio_ccw_schib_region_release, 6724c98674SFarhan Ali }; 6824c98674SFarhan Ali 6924c98674SFarhan Ali int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private) 7024c98674SFarhan Ali { 7124c98674SFarhan Ali return vfio_ccw_register_dev_region(private, 7224c98674SFarhan Ali VFIO_REGION_SUBTYPE_CCW_SCHIB, 7324c98674SFarhan Ali &vfio_ccw_schib_region_ops, 7424c98674SFarhan Ali sizeof(struct ccw_schib_region), 7524c98674SFarhan Ali VFIO_REGION_INFO_FLAG_READ, 7624c98674SFarhan Ali private->schib_region); 7724c98674SFarhan Ali } 78d8cac29bSFarhan Ali 79d8cac29bSFarhan Ali static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private, 80d8cac29bSFarhan Ali char __user *buf, size_t count, 81d8cac29bSFarhan Ali loff_t *ppos) 82d8cac29bSFarhan Ali { 83d8cac29bSFarhan Ali unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 84d8cac29bSFarhan Ali loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 85d8cac29bSFarhan Ali struct ccw_crw_region *region; 863f02cb2fSFarhan Ali struct vfio_ccw_crw *crw; 87d8cac29bSFarhan Ali int ret; 88d8cac29bSFarhan Ali 89d8cac29bSFarhan Ali if (pos + count > sizeof(*region)) 90d8cac29bSFarhan Ali return -EINVAL; 91d8cac29bSFarhan Ali 923f02cb2fSFarhan Ali crw = list_first_entry_or_null(&private->crw, 933f02cb2fSFarhan Ali struct vfio_ccw_crw, next); 943f02cb2fSFarhan Ali 953f02cb2fSFarhan Ali if (crw) 963f02cb2fSFarhan Ali list_del(&crw->next); 973f02cb2fSFarhan Ali 98d8cac29bSFarhan Ali mutex_lock(&private->io_mutex); 99d8cac29bSFarhan Ali region = private->region[i].data; 100d8cac29bSFarhan Ali 1013f02cb2fSFarhan Ali if (crw) 1023f02cb2fSFarhan Ali memcpy(®ion->crw, &crw->crw, sizeof(region->crw)); 1033f02cb2fSFarhan Ali 104d8cac29bSFarhan Ali if (copy_to_user(buf, (void *)region + pos, count)) 105d8cac29bSFarhan Ali ret = -EFAULT; 106d8cac29bSFarhan Ali else 107d8cac29bSFarhan Ali ret = count; 108d8cac29bSFarhan Ali 109d8cac29bSFarhan Ali region->crw = 0; 110d8cac29bSFarhan Ali 111d8cac29bSFarhan Ali mutex_unlock(&private->io_mutex); 1123f02cb2fSFarhan Ali 1133f02cb2fSFarhan Ali kfree(crw); 1143f02cb2fSFarhan Ali 1153f02cb2fSFarhan Ali /* Notify the guest if more CRWs are on our queue */ 1163f02cb2fSFarhan Ali if (!list_empty(&private->crw) && private->crw_trigger) 1173f02cb2fSFarhan Ali eventfd_signal(private->crw_trigger, 1); 1183f02cb2fSFarhan Ali 119d8cac29bSFarhan Ali return ret; 120d8cac29bSFarhan Ali } 121d8cac29bSFarhan Ali 122d8cac29bSFarhan Ali static ssize_t vfio_ccw_crw_region_write(struct vfio_ccw_private *private, 123d8cac29bSFarhan Ali const char __user *buf, size_t count, 124d8cac29bSFarhan Ali loff_t *ppos) 125d8cac29bSFarhan Ali { 126d8cac29bSFarhan Ali return -EINVAL; 127d8cac29bSFarhan Ali } 128d8cac29bSFarhan Ali 129d8cac29bSFarhan Ali static void vfio_ccw_crw_region_release(struct vfio_ccw_private *private, 130d8cac29bSFarhan Ali struct vfio_ccw_region *region) 131d8cac29bSFarhan Ali { 132d8cac29bSFarhan Ali 133d8cac29bSFarhan Ali } 134d8cac29bSFarhan Ali 135bfa50e14SVasily Gorbik static const struct vfio_ccw_regops vfio_ccw_crw_region_ops = { 136d8cac29bSFarhan Ali .read = vfio_ccw_crw_region_read, 137d8cac29bSFarhan Ali .write = vfio_ccw_crw_region_write, 138d8cac29bSFarhan Ali .release = vfio_ccw_crw_region_release, 139d8cac29bSFarhan Ali }; 140d8cac29bSFarhan Ali 141d8cac29bSFarhan Ali int vfio_ccw_register_crw_dev_regions(struct vfio_ccw_private *private) 142d8cac29bSFarhan Ali { 143d8cac29bSFarhan Ali return vfio_ccw_register_dev_region(private, 144d8cac29bSFarhan Ali VFIO_REGION_SUBTYPE_CCW_CRW, 145d8cac29bSFarhan Ali &vfio_ccw_crw_region_ops, 146d8cac29bSFarhan Ali sizeof(struct ccw_crw_region), 147d8cac29bSFarhan Ali VFIO_REGION_INFO_FLAG_READ, 148d8cac29bSFarhan Ali private->crw_region); 149d8cac29bSFarhan Ali } 150