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 1124c98674SFarhan Ali #include <linux/vfio.h> 1224c98674SFarhan Ali #include "vfio_ccw_private.h" 1324c98674SFarhan Ali 1424c98674SFarhan Ali static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private, 1524c98674SFarhan Ali char __user *buf, size_t count, 1624c98674SFarhan Ali loff_t *ppos) 1724c98674SFarhan Ali { 1824c98674SFarhan Ali unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 1924c98674SFarhan Ali loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 2024c98674SFarhan Ali struct ccw_schib_region *region; 2124c98674SFarhan Ali int ret; 2224c98674SFarhan Ali 2324c98674SFarhan Ali if (pos + count > sizeof(*region)) 2424c98674SFarhan Ali return -EINVAL; 2524c98674SFarhan Ali 2624c98674SFarhan Ali mutex_lock(&private->io_mutex); 2724c98674SFarhan Ali region = private->region[i].data; 2824c98674SFarhan Ali 2924c98674SFarhan Ali if (cio_update_schib(private->sch)) { 3024c98674SFarhan Ali ret = -ENODEV; 3124c98674SFarhan Ali goto out; 3224c98674SFarhan Ali } 3324c98674SFarhan Ali 3424c98674SFarhan Ali memcpy(region, &private->sch->schib, sizeof(*region)); 3524c98674SFarhan Ali 3624c98674SFarhan Ali if (copy_to_user(buf, (void *)region + pos, count)) { 3724c98674SFarhan Ali ret = -EFAULT; 3824c98674SFarhan Ali goto out; 3924c98674SFarhan Ali } 4024c98674SFarhan Ali 4124c98674SFarhan Ali ret = count; 4224c98674SFarhan Ali 4324c98674SFarhan Ali out: 4424c98674SFarhan Ali mutex_unlock(&private->io_mutex); 4524c98674SFarhan Ali return ret; 4624c98674SFarhan Ali } 4724c98674SFarhan Ali 4824c98674SFarhan Ali static ssize_t vfio_ccw_schib_region_write(struct vfio_ccw_private *private, 4924c98674SFarhan Ali const char __user *buf, size_t count, 5024c98674SFarhan Ali loff_t *ppos) 5124c98674SFarhan Ali { 5224c98674SFarhan Ali return -EINVAL; 5324c98674SFarhan Ali } 5424c98674SFarhan Ali 5524c98674SFarhan Ali 5624c98674SFarhan Ali static void vfio_ccw_schib_region_release(struct vfio_ccw_private *private, 5724c98674SFarhan Ali struct vfio_ccw_region *region) 5824c98674SFarhan Ali { 5924c98674SFarhan Ali 6024c98674SFarhan Ali } 6124c98674SFarhan Ali 6224c98674SFarhan Ali const struct vfio_ccw_regops vfio_ccw_schib_region_ops = { 6324c98674SFarhan Ali .read = vfio_ccw_schib_region_read, 6424c98674SFarhan Ali .write = vfio_ccw_schib_region_write, 6524c98674SFarhan Ali .release = vfio_ccw_schib_region_release, 6624c98674SFarhan Ali }; 6724c98674SFarhan Ali 6824c98674SFarhan Ali int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private) 6924c98674SFarhan Ali { 7024c98674SFarhan Ali return vfio_ccw_register_dev_region(private, 7124c98674SFarhan Ali VFIO_REGION_SUBTYPE_CCW_SCHIB, 7224c98674SFarhan Ali &vfio_ccw_schib_region_ops, 7324c98674SFarhan Ali sizeof(struct ccw_schib_region), 7424c98674SFarhan Ali VFIO_REGION_INFO_FLAG_READ, 7524c98674SFarhan Ali private->schib_region); 7624c98674SFarhan Ali } 77d8cac29bSFarhan Ali 78d8cac29bSFarhan Ali static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private, 79d8cac29bSFarhan Ali char __user *buf, size_t count, 80d8cac29bSFarhan Ali loff_t *ppos) 81d8cac29bSFarhan Ali { 82d8cac29bSFarhan Ali unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS; 83d8cac29bSFarhan Ali loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 84d8cac29bSFarhan Ali struct ccw_crw_region *region; 853f02cb2fSFarhan Ali struct vfio_ccw_crw *crw; 86d8cac29bSFarhan Ali int ret; 87d8cac29bSFarhan Ali 88d8cac29bSFarhan Ali if (pos + count > sizeof(*region)) 89d8cac29bSFarhan Ali return -EINVAL; 90d8cac29bSFarhan Ali 913f02cb2fSFarhan Ali crw = list_first_entry_or_null(&private->crw, 923f02cb2fSFarhan Ali struct vfio_ccw_crw, next); 933f02cb2fSFarhan Ali 943f02cb2fSFarhan Ali if (crw) 953f02cb2fSFarhan Ali list_del(&crw->next); 963f02cb2fSFarhan Ali 97d8cac29bSFarhan Ali mutex_lock(&private->io_mutex); 98d8cac29bSFarhan Ali region = private->region[i].data; 99d8cac29bSFarhan Ali 1003f02cb2fSFarhan Ali if (crw) 1013f02cb2fSFarhan Ali memcpy(®ion->crw, &crw->crw, sizeof(region->crw)); 1023f02cb2fSFarhan Ali 103d8cac29bSFarhan Ali if (copy_to_user(buf, (void *)region + pos, count)) 104d8cac29bSFarhan Ali ret = -EFAULT; 105d8cac29bSFarhan Ali else 106d8cac29bSFarhan Ali ret = count; 107d8cac29bSFarhan Ali 108d8cac29bSFarhan Ali region->crw = 0; 109d8cac29bSFarhan Ali 110d8cac29bSFarhan Ali mutex_unlock(&private->io_mutex); 1113f02cb2fSFarhan Ali 1123f02cb2fSFarhan Ali kfree(crw); 1133f02cb2fSFarhan Ali 1143f02cb2fSFarhan Ali /* Notify the guest if more CRWs are on our queue */ 1153f02cb2fSFarhan Ali if (!list_empty(&private->crw) && private->crw_trigger) 1163f02cb2fSFarhan Ali eventfd_signal(private->crw_trigger, 1); 1173f02cb2fSFarhan Ali 118d8cac29bSFarhan Ali return ret; 119d8cac29bSFarhan Ali } 120d8cac29bSFarhan Ali 121d8cac29bSFarhan Ali static ssize_t vfio_ccw_crw_region_write(struct vfio_ccw_private *private, 122d8cac29bSFarhan Ali const char __user *buf, size_t count, 123d8cac29bSFarhan Ali loff_t *ppos) 124d8cac29bSFarhan Ali { 125d8cac29bSFarhan Ali return -EINVAL; 126d8cac29bSFarhan Ali } 127d8cac29bSFarhan Ali 128d8cac29bSFarhan Ali static void vfio_ccw_crw_region_release(struct vfio_ccw_private *private, 129d8cac29bSFarhan Ali struct vfio_ccw_region *region) 130d8cac29bSFarhan Ali { 131d8cac29bSFarhan Ali 132d8cac29bSFarhan Ali } 133d8cac29bSFarhan Ali 134d8cac29bSFarhan Ali const struct vfio_ccw_regops vfio_ccw_crw_region_ops = { 135d8cac29bSFarhan Ali .read = vfio_ccw_crw_region_read, 136d8cac29bSFarhan Ali .write = vfio_ccw_crw_region_write, 137d8cac29bSFarhan Ali .release = vfio_ccw_crw_region_release, 138d8cac29bSFarhan Ali }; 139d8cac29bSFarhan Ali 140d8cac29bSFarhan Ali int vfio_ccw_register_crw_dev_regions(struct vfio_ccw_private *private) 141d8cac29bSFarhan Ali { 142d8cac29bSFarhan Ali return vfio_ccw_register_dev_region(private, 143d8cac29bSFarhan Ali VFIO_REGION_SUBTYPE_CCW_CRW, 144d8cac29bSFarhan Ali &vfio_ccw_crw_region_ops, 145d8cac29bSFarhan Ali sizeof(struct ccw_crw_region), 146d8cac29bSFarhan Ali VFIO_REGION_INFO_FLAG_READ, 147d8cac29bSFarhan Ali private->crw_region); 148d8cac29bSFarhan Ali } 149