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