Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfio: ccw: register vfio_ccw to the mediated device framework

To make vfio support subchannel devices, we need to leverage the
mediated device framework to create a mediated device for the
subchannel device.

This registers the subchannel device to the mediated device
framework during probe to enable mediated device creation.

Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Message-Id: <20170317031743.40128-7-bjsdjshi@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>

authored by

Dong Jia Shi and committed by
Cornelia Huck
84cd8fc4 0a19e61e

+171 -3
+1 -1
arch/s390/Kconfig
··· 675 675 config VFIO_CCW 676 676 def_tristate n 677 677 prompt "Support for VFIO-CCW subchannels" 678 - depends on S390_CCW_IOMMU && VFIO 678 + depends on S390_CCW_IOMMU && VFIO_MDEV 679 679 help 680 680 This driver allows usage of I/O subchannels via VFIO-CCW. 681 681
+1 -1
drivers/s390/cio/Makefile
··· 18 18 qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o 19 19 obj-$(CONFIG_QDIO) += qdio.o 20 20 21 - vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o 21 + vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o 22 22 obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o
+11 -1
drivers/s390/cio/vfio_ccw_drv.c
··· 19 19 /* 20 20 * Helpers 21 21 */ 22 - static int vfio_ccw_sch_quiesce(struct subchannel *sch) 22 + int vfio_ccw_sch_quiesce(struct subchannel *sch) 23 23 { 24 24 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 25 25 DECLARE_COMPLETION_ONSTACK(completion); ··· 152 152 if (ret) 153 153 goto out_disable; 154 154 155 + ret = vfio_ccw_mdev_reg(sch); 156 + if (ret) 157 + goto out_rm_group; 158 + 159 + atomic_set(&private->avail, 1); 160 + 155 161 return 0; 156 162 163 + out_rm_group: 164 + sysfs_remove_group(&sch->dev.kobj, &vfio_subchannel_attr_group); 157 165 out_disable: 158 166 cio_disable_subchannel(sch); 159 167 out_free: ··· 175 167 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 176 168 177 169 vfio_ccw_sch_quiesce(sch); 170 + 171 + vfio_ccw_mdev_unreg(sch); 178 172 179 173 sysfs_remove_group(&sch->dev.kobj, &vfio_subchannel_attr_group); 180 174
+147
drivers/s390/cio/vfio_ccw_ops.c
··· 1 + /* 2 + * Physical device callbacks for vfio_ccw 3 + * 4 + * Copyright IBM Corp. 2017 5 + * 6 + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> 7 + * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> 8 + */ 9 + 10 + #include <linux/vfio.h> 11 + #include <linux/mdev.h> 12 + 13 + #include "vfio_ccw_private.h" 14 + 15 + static int vfio_ccw_mdev_notifier(struct notifier_block *nb, 16 + unsigned long action, 17 + void *data) 18 + { 19 + struct vfio_ccw_private *private = 20 + container_of(nb, struct vfio_ccw_private, nb); 21 + 22 + if (!private) 23 + return NOTIFY_STOP; 24 + 25 + /* 26 + * TODO: 27 + * Vendor drivers MUST unpin pages in response to an 28 + * invalidation. 29 + */ 30 + if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) 31 + return NOTIFY_BAD; 32 + 33 + return NOTIFY_DONE; 34 + } 35 + 36 + static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf) 37 + { 38 + return sprintf(buf, "I/O subchannel (Non-QDIO)\n"); 39 + } 40 + MDEV_TYPE_ATTR_RO(name); 41 + 42 + static ssize_t device_api_show(struct kobject *kobj, struct device *dev, 43 + char *buf) 44 + { 45 + return sprintf(buf, "%s\n", VFIO_DEVICE_API_CCW_STRING); 46 + } 47 + MDEV_TYPE_ATTR_RO(device_api); 48 + 49 + static ssize_t available_instances_show(struct kobject *kobj, 50 + struct device *dev, char *buf) 51 + { 52 + struct vfio_ccw_private *private = dev_get_drvdata(dev); 53 + 54 + return sprintf(buf, "%d\n", atomic_read(&private->avail)); 55 + } 56 + MDEV_TYPE_ATTR_RO(available_instances); 57 + 58 + static struct attribute *mdev_types_attrs[] = { 59 + &mdev_type_attr_name.attr, 60 + &mdev_type_attr_device_api.attr, 61 + &mdev_type_attr_available_instances.attr, 62 + NULL, 63 + }; 64 + 65 + static struct attribute_group mdev_type_group = { 66 + .name = "io", 67 + .attrs = mdev_types_attrs, 68 + }; 69 + 70 + struct attribute_group *mdev_type_groups[] = { 71 + &mdev_type_group, 72 + NULL, 73 + }; 74 + 75 + static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) 76 + { 77 + struct vfio_ccw_private *private = 78 + dev_get_drvdata(mdev_parent_dev(mdev)); 79 + 80 + if (atomic_dec_if_positive(&private->avail) < 0) 81 + return -EPERM; 82 + 83 + private->mdev = mdev; 84 + 85 + return 0; 86 + } 87 + 88 + static int vfio_ccw_mdev_remove(struct mdev_device *mdev) 89 + { 90 + struct vfio_ccw_private *private; 91 + struct subchannel *sch; 92 + int ret; 93 + 94 + private = dev_get_drvdata(mdev_parent_dev(mdev)); 95 + sch = private->sch; 96 + ret = vfio_ccw_sch_quiesce(sch); 97 + if (ret) 98 + return ret; 99 + ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); 100 + if (ret) 101 + return ret; 102 + 103 + private->mdev = NULL; 104 + atomic_inc(&private->avail); 105 + 106 + return 0; 107 + } 108 + 109 + static int vfio_ccw_mdev_open(struct mdev_device *mdev) 110 + { 111 + struct vfio_ccw_private *private = 112 + dev_get_drvdata(mdev_parent_dev(mdev)); 113 + unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; 114 + 115 + private->nb.notifier_call = vfio_ccw_mdev_notifier; 116 + 117 + return vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 118 + &events, &private->nb); 119 + } 120 + 121 + void vfio_ccw_mdev_release(struct mdev_device *mdev) 122 + { 123 + struct vfio_ccw_private *private = 124 + dev_get_drvdata(mdev_parent_dev(mdev)); 125 + 126 + vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, 127 + &private->nb); 128 + } 129 + 130 + static const struct mdev_parent_ops vfio_ccw_mdev_ops = { 131 + .owner = THIS_MODULE, 132 + .supported_type_groups = mdev_type_groups, 133 + .create = vfio_ccw_mdev_create, 134 + .remove = vfio_ccw_mdev_remove, 135 + .open = vfio_ccw_mdev_open, 136 + .release = vfio_ccw_mdev_release, 137 + }; 138 + 139 + int vfio_ccw_mdev_reg(struct subchannel *sch) 140 + { 141 + return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops); 142 + } 143 + 144 + void vfio_ccw_mdev_unreg(struct subchannel *sch) 145 + { 146 + mdev_unregister_device(&sch->dev); 147 + }
+11
drivers/s390/cio/vfio_ccw_private.h
··· 16 16 * struct vfio_ccw_private 17 17 * @sch: pointer to the subchannel 18 18 * @completion: synchronization helper of the I/O completion 19 + * @avail: available for creating a mediated device 20 + * @mdev: pointer to the mediated device 21 + * @nb: notifier for vfio events 19 22 */ 20 23 struct vfio_ccw_private { 21 24 struct subchannel *sch; 22 25 struct completion *completion; 26 + atomic_t avail; 27 + struct mdev_device *mdev; 28 + struct notifier_block nb; 23 29 } __aligned(8); 30 + 31 + extern int vfio_ccw_mdev_reg(struct subchannel *sch); 32 + extern void vfio_ccw_mdev_unreg(struct subchannel *sch); 33 + 34 + extern int vfio_ccw_sch_quiesce(struct subchannel *sch); 24 35 25 36 #endif