linux/drivers/s390/crypto/vfio_ap_drv.c
<<
>>
Prefs
   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 */
   9
  10#include <linux/module.h>
  11#include <linux/mod_devicetable.h>
  12#include <linux/slab.h>
  13#include <linux/string.h>
  14#include <asm/facility.h>
  15#include "vfio_ap_private.h"
  16
  17#define VFIO_AP_ROOT_NAME "vfio_ap"
  18#define VFIO_AP_DEV_TYPE_NAME "ap_matrix"
  19#define VFIO_AP_DEV_NAME "matrix"
  20
  21MODULE_AUTHOR("IBM Corporation");
  22MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
  23MODULE_LICENSE("GPL v2");
  24
  25static struct ap_driver vfio_ap_drv;
  26
  27static struct device_type vfio_ap_dev_type = {
  28        .name = VFIO_AP_DEV_TYPE_NAME,
  29};
  30
  31struct ap_matrix_dev *matrix_dev;
  32
  33/* Only type 10 adapters (CEX4 and later) are supported
  34 * by the AP matrix device driver
  35 */
  36static struct ap_device_id ap_queue_ids[] = {
  37        { .dev_type = AP_DEVICE_TYPE_CEX4,
  38          .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  39        { .dev_type = AP_DEVICE_TYPE_CEX5,
  40          .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  41        { .dev_type = AP_DEVICE_TYPE_CEX6,
  42          .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
  43        { /* end of sibling */ },
  44};
  45
  46MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
  47
  48static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
  49{
  50        return 0;
  51}
  52
  53static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
  54{
  55        /* Nothing to do yet */
  56}
  57
  58static void vfio_ap_matrix_dev_release(struct device *dev)
  59{
  60        struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
  61
  62        kfree(matrix_dev);
  63}
  64
  65static int vfio_ap_matrix_dev_create(void)
  66{
  67        int ret;
  68        struct device *root_device;
  69
  70        root_device = root_device_register(VFIO_AP_ROOT_NAME);
  71        if (IS_ERR(root_device))
  72                return PTR_ERR(root_device);
  73
  74        matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
  75        if (!matrix_dev) {
  76                ret = -ENOMEM;
  77                goto matrix_alloc_err;
  78        }
  79
  80        /* Fill in config info via PQAP(QCI), if available */
  81        if (test_facility(12)) {
  82                ret = ap_qci(&matrix_dev->info);
  83                if (ret)
  84                        goto matrix_alloc_err;
  85        }
  86
  87        mutex_init(&matrix_dev->lock);
  88        INIT_LIST_HEAD(&matrix_dev->mdev_list);
  89
  90        matrix_dev->device.type = &vfio_ap_dev_type;
  91        dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  92        matrix_dev->device.parent = root_device;
  93        matrix_dev->device.release = vfio_ap_matrix_dev_release;
  94        matrix_dev->device.driver = &vfio_ap_drv.driver;
  95
  96        ret = device_register(&matrix_dev->device);
  97        if (ret)
  98                goto matrix_reg_err;
  99
 100        return 0;
 101
 102matrix_reg_err:
 103        put_device(&matrix_dev->device);
 104matrix_alloc_err:
 105        root_device_unregister(root_device);
 106
 107        return ret;
 108}
 109
 110static void vfio_ap_matrix_dev_destroy(void)
 111{
 112        device_unregister(&matrix_dev->device);
 113        root_device_unregister(matrix_dev->device.parent);
 114}
 115
 116static int __init vfio_ap_init(void)
 117{
 118        int ret;
 119
 120        /* If there are no AP instructions, there is nothing to pass through. */
 121        if (!ap_instructions_available())
 122                return -ENODEV;
 123
 124        ret = vfio_ap_matrix_dev_create();
 125        if (ret)
 126                return ret;
 127
 128        memset(&vfio_ap_drv, 0, sizeof(vfio_ap_drv));
 129        vfio_ap_drv.probe = vfio_ap_queue_dev_probe;
 130        vfio_ap_drv.remove = vfio_ap_queue_dev_remove;
 131        vfio_ap_drv.ids = ap_queue_ids;
 132
 133        ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);
 134        if (ret) {
 135                vfio_ap_matrix_dev_destroy();
 136                return ret;
 137        }
 138
 139        ret = vfio_ap_mdev_register();
 140        if (ret) {
 141                ap_driver_unregister(&vfio_ap_drv);
 142                vfio_ap_matrix_dev_destroy();
 143
 144                return ret;
 145        }
 146
 147        return 0;
 148}
 149
 150static void __exit vfio_ap_exit(void)
 151{
 152        vfio_ap_mdev_unregister();
 153        ap_driver_unregister(&vfio_ap_drv);
 154        vfio_ap_matrix_dev_destroy();
 155}
 156
 157module_init(vfio_ap_init);
 158module_exit(vfio_ap_exit);
 159