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 18124c98674SFarhan Ali return ret; 18224c98674SFarhan Ali 18324c98674SFarhan Ali out_unregister: 18424c98674SFarhan Ali vfio_ccw_unregister_dev_regions(private); 185d5afd5d1SCornelia Huck vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 186d5afd5d1SCornelia Huck &private->nb); 187d5afd5d1SCornelia Huck return ret; 18884cd8fc4SDong Jia Shi } 18984cd8fc4SDong Jia Shi 1905bf18536SSebastian Ott static void vfio_ccw_mdev_release(struct mdev_device *mdev) 19184cd8fc4SDong Jia Shi { 19284cd8fc4SDong Jia Shi struct vfio_ccw_private *private = 19384cd8fc4SDong Jia Shi dev_get_drvdata(mdev_parent_dev(mdev)); 19484cd8fc4SDong Jia Shi 195b49bdc86SFarhan Ali if ((private->state != VFIO_CCW_STATE_NOT_OPER) && 196b49bdc86SFarhan Ali (private->state != VFIO_CCW_STATE_STANDBY)) { 197b49bdc86SFarhan Ali if (!vfio_ccw_mdev_reset(mdev)) 198b49bdc86SFarhan Ali private->state = VFIO_CCW_STATE_STANDBY; 199b49bdc86SFarhan Ali /* The state will be NOT_OPER on error. */ 200b49bdc86SFarhan Ali } 201b49bdc86SFarhan Ali 202b49bdc86SFarhan Ali cp_free(&private->cp); 203600279b5SEric Farman vfio_ccw_unregister_dev_regions(private); 20484cd8fc4SDong Jia Shi vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 20584cd8fc4SDong Jia Shi &private->nb); 20684cd8fc4SDong Jia Shi } 20784cd8fc4SDong Jia Shi 208db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private, 209db8e5d17SCornelia Huck char __user *buf, size_t count, 210060d2b5aSDong Jia Shi loff_t *ppos) 211060d2b5aSDong Jia Shi { 212db8e5d17SCornelia Huck loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 213060d2b5aSDong Jia Shi struct ccw_io_region *region; 2144f766173SCornelia Huck int ret; 215060d2b5aSDong Jia Shi 216db8e5d17SCornelia Huck if (pos + count > sizeof(*region)) 217060d2b5aSDong Jia Shi return -EINVAL; 218060d2b5aSDong Jia Shi 2194f766173SCornelia Huck mutex_lock(&private->io_mutex); 220c98e16b2SEric Farman region = private->io_region; 221db8e5d17SCornelia Huck if (copy_to_user(buf, (void *)region + pos, count)) 2224f766173SCornelia Huck ret = -EFAULT; 2234f766173SCornelia Huck else 2244f766173SCornelia Huck ret = count; 2254f766173SCornelia Huck mutex_unlock(&private->io_mutex); 2264f766173SCornelia Huck return ret; 227060d2b5aSDong Jia Shi } 228060d2b5aSDong Jia Shi 229db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev, 230db8e5d17SCornelia Huck char __user *buf, 231060d2b5aSDong Jia Shi size_t count, 232060d2b5aSDong Jia Shi loff_t *ppos) 233060d2b5aSDong Jia Shi { 234db8e5d17SCornelia Huck unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); 235060d2b5aSDong Jia Shi struct vfio_ccw_private *private; 236db8e5d17SCornelia Huck 237db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 238db8e5d17SCornelia Huck 239db8e5d17SCornelia Huck if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) 240db8e5d17SCornelia Huck return -EINVAL; 241db8e5d17SCornelia Huck 242db8e5d17SCornelia Huck switch (index) { 243db8e5d17SCornelia Huck case VFIO_CCW_CONFIG_REGION_INDEX: 244db8e5d17SCornelia Huck return vfio_ccw_mdev_read_io_region(private, buf, count, ppos); 245db8e5d17SCornelia Huck default: 246db8e5d17SCornelia Huck index -= VFIO_CCW_NUM_REGIONS; 247db8e5d17SCornelia Huck return private->region[index].ops->read(private, buf, count, 248db8e5d17SCornelia Huck ppos); 249db8e5d17SCornelia Huck } 250db8e5d17SCornelia Huck 251db8e5d17SCornelia Huck return -EINVAL; 252db8e5d17SCornelia Huck } 253db8e5d17SCornelia Huck 254db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private, 255db8e5d17SCornelia Huck const char __user *buf, 256db8e5d17SCornelia Huck size_t count, loff_t *ppos) 257db8e5d17SCornelia Huck { 258db8e5d17SCornelia Huck loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK; 259060d2b5aSDong Jia Shi struct ccw_io_region *region; 2604f766173SCornelia Huck int ret; 261060d2b5aSDong Jia Shi 262db8e5d17SCornelia Huck if (pos + count > sizeof(*region)) 263060d2b5aSDong Jia Shi return -EINVAL; 264060d2b5aSDong Jia Shi 2654f766173SCornelia Huck if (!mutex_trylock(&private->io_mutex)) 2664f766173SCornelia Huck return -EAGAIN; 267060d2b5aSDong Jia Shi 268c98e16b2SEric Farman region = private->io_region; 269db8e5d17SCornelia Huck if (copy_from_user((void *)region + pos, buf, count)) { 2704f766173SCornelia Huck ret = -EFAULT; 2714f766173SCornelia Huck goto out_unlock; 272bbe37e4cSDong Jia Shi } 273060d2b5aSDong Jia Shi 2744f766173SCornelia Huck vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ); 2754f766173SCornelia Huck if (region->ret_code != 0) 2764f766173SCornelia Huck private->state = VFIO_CCW_STATE_IDLE; 2774f766173SCornelia Huck ret = (region->ret_code != 0) ? region->ret_code : count; 2784f766173SCornelia Huck 2794f766173SCornelia Huck out_unlock: 2804f766173SCornelia Huck mutex_unlock(&private->io_mutex); 2814f766173SCornelia Huck return ret; 282060d2b5aSDong Jia Shi } 283060d2b5aSDong Jia Shi 284db8e5d17SCornelia Huck static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev, 285db8e5d17SCornelia Huck const char __user *buf, 286db8e5d17SCornelia Huck size_t count, 287db8e5d17SCornelia Huck loff_t *ppos) 288e01bcdd6SDong Jia Shi { 289db8e5d17SCornelia Huck unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); 290db8e5d17SCornelia Huck struct vfio_ccw_private *private; 291db8e5d17SCornelia Huck 292db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 293db8e5d17SCornelia Huck 294db8e5d17SCornelia Huck if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) 295db8e5d17SCornelia Huck return -EINVAL; 296db8e5d17SCornelia Huck 297db8e5d17SCornelia Huck switch (index) { 298db8e5d17SCornelia Huck case VFIO_CCW_CONFIG_REGION_INDEX: 299db8e5d17SCornelia Huck return vfio_ccw_mdev_write_io_region(private, buf, count, ppos); 300db8e5d17SCornelia Huck default: 301db8e5d17SCornelia Huck index -= VFIO_CCW_NUM_REGIONS; 302db8e5d17SCornelia Huck return private->region[index].ops->write(private, buf, count, 303db8e5d17SCornelia Huck ppos); 304db8e5d17SCornelia Huck } 305db8e5d17SCornelia Huck 306db8e5d17SCornelia Huck return -EINVAL; 307db8e5d17SCornelia Huck } 308db8e5d17SCornelia Huck 309db8e5d17SCornelia Huck static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info, 310db8e5d17SCornelia Huck struct mdev_device *mdev) 311db8e5d17SCornelia Huck { 312db8e5d17SCornelia Huck struct vfio_ccw_private *private; 313db8e5d17SCornelia Huck 314db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 31583d1193aSDong Jia Shi info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET; 316db8e5d17SCornelia Huck info->num_regions = VFIO_CCW_NUM_REGIONS + private->num_regions; 317120e214eSDong Jia Shi info->num_irqs = VFIO_CCW_NUM_IRQS; 318e01bcdd6SDong Jia Shi 319e01bcdd6SDong Jia Shi return 0; 320e01bcdd6SDong Jia Shi } 321e01bcdd6SDong Jia Shi 322e01bcdd6SDong Jia Shi static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info, 323db8e5d17SCornelia Huck struct mdev_device *mdev, 324db8e5d17SCornelia Huck unsigned long arg) 325e01bcdd6SDong Jia Shi { 326db8e5d17SCornelia Huck struct vfio_ccw_private *private; 327db8e5d17SCornelia Huck int i; 328db8e5d17SCornelia Huck 329db8e5d17SCornelia Huck private = dev_get_drvdata(mdev_parent_dev(mdev)); 330e01bcdd6SDong Jia Shi switch (info->index) { 331e01bcdd6SDong Jia Shi case VFIO_CCW_CONFIG_REGION_INDEX: 332e01bcdd6SDong Jia Shi info->offset = 0; 333e01bcdd6SDong Jia Shi info->size = sizeof(struct ccw_io_region); 334e01bcdd6SDong Jia Shi info->flags = VFIO_REGION_INFO_FLAG_READ 335e01bcdd6SDong Jia Shi | VFIO_REGION_INFO_FLAG_WRITE; 336e01bcdd6SDong Jia Shi return 0; 337db8e5d17SCornelia Huck default: /* all other regions are handled via capability chain */ 338db8e5d17SCornelia Huck { 339db8e5d17SCornelia Huck struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; 340db8e5d17SCornelia Huck struct vfio_region_info_cap_type cap_type = { 341db8e5d17SCornelia Huck .header.id = VFIO_REGION_INFO_CAP_TYPE, 342db8e5d17SCornelia Huck .header.version = 1 }; 343db8e5d17SCornelia Huck int ret; 344db8e5d17SCornelia Huck 345db8e5d17SCornelia Huck if (info->index >= 346db8e5d17SCornelia Huck VFIO_CCW_NUM_REGIONS + private->num_regions) 347e01bcdd6SDong Jia Shi return -EINVAL; 348db8e5d17SCornelia Huck 349db8e5d17SCornelia Huck info->index = array_index_nospec(info->index, 350db8e5d17SCornelia Huck VFIO_CCW_NUM_REGIONS + 351db8e5d17SCornelia Huck private->num_regions); 352db8e5d17SCornelia Huck 353db8e5d17SCornelia Huck i = info->index - VFIO_CCW_NUM_REGIONS; 354db8e5d17SCornelia Huck 355db8e5d17SCornelia Huck info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index); 356db8e5d17SCornelia Huck info->size = private->region[i].size; 357db8e5d17SCornelia Huck info->flags = private->region[i].flags; 358db8e5d17SCornelia Huck 359db8e5d17SCornelia Huck cap_type.type = private->region[i].type; 360db8e5d17SCornelia Huck cap_type.subtype = private->region[i].subtype; 361db8e5d17SCornelia Huck 362db8e5d17SCornelia Huck ret = vfio_info_add_capability(&caps, &cap_type.header, 363db8e5d17SCornelia Huck sizeof(cap_type)); 364db8e5d17SCornelia Huck if (ret) 365db8e5d17SCornelia Huck return ret; 366db8e5d17SCornelia Huck 367db8e5d17SCornelia Huck info->flags |= VFIO_REGION_INFO_FLAG_CAPS; 368db8e5d17SCornelia Huck if (info->argsz < sizeof(*info) + caps.size) { 369db8e5d17SCornelia Huck info->argsz = sizeof(*info) + caps.size; 370db8e5d17SCornelia Huck info->cap_offset = 0; 371db8e5d17SCornelia Huck } else { 372db8e5d17SCornelia Huck vfio_info_cap_shift(&caps, sizeof(*info)); 373db8e5d17SCornelia Huck if (copy_to_user((void __user *)arg + sizeof(*info), 374db8e5d17SCornelia Huck caps.buf, caps.size)) { 375db8e5d17SCornelia Huck kfree(caps.buf); 376db8e5d17SCornelia Huck return -EFAULT; 377e01bcdd6SDong Jia Shi } 378db8e5d17SCornelia Huck info->cap_offset = sizeof(*info); 379db8e5d17SCornelia Huck } 380db8e5d17SCornelia Huck 381db8e5d17SCornelia Huck kfree(caps.buf); 382db8e5d17SCornelia Huck 383db8e5d17SCornelia Huck } 384db8e5d17SCornelia Huck } 385db8e5d17SCornelia Huck return 0; 386e01bcdd6SDong Jia Shi } 387e01bcdd6SDong Jia Shi 3885bf18536SSebastian Ott static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info) 389120e214eSDong Jia Shi { 390*4296151dSEric Farman switch (info->index) { 391*4296151dSEric Farman case VFIO_CCW_IO_IRQ_INDEX: 392120e214eSDong Jia Shi info->count = 1; 393120e214eSDong Jia Shi info->flags = VFIO_IRQ_INFO_EVENTFD; 394*4296151dSEric Farman break; 395*4296151dSEric Farman default: 396*4296151dSEric Farman return -EINVAL; 397*4296151dSEric Farman } 398120e214eSDong Jia Shi 399120e214eSDong Jia Shi return 0; 400120e214eSDong Jia Shi } 401120e214eSDong Jia Shi 402120e214eSDong Jia Shi static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev, 403120e214eSDong Jia Shi uint32_t flags, 404*4296151dSEric Farman uint32_t index, 405120e214eSDong Jia Shi void __user *data) 406120e214eSDong Jia Shi { 407120e214eSDong Jia Shi struct vfio_ccw_private *private; 408120e214eSDong Jia Shi struct eventfd_ctx **ctx; 409120e214eSDong Jia Shi 410120e214eSDong Jia Shi if (!(flags & VFIO_IRQ_SET_ACTION_TRIGGER)) 411120e214eSDong Jia Shi return -EINVAL; 412120e214eSDong Jia Shi 413120e214eSDong Jia Shi private = dev_get_drvdata(mdev_parent_dev(mdev)); 414*4296151dSEric Farman 415*4296151dSEric Farman switch (index) { 416*4296151dSEric Farman case VFIO_CCW_IO_IRQ_INDEX: 417120e214eSDong Jia Shi ctx = &private->io_trigger; 418*4296151dSEric Farman break; 419*4296151dSEric Farman default: 420*4296151dSEric Farman return -EINVAL; 421*4296151dSEric Farman } 422120e214eSDong Jia Shi 423120e214eSDong Jia Shi switch (flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { 424120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_NONE: 425120e214eSDong Jia Shi { 426120e214eSDong Jia Shi if (*ctx) 427120e214eSDong Jia Shi eventfd_signal(*ctx, 1); 428120e214eSDong Jia Shi return 0; 429120e214eSDong Jia Shi } 430120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_BOOL: 431120e214eSDong Jia Shi { 432120e214eSDong Jia Shi uint8_t trigger; 433120e214eSDong Jia Shi 434120e214eSDong Jia Shi if (get_user(trigger, (uint8_t __user *)data)) 435120e214eSDong Jia Shi return -EFAULT; 436120e214eSDong Jia Shi 437120e214eSDong Jia Shi if (trigger && *ctx) 438120e214eSDong Jia Shi eventfd_signal(*ctx, 1); 439120e214eSDong Jia Shi return 0; 440120e214eSDong Jia Shi } 441120e214eSDong Jia Shi case VFIO_IRQ_SET_DATA_EVENTFD: 442120e214eSDong Jia Shi { 443120e214eSDong Jia Shi int32_t fd; 444120e214eSDong Jia Shi 445120e214eSDong Jia Shi if (get_user(fd, (int32_t __user *)data)) 446120e214eSDong Jia Shi return -EFAULT; 447120e214eSDong Jia Shi 448120e214eSDong Jia Shi if (fd == -1) { 449120e214eSDong Jia Shi if (*ctx) 450120e214eSDong Jia Shi eventfd_ctx_put(*ctx); 451120e214eSDong Jia Shi *ctx = NULL; 452120e214eSDong Jia Shi } else if (fd >= 0) { 453120e214eSDong Jia Shi struct eventfd_ctx *efdctx; 454120e214eSDong Jia Shi 455120e214eSDong Jia Shi efdctx = eventfd_ctx_fdget(fd); 456120e214eSDong Jia Shi if (IS_ERR(efdctx)) 457120e214eSDong Jia Shi return PTR_ERR(efdctx); 458120e214eSDong Jia Shi 459120e214eSDong Jia Shi if (*ctx) 460120e214eSDong Jia Shi eventfd_ctx_put(*ctx); 461120e214eSDong Jia Shi 462120e214eSDong Jia Shi *ctx = efdctx; 463120e214eSDong Jia Shi } else 464120e214eSDong Jia Shi return -EINVAL; 465120e214eSDong Jia Shi 466120e214eSDong Jia Shi return 0; 467120e214eSDong Jia Shi } 468120e214eSDong Jia Shi default: 469120e214eSDong Jia Shi return -EINVAL; 470120e214eSDong Jia Shi } 471120e214eSDong Jia Shi } 472120e214eSDong Jia Shi 473db8e5d17SCornelia Huck int vfio_ccw_register_dev_region(struct vfio_ccw_private *private, 474db8e5d17SCornelia Huck unsigned int subtype, 475db8e5d17SCornelia Huck const struct vfio_ccw_regops *ops, 476db8e5d17SCornelia Huck size_t size, u32 flags, void *data) 477db8e5d17SCornelia Huck { 478db8e5d17SCornelia Huck struct vfio_ccw_region *region; 479db8e5d17SCornelia Huck 480db8e5d17SCornelia Huck region = krealloc(private->region, 481db8e5d17SCornelia Huck (private->num_regions + 1) * sizeof(*region), 482db8e5d17SCornelia Huck GFP_KERNEL); 483db8e5d17SCornelia Huck if (!region) 484db8e5d17SCornelia Huck return -ENOMEM; 485db8e5d17SCornelia Huck 486db8e5d17SCornelia Huck private->region = region; 487db8e5d17SCornelia Huck private->region[private->num_regions].type = VFIO_REGION_TYPE_CCW; 488db8e5d17SCornelia Huck private->region[private->num_regions].subtype = subtype; 489db8e5d17SCornelia Huck private->region[private->num_regions].ops = ops; 490db8e5d17SCornelia Huck private->region[private->num_regions].size = size; 491db8e5d17SCornelia Huck private->region[private->num_regions].flags = flags; 492db8e5d17SCornelia Huck private->region[private->num_regions].data = data; 493db8e5d17SCornelia Huck 494db8e5d17SCornelia Huck private->num_regions++; 495db8e5d17SCornelia Huck 496db8e5d17SCornelia Huck return 0; 497db8e5d17SCornelia Huck } 498db8e5d17SCornelia Huck 499600279b5SEric Farman void vfio_ccw_unregister_dev_regions(struct vfio_ccw_private *private) 500600279b5SEric Farman { 501600279b5SEric Farman int i; 502600279b5SEric Farman 503600279b5SEric Farman for (i = 0; i < private->num_regions; i++) 504600279b5SEric Farman private->region[i].ops->release(private, &private->region[i]); 505600279b5SEric Farman private->num_regions = 0; 506600279b5SEric Farman kfree(private->region); 507600279b5SEric Farman private->region = NULL; 508600279b5SEric Farman } 509600279b5SEric Farman 510e01bcdd6SDong Jia Shi static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, 511e01bcdd6SDong Jia Shi unsigned int cmd, 512e01bcdd6SDong Jia Shi unsigned long arg) 513e01bcdd6SDong Jia Shi { 514e01bcdd6SDong Jia Shi int ret = 0; 515e01bcdd6SDong Jia Shi unsigned long minsz; 516e01bcdd6SDong Jia Shi 517e01bcdd6SDong Jia Shi switch (cmd) { 518e01bcdd6SDong Jia Shi case VFIO_DEVICE_GET_INFO: 519e01bcdd6SDong Jia Shi { 520e01bcdd6SDong Jia Shi struct vfio_device_info info; 521e01bcdd6SDong Jia Shi 522e01bcdd6SDong Jia Shi minsz = offsetofend(struct vfio_device_info, num_irqs); 523e01bcdd6SDong Jia Shi 524e01bcdd6SDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 525e01bcdd6SDong Jia Shi return -EFAULT; 526e01bcdd6SDong Jia Shi 527e01bcdd6SDong Jia Shi if (info.argsz < minsz) 528e01bcdd6SDong Jia Shi return -EINVAL; 529e01bcdd6SDong Jia Shi 530db8e5d17SCornelia Huck ret = vfio_ccw_mdev_get_device_info(&info, mdev); 531e01bcdd6SDong Jia Shi if (ret) 532e01bcdd6SDong Jia Shi return ret; 533e01bcdd6SDong Jia Shi 534e01bcdd6SDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 535e01bcdd6SDong Jia Shi } 536e01bcdd6SDong Jia Shi case VFIO_DEVICE_GET_REGION_INFO: 537e01bcdd6SDong Jia Shi { 538e01bcdd6SDong Jia Shi struct vfio_region_info info; 539e01bcdd6SDong Jia Shi 540e01bcdd6SDong Jia Shi minsz = offsetofend(struct vfio_region_info, offset); 541e01bcdd6SDong Jia Shi 542e01bcdd6SDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 543e01bcdd6SDong Jia Shi return -EFAULT; 544e01bcdd6SDong Jia Shi 545e01bcdd6SDong Jia Shi if (info.argsz < minsz) 546e01bcdd6SDong Jia Shi return -EINVAL; 547e01bcdd6SDong Jia Shi 548db8e5d17SCornelia Huck ret = vfio_ccw_mdev_get_region_info(&info, mdev, arg); 549e01bcdd6SDong Jia Shi if (ret) 550e01bcdd6SDong Jia Shi return ret; 551e01bcdd6SDong Jia Shi 552e01bcdd6SDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 553e01bcdd6SDong Jia Shi } 554120e214eSDong Jia Shi case VFIO_DEVICE_GET_IRQ_INFO: 555120e214eSDong Jia Shi { 556120e214eSDong Jia Shi struct vfio_irq_info info; 557120e214eSDong Jia Shi 558120e214eSDong Jia Shi minsz = offsetofend(struct vfio_irq_info, count); 559120e214eSDong Jia Shi 560120e214eSDong Jia Shi if (copy_from_user(&info, (void __user *)arg, minsz)) 561120e214eSDong Jia Shi return -EFAULT; 562120e214eSDong Jia Shi 563120e214eSDong Jia Shi if (info.argsz < minsz || info.index >= VFIO_CCW_NUM_IRQS) 564120e214eSDong Jia Shi return -EINVAL; 565120e214eSDong Jia Shi 566120e214eSDong Jia Shi ret = vfio_ccw_mdev_get_irq_info(&info); 567120e214eSDong Jia Shi if (ret) 568120e214eSDong Jia Shi return ret; 569120e214eSDong Jia Shi 570120e214eSDong Jia Shi if (info.count == -1) 571120e214eSDong Jia Shi return -EINVAL; 572120e214eSDong Jia Shi 573120e214eSDong Jia Shi return copy_to_user((void __user *)arg, &info, minsz); 574120e214eSDong Jia Shi } 575120e214eSDong Jia Shi case VFIO_DEVICE_SET_IRQS: 576120e214eSDong Jia Shi { 577120e214eSDong Jia Shi struct vfio_irq_set hdr; 578120e214eSDong Jia Shi size_t data_size; 579120e214eSDong Jia Shi void __user *data; 580120e214eSDong Jia Shi 581120e214eSDong Jia Shi minsz = offsetofend(struct vfio_irq_set, count); 582120e214eSDong Jia Shi 583120e214eSDong Jia Shi if (copy_from_user(&hdr, (void __user *)arg, minsz)) 584120e214eSDong Jia Shi return -EFAULT; 585120e214eSDong Jia Shi 586120e214eSDong Jia Shi ret = vfio_set_irqs_validate_and_prepare(&hdr, 1, 587120e214eSDong Jia Shi VFIO_CCW_NUM_IRQS, 588120e214eSDong Jia Shi &data_size); 589120e214eSDong Jia Shi if (ret) 590120e214eSDong Jia Shi return ret; 591120e214eSDong Jia Shi 592120e214eSDong Jia Shi data = (void __user *)(arg + minsz); 593*4296151dSEric Farman return vfio_ccw_mdev_set_irqs(mdev, hdr.flags, hdr.index, data); 594120e214eSDong Jia Shi } 59583d1193aSDong Jia Shi case VFIO_DEVICE_RESET: 59683d1193aSDong Jia Shi return vfio_ccw_mdev_reset(mdev); 597e01bcdd6SDong Jia Shi default: 598e01bcdd6SDong Jia Shi return -ENOTTY; 599e01bcdd6SDong Jia Shi } 600e01bcdd6SDong Jia Shi } 601e01bcdd6SDong Jia Shi 60284cd8fc4SDong Jia Shi static const struct mdev_parent_ops vfio_ccw_mdev_ops = { 60384cd8fc4SDong Jia Shi .owner = THIS_MODULE, 60484cd8fc4SDong Jia Shi .supported_type_groups = mdev_type_groups, 60584cd8fc4SDong Jia Shi .create = vfio_ccw_mdev_create, 60684cd8fc4SDong Jia Shi .remove = vfio_ccw_mdev_remove, 60784cd8fc4SDong Jia Shi .open = vfio_ccw_mdev_open, 60884cd8fc4SDong Jia Shi .release = vfio_ccw_mdev_release, 609060d2b5aSDong Jia Shi .read = vfio_ccw_mdev_read, 610060d2b5aSDong Jia Shi .write = vfio_ccw_mdev_write, 611e01bcdd6SDong Jia Shi .ioctl = vfio_ccw_mdev_ioctl, 61284cd8fc4SDong Jia Shi }; 61384cd8fc4SDong Jia Shi 61484cd8fc4SDong Jia Shi int vfio_ccw_mdev_reg(struct subchannel *sch) 61584cd8fc4SDong Jia Shi { 61684cd8fc4SDong Jia Shi return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops); 61784cd8fc4SDong Jia Shi } 61884cd8fc4SDong Jia Shi 61984cd8fc4SDong Jia Shi void vfio_ccw_mdev_unreg(struct subchannel *sch) 62084cd8fc4SDong Jia Shi { 62184cd8fc4SDong Jia Shi mdev_unregister_device(&sch->dev); 62284cd8fc4SDong Jia Shi } 623