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(§ion, (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