1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * VFIO based AP device driver 4 * 5 * Copyright IBM Corp. 2018 6 * 7 * Author(s): Tony Krowiak <akrowiak@linux.ibm.com> 8 * Pierre Morel <pmorel@linux.ibm.com> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/mod_devicetable.h> 13 #include <linux/slab.h> 14 #include <linux/string.h> 15 #include <asm/facility.h> 16 #include "vfio_ap_private.h" 17 #include "vfio_ap_debug.h" 18 19 #define VFIO_AP_ROOT_NAME "vfio_ap" 20 #define VFIO_AP_DEV_NAME "matrix" 21 #define AP_QUEUE_ASSIGNED "assigned" 22 #define AP_QUEUE_UNASSIGNED "unassigned" 23 #define AP_QUEUE_IN_USE "in use" 24 25 MODULE_AUTHOR("IBM Corporation"); 26 MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018"); 27 MODULE_LICENSE("GPL v2"); 28 29 struct ap_matrix_dev *matrix_dev; 30 debug_info_t *vfio_ap_dbf_info; 31 32 /* Only type 10 adapters (CEX4 and later) are supported 33 * by the AP matrix device driver 34 */ 35 static struct ap_device_id ap_queue_ids[] = { 36 { .dev_type = AP_DEVICE_TYPE_CEX4, 37 .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, 38 { .dev_type = AP_DEVICE_TYPE_CEX5, 39 .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, 40 { .dev_type = AP_DEVICE_TYPE_CEX6, 41 .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, 42 { .dev_type = AP_DEVICE_TYPE_CEX7, 43 .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, 44 { .dev_type = AP_DEVICE_TYPE_CEX8, 45 .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, 46 { /* end of sibling */ }, 47 }; 48 49 MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids); 50 51 static struct ap_matrix_mdev *vfio_ap_mdev_for_queue(struct vfio_ap_queue *q) 52 { 53 struct ap_matrix_mdev *matrix_mdev; 54 unsigned long apid = AP_QID_CARD(q->apqn); 55 unsigned long apqi = AP_QID_QUEUE(q->apqn); 56 57 list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) { 58 if (test_bit_inv(apid, matrix_mdev->matrix.apm) && 59 test_bit_inv(apqi, matrix_mdev->matrix.aqm)) 60 return matrix_mdev; 61 } 62 63 return NULL; 64 } 65 66 static ssize_t status_show(struct device *dev, 67 struct device_attribute *attr, 68 char *buf) 69 { 70 ssize_t nchars = 0; 71 struct vfio_ap_queue *q; 72 struct ap_matrix_mdev *matrix_mdev; 73 struct ap_device *apdev = to_ap_dev(dev); 74 75 mutex_lock(&matrix_dev->lock); 76 q = dev_get_drvdata(&apdev->device); 77 matrix_mdev = vfio_ap_mdev_for_queue(q); 78 79 if (matrix_mdev) { 80 if (matrix_mdev->kvm) 81 nchars = scnprintf(buf, PAGE_SIZE, "%s\n", 82 AP_QUEUE_IN_USE); 83 else 84 nchars = scnprintf(buf, PAGE_SIZE, "%s\n", 85 AP_QUEUE_ASSIGNED); 86 } else { 87 nchars = scnprintf(buf, PAGE_SIZE, "%s\n", 88 AP_QUEUE_UNASSIGNED); 89 } 90 91 mutex_unlock(&matrix_dev->lock); 92 93 return nchars; 94 } 95 96 static DEVICE_ATTR_RO(status); 97 98 static struct attribute *vfio_queue_attrs[] = { 99 &dev_attr_status.attr, 100 NULL, 101 }; 102 103 static const struct attribute_group vfio_queue_attr_group = { 104 .attrs = vfio_queue_attrs, 105 }; 106 107 /** 108 * vfio_ap_queue_dev_probe: Allocate a vfio_ap_queue structure and associate it 109 * with the device as driver_data. 110 * 111 * @apdev: the AP device being probed 112 * 113 * Return: returns 0 if the probe succeeded; otherwise, returns an error if 114 * storage could not be allocated for a vfio_ap_queue object or the 115 * sysfs 'status' attribute could not be created for the queue device. 116 */ 117 static int vfio_ap_queue_dev_probe(struct ap_device *apdev) 118 { 119 int ret; 120 struct vfio_ap_queue *q; 121 122 q = kzalloc(sizeof(*q), GFP_KERNEL); 123 if (!q) 124 return -ENOMEM; 125 126 mutex_lock(&matrix_dev->lock); 127 dev_set_drvdata(&apdev->device, q); 128 q->apqn = to_ap_queue(&apdev->device)->qid; 129 q->saved_isc = VFIO_AP_ISC_INVALID; 130 131 ret = sysfs_create_group(&apdev->device.kobj, &vfio_queue_attr_group); 132 if (ret) { 133 dev_set_drvdata(&apdev->device, NULL); 134 kfree(q); 135 } 136 137 mutex_unlock(&matrix_dev->lock); 138 139 return ret; 140 } 141 142 /** 143 * vfio_ap_queue_dev_remove: Free the associated vfio_ap_queue structure. 144 * 145 * @apdev: the AP device being removed 146 * 147 * Takes the matrix lock to avoid actions on this device while doing the remove. 148 */ 149 static void vfio_ap_queue_dev_remove(struct ap_device *apdev) 150 { 151 struct vfio_ap_queue *q; 152 153 mutex_lock(&matrix_dev->lock); 154 sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group); 155 q = dev_get_drvdata(&apdev->device); 156 vfio_ap_mdev_reset_queue(q, 1); 157 dev_set_drvdata(&apdev->device, NULL); 158 kfree(q); 159 mutex_unlock(&matrix_dev->lock); 160 } 161 162 static struct ap_driver vfio_ap_drv = { 163 .probe = vfio_ap_queue_dev_probe, 164 .remove = vfio_ap_queue_dev_remove, 165 .ids = ap_queue_ids, 166 }; 167 168 static void vfio_ap_matrix_dev_release(struct device *dev) 169 { 170 struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev); 171 172 kfree(matrix_dev); 173 } 174 175 static int matrix_bus_match(struct device *dev, struct device_driver *drv) 176 { 177 return 1; 178 } 179 180 static struct bus_type matrix_bus = { 181 .name = "matrix", 182 .match = &matrix_bus_match, 183 }; 184 185 static struct device_driver matrix_driver = { 186 .name = "vfio_ap", 187 .bus = &matrix_bus, 188 .suppress_bind_attrs = true, 189 }; 190 191 static int vfio_ap_matrix_dev_create(void) 192 { 193 int ret; 194 struct device *root_device; 195 196 root_device = root_device_register(VFIO_AP_ROOT_NAME); 197 if (IS_ERR(root_device)) 198 return PTR_ERR(root_device); 199 200 ret = bus_register(&matrix_bus); 201 if (ret) 202 goto bus_register_err; 203 204 matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL); 205 if (!matrix_dev) { 206 ret = -ENOMEM; 207 goto matrix_alloc_err; 208 } 209 210 /* Fill in config info via PQAP(QCI), if available */ 211 if (test_facility(12)) { 212 ret = ap_qci(&matrix_dev->info); 213 if (ret) 214 goto matrix_alloc_err; 215 } 216 217 mutex_init(&matrix_dev->lock); 218 INIT_LIST_HEAD(&matrix_dev->mdev_list); 219 220 dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); 221 matrix_dev->device.parent = root_device; 222 matrix_dev->device.bus = &matrix_bus; 223 matrix_dev->device.release = vfio_ap_matrix_dev_release; 224 matrix_dev->vfio_ap_drv = &vfio_ap_drv; 225 226 ret = device_register(&matrix_dev->device); 227 if (ret) 228 goto matrix_reg_err; 229 230 ret = driver_register(&matrix_driver); 231 if (ret) 232 goto matrix_drv_err; 233 234 return 0; 235 236 matrix_drv_err: 237 device_unregister(&matrix_dev->device); 238 matrix_reg_err: 239 put_device(&matrix_dev->device); 240 matrix_alloc_err: 241 bus_unregister(&matrix_bus); 242 bus_register_err: 243 root_device_unregister(root_device); 244 return ret; 245 } 246 247 static void vfio_ap_matrix_dev_destroy(void) 248 { 249 struct device *root_device = matrix_dev->device.parent; 250 251 driver_unregister(&matrix_driver); 252 device_unregister(&matrix_dev->device); 253 bus_unregister(&matrix_bus); 254 root_device_unregister(root_device); 255 } 256 257 static int __init vfio_ap_dbf_info_init(void) 258 { 259 vfio_ap_dbf_info = debug_register("vfio_ap", 1, 1, 260 DBF_MAX_SPRINTF_ARGS * sizeof(long)); 261 262 if (!vfio_ap_dbf_info) 263 return -ENOENT; 264 265 debug_register_view(vfio_ap_dbf_info, &debug_sprintf_view); 266 debug_set_level(vfio_ap_dbf_info, DBF_WARN); 267 268 return 0; 269 } 270 271 static int __init vfio_ap_init(void) 272 { 273 int ret; 274 275 ret = vfio_ap_dbf_info_init(); 276 if (ret) 277 return ret; 278 279 /* If there are no AP instructions, there is nothing to pass through. */ 280 if (!ap_instructions_available()) 281 return -ENODEV; 282 283 ret = vfio_ap_matrix_dev_create(); 284 if (ret) 285 return ret; 286 287 ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME); 288 if (ret) { 289 vfio_ap_matrix_dev_destroy(); 290 return ret; 291 } 292 293 ret = vfio_ap_mdev_register(); 294 if (ret) { 295 ap_driver_unregister(&vfio_ap_drv); 296 vfio_ap_matrix_dev_destroy(); 297 298 return ret; 299 } 300 301 return 0; 302 } 303 304 static void __exit vfio_ap_exit(void) 305 { 306 vfio_ap_mdev_unregister(); 307 ap_driver_unregister(&vfio_ap_drv); 308 vfio_ap_matrix_dev_destroy(); 309 debug_unregister(vfio_ap_dbf_info); 310 } 311 312 module_init(vfio_ap_init); 313 module_exit(vfio_ap_exit); 314