1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
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