root/drivers/s390/crypto/vfio_ap_drv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vfio_ap_queue_dev_probe
  2. vfio_ap_queue_dev_remove
  3. vfio_ap_matrix_dev_release
  4. matrix_bus_match
  5. vfio_ap_matrix_dev_create
  6. vfio_ap_matrix_dev_destroy
  7. vfio_ap_init
  8. vfio_ap_exit

   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 
  18 #define VFIO_AP_ROOT_NAME "vfio_ap"
  19 #define VFIO_AP_DEV_NAME "matrix"
  20 
  21 MODULE_AUTHOR("IBM Corporation");
  22 MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
  23 MODULE_LICENSE("GPL v2");
  24 
  25 static struct ap_driver vfio_ap_drv;
  26 
  27 struct ap_matrix_dev *matrix_dev;
  28 
  29 /* Only type 10 adapters (CEX4 and later) are supported
  30  * by the AP matrix device driver
  31  */
  32 static struct ap_device_id ap_queue_ids[] = {
  33         { .dev_type = AP_DEVICE_TYPE_CEX4,
  34           .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  35         { .dev_type = AP_DEVICE_TYPE_CEX5,
  36           .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  37         { .dev_type = AP_DEVICE_TYPE_CEX6,
  38           .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  39         { .dev_type = AP_DEVICE_TYPE_CEX7,
  40           .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  41         { /* end of sibling */ },
  42 };
  43 
  44 MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
  45 
  46 /**
  47  * vfio_ap_queue_dev_probe:
  48  *
  49  * Allocate a vfio_ap_queue structure and associate it
  50  * with the device as driver_data.
  51  */
  52 static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
  53 {
  54         struct vfio_ap_queue *q;
  55 
  56         q = kzalloc(sizeof(*q), GFP_KERNEL);
  57         if (!q)
  58                 return -ENOMEM;
  59         dev_set_drvdata(&apdev->device, q);
  60         q->apqn = to_ap_queue(&apdev->device)->qid;
  61         q->saved_isc = VFIO_AP_ISC_INVALID;
  62         return 0;
  63 }
  64 
  65 /**
  66  * vfio_ap_queue_dev_remove:
  67  *
  68  * Takes the matrix lock to avoid actions on this device while removing
  69  * Free the associated vfio_ap_queue structure
  70  */
  71 static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
  72 {
  73         struct vfio_ap_queue *q;
  74         int apid, apqi;
  75 
  76         mutex_lock(&matrix_dev->lock);
  77         q = dev_get_drvdata(&apdev->device);
  78         dev_set_drvdata(&apdev->device, NULL);
  79         apid = AP_QID_CARD(q->apqn);
  80         apqi = AP_QID_QUEUE(q->apqn);
  81         vfio_ap_mdev_reset_queue(apid, apqi, 1);
  82         vfio_ap_irq_disable(q);
  83         kfree(q);
  84         mutex_unlock(&matrix_dev->lock);
  85 }
  86 
  87 static void vfio_ap_matrix_dev_release(struct device *dev)
  88 {
  89         struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
  90 
  91         kfree(matrix_dev);
  92 }
  93 
  94 static int matrix_bus_match(struct device *dev, struct device_driver *drv)
  95 {
  96         return 1;
  97 }
  98 
  99 static struct bus_type matrix_bus = {
 100         .name = "matrix",
 101         .match = &matrix_bus_match,
 102 };
 103 
 104 static struct device_driver matrix_driver = {
 105         .name = "vfio_ap",
 106         .bus = &matrix_bus,
 107         .suppress_bind_attrs = true,
 108 };
 109 
 110 static int vfio_ap_matrix_dev_create(void)
 111 {
 112         int ret;
 113         struct device *root_device;
 114 
 115         root_device = root_device_register(VFIO_AP_ROOT_NAME);
 116         if (IS_ERR(root_device))
 117                 return PTR_ERR(root_device);
 118 
 119         ret = bus_register(&matrix_bus);
 120         if (ret)
 121                 goto bus_register_err;
 122 
 123         matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
 124         if (!matrix_dev) {
 125                 ret = -ENOMEM;
 126                 goto matrix_alloc_err;
 127         }
 128 
 129         /* Fill in config info via PQAP(QCI), if available */
 130         if (test_facility(12)) {
 131                 ret = ap_qci(&matrix_dev->info);
 132                 if (ret)
 133                         goto matrix_alloc_err;
 134         }
 135 
 136         mutex_init(&matrix_dev->lock);
 137         INIT_LIST_HEAD(&matrix_dev->mdev_list);
 138 
 139         dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
 140         matrix_dev->device.parent = root_device;
 141         matrix_dev->device.bus = &matrix_bus;
 142         matrix_dev->device.release = vfio_ap_matrix_dev_release;
 143         matrix_dev->vfio_ap_drv = &vfio_ap_drv;
 144 
 145         ret = device_register(&matrix_dev->device);
 146         if (ret)
 147                 goto matrix_reg_err;
 148 
 149         ret = driver_register(&matrix_driver);
 150         if (ret)
 151                 goto matrix_drv_err;
 152 
 153         return 0;
 154 
 155 matrix_drv_err:
 156         device_unregister(&matrix_dev->device);
 157 matrix_reg_err:
 158         put_device(&matrix_dev->device);
 159 matrix_alloc_err:
 160         bus_unregister(&matrix_bus);
 161 bus_register_err:
 162         root_device_unregister(root_device);
 163         return ret;
 164 }
 165 
 166 static void vfio_ap_matrix_dev_destroy(void)
 167 {
 168         struct device *root_device = matrix_dev->device.parent;
 169 
 170         driver_unregister(&matrix_driver);
 171         device_unregister(&matrix_dev->device);
 172         bus_unregister(&matrix_bus);
 173         root_device_unregister(root_device);
 174 }
 175 
 176 static int __init vfio_ap_init(void)
 177 {
 178         int ret;
 179 
 180         /* If there are no AP instructions, there is nothing to pass through. */
 181         if (!ap_instructions_available())
 182                 return -ENODEV;
 183 
 184         ret = vfio_ap_matrix_dev_create();
 185         if (ret)
 186                 return ret;
 187 
 188         memset(&vfio_ap_drv, 0, sizeof(vfio_ap_drv));
 189         vfio_ap_drv.probe = vfio_ap_queue_dev_probe;
 190         vfio_ap_drv.remove = vfio_ap_queue_dev_remove;
 191         vfio_ap_drv.ids = ap_queue_ids;
 192 
 193         ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);
 194         if (ret) {
 195                 vfio_ap_matrix_dev_destroy();
 196                 return ret;
 197         }
 198 
 199         ret = vfio_ap_mdev_register();
 200         if (ret) {
 201                 ap_driver_unregister(&vfio_ap_drv);
 202                 vfio_ap_matrix_dev_destroy();
 203 
 204                 return ret;
 205         }
 206 
 207         return 0;
 208 }
 209 
 210 static void __exit vfio_ap_exit(void)
 211 {
 212         vfio_ap_mdev_unregister();
 213         ap_driver_unregister(&vfio_ap_drv);
 214         vfio_ap_matrix_dev_destroy();
 215 }
 216 
 217 module_init(vfio_ap_init);
 218 module_exit(vfio_ap_exit);

/* [<][>][^][v][top][bottom][index][help] */