1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 284cd8fc4SDong Jia Shi /* 384cd8fc4SDong Jia Shi * Physical device callbacks for vfio_ccw 484cd8fc4SDong Jia Shi * 584cd8fc4SDong Jia Shi * Copyright IBM Corp. 2017 6db8e5d17SCornelia Huck * Copyright Red Hat, Inc. 2019 784cd8fc4SDong Jia Shi * 884cd8fc4SDong Jia Shi * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> 984cd8fc4SDong Jia Shi * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> 10db8e5d17SCornelia Huck * Cornelia Huck <cohuck@redhat.com> 1184cd8fc4SDong Jia Shi */ 1284cd8fc4SDong Jia Shi 1384cd8fc4SDong Jia Shi #include <linux/vfio.h> 1484cd8fc4SDong Jia Shi #include <linux/mdev.h> 15db8e5d17SCornelia Huck #include <linux/nospec.h> 16db8e5d17SCornelia Huck #include <linux/slab.h> 1784cd8fc4SDong Jia Shi 1884cd8fc4SDong Jia Shi #include "vfio_ccw_private.h" 1984cd8fc4SDong Jia Shi 2083d1193aSDong Jia Shi static int vfio_ccw_mdev_reset(struct mdev_device *mdev) 2183d1193aSDong Jia Shi { 2283d1193aSDong Jia Shi struct vfio_ccw_private *private; 2383d1193aSDong Jia Shi struct subchannel *sch; 2483d1193aSDong Jia Shi int ret; 2583d1193aSDong Jia Shi 2683d1193aSDong Jia Shi private = dev_get_drvdata(mdev_parent_dev(mdev)); 2783d1193aSDong Jia Shi sch = private->sch; 2883d1193aSDong Jia Shi /* 2983d1193aSDong Jia Shi * TODO: 3083d1193aSDong Jia Shi * In the cureent stage, some things like "no I/O running" and "no 3183d1193aSDong Jia Shi * interrupt pending" are clear, but we are not sure what other state 3283d1193aSDong Jia Shi * we need to care about. 3383d1193aSDong Jia Shi * There are still a lot more instructions need to be handled. We 3483d1193aSDong Jia Shi * should come back here later. 3583d1193aSDong Jia Shi */ 3683d1193aSDong Jia Shi ret = vfio_ccw_sch_quiesce(sch); 3783d1193aSDong Jia Shi if (ret) 3883d1193aSDong Jia Shi return ret; 3983d1193aSDong Jia Shi 40bbe37e4cSDong Jia Shi ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); 41bbe37e4cSDong Jia Shi if (!ret) 42bbe37e4cSDong Jia Shi private->state = VFIO_CCW_STATE_IDLE; 43bbe37e4cSDong Jia Shi 44bbe37e4cSDong Jia Shi return ret; 4583d1193aSDong Jia Shi } 4683d1193aSDong Jia Shi 4784cd8fc4SDong Jia Shi static int vfio_ccw_mdev_notifier(struct notifier_block *nb, 4884cd8fc4SDong Jia Shi unsigned long action, 4984cd8fc4SDong Jia Shi void *data) 5084cd8fc4SDong Jia Shi { 5184cd8fc4SDong Jia Shi struct vfio_ccw_private *private = 5284cd8fc4SDong Jia Shi container_of(nb, struct vfio_ccw_private, nb); 5384cd8fc4SDong Jia Shi 5484cd8fc4SDong Jia Shi /* 5584cd8fc4SDong Jia Shi * Vendor drivers MUST unpin pages in response to an 5684cd8fc4SDong Jia Shi * invalidation. 5784cd8fc4SDong Jia Shi */ 584e149e43SDong Jia Shi if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { 594e149e43SDong Jia Shi struct vfio_iommu_type1_dma_unmap *unmap = data; 604e149e43SDong Jia Shi 614e149e43SDong Jia Shi if (!cp_iova_pinned(&private->cp, unmap->iova)) 624e149e43SDong Jia Shi return NOTIFY_OK; 634e149e43SDong Jia Shi 6483d1193aSDong Jia Shi if (vfio_ccw_mdev_reset(private->mdev)) 654e149e43SDong Jia Shi return NOTIFY_BAD; 664e149e43SDong Jia Shi 674e149e43SDong Jia Shi cp_free(&private->cp); 684e149e43SDong Jia Shi return NOTIFY_OK; 694e149e43SDong Jia Shi } 704e149e43SDong Jia Shi 7184cd8fc4SDong Jia Shi return NOTIFY_DONE; 7284cd8fc4SDong Jia Shi } 7384cd8fc4SDong Jia Shi 7484cd8fc4SDong Jia Shi static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf) 7584cd8fc4SDong Jia Shi { 7684cd8fc4SDong Jia Shi return sprintf(buf, "I/O subchannel (Non-QDIO)\n"); 7784cd8fc4SDong Jia Shi } 785bf18536SSebastian Ott static MDEV_TYPE_ATTR_RO(name); 7984cd8fc4SDong Jia Shi 8084cd8fc4SDong Jia Shi static ssize_t device_api_show(struct kobject *kobj, struct device *dev, 8184cd8fc4SDong Jia Shi char *buf) 8284cd8fc4SDong Jia Shi { 8384cd8fc4SDong Jia Shi return sprintf(buf, "%s\n", VFIO_DEVICE_API_CCW_STRING); 8484cd8fc4SDong Jia Shi } 855bf18536SSebastian Ott static MDEV_TYPE_ATTR_RO(device_api); 8684cd8fc4SDong Jia Shi 8784cd8fc4SDong Jia Shi static ssize_t available_instances_show(struct kobject *kobj, 8884cd8fc4SDong Jia Shi struct device *dev, char *buf) 8984cd8fc4SDong Jia Shi { 9084cd8fc4SDong Jia Shi struct vfio_ccw_private *private = dev_get_drvdata(dev); 9184cd8fc4SDong Jia Shi 9284cd8fc4SDong Jia Shi return sprintf(buf, "%d\n", atomic_read(&private->avail)); 9384cd8fc4SDong Jia Shi } 945bf18536SSebastian Ott static MDEV_TYPE_ATTR_RO(available_instances); 9584cd8fc4SDong Jia Shi 9684cd8fc4SDong Jia Shi static struct attribute *mdev_types_attrs[] = { 9784cd8fc4SDong Jia Shi &mdev_type_attr_name.attr, 9884cd8fc4SDong Jia Shi &mdev_type_attr_device_api.attr, 9984cd8fc4SDong Jia Shi &mdev_type_attr_available_instances.attr, 10084cd8fc4SDong Jia Shi NULL, 10184cd8fc4SDong Jia Shi }; 10284cd8fc4SDong Jia Shi 10384cd8fc4SDong Jia Shi static struct attribute_group mdev_type_group = { 10484cd8fc4SDong Jia Shi .name = "io", 10584cd8fc4SDong Jia Shi .attrs = mdev_types_attrs, 10684cd8fc4SDong Jia Shi }; 10784cd8fc4SDong Jia Shi 1085bf18536SSebastian Ott static struct attribute_group *mdev_type_groups[] = { 10984cd8fc4SDong Jia Shi &mdev_type_group, 11084cd8fc4SDong Jia Shi NULL, 11184cd8fc4SDong Jia Shi }; 11284cd8fc4SDong Jia Shi 11384cd8fc4SDong Jia Shi static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) 11484cd8fc4SDong Jia Shi { 11584cd8fc4SDong Jia Shi struct vfio_ccw_private *private = 11684cd8fc4SDong Jia Shi dev_get_drvdata(mdev_parent_dev(mdev)); 11784cd8fc4SDong Jia Shi 118bbe37e4cSDong Jia Shi if (private->state == VFIO_CCW_STATE_NOT_OPER) 119bbe37e4cSDong Jia Shi return -ENODEV; 120bbe37e4cSDong Jia Shi 12184cd8fc4SDong Jia Shi if (atomic_dec_if_positive(&private->avail) < 0) 12284cd8fc4SDong Jia Shi return -EPERM; 12384cd8fc4SDong Jia Shi 12484cd8fc4SDong Jia Shi private->mdev = mdev; 125bbe37e4cSDong Jia Shi private->state = VFIO_CCW_STATE_IDLE; 12684cd8fc4SDong Jia Shi 12760e05d1cSCornelia Huck VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: create\n", 12860e05d1cSCornelia Huck mdev_uuid(mdev), private->sch->schid.cssid, 12960e05d1cSCornelia Huck private->sch->schid.ssid, 13060e05d1cSCornelia Huck private->sch->schid.sch_no); 13160e05d1cSCornelia Huck 13284cd8fc4SDong Jia Shi return 0; 13384cd8fc4SDong Jia Shi } 13484cd8fc4SDong Jia Shi 13584cd8fc4SDong Jia Shi static int vfio_ccw_mdev_remove(struct mdev_device *mdev) 13684cd8fc4SDong Jia Shi { 13783d1193aSDong Jia Shi struct vfio_ccw_private *private = 13883d1193aSDong Jia Shi dev_get_drvdata(mdev_parent_dev(mdev)); 13984cd8fc4SDong Jia Shi 14060e05d1cSCornelia Huck VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n", 14160e05d1cSCornelia Huck mdev_uuid(mdev), private->sch->schid.cssid, 14260e05d1cSCornelia Huck private->sch->schid.ssid, 14360e05d1cSCornelia Huck private->sch->schid.sch_no); 14460e05d1cSCornelia Huck 145129cc19aSDong Jia Shi if ((private->state != VFIO_CCW_STATE_NOT_OPER) && 146129cc19aSDong Jia Shi (private->state != VFIO_CCW_STATE_STANDBY)) { 147b49bdc86SFarhan Ali if (!vfio_ccw_sch_quiesce(private->sch)) 148bbe37e4cSDong Jia Shi private->state = VFIO_CCW_STATE_STANDBY; 149129cc19aSDong Jia Shi /* The state will be NOT_OPER on error. */ 150129cc19aSDong Jia Shi } 151bbe37e4cSDong Jia Shi 152b49bdc86SFarhan Ali cp_free(&private->cp); 15384cd8fc4SDong Jia Shi private->mdev = NULL; 15484cd8fc4SDong Jia Shi atomic_inc(&private->avail); 15584cd8fc4SDong Jia Shi 15684cd8fc4SDong Jia Shi return 0; 15784cd8fc4SDong Jia Shi } 15884cd8fc4SDong Jia Shi 15984cd8fc4SDong Jia Shi static int vfio_ccw_mdev_open(struct mdev_device *mdev) 16084cd8fc4SDong Jia Shi { 16184cd8fc4SDong Jia Shi struct vfio_ccw_private *private = 16284cd8fc4SDong Jia Shi dev_get_drvdata(mdev_parent_dev(mdev)); 16384cd8fc4SDong Jia Shi unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; 164d5afd5d1SCornelia Huck int ret; 16584cd8fc4SDong Jia Shi 16684cd8fc4SDong Jia Shi private->nb.notifier_call = vfio_ccw_mdev_notifier; 16784cd8fc4SDong Jia Shi 168d5afd5d1SCornelia Huck ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 16984cd8fc4SDong Jia Shi &events, &private->nb); 170d5afd5d1SCornelia Huck if (ret) 171d5afd5d1SCornelia Huck return ret; 172d5afd5d1SCornelia Huck 173d5afd5d1SCornelia Huck ret = vfio_ccw_register_async_dev_regions(private); 174d5afd5d1SCornelia Huck if (ret) 17524c98674SFarhan Ali goto out_unregister; 17624c98674SFarhan Ali 17724c98674SFarhan Ali ret = vfio_ccw_register_schib_dev_regions(private); 17824c98674SFarhan Ali if (ret) 17924c98674SFarhan Ali goto out_unregister; 18024c98674SFarhan Ali 181*d8cac29bSFarhan Ali ret = vfio_ccw_register_crw_dev_regions(private); 182*d8cac29bSFarhan Ali if (ret) 183*d8cac29bSFarhan Ali goto out_unregister; 184*d8cac29bSFarhan Ali 18524c98674SFarhan Ali return ret; 18624c98674SFarhan Ali 18724c98674SFarhan Ali out_unregister: 18824c98674SFarhan Ali vfio_ccw_unregister_dev_regions(private); 189d5afd5d1SCornelia Huck vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 190d5afd5d1SCornelia Huck &private->nb); 191d5afd5d1SCornelia Huck return ret; 19284cd8fc4SDong Jia Shi } 19384cd8fc4SDong Jia Shi 1945bf18536SSebastian Ott static void vfio_ccw_mdev_release(struct mdev_device *mdev) 19584cd8fc4SDong Jia Shi { 19684cd8fc4SDong Jia Shi struct vfio_ccw_private *private = 19784cd8fc4SDong Jia Shi dev_get_drvdata(mdev_parent_dev(mdev)); 19884cd8fc4SDong Jia Shi 199b49bdc86SFarhan Ali if ((private->state != VFIO_CCW_STATE_NOT_OPER) && 200b49bdc86SFarhan Ali (private->state != VFIO_CCW_STATE_STANDBY)) { 201b49bdc86SFarhan Ali if (!vfio_ccw_mdev_reset(mdev)) 202b49bdc86SFarhan Ali private->state = VFIO_CCW_STATE_STANDBY; 203b49bdc86SFarhan Ali /* The state will be NOT_OPER on error. */ 204b49bdc86SFarhan Ali } 205b49bdc86SFarhan Ali 206b49bdc86SFarhan Ali cp_free(&private->cp); 207600279b5SEric Farman vfio_ccw_unregister_dev_regions(private); 20884cd8fc4SDong Jia Shi vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 20984cd8fc4SDong Jia Shi &private->nb); 21084cd8fc4SDong Jia Shi } 21184cd8fc4SDong Jia Shi 212db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private, 213db8e5d17SCornelia Huck char __user *buf, size_t count, 214060d2b5aSDong Jia Shi loff_t *ppos) 215060d2b5aSDong Jia Shi { 216db8e5d17SCornelia Huck loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 217060d2b5aSDong Jia Shi struct ccw_io_region *region; 2184f766173SCornelia Huck int ret; 219060d2b5aSDong Jia Shi 220db8e5d17SCornelia Huck if (pos + count > sizeof(*region)) 221060d2b5aSDong Jia Shi return -EINVAL; 222060d2b5aSDong Jia Shi 2234f766173SCornelia Huck mutex_lock(&private->io_mutex); 224c98e16b2SEric Farman region = private->io_region; 225db8e5d17SCornelia Huck if (copy_to_user(buf, (void *)region + pos, count)) 2264f766173SCornelia Huck ret = -EFAULT; 2274f766173SCornelia Huck else 2284f766173SCornelia Huck ret = count; 2294f766173SCornelia Huck mutex_unlock(&private->io_mutex); 2304f766173SCornelia Huck return ret; 231060d2b5aSDong Jia Shi } 232060d2b5aSDong Jia Shi 233db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev, 234db8e5d17SCornelia Huck char __user *buf, 235060d2b5aSDong Jia Shi size_t count, 236060d2b5aSDong Jia Shi loff_t *ppos) 237060d2b5aSDong Jia Shi { 238db8e5d17SCornelia Huck unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); 239060d2b5aSDong Jia Shi struct vfio_ccw_private *private; 240db8e5d17SCornelia Huck 241db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 242db8e5d17SCornelia Huck 243db8e5d17SCornelia Huck if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) 244db8e5d17SCornelia Huck return -EINVAL; 245db8e5d17SCornelia Huck 246db8e5d17SCornelia Huck switch (index) { 247db8e5d17SCornelia Huck case VFIO_CCW_CONFIG_REGION_INDEX: 248db8e5d17SCornelia Huck return vfio_ccw_mdev_read_io_region(private, buf, count, ppos); 249db8e5d17SCornelia Huck default: 250db8e5d17SCornelia Huck index -= VFIO_CCW_NUM_REGIONS; 251db8e5d17SCornelia Huck return private->region[index].ops->read(private, buf, count, 252db8e5d17SCornelia Huck ppos); 253db8e5d17SCornelia Huck } 254db8e5d17SCornelia Huck 255db8e5d17SCornelia Huck return -EINVAL; 256db8e5d17SCornelia Huck } 257db8e5d17SCornelia Huck 258db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private, 259db8e5d17SCornelia Huck const char __user *buf, 260db8e5d17SCornelia Huck size_t count, loff_t *ppos) 261db8e5d17SCornelia Huck { 262db8e5d17SCornelia Huck loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 263060d2b5aSDong Jia Shi struct ccw_io_region *region; 2644f766173SCornelia Huck int ret; 265060d2b5aSDong Jia Shi 266db8e5d17SCornelia Huck if (pos + count > sizeof(*region)) 267060d2b5aSDong Jia Shi return -EINVAL; 268060d2b5aSDong Jia Shi 2694f766173SCornelia Huck if (!mutex_trylock(&private->io_mutex)) 2704f766173SCornelia Huck return -EAGAIN; 271060d2b5aSDong Jia Shi 272c98e16b2SEric Farman region = private->io_region; 273db8e5d17SCornelia Huck if (copy_from_user((void *)region + pos, buf, count)) { 2744f766173SCornelia Huck ret = -EFAULT; 2754f766173SCornelia Huck goto out_unlock; 276bbe37e4cSDong Jia Shi } 277060d2b5aSDong Jia Shi 2784f766173SCornelia Huck vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ); 2794f766173SCornelia Huck if (region->ret_code != 0) 2804f766173SCornelia Huck private->state = VFIO_CCW_STATE_IDLE; 2814f766173SCornelia Huck ret = (region->ret_code != 0) ? region->ret_code : count; 2824f766173SCornelia Huck 2834f766173SCornelia Huck out_unlock: 2844f766173SCornelia Huck mutex_unlock(&private->io_mutex); 2854f766173SCornelia Huck return ret; 286060d2b5aSDong Jia Shi } 287060d2b5aSDong Jia Shi 288db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev, 289db8e5d17SCornelia Huck const char __user *buf, 290db8e5d17SCornelia Huck size_t count, 291db8e5d17SCornelia Huck loff_t *ppos) 292e01bcdd6SDong Jia Shi { 293db8e5d17SCornelia Huck unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); 294db8e5d17SCornelia Huck struct vfio_ccw_private *private; 295db8e5d17SCornelia Huck 296db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 297db8e5d17SCornelia Huck 298db8e5d17SCornelia Huck if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) 299db8e5d17SCornelia Huck return -EINVAL; 300db8e5d17SCornelia Huck 301db8e5d17SCornelia Huck switch (index) { 302db8e5d17SCornelia Huck case VFIO_CCW_CONFIG_REGION_INDEX: 303db8e5d17SCornelia Huck return vfio_ccw_mdev_write_io_region(private, buf, count, ppos); 304db8e5d17SCornelia Huck default: 305db8e5d17SCornelia Huck index -= VFIO_CCW_NUM_REGIONS; 306db8e5d17SCornelia Huck return private->region[index].ops->write(private, buf, count, 307db8e5d17SCornelia Huck ppos); 308db8e5d17SCornelia Huck } 309db8e5d17SCornelia Huck 310db8e5d17SCornelia Huck return -EINVAL; 311db8e5d17SCornelia Huck } 312db8e5d17SCornelia Huck 313db8e5d17SCornelia Huck static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info, 314db8e5d17SCornelia Huck struct mdev_device *mdev) 315db8e5d17SCornelia Huck { 316db8e5d17SCornelia Huck struct vfio_ccw_private *private; 317db8e5d17SCornelia Huck 318db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 31983d1193aSDong Jia Shi info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET; 320db8e5d17SCornelia Huck info->num_regions = VFIO_CCW_NUM_REGIONS + private->num_regions; 321120e214eSDong Jia Shi info->num_irqs = VFIO_CCW_NUM_IRQS; 322e01bcdd6SDong Jia Shi 323e01bcdd6SDong Jia Shi return 0; 324e01bcdd6SDong Jia Shi } 325e01bcdd6SDong Jia Shi 326e01bcdd6SDong Jia Shi static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info, 327db8e5d17SCornelia Huck struct mdev_device *mdev, 328db8e5d17SCornelia Huck unsigned long arg) 329e01bcdd6SDong Jia Shi { 330db8e5d17SCornelia Huck struct vfio_ccw_private *private; 331db8e5d17SCornelia Huck int i; 332db8e5d17SCornelia Huck 333db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 334e01bcdd6SDong Jia Shi switch (info->index) { 335e01bcdd6SDong Jia Shi case VFIO_CCW_CONFIG_REGION_INDEX: 336e01bcdd6SDong Jia Shi info->offset = 0; 337e01bcdd6SDong Jia Shi info->size = sizeof(struct ccw_io_region); 338e01bcdd6SDong Jia Shi info->flags = VFIO_REGION_INFO_FLAG_READ 339e01bcdd6SDong Jia Shi | VFIO_REGION_INFO_FLAG_WRITE; 340e01bcdd6SDong Jia Shi return 0; 341db8e5d17SCornelia Huck default: /* all other regions are handled via capability chain */ 342db8e5d17SCornelia Huck { 343db8e5d17SCornelia Huck struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; 344db8e5d17SCornelia Huck struct vfio_region_info_cap_type cap_type = { 345db8e5d17SCornelia Huck .header.id = VFIO_REGION_INFO_CAP_TYPE, 346db8e5d17SCornelia Huck .header.version = 1 }; 347db8e5d17SCornelia Huck int ret; 348db8e5d17SCornelia Huck 349db8e5d17SCornelia Huck if (info->index >= 350db8e5d17SCornelia Huck VFIO_CCW_NUM_REGIONS + private->num_regions) 351e01bcdd6SDong Jia Shi return -EINVAL; 352db8e5d17SCornelia Huck 353db8e5d17SCornelia Huck info->index = array_index_nospec(info->index, 354db8e5d17SCornelia Huck VFIO_CCW_NUM_REGIONS + 355db8e5d17SCornelia Huck private->num_regions); 356db8e5d17SCornelia Huck 357db8e5d17SCornelia Huck i = info->index - VFIO_CCW_NUM_REGIONS; 358db8e5d17SCornelia Huck 359db8e5d17SCornelia Huck info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index); 360db8e5d17SCornelia Huck info->size = private->region[i].size; 361db8e5d17SCornelia Huck info->flags = private->region[i].flags; 362db8e5d17SCornelia Huck 363db8e5d17SCornelia Huck cap_type.type = private->region[i].type; 364db8e5d17SCornelia Huck cap_type.subtype = private->region[i].subtype; 365db8e5d17SCornelia Huck 366db8e5d17SCornelia Huck ret = vfio_info_add_capability(&caps, &cap_type.header, 367db8e5d17SCornelia Huck sizeof(cap_type)); 368db8e5d17SCornelia Huck if (ret) 369db8e5d17SCornelia Huck return ret; 370db8e5d17SCornelia Huck 371db8e5d17SCornelia Huck info->flags |= VFIO_REGION_INFO_FLAG_CAPS; 372db8e5d17SCornelia Huck if (info->argsz < sizeof(*info) + caps.size) { 373db8e5d17SCornelia Huck info->argsz = sizeof(*info) + caps.size; 374db8e5d17SCornelia Huck info->cap_offset = 0; 375db8e5d17SCornelia Huck } else { 376db8e5d17SCornelia Huck vfio_info_cap_shift(&caps, sizeof(*info)); 377db8e5d17SCornelia Huck if (copy_to_user((void __user *)arg + sizeof(*info), 378db8e5d17SCornelia Huck caps.buf, caps.size)) { 379db8e5d17SCornelia Huck kfree(caps.buf); 380db8e5d17SCornelia Huck return -EFAULT; 381e01bcdd6SDong Jia Shi } 382db8e5d17SCornelia Huck info->cap_offset = sizeof(*info); 383db8e5d17SCornelia Huck } 384db8e5d17SCornelia Huck 385db8e5d17SCornelia Huck kfree(caps.buf); 386db8e5d17SCornelia Huck 387db8e5d17SCornelia Huck } 388db8e5d17SCornelia Huck } 389db8e5d17SCornelia Huck return 0; 390e01bcdd6SDong Jia Shi } 391e01bcdd6SDong Jia Shi 3925bf18536SSebastian Ott static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info) 393120e214eSDong Jia Shi { 3944296151dSEric Farman switch (info->index) { 3954296151dSEric Farman case VFIO_CCW_IO_IRQ_INDEX: 396*d8cac29bSFarhan Ali case VFIO_CCW_CRW_IRQ_INDEX: 397120e214eSDong Jia Shi info->count = 1; 398120e214eSDong Jia Shi info->flags = VFIO_IRQ_INFO_EVENTFD; 3994296151dSEric Farman break; 4004296151dSEric Farman default: 4014296151dSEric Farman return -EINVAL; 4024296151dSEric Farman } 403120e214eSDong Jia Shi 404120e214eSDong Jia Shi return 0; 405120e214eSDong Jia Shi } 406120e214eSDong Jia Shi 407120e214eSDong Jia Shi static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev, 408120e214eSDong Jia Shi uint32_t flags, 4094296151dSEric Farman uint32_t index, 410120e214eSDong Jia Shi void __user *data) 411120e214eSDong Jia Shi { 412120e214eSDong Jia Shi struct vfio_ccw_private *private; 413120e214eSDong Jia Shi struct eventfd_ctx **ctx; 414120e214eSDong Jia Shi 415120e214eSDong Jia Shi if (!(flags & VFIO_IRQ_SET_ACTION_TRIGGER)) 416120e214eSDong Jia Shi return -EINVAL; 417120e214eSDong Jia Shi 418120e214eSDong Jia Shi private = dev_get_drvdata(mdev_parent_dev(mdev)); 4194296151dSEric Farman 4204296151dSEric Farman switch (index) { 4214296151dSEric Farman case VFIO_CCW_IO_IRQ_INDEX: 422120e214eSDong Jia Shi ctx = &private->io_trigger; 4234296151dSEric Farman break; 424*d8cac29bSFarhan Ali case VFIO_CCW_CRW_IRQ_INDEX: 425*d8cac29bSFarhan Ali ctx = &private->crw_trigger; 426*d8cac29bSFarhan Ali break; 4274296151dSEric Farman default: 4284296151dSEric Farman return -EINVAL; 4294296151dSEric Farman } 430120e214eSDong Jia Shi 431120e214eSDong Jia Shi switch (flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { 432120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_NONE: 433120e214eSDong Jia Shi { 434120e214eSDong Jia Shi if (*ctx) 435120e214eSDong Jia Shi eventfd_signal(*ctx, 1); 436120e214eSDong Jia Shi return 0; 437120e214eSDong Jia Shi } 438120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_BOOL: 439120e214eSDong Jia Shi { 440120e214eSDong Jia Shi uint8_t trigger; 441120e214eSDong Jia Shi 442120e214eSDong Jia Shi if (get_user(trigger, (uint8_t __user *)data)) 443120e214eSDong Jia Shi return -EFAULT; 444120e214eSDong Jia Shi 445120e214eSDong Jia Shi if (trigger && *ctx) 446120e214eSDong Jia Shi eventfd_signal(*ctx, 1); 447120e214eSDong Jia Shi return 0; 448120e214eSDong Jia Shi } 449120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_EVENTFD: 450120e214eSDong Jia Shi { 451120e214eSDong Jia Shi int32_t fd; 452120e214eSDong Jia Shi 453120e214eSDong Jia Shi if (get_user(fd, (int32_t __user *)data)) 454120e214eSDong Jia Shi return -EFAULT; 455120e214eSDong Jia Shi 456120e214eSDong Jia Shi if (fd == -1) { 457120e214eSDong Jia Shi if (*ctx) 458120e214eSDong Jia Shi eventfd_ctx_put(*ctx); 459120e214eSDong Jia Shi *ctx = NULL; 460120e214eSDong Jia Shi } else if (fd >= 0) { 461120e214eSDong Jia Shi struct eventfd_ctx *efdctx; 462120e214eSDong Jia Shi 463120e214eSDong Jia Shi efdctx = eventfd_ctx_fdget(fd); 464120e214eSDong Jia Shi if (IS_ERR(efdctx)) 465120e214eSDong Jia Shi return PTR_ERR(efdctx); 466120e214eSDong Jia Shi 467120e214eSDong Jia Shi if (*ctx) 468120e214eSDong Jia Shi eventfd_ctx_put(*ctx); 469120e214eSDong Jia Shi 470120e214eSDong Jia Shi *ctx = efdctx; 471120e214eSDong Jia Shi } else 472120e214eSDong Jia Shi return -EINVAL; 473120e214eSDong Jia Shi 474120e214eSDong Jia Shi return 0; 475120e214eSDong Jia Shi } 476120e214eSDong Jia Shi default: 477120e214eSDong Jia Shi return -EINVAL; 478120e214eSDong Jia Shi } 479120e214eSDong Jia Shi } 480120e214eSDong Jia Shi 481db8e5d17SCornelia Huck int vfio_ccw_register_dev_region(struct vfio_ccw_private *private, 482db8e5d17SCornelia Huck unsigned int subtype, 483db8e5d17SCornelia Huck const struct vfio_ccw_regops *ops, 484db8e5d17SCornelia Huck size_t size, u32 flags, void *data) 485db8e5d17SCornelia Huck { 486db8e5d17SCornelia Huck struct vfio_ccw_region *region; 487db8e5d17SCornelia Huck 488db8e5d17SCornelia Huck region = krealloc(private->region, 489db8e5d17SCornelia Huck (private->num_regions + 1) * sizeof(*region), 490db8e5d17SCornelia Huck GFP_KERNEL); 491db8e5d17SCornelia Huck if (!region) 492db8e5d17SCornelia Huck return -ENOMEM; 493db8e5d17SCornelia Huck 494db8e5d17SCornelia Huck private->region = region; 495db8e5d17SCornelia Huck private->region[private->num_regions].type = VFIO_REGION_TYPE_CCW; 496db8e5d17SCornelia Huck private->region[private->num_regions].subtype = subtype; 497db8e5d17SCornelia Huck private->region[private->num_regions].ops = ops; 498db8e5d17SCornelia Huck private->region[private->num_regions].size = size; 499db8e5d17SCornelia Huck private->region[private->num_regions].flags = flags; 500db8e5d17SCornelia Huck private->region[private->num_regions].data = data; 501db8e5d17SCornelia Huck 502db8e5d17SCornelia Huck private->num_regions++; 503db8e5d17SCornelia Huck 504db8e5d17SCornelia Huck return 0; 505db8e5d17SCornelia Huck } 506db8e5d17SCornelia Huck 507600279b5SEric Farman void vfio_ccw_unregister_dev_regions(struct vfio_ccw_private *private) 508600279b5SEric Farman { 509600279b5SEric Farman int i; 510600279b5SEric Farman 511600279b5SEric Farman for (i = 0; i < private->num_regions; i++) 512600279b5SEric Farman private->region[i].ops->release(private, &private->region[i]); 513600279b5SEric Farman private->num_regions = 0; 514600279b5SEric Farman kfree(private->region); 515600279b5SEric Farman private->region = NULL; 516600279b5SEric Farman } 517600279b5SEric Farman 518e01bcdd6SDong Jia Shi static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, 519e01bcdd6SDong Jia Shi unsigned int cmd, 520e01bcdd6SDong Jia Shi unsigned long arg) 521e01bcdd6SDong Jia Shi { 522e01bcdd6SDong Jia Shi int ret = 0; 523e01bcdd6SDong Jia Shi unsigned long minsz; 524e01bcdd6SDong Jia Shi 525e01bcdd6SDong Jia Shi switch (cmd) { 526e01bcdd6SDong Jia Shi case VFIO_DEVICE_GET_INFO: 527e01bcdd6SDong Jia Shi { 528e01bcdd6SDong Jia Shi struct vfio_device_info info; 529e01bcdd6SDong Jia Shi 530e01bcdd6SDong Jia Shi minsz = offsetofend(struct vfio_device_info, num_irqs); 531e01bcdd6SDong Jia Shi 532e01bcdd6SDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 533e01bcdd6SDong Jia Shi return -EFAULT; 534e01bcdd6SDong Jia Shi 535e01bcdd6SDong Jia Shi if (info.argsz < minsz) 536e01bcdd6SDong Jia Shi return -EINVAL; 537e01bcdd6SDong Jia Shi 538db8e5d17SCornelia Huck ret = vfio_ccw_mdev_get_device_info(&info, mdev); 539e01bcdd6SDong Jia Shi if (ret) 540e01bcdd6SDong Jia Shi return ret; 541e01bcdd6SDong Jia Shi 542e01bcdd6SDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 543e01bcdd6SDong Jia Shi } 544e01bcdd6SDong Jia Shi case VFIO_DEVICE_GET_REGION_INFO: 545e01bcdd6SDong Jia Shi { 546e01bcdd6SDong Jia Shi struct vfio_region_info info; 547e01bcdd6SDong Jia Shi 548e01bcdd6SDong Jia Shi minsz = offsetofend(struct vfio_region_info, offset); 549e01bcdd6SDong Jia Shi 550e01bcdd6SDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 551e01bcdd6SDong Jia Shi return -EFAULT; 552e01bcdd6SDong Jia Shi 553e01bcdd6SDong Jia Shi if (info.argsz < minsz) 554e01bcdd6SDong Jia Shi return -EINVAL; 555e01bcdd6SDong Jia Shi 556db8e5d17SCornelia Huck ret = vfio_ccw_mdev_get_region_info(&info, mdev, arg); 557e01bcdd6SDong Jia Shi if (ret) 558e01bcdd6SDong Jia Shi return ret; 559e01bcdd6SDong Jia Shi 560e01bcdd6SDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 561e01bcdd6SDong Jia Shi } 562120e214eSDong Jia Shi case VFIO_DEVICE_GET_IRQ_INFO: 563120e214eSDong Jia Shi { 564120e214eSDong Jia Shi struct vfio_irq_info info; 565120e214eSDong Jia Shi 566120e214eSDong Jia Shi minsz = offsetofend(struct vfio_irq_info, count); 567120e214eSDong Jia Shi 568120e214eSDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 569120e214eSDong Jia Shi return -EFAULT; 570120e214eSDong Jia Shi 571120e214eSDong Jia Shi if (info.argsz < minsz || info.index >= VFIO_CCW_NUM_IRQS) 572120e214eSDong Jia Shi return -EINVAL; 573120e214eSDong Jia Shi 574120e214eSDong Jia Shi ret = vfio_ccw_mdev_get_irq_info(&info); 575120e214eSDong Jia Shi if (ret) 576120e214eSDong Jia Shi return ret; 577120e214eSDong Jia Shi 578120e214eSDong Jia Shi if (info.count == -1) 579120e214eSDong Jia Shi return -EINVAL; 580120e214eSDong Jia Shi 581120e214eSDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 582120e214eSDong Jia Shi } 583120e214eSDong Jia Shi case VFIO_DEVICE_SET_IRQS: 584120e214eSDong Jia Shi { 585120e214eSDong Jia Shi struct vfio_irq_set hdr; 586120e214eSDong Jia Shi size_t data_size; 587120e214eSDong Jia Shi void __user *data; 588120e214eSDong Jia Shi 589120e214eSDong Jia Shi minsz = offsetofend(struct vfio_irq_set, count); 590120e214eSDong Jia Shi 591120e214eSDong Jia Shi if (copy_from_user(&hdr, (void __user *)arg, minsz)) 592120e214eSDong Jia Shi return -EFAULT; 593120e214eSDong Jia Shi 594120e214eSDong Jia Shi ret = vfio_set_irqs_validate_and_prepare(&hdr, 1, 595120e214eSDong Jia Shi VFIO_CCW_NUM_IRQS, 596120e214eSDong Jia Shi &data_size); 597120e214eSDong Jia Shi if (ret) 598120e214eSDong Jia Shi return ret; 599120e214eSDong Jia Shi 600120e214eSDong Jia Shi data = (void __user *)(arg + minsz); 6014296151dSEric Farman return vfio_ccw_mdev_set_irqs(mdev, hdr.flags, hdr.index, data); 602120e214eSDong Jia Shi } 60383d1193aSDong Jia Shi case VFIO_DEVICE_RESET: 60483d1193aSDong Jia Shi return vfio_ccw_mdev_reset(mdev); 605e01bcdd6SDong Jia Shi default: 606e01bcdd6SDong Jia Shi return -ENOTTY; 607e01bcdd6SDong Jia Shi } 608e01bcdd6SDong Jia Shi } 609e01bcdd6SDong Jia Shi 61084cd8fc4SDong Jia Shi static const struct mdev_parent_ops vfio_ccw_mdev_ops = { 61184cd8fc4SDong Jia Shi .owner = THIS_MODULE, 61284cd8fc4SDong Jia Shi .supported_type_groups = mdev_type_groups, 61384cd8fc4SDong Jia Shi .create = vfio_ccw_mdev_create, 61484cd8fc4SDong Jia Shi .remove = vfio_ccw_mdev_remove, 61584cd8fc4SDong Jia Shi .open = vfio_ccw_mdev_open, 61684cd8fc4SDong Jia Shi .release = vfio_ccw_mdev_release, 617060d2b5aSDong Jia Shi .read = vfio_ccw_mdev_read, 618060d2b5aSDong Jia Shi .write = vfio_ccw_mdev_write, 619e01bcdd6SDong Jia Shi .ioctl = vfio_ccw_mdev_ioctl, 62084cd8fc4SDong Jia Shi }; 62184cd8fc4SDong Jia Shi 62284cd8fc4SDong Jia Shi int vfio_ccw_mdev_reg(struct subchannel *sch) 62384cd8fc4SDong Jia Shi { 62484cd8fc4SDong Jia Shi return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops); 62584cd8fc4SDong Jia Shi } 62684cd8fc4SDong Jia Shi 62784cd8fc4SDong Jia Shi void vfio_ccw_mdev_unreg(struct subchannel *sch) 62884cd8fc4SDong Jia Shi { 62984cd8fc4SDong Jia Shi mdev_unregister_device(&sch->dev); 63084cd8fc4SDong Jia Shi } 631