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

vfio: ccw: basic implementation for vfio_ccw driver

To make vfio support subchannel devices, we need a css driver for
the vfio subchannels. This patch adds a basic vfio-ccw subchannel
driver for this purpose.

To enable VFIO for vfio-ccw, enable S390_CCW_IOMMU config option
and configure VFIO as required.

Acked-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Message-Id: <20170317031743.40128-5-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
63f1934d aec390b9

+309
+10
arch/s390/Kconfig
··· 672 672 To compile this driver as a module, choose M here: the 673 673 module will be called eadm_sch. 674 674 675 + config VFIO_CCW 676 + def_tristate n 677 + prompt "Support for VFIO-CCW subchannels" 678 + depends on S390_CCW_IOMMU && VFIO 679 + help 680 + This driver allows usage of I/O subchannels via VFIO-CCW. 681 + 682 + To compile this driver as a module, choose M here: the 683 + module will be called vfio_ccw. 684 + 675 685 endmenu 676 686 677 687 menu "Dump support"
+1
arch/s390/include/asm/isc.h
··· 16 16 #define CONSOLE_ISC 1 /* console I/O subchannel */ 17 17 #define EADM_SCH_ISC 4 /* EADM subchannels */ 18 18 #define CHSC_SCH_ISC 7 /* CHSC subchannels */ 19 + #define VFIO_CCW_ISC IO_SCH_ISC /* VFIO-CCW I/O subchannels */ 19 20 /* Adapter interrupts. */ 20 21 #define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ 21 22 #define PCI_ISC 2 /* PCI I/O subchannels */
+8
drivers/iommu/Kconfig
··· 327 327 help 328 328 Support for the IOMMU API for s390 PCI devices. 329 329 330 + config S390_CCW_IOMMU 331 + bool "S390 CCW IOMMU Support" 332 + depends on S390 && CCW 333 + select IOMMU_API 334 + help 335 + Enables bits of IOMMU API required by VFIO. The iommu_ops 336 + is not implemented as it is not necessary for VFIO. 337 + 330 338 config MTK_IOMMU 331 339 bool "MTK IOMMU Support" 332 340 depends on ARM || ARM64
+3
drivers/s390/cio/Makefile
··· 17 17 18 18 qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o 19 19 obj-$(CONFIG_QDIO) += qdio.o 20 + 21 + vfio_ccw-objs += vfio_ccw_drv.o 22 + obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o
+262
drivers/s390/cio/vfio_ccw_drv.c
··· 1 + /* 2 + * VFIO based Physical Subchannel device driver 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/module.h> 11 + #include <linux/init.h> 12 + #include <linux/device.h> 13 + #include <linux/slab.h> 14 + 15 + #include <asm/isc.h> 16 + 17 + #include "vfio_ccw_private.h" 18 + 19 + /* 20 + * Helpers 21 + */ 22 + static int vfio_ccw_sch_quiesce(struct subchannel *sch) 23 + { 24 + struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 25 + DECLARE_COMPLETION_ONSTACK(completion); 26 + int iretry, ret = 0; 27 + 28 + spin_lock_irq(sch->lock); 29 + if (!sch->schib.pmcw.ena) 30 + goto out_unlock; 31 + ret = cio_disable_subchannel(sch); 32 + if (ret != -EBUSY) 33 + goto out_unlock; 34 + 35 + do { 36 + iretry = 255; 37 + 38 + ret = cio_cancel_halt_clear(sch, &iretry); 39 + while (ret == -EBUSY) { 40 + /* 41 + * Flush all I/O and wait for 42 + * cancel/halt/clear completion. 43 + */ 44 + private->completion = &completion; 45 + spin_unlock_irq(sch->lock); 46 + 47 + wait_for_completion_timeout(&completion, 3*HZ); 48 + 49 + spin_lock_irq(sch->lock); 50 + private->completion = NULL; 51 + ret = cio_cancel_halt_clear(sch, &iretry); 52 + }; 53 + 54 + ret = cio_disable_subchannel(sch); 55 + } while (ret == -EBUSY); 56 + 57 + out_unlock: 58 + spin_unlock_irq(sch->lock); 59 + return ret; 60 + } 61 + 62 + /* 63 + * Sysfs interfaces 64 + */ 65 + static ssize_t chpids_show(struct device *dev, 66 + struct device_attribute *attr, 67 + char *buf) 68 + { 69 + struct subchannel *sch = to_subchannel(dev); 70 + struct chsc_ssd_info *ssd = &sch->ssd_info; 71 + ssize_t ret = 0; 72 + int chp; 73 + int mask; 74 + 75 + for (chp = 0; chp < 8; chp++) { 76 + mask = 0x80 >> chp; 77 + if (ssd->path_mask & mask) 78 + ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id); 79 + else 80 + ret += sprintf(buf + ret, "00 "); 81 + } 82 + ret += sprintf(buf+ret, "\n"); 83 + return ret; 84 + } 85 + 86 + static ssize_t pimpampom_show(struct device *dev, 87 + struct device_attribute *attr, 88 + char *buf) 89 + { 90 + struct subchannel *sch = to_subchannel(dev); 91 + struct pmcw *pmcw = &sch->schib.pmcw; 92 + 93 + return sprintf(buf, "%02x %02x %02x\n", 94 + pmcw->pim, pmcw->pam, pmcw->pom); 95 + } 96 + 97 + static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); 98 + static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); 99 + 100 + static struct attribute *vfio_subchannel_attrs[] = { 101 + &dev_attr_chpids.attr, 102 + &dev_attr_pimpampom.attr, 103 + NULL, 104 + }; 105 + 106 + static struct attribute_group vfio_subchannel_attr_group = { 107 + .attrs = vfio_subchannel_attrs, 108 + }; 109 + 110 + /* 111 + * Css driver callbacks 112 + */ 113 + static void vfio_ccw_sch_irq(struct subchannel *sch) 114 + { 115 + struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 116 + 117 + inc_irq_stat(IRQIO_CIO); 118 + 119 + if (!private) 120 + return; 121 + 122 + if (private->completion) 123 + complete(private->completion); 124 + } 125 + 126 + static int vfio_ccw_sch_probe(struct subchannel *sch) 127 + { 128 + struct pmcw *pmcw = &sch->schib.pmcw; 129 + struct vfio_ccw_private *private; 130 + int ret; 131 + 132 + if (pmcw->qf) { 133 + dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n", 134 + dev_name(&sch->dev)); 135 + return -ENODEV; 136 + } 137 + 138 + private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); 139 + if (!private) 140 + return -ENOMEM; 141 + private->sch = sch; 142 + dev_set_drvdata(&sch->dev, private); 143 + 144 + spin_lock_irq(sch->lock); 145 + sch->isc = VFIO_CCW_ISC; 146 + ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); 147 + spin_unlock_irq(sch->lock); 148 + if (ret) 149 + goto out_free; 150 + 151 + ret = sysfs_create_group(&sch->dev.kobj, &vfio_subchannel_attr_group); 152 + if (ret) 153 + goto out_disable; 154 + 155 + return 0; 156 + 157 + out_disable: 158 + cio_disable_subchannel(sch); 159 + out_free: 160 + dev_set_drvdata(&sch->dev, NULL); 161 + kfree(private); 162 + return ret; 163 + } 164 + 165 + static int vfio_ccw_sch_remove(struct subchannel *sch) 166 + { 167 + struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 168 + 169 + vfio_ccw_sch_quiesce(sch); 170 + 171 + sysfs_remove_group(&sch->dev.kobj, &vfio_subchannel_attr_group); 172 + 173 + dev_set_drvdata(&sch->dev, NULL); 174 + 175 + kfree(private); 176 + 177 + return 0; 178 + } 179 + 180 + static void vfio_ccw_sch_shutdown(struct subchannel *sch) 181 + { 182 + vfio_ccw_sch_quiesce(sch); 183 + } 184 + 185 + /** 186 + * vfio_ccw_sch_event - process subchannel event 187 + * @sch: subchannel 188 + * @process: non-zero if function is called in process context 189 + * 190 + * An unspecified event occurred for this subchannel. Adjust data according 191 + * to the current operational state of the subchannel. Return zero when the 192 + * event has been handled sufficiently or -EAGAIN when this function should 193 + * be called again in process context. 194 + */ 195 + static int vfio_ccw_sch_event(struct subchannel *sch, int process) 196 + { 197 + unsigned long flags; 198 + 199 + spin_lock_irqsave(sch->lock, flags); 200 + if (!device_is_registered(&sch->dev)) 201 + goto out_unlock; 202 + 203 + if (work_pending(&sch->todo_work)) 204 + goto out_unlock; 205 + 206 + if (cio_update_schib(sch)) { 207 + /* Not operational. */ 208 + css_sched_sch_todo(sch, SCH_TODO_UNREG); 209 + 210 + /* 211 + * TODO: 212 + * Probably we should send the machine check to the guest. 213 + */ 214 + goto out_unlock; 215 + } 216 + 217 + out_unlock: 218 + spin_unlock_irqrestore(sch->lock, flags); 219 + 220 + return 0; 221 + } 222 + 223 + static struct css_device_id vfio_ccw_sch_ids[] = { 224 + { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, 225 + { /* end of list */ }, 226 + }; 227 + MODULE_DEVICE_TABLE(css, vfio_ccw_sch_ids); 228 + 229 + static struct css_driver vfio_ccw_sch_driver = { 230 + .drv = { 231 + .name = "vfio_ccw", 232 + .owner = THIS_MODULE, 233 + }, 234 + .subchannel_type = vfio_ccw_sch_ids, 235 + .irq = vfio_ccw_sch_irq, 236 + .probe = vfio_ccw_sch_probe, 237 + .remove = vfio_ccw_sch_remove, 238 + .shutdown = vfio_ccw_sch_shutdown, 239 + .sch_event = vfio_ccw_sch_event, 240 + }; 241 + 242 + static int __init vfio_ccw_sch_init(void) 243 + { 244 + int ret; 245 + 246 + isc_register(VFIO_CCW_ISC); 247 + ret = css_driver_register(&vfio_ccw_sch_driver); 248 + if (ret) 249 + isc_unregister(VFIO_CCW_ISC); 250 + 251 + return ret; 252 + } 253 + 254 + static void __exit vfio_ccw_sch_exit(void) 255 + { 256 + css_driver_unregister(&vfio_ccw_sch_driver); 257 + isc_unregister(VFIO_CCW_ISC); 258 + } 259 + module_init(vfio_ccw_sch_init); 260 + module_exit(vfio_ccw_sch_exit); 261 + 262 + MODULE_LICENSE("GPL v2");
+25
drivers/s390/cio/vfio_ccw_private.h
··· 1 + /* 2 + * Private stuff for vfio_ccw driver 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 + #ifndef _VFIO_CCW_PRIVATE_H_ 11 + #define _VFIO_CCW_PRIVATE_H_ 12 + 13 + #include "css.h" 14 + 15 + /** 16 + * struct vfio_ccw_private 17 + * @sch: pointer to the subchannel 18 + * @completion: synchronization helper of the I/O completion 19 + */ 20 + struct vfio_ccw_private { 21 + struct subchannel *sch; 22 + struct completion *completion; 23 + } __aligned(8); 24 + 25 + #endif