Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * VFIO based AP device driver
0004  *
0005  * Copyright IBM Corp. 2018
0006  *
0007  * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
0008  *        Pierre Morel <pmorel@linux.ibm.com>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/slab.h>
0014 #include <linux/string.h>
0015 #include <asm/facility.h>
0016 #include "vfio_ap_private.h"
0017 #include "vfio_ap_debug.h"
0018 
0019 #define VFIO_AP_ROOT_NAME "vfio_ap"
0020 #define VFIO_AP_DEV_NAME "matrix"
0021 
0022 MODULE_AUTHOR("IBM Corporation");
0023 MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
0024 MODULE_LICENSE("GPL v2");
0025 
0026 struct ap_matrix_dev *matrix_dev;
0027 debug_info_t *vfio_ap_dbf_info;
0028 
0029 /* Only type 10 adapters (CEX4 and later) are supported
0030  * by the AP matrix device driver
0031  */
0032 static struct ap_device_id ap_queue_ids[] = {
0033     { .dev_type = AP_DEVICE_TYPE_CEX4,
0034       .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
0035     { .dev_type = AP_DEVICE_TYPE_CEX5,
0036       .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
0037     { .dev_type = AP_DEVICE_TYPE_CEX6,
0038       .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
0039     { .dev_type = AP_DEVICE_TYPE_CEX7,
0040       .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
0041     { .dev_type = AP_DEVICE_TYPE_CEX8,
0042       .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
0043     { /* end of sibling */ },
0044 };
0045 
0046 static struct ap_driver vfio_ap_drv = {
0047     .probe = vfio_ap_mdev_probe_queue,
0048     .remove = vfio_ap_mdev_remove_queue,
0049     .in_use = vfio_ap_mdev_resource_in_use,
0050     .on_config_changed = vfio_ap_on_cfg_changed,
0051     .on_scan_complete = vfio_ap_on_scan_complete,
0052     .ids = ap_queue_ids,
0053 };
0054 
0055 static void vfio_ap_matrix_dev_release(struct device *dev)
0056 {
0057     struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
0058 
0059     kfree(matrix_dev);
0060 }
0061 
0062 static int matrix_bus_match(struct device *dev, struct device_driver *drv)
0063 {
0064     return 1;
0065 }
0066 
0067 static struct bus_type matrix_bus = {
0068     .name = "matrix",
0069     .match = &matrix_bus_match,
0070 };
0071 
0072 static struct device_driver matrix_driver = {
0073     .name = "vfio_ap",
0074     .bus = &matrix_bus,
0075     .suppress_bind_attrs = true,
0076 };
0077 
0078 static int vfio_ap_matrix_dev_create(void)
0079 {
0080     int ret;
0081     struct device *root_device;
0082 
0083     root_device = root_device_register(VFIO_AP_ROOT_NAME);
0084     if (IS_ERR(root_device))
0085         return PTR_ERR(root_device);
0086 
0087     ret = bus_register(&matrix_bus);
0088     if (ret)
0089         goto bus_register_err;
0090 
0091     matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
0092     if (!matrix_dev) {
0093         ret = -ENOMEM;
0094         goto matrix_alloc_err;
0095     }
0096 
0097     /* Fill in config info via PQAP(QCI), if available */
0098     if (test_facility(12)) {
0099         ret = ap_qci(&matrix_dev->info);
0100         if (ret)
0101             goto matrix_alloc_err;
0102     }
0103 
0104     mutex_init(&matrix_dev->mdevs_lock);
0105     INIT_LIST_HEAD(&matrix_dev->mdev_list);
0106     mutex_init(&matrix_dev->guests_lock);
0107 
0108     dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
0109     matrix_dev->device.parent = root_device;
0110     matrix_dev->device.bus = &matrix_bus;
0111     matrix_dev->device.release = vfio_ap_matrix_dev_release;
0112     matrix_dev->vfio_ap_drv = &vfio_ap_drv;
0113 
0114     ret = device_register(&matrix_dev->device);
0115     if (ret)
0116         goto matrix_reg_err;
0117 
0118     ret = driver_register(&matrix_driver);
0119     if (ret)
0120         goto matrix_drv_err;
0121 
0122     return 0;
0123 
0124 matrix_drv_err:
0125     device_unregister(&matrix_dev->device);
0126 matrix_reg_err:
0127     put_device(&matrix_dev->device);
0128 matrix_alloc_err:
0129     bus_unregister(&matrix_bus);
0130 bus_register_err:
0131     root_device_unregister(root_device);
0132     return ret;
0133 }
0134 
0135 static void vfio_ap_matrix_dev_destroy(void)
0136 {
0137     struct device *root_device = matrix_dev->device.parent;
0138 
0139     driver_unregister(&matrix_driver);
0140     device_unregister(&matrix_dev->device);
0141     bus_unregister(&matrix_bus);
0142     root_device_unregister(root_device);
0143 }
0144 
0145 static int __init vfio_ap_dbf_info_init(void)
0146 {
0147     vfio_ap_dbf_info = debug_register("vfio_ap", 1, 1,
0148                       DBF_MAX_SPRINTF_ARGS * sizeof(long));
0149 
0150     if (!vfio_ap_dbf_info)
0151         return -ENOENT;
0152 
0153     debug_register_view(vfio_ap_dbf_info, &debug_sprintf_view);
0154     debug_set_level(vfio_ap_dbf_info, DBF_WARN);
0155 
0156     return 0;
0157 }
0158 
0159 static int __init vfio_ap_init(void)
0160 {
0161     int ret;
0162 
0163     ret = vfio_ap_dbf_info_init();
0164     if (ret)
0165         return ret;
0166 
0167     /* If there are no AP instructions, there is nothing to pass through. */
0168     if (!ap_instructions_available())
0169         return -ENODEV;
0170 
0171     ret = vfio_ap_matrix_dev_create();
0172     if (ret)
0173         return ret;
0174 
0175     ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);
0176     if (ret) {
0177         vfio_ap_matrix_dev_destroy();
0178         return ret;
0179     }
0180 
0181     ret = vfio_ap_mdev_register();
0182     if (ret) {
0183         ap_driver_unregister(&vfio_ap_drv);
0184         vfio_ap_matrix_dev_destroy();
0185 
0186         return ret;
0187     }
0188 
0189     return 0;
0190 }
0191 
0192 static void __exit vfio_ap_exit(void)
0193 {
0194     vfio_ap_mdev_unregister();
0195     ap_driver_unregister(&vfio_ap_drv);
0196     vfio_ap_matrix_dev_destroy();
0197     debug_unregister(vfio_ap_dbf_info);
0198 }
0199 
0200 module_init(vfio_ap_init);
0201 module_exit(vfio_ap_exit);