linux/drivers/crypto/qat/qat_common/adf_ctl_drv.c
<<
>>
Prefs
   1/*
   2  This file is provided under a dual BSD/GPLv2 license.  When using or
   3  redistributing this file, you may do so under either license.
   4
   5  GPL LICENSE SUMMARY
   6  Copyright(c) 2014 Intel Corporation.
   7  This program is free software; you can redistribute it and/or modify
   8  it under the terms of version 2 of the GNU General Public License as
   9  published by the Free Software Foundation.
  10
  11  This program is distributed in the hope that it will be useful, but
  12  WITHOUT ANY WARRANTY; without even the implied warranty of
  13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14  General Public License for more details.
  15
  16  Contact Information:
  17  qat-linux@intel.com
  18
  19  BSD LICENSE
  20  Copyright(c) 2014 Intel Corporation.
  21  Redistribution and use in source and binary forms, with or without
  22  modification, are permitted provided that the following conditions
  23  are met:
  24
  25    * Redistributions of source code must retain the above copyright
  26      notice, this list of conditions and the following disclaimer.
  27    * Redistributions in binary form must reproduce the above copyright
  28      notice, this list of conditions and the following disclaimer in
  29      the documentation and/or other materials provided with the
  30      distribution.
  31    * Neither the name of Intel Corporation nor the names of its
  32      contributors may be used to endorse or promote products derived
  33      from this software without specific prior written permission.
  34
  35  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  36  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  37  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  38  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  39  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  42  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  43  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  44  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  45  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46*/
  47#include <linux/module.h>
  48#include <linux/mutex.h>
  49#include <linux/slab.h>
  50#include <linux/fs.h>
  51#include <linux/bitops.h>
  52#include <linux/pci.h>
  53#include <linux/cdev.h>
  54#include <linux/uaccess.h>
  55
  56#include "adf_accel_devices.h"
  57#include "adf_common_drv.h"
  58#include "adf_cfg.h"
  59#include "adf_cfg_common.h"
  60#include "adf_cfg_user.h"
  61
  62#define DEVICE_NAME "qat_adf_ctl"
  63
  64static DEFINE_MUTEX(adf_ctl_lock);
  65static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
  66
  67static const struct file_operations adf_ctl_ops = {
  68        .owner = THIS_MODULE,
  69        .unlocked_ioctl = adf_ctl_ioctl,
  70        .compat_ioctl = adf_ctl_ioctl,
  71};
  72
  73struct adf_ctl_drv_info {
  74        unsigned int major;
  75        struct cdev drv_cdev;
  76        struct class *drv_class;
  77};
  78
  79static struct adf_ctl_drv_info adt_ctl_drv;
  80
  81static void adf_chr_drv_destroy(void)
  82{
  83        device_destroy(adt_ctl_drv.drv_class, MKDEV(adt_ctl_drv.major, 0));
  84        cdev_del(&adt_ctl_drv.drv_cdev);
  85        class_destroy(adt_ctl_drv.drv_class);
  86        unregister_chrdev_region(MKDEV(adt_ctl_drv.major, 0), 1);
  87}
  88
  89static int adf_chr_drv_create(void)
  90{
  91        dev_t dev_id;
  92        struct device *drv_device;
  93
  94        if (alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME)) {
  95                pr_err("QAT: unable to allocate chrdev region\n");
  96                return -EFAULT;
  97        }
  98
  99        adt_ctl_drv.drv_class = class_create(THIS_MODULE, DEVICE_NAME);
 100        if (IS_ERR(adt_ctl_drv.drv_class)) {
 101                pr_err("QAT: class_create failed for adf_ctl\n");
 102                goto err_chrdev_unreg;
 103        }
 104        adt_ctl_drv.major = MAJOR(dev_id);
 105        cdev_init(&adt_ctl_drv.drv_cdev, &adf_ctl_ops);
 106        if (cdev_add(&adt_ctl_drv.drv_cdev, dev_id, 1)) {
 107                pr_err("QAT: cdev add failed\n");
 108                goto err_class_destr;
 109        }
 110
 111        drv_device = device_create(adt_ctl_drv.drv_class, NULL,
 112                                   MKDEV(adt_ctl_drv.major, 0),
 113                                   NULL, DEVICE_NAME);
 114        if (IS_ERR(drv_device)) {
 115                pr_err("QAT: failed to create device\n");
 116                goto err_cdev_del;
 117        }
 118        return 0;
 119err_cdev_del:
 120        cdev_del(&adt_ctl_drv.drv_cdev);
 121err_class_destr:
 122        class_destroy(adt_ctl_drv.drv_class);
 123err_chrdev_unreg:
 124        unregister_chrdev_region(dev_id, 1);
 125        return -EFAULT;
 126}
 127
 128static int adf_ctl_alloc_resources(struct adf_user_cfg_ctl_data **ctl_data,
 129                                   unsigned long arg)
 130{
 131        struct adf_user_cfg_ctl_data *cfg_data;
 132
 133        cfg_data = kzalloc(sizeof(*cfg_data), GFP_KERNEL);
 134        if (!cfg_data)
 135                return -ENOMEM;
 136
 137        /* Initialize device id to NO DEVICE as 0 is a valid device id */
 138        cfg_data->device_id = ADF_CFG_NO_DEVICE;
 139
 140        if (copy_from_user(cfg_data, (void __user *)arg, sizeof(*cfg_data))) {
 141                pr_err("QAT: failed to copy from user cfg_data.\n");
 142                kfree(cfg_data);
 143                return -EIO;
 144        }
 145
 146        *ctl_data = cfg_data;
 147        return 0;
 148}
 149
 150static int adf_add_key_value_data(struct adf_accel_dev *accel_dev,
 151                                  const char *section,
 152                                  const struct adf_user_cfg_key_val *key_val)
 153{
 154        if (key_val->type == ADF_HEX) {
 155                long *ptr = (long *)key_val->val;
 156                long val = *ptr;
 157
 158                if (adf_cfg_add_key_value_param(accel_dev, section,
 159                                                key_val->key, (void *)val,
 160                                                key_val->type)) {
 161                        pr_err("QAT: failed to add keyvalue.\n");
 162                        return -EFAULT;
 163                }
 164        } else {
 165                if (adf_cfg_add_key_value_param(accel_dev, section,
 166                                                key_val->key, key_val->val,
 167                                                key_val->type)) {
 168                        pr_err("QAT: failed to add keyvalue.\n");
 169                        return -EFAULT;
 170                }
 171        }
 172        return 0;
 173}
 174
 175static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev,
 176                                   struct adf_user_cfg_ctl_data *ctl_data)
 177{
 178        struct adf_user_cfg_key_val key_val;
 179        struct adf_user_cfg_key_val *params_head;
 180        struct adf_user_cfg_section section, *section_head;
 181
 182        section_head = ctl_data->config_section;
 183
 184        while (section_head) {
 185                if (copy_from_user(&section, (void __user *)section_head,
 186                                   sizeof(*section_head))) {
 187                        pr_err("QAT: failed to copy section info\n");
 188                        goto out_err;
 189                }
 190
 191                if (adf_cfg_section_add(accel_dev, section.name)) {
 192                        pr_err("QAT: failed to add section.\n");
 193                        goto out_err;
 194                }
 195
 196                params_head = section_head->params;
 197
 198                while (params_head) {
 199                        if (copy_from_user(&key_val, (void __user *)params_head,
 200                                           sizeof(key_val))) {
 201                                pr_err("QAT: Failed to copy keyvalue.\n");
 202                                goto out_err;
 203                        }
 204                        if (adf_add_key_value_data(accel_dev, section.name,
 205                                                   &key_val)) {
 206                                goto out_err;
 207                        }
 208                        params_head = key_val.next;
 209                }
 210                section_head = section.next;
 211        }
 212        return 0;
 213out_err:
 214        adf_cfg_del_all(accel_dev);
 215        return -EFAULT;
 216}
 217
 218static int adf_ctl_ioctl_dev_config(struct file *fp, unsigned int cmd,
 219                                    unsigned long arg)
 220{
 221        int ret;
 222        struct adf_user_cfg_ctl_data *ctl_data;
 223        struct adf_accel_dev *accel_dev;
 224
 225        ret = adf_ctl_alloc_resources(&ctl_data, arg);
 226        if (ret)
 227                return ret;
 228
 229        accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id);
 230        if (!accel_dev) {
 231                ret = -EFAULT;
 232                goto out;
 233        }
 234
 235        if (adf_dev_started(accel_dev)) {
 236                ret = -EFAULT;
 237                goto out;
 238        }
 239
 240        if (adf_copy_key_value_data(accel_dev, ctl_data)) {
 241                ret = -EFAULT;
 242                goto out;
 243        }
 244        set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
 245out:
 246        kfree(ctl_data);
 247        return ret;
 248}
 249
 250static int adf_ctl_is_device_in_use(int id)
 251{
 252        struct list_head *itr, *head = adf_devmgr_get_head();
 253
 254        list_for_each(itr, head) {
 255                struct adf_accel_dev *dev =
 256                                list_entry(itr, struct adf_accel_dev, list);
 257
 258                if (id == dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
 259                        if (adf_devmgr_in_reset(dev) || adf_dev_in_use(dev)) {
 260                                pr_info("QAT: device qat_dev%d is busy\n",
 261                                        dev->accel_id);
 262                                return -EBUSY;
 263                        }
 264                }
 265        }
 266        return 0;
 267}
 268
 269static int adf_ctl_stop_devices(uint32_t id)
 270{
 271        struct list_head *itr, *head = adf_devmgr_get_head();
 272        int ret = 0;
 273
 274        list_for_each(itr, head) {
 275                struct adf_accel_dev *accel_dev =
 276                                list_entry(itr, struct adf_accel_dev, list);
 277                if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
 278                        if (!adf_dev_started(accel_dev))
 279                                continue;
 280
 281                        if (adf_dev_stop(accel_dev)) {
 282                                pr_err("QAT: Failed to stop qat_dev%d\n", id);
 283                                ret = -EFAULT;
 284                        }
 285                }
 286        }
 287        return ret;
 288}
 289
 290static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd,
 291                                  unsigned long arg)
 292{
 293        int ret;
 294        struct adf_user_cfg_ctl_data *ctl_data;
 295
 296        ret = adf_ctl_alloc_resources(&ctl_data, arg);
 297        if (ret)
 298                return ret;
 299
 300        if (adf_devmgr_verify_id(ctl_data->device_id)) {
 301                pr_err("QAT: Device %d not found\n", ctl_data->device_id);
 302                ret = -ENODEV;
 303                goto out;
 304        }
 305
 306        ret = adf_ctl_is_device_in_use(ctl_data->device_id);
 307        if (ret)
 308                goto out;
 309
 310        if (ctl_data->device_id == ADF_CFG_ALL_DEVICES)
 311                pr_info("QAT: Stopping all acceleration devices.\n");
 312        else
 313                pr_info("QAT: Stopping acceleration device qat_dev%d.\n",
 314                        ctl_data->device_id);
 315
 316        ret = adf_ctl_stop_devices(ctl_data->device_id);
 317        if (ret)
 318                pr_err("QAT: failed to stop device.\n");
 319out:
 320        kfree(ctl_data);
 321        return ret;
 322}
 323
 324static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd,
 325                                   unsigned long arg)
 326{
 327        int ret;
 328        struct adf_user_cfg_ctl_data *ctl_data;
 329        struct adf_accel_dev *accel_dev;
 330
 331        ret = adf_ctl_alloc_resources(&ctl_data, arg);
 332        if (ret)
 333                return ret;
 334
 335        accel_dev = adf_devmgr_get_dev_by_id(ctl_data->device_id);
 336        if (!accel_dev) {
 337                pr_err("QAT: Device %d not found\n", ctl_data->device_id);
 338                ret = -ENODEV;
 339                goto out;
 340        }
 341
 342        if (!adf_dev_started(accel_dev)) {
 343                pr_info("QAT: Starting acceleration device qat_dev%d.\n",
 344                        ctl_data->device_id);
 345                ret = adf_dev_start(accel_dev);
 346        } else {
 347                pr_info("QAT: Acceleration device qat_dev%d already started.\n",
 348                        ctl_data->device_id);
 349        }
 350        if (ret) {
 351                pr_err("QAT: Failed to start qat_dev%d\n", ctl_data->device_id);
 352                adf_dev_stop(accel_dev);
 353        }
 354out:
 355        kfree(ctl_data);
 356        return ret;
 357}
 358
 359static int adf_ctl_ioctl_get_num_devices(struct file *fp, unsigned int cmd,
 360                                         unsigned long arg)
 361{
 362        uint32_t num_devices = 0;
 363
 364        adf_devmgr_get_num_dev(&num_devices);
 365        if (copy_to_user((void __user *)arg, &num_devices, sizeof(num_devices)))
 366                return -EFAULT;
 367
 368        return 0;
 369}
 370
 371static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd,
 372                                    unsigned long arg)
 373{
 374        struct adf_hw_device_data *hw_data;
 375        struct adf_dev_status_info dev_info;
 376        struct adf_accel_dev *accel_dev;
 377
 378        if (copy_from_user(&dev_info, (void __user *)arg,
 379                           sizeof(struct adf_dev_status_info))) {
 380                pr_err("QAT: failed to copy from user.\n");
 381                return -EFAULT;
 382        }
 383
 384        accel_dev = adf_devmgr_get_dev_by_id(dev_info.accel_id);
 385        if (!accel_dev) {
 386                pr_err("QAT: Device %d not found\n", dev_info.accel_id);
 387                return -ENODEV;
 388        }
 389        hw_data = accel_dev->hw_device;
 390        dev_info.state = adf_dev_started(accel_dev) ? DEV_UP : DEV_DOWN;
 391        dev_info.num_ae = hw_data->get_num_aes(hw_data);
 392        dev_info.num_accel = hw_data->get_num_accels(hw_data);
 393        dev_info.num_logical_accel = hw_data->num_logical_accel;
 394        dev_info.banks_per_accel = hw_data->num_banks
 395                                        / hw_data->num_logical_accel;
 396        strlcpy(dev_info.name, hw_data->dev_class->name, sizeof(dev_info.name));
 397        dev_info.instance_id = hw_data->instance_id;
 398        dev_info.type = hw_data->dev_class->type;
 399        dev_info.bus = accel_to_pci_dev(accel_dev)->bus->number;
 400        dev_info.dev = PCI_SLOT(accel_to_pci_dev(accel_dev)->devfn);
 401        dev_info.fun = PCI_FUNC(accel_to_pci_dev(accel_dev)->devfn);
 402
 403        if (copy_to_user((void __user *)arg, &dev_info,
 404                         sizeof(struct adf_dev_status_info))) {
 405                pr_err("QAT: failed to copy status.\n");
 406                return -EFAULT;
 407        }
 408        return 0;
 409}
 410
 411static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 412{
 413        int ret;
 414
 415        if (mutex_lock_interruptible(&adf_ctl_lock))
 416                return -EFAULT;
 417
 418        switch (cmd) {
 419        case IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS:
 420                ret = adf_ctl_ioctl_dev_config(fp, cmd, arg);
 421                break;
 422
 423        case IOCTL_STOP_ACCEL_DEV:
 424                ret = adf_ctl_ioctl_dev_stop(fp, cmd, arg);
 425                break;
 426
 427        case IOCTL_START_ACCEL_DEV:
 428                ret = adf_ctl_ioctl_dev_start(fp, cmd, arg);
 429                break;
 430
 431        case IOCTL_GET_NUM_DEVICES:
 432                ret = adf_ctl_ioctl_get_num_devices(fp, cmd, arg);
 433                break;
 434
 435        case IOCTL_STATUS_ACCEL_DEV:
 436                ret = adf_ctl_ioctl_get_status(fp, cmd, arg);
 437                break;
 438        default:
 439                pr_err("QAT: Invalid ioctl\n");
 440                ret = -EFAULT;
 441                break;
 442        }
 443        mutex_unlock(&adf_ctl_lock);
 444        return ret;
 445}
 446
 447static int __init adf_register_ctl_device_driver(void)
 448{
 449        mutex_init(&adf_ctl_lock);
 450
 451        if (qat_algs_init())
 452                goto err_algs_init;
 453
 454        if (adf_chr_drv_create())
 455                goto err_chr_dev;
 456
 457        if (adf_init_aer())
 458                goto err_aer;
 459
 460        if (qat_crypto_register())
 461                goto err_crypto_register;
 462
 463        return 0;
 464
 465err_crypto_register:
 466        adf_exit_aer();
 467err_aer:
 468        adf_chr_drv_destroy();
 469err_chr_dev:
 470        qat_algs_exit();
 471err_algs_init:
 472        mutex_destroy(&adf_ctl_lock);
 473        return -EFAULT;
 474}
 475
 476static void __exit adf_unregister_ctl_device_driver(void)
 477{
 478        adf_chr_drv_destroy();
 479        adf_exit_aer();
 480        qat_crypto_unregister();
 481        qat_algs_exit();
 482        mutex_destroy(&adf_ctl_lock);
 483}
 484
 485module_init(adf_register_ctl_device_driver);
 486module_exit(adf_unregister_ctl_device_driver);
 487MODULE_LICENSE("Dual BSD/GPL");
 488MODULE_AUTHOR("Intel");
 489MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
 490MODULE_ALIAS("intel_qat");
 491