2 * Copyright (c) 2013-2014 NVIDIA Corporation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <linux/atomic.h>
20 #include <linux/uaccess.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
24 #include <linux/printk.h>
25 #include <linux/ioctl.h>
26 #include <linux/miscdevice.h>
28 #include <asm/cacheflush.h>
29 #include <asm/outercache.h>
30 #include <linux/list.h>
31 #include <linux/dma-mapping.h>
33 #include "ote_protocol.h"
35 #define SET_ANSWER(a, r, ro) { a.result = r; a.result_origin = ro; }
37 struct tlk_device tlk_dev;
38 DEFINE_MUTEX(smc_lock);
40 static int te_create_free_cmd_list(struct tlk_device *dev)
42 int cmd_desc_count, ret = 0;
43 struct te_cmd_req_desc *req_desc;
44 struct te_cmd_req_desc_compat *req_desc_compat;
49 * Check if new shared req/param register SMC is supported.
51 * If it is, TLK can map in the shared req/param buffers and do_smc
52 * only needs to send the offsets within each (with cache coherency
53 * being maintained by HW through an NS mapping).
55 * If the SMC support is not yet present, then fallback to the old
56 * mode of writing to an uncached buffer to maintain coherency (and
57 * phys addresses are passed in do_smc).
59 dev->req_param_buf = NULL;
60 use_reqbuf = !tlk_generic_smc(TE_SMC_REGISTER_REQ_BUF, 0, 0);
63 dev->req_param_buf = kmalloc((2 * PAGE_SIZE), GFP_KERNEL);
65 /* requests in the first page, params in the second */
66 dev->req_addr = (struct te_request *) dev->req_param_buf;
67 dev->param_addr = (struct te_oper_param *)
68 (dev->req_param_buf + PAGE_SIZE);
70 tlk_generic_smc(TE_SMC_REGISTER_REQ_BUF,
71 (uintptr_t)dev->req_addr, (2 * PAGE_SIZE));
73 dev->req_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
74 &dev->req_addr_phys, GFP_KERNEL);
75 dev->param_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
76 &dev->param_addr_phys, GFP_KERNEL);
79 if (!dev->req_addr || !dev->param_addr || !dev->req_param_buf) {
84 /* requests in the first page, params in the second */
85 dev->req_addr_compat = (struct te_request_compat *)
87 dev->param_addr_compat = (struct te_oper_param_compat *)
88 (dev->req_param_buf + PAGE_SIZE);
90 /* alloc param bitmap allocator */
91 bitmap_size = BITS_TO_LONGS(TE_PARAM_MAX) * sizeof(long);
92 dev->param_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
94 for (cmd_desc_count = 0;
95 cmd_desc_count < TE_CMD_DESC_MAX; cmd_desc_count++) {
97 req_desc = kzalloc(sizeof(struct te_cmd_req_desc), GFP_KERNEL);
98 if (req_desc == NULL) {
99 pr_err("Failed to allocate cmd req descriptor\n");
103 req_desc->req_addr = dev->req_addr + cmd_desc_count;
104 INIT_LIST_HEAD(&(req_desc->list));
106 /* Add the cmd param descriptor to free list */
107 list_add_tail(&req_desc->list, &(dev->free_cmd_list));
110 for (cmd_desc_count = 0;
111 cmd_desc_count < TE_CMD_DESC_MAX_COMPAT; cmd_desc_count++) {
113 req_desc_compat = kzalloc(sizeof(struct te_cmd_req_desc_compat),
115 if (req_desc_compat == NULL) {
116 pr_err("Failed to allocate cmd req descriptor\n");
120 req_desc_compat->req_addr =
121 dev->req_addr_compat + cmd_desc_count;
122 INIT_LIST_HEAD(&(req_desc_compat->list));
124 /* Add the cmd param descriptor to free list */
125 list_add_tail(&req_desc_compat->list, &(dev->free_cmd_list));
132 static struct te_oper_param *te_get_free_params(struct tlk_device *dev,
133 unsigned int nparams)
135 struct te_oper_param *params = NULL;
139 nbits = get_count_order(nparams);
140 idx = bitmap_find_free_region(dev->param_bitmap,
141 TE_PARAM_MAX, nbits);
143 params = dev->param_addr + idx;
148 static void te_put_free_params(struct tlk_device *dev,
149 struct te_oper_param *params, uint32_t nparams)
153 idx = (params - dev->param_addr);
154 nbits = get_count_order(nparams);
155 bitmap_release_region(dev->param_bitmap, idx, nbits);
158 static struct te_oper_param_compat *
159 te_get_free_params_compat(struct tlk_device *dev, unsigned int nparams)
161 struct te_oper_param_compat *params = NULL;
165 nbits = get_count_order(nparams);
166 idx = bitmap_find_free_region(dev->param_bitmap,
167 TE_PARAM_MAX, nbits);
169 params = dev->param_addr_compat + idx;
174 static void te_put_free_params_compat(struct tlk_device *dev,
175 struct te_oper_param_compat *params, uint32_t nparams)
179 idx = (params - dev->param_addr_compat);
180 nbits = get_count_order(nparams);
181 bitmap_release_region(dev->param_bitmap, idx, nbits);
184 static struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev)
186 struct te_cmd_req_desc *cmd_desc = NULL;
188 if (!(list_empty(&(dev->free_cmd_list)))) {
189 cmd_desc = list_first_entry(&(dev->free_cmd_list),
190 struct te_cmd_req_desc, list);
191 list_del(&(cmd_desc->list));
192 list_add_tail(&cmd_desc->list, &(dev->used_cmd_list));
197 static void te_put_used_cmd_desc(struct tlk_device *dev,
198 struct te_cmd_req_desc *cmd_desc)
200 struct te_cmd_req_desc *param_desc, *tmp_param_desc;
203 list_for_each_entry_safe(param_desc, tmp_param_desc,
204 &(dev->used_cmd_list), list) {
205 if (cmd_desc->req_addr == param_desc->req_addr) {
206 list_del(¶m_desc->list);
207 list_add_tail(¶m_desc->list,
208 &(dev->free_cmd_list));
214 static struct te_cmd_req_desc_compat *
215 te_get_free_cmd_desc_compat(struct tlk_device *dev)
217 struct te_cmd_req_desc_compat *cmd_desc = NULL;
219 if (!(list_empty(&(dev->free_cmd_list)))) {
220 cmd_desc = list_first_entry(&(dev->free_cmd_list),
221 struct te_cmd_req_desc_compat, list);
222 list_del(&(cmd_desc->list));
223 list_add_tail(&cmd_desc->list, &(dev->used_cmd_list));
228 static void te_put_used_cmd_desc_compat(struct tlk_device *dev,
229 struct te_cmd_req_desc_compat *cmd_desc)
231 struct te_cmd_req_desc_compat *param_desc, *tmp_param_desc;
234 list_for_each_entry_safe(param_desc, tmp_param_desc,
235 &(dev->used_cmd_list), list) {
236 if (cmd_desc->req_addr == param_desc->req_addr) {
237 list_del(¶m_desc->list);
238 list_add_tail(¶m_desc->list,
239 &(dev->free_cmd_list));
245 static void __attribute__((unused)) te_print_cmd_list(
246 struct tlk_device *dev, int used_list)
248 struct te_cmd_req_desc *param_desc;
251 pr_info("Printing free cmd list\n");
252 if (!(list_empty(&(dev->free_cmd_list)))) {
253 list_for_each_entry(param_desc, &(dev->free_cmd_list),
255 pr_info("Phys addr for cmd req desc (%p)\n",
256 param_desc->req_addr);
259 pr_info("Printing used cmd list\n");
260 if (!(list_empty(&(dev->used_cmd_list)))) {
261 list_for_each_entry(param_desc, &(dev->used_cmd_list),
263 pr_info("Phys addr for cmd req desc (%p)\n",
264 param_desc->req_addr);
269 static int tlk_device_open(struct inode *inode, struct file *file)
271 struct tlk_context *context;
274 context = kzalloc(sizeof(struct tlk_context), GFP_KERNEL);
279 context->dev = &tlk_dev;
280 INIT_LIST_HEAD(&(context->shmem_alloc_list));
282 file->private_data = context;
288 static int tlk_device_release(struct inode *inode, struct file *file)
290 kfree(file->private_data);
291 file->private_data = NULL;
295 static int copy_params_from_user(struct te_request *req,
296 struct te_operation *operation)
298 struct te_oper_param *param_array;
299 struct te_oper_param *user_param;
302 if (operation->list_count == 0)
305 param_array = req->params;
306 if (param_array == NULL) {
307 pr_err("param_array empty\n");
311 user_param = operation->list_head;
312 for (i = 0; i < operation->list_count && user_param != NULL; i++) {
313 if (copy_from_user(param_array + i, user_param,
314 sizeof(struct te_oper_param))) {
315 pr_err("Failed to copy operation parameter:%d, %p, " \
317 i, user_param, operation->list_count);
320 user_param = param_array[i].next_ptr_user;
325 static int copy_params_to_user(struct te_request *req,
326 struct te_operation *operation)
328 struct te_oper_param *param_array;
329 struct te_oper_param *user_param;
332 if (operation->list_count == 0)
335 param_array = req->params;
336 if (param_array == NULL) {
337 pr_err("param_array empty\n");
341 user_param = operation->list_head;
342 for (i = 0; i < req->params_size; i++) {
343 if (copy_to_user(user_param, param_array + i,
344 sizeof(struct te_oper_param))) {
345 pr_err("Failed to copy back parameter:%d %p\n", i,
349 user_param = param_array[i].next_ptr_user;
354 static long te_handle_trustedapp_ioctl(struct file *file,
355 unsigned int ioctl_num, unsigned long ioctl_param)
359 void *ptr_user_answer = NULL;
360 struct te_operation *operation = NULL;
361 struct te_oper_param *params = NULL;
362 struct te_answer answer;
363 struct te_request *request;
365 struct te_cmd_req_desc *cmd_desc = NULL;
366 struct tlk_context *context = file->private_data;
367 struct tlk_device *dev = context->dev;
369 if (copy_from_user(&cmd, (void __user *)ioctl_param,
370 sizeof(union te_cmd))) {
371 pr_err("Failed to copy command request\n");
376 memset(&answer, 0, sizeof(struct te_answer));
379 case TE_IOCTL_OPEN_CLIENT_SESSION:
380 operation = &cmd.opensession.operation;
381 ptr_user_answer = (void *)cmd.opensession.answer;
383 cmd_desc = te_get_free_cmd_desc(dev);
384 params = te_get_free_params(dev, operation->list_count);
386 if (!cmd_desc || (operation->list_count && !params)) {
388 OTE_ERROR_OUT_OF_MEMORY,
389 OTE_RESULT_ORIGIN_COMMS);
390 pr_err("failed to get cmd_desc/params\n");
394 request = cmd_desc->req_addr;
395 memset(request, 0, sizeof(struct te_request));
397 request->params = params;
398 request->params_size = operation->list_count;
400 if (copy_params_from_user(request, operation)) {
402 pr_info("failed to copy params from user\n");
406 te_open_session(&cmd.opensession, request, context);
408 SET_ANSWER(answer, request->result, request->result_origin);
409 answer.session_id = request->session_id;
412 case TE_IOCTL_CLOSE_CLIENT_SESSION:
413 ptr_user_answer = (void *)cmd.closesession.answer;
414 cmd_desc = te_get_free_cmd_desc(dev);
417 OTE_ERROR_OUT_OF_MEMORY,
418 OTE_RESULT_ORIGIN_COMMS);
419 pr_err("failed to get cmd_desc\n");
423 request = cmd_desc->req_addr;
424 memset(request, 0, sizeof(struct te_request));
426 /* close session cannot fail */
427 te_close_session(&cmd.closesession, request, context);
430 case TE_IOCTL_LAUNCH_OPERATION:
431 operation = &cmd.launchop.operation;
432 ptr_user_answer = (void *)cmd.launchop.answer;
434 cmd_desc = te_get_free_cmd_desc(dev);
435 params = te_get_free_params(dev, operation->list_count);
437 if (!cmd_desc || (operation->list_count && !params)) {
439 OTE_ERROR_OUT_OF_MEMORY,
440 OTE_RESULT_ORIGIN_COMMS);
441 pr_err("failed to get cmd_desc/params\n");
445 request = cmd_desc->req_addr;
446 memset(request, 0, sizeof(struct te_request));
448 request->params = params;
449 request->params_size = operation->list_count;
451 if (copy_params_from_user(request, operation)) {
453 pr_info("failed to copy params from user\n");
457 te_launch_operation(&cmd.launchop, request, context);
459 SET_ANSWER(answer, request->result, request->result_origin);
463 pr_err("Invalid IOCTL Cmd\n");
467 if (ptr_user_answer && !err) {
468 if (copy_to_user(ptr_user_answer, &answer,
469 sizeof(struct te_answer))) {
470 pr_err("Failed to copy answer\n");
474 if (request->params && !err) {
475 if (copy_params_to_user(request, operation)) {
476 pr_err("Failed to copy return params\n");
483 te_put_used_cmd_desc(dev, cmd_desc);
485 te_put_free_params(dev, params, operation->list_count);
489 static int copy_params_from_user_compat(struct te_request_compat *req,
490 struct te_operation_compat *operation)
492 struct te_oper_param_compat *param_array;
493 struct te_oper_param_compat *user_param;
496 if (operation->list_count == 0)
499 param_array = (struct te_oper_param_compat *)(uintptr_t)req->params;
500 if (param_array == NULL) {
501 pr_err("param_array empty\n");
505 user_param = (struct te_oper_param_compat *)(uintptr_t)
506 operation->list_head;
507 for (i = 0; i < operation->list_count && user_param != NULL; i++) {
508 if (copy_from_user(param_array + i, user_param,
509 sizeof(struct te_oper_param_compat))) {
510 pr_err("Failed to copy operation parameter:%d, %p, " \
512 i, user_param, operation->list_count);
515 user_param = (struct te_oper_param_compat *)(uintptr_t)
516 param_array[i].next_ptr_user;
521 static int copy_params_to_user_compat(struct te_request_compat *req,
522 struct te_operation_compat *operation)
524 struct te_oper_param_compat *param_array;
525 struct te_oper_param_compat *user_param;
528 if (operation->list_count == 0)
532 (struct te_oper_param_compat *)(uintptr_t)req->params;
533 if (param_array == NULL) {
534 pr_err("param_array empty\n");
539 (struct te_oper_param_compat *)(uintptr_t)operation->list_head;
540 for (i = 0; i < req->params_size; i++) {
541 if (copy_to_user(user_param, param_array + i,
542 sizeof(struct te_oper_param_compat))) {
543 pr_err("Failed to copy back parameter:%d %p\n", i,
547 user_param = (struct te_oper_param_compat *)(uintptr_t)
548 param_array[i].next_ptr_user;
553 static long te_handle_trustedapp_ioctl_compat(struct file *file,
554 unsigned int ioctl_num, unsigned long ioctl_param)
557 union te_cmd_compat cmd_compat;
558 struct te_operation_compat *operation = NULL;
559 struct te_oper_param_compat *params = NULL;
560 struct te_request_compat *request;
561 void __user *ptr_user_answer = NULL;
562 struct te_answer answer;
563 struct te_cmd_req_desc_compat *cmd_desc = NULL;
564 struct tlk_context *context = file->private_data;
565 struct tlk_device *dev = context->dev;
567 if (copy_from_user(&cmd_compat, (void __user *)ioctl_param,
568 sizeof(union te_cmd_compat))) {
569 pr_err("Failed to copy command request\n");
574 memset(&answer, 0, sizeof(struct te_answer));
577 case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT:
578 operation = &cmd_compat.opensession.operation;
579 ptr_user_answer = (void *)(uintptr_t)
580 cmd_compat.opensession.answer;
582 cmd_desc = te_get_free_cmd_desc_compat(dev);
583 params = te_get_free_params_compat(dev, operation->list_count);
585 if (!cmd_desc || (operation->list_count && !params)) {
587 OTE_ERROR_OUT_OF_MEMORY,
588 OTE_RESULT_ORIGIN_COMMS);
589 pr_err("failed to get cmd_desc/params\n");
593 request = cmd_desc->req_addr;
594 memset(request, 0, sizeof(struct te_request_compat));
596 request->params = (uintptr_t)params;
597 request->params_size = operation->list_count;
599 if (copy_params_from_user_compat(request, operation)) {
601 pr_info("failed to copy params from user\n");
605 te_open_session_compat(&cmd_compat.opensession,
608 SET_ANSWER(answer, request->result, request->result_origin);
609 answer.session_id = request->session_id;
612 case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT:
613 ptr_user_answer = (void *)(uintptr_t)
614 cmd_compat.closesession.answer;
615 cmd_desc = te_get_free_cmd_desc_compat(dev);
618 OTE_ERROR_OUT_OF_MEMORY,
619 OTE_RESULT_ORIGIN_COMMS);
620 pr_err("failed to get cmd_desc\n");
624 request = cmd_desc->req_addr;
625 memset(request, 0, sizeof(struct te_request_compat));
627 /* close session cannot fail */
628 te_close_session_compat(&cmd_compat.closesession,
632 case TE_IOCTL_LAUNCH_OPERATION_COMPAT:
633 operation = &cmd_compat.launchop.operation;
634 ptr_user_answer = (void *)(uintptr_t)cmd_compat.launchop.answer;
636 cmd_desc = te_get_free_cmd_desc_compat(dev);
637 params = te_get_free_params_compat(dev, operation->list_count);
639 if (!cmd_desc || (operation->list_count && !params)) {
641 OTE_ERROR_OUT_OF_MEMORY,
642 OTE_RESULT_ORIGIN_COMMS);
643 pr_err("failed to get cmd_desc/params\n");
647 request = cmd_desc->req_addr;
648 memset(request, 0, sizeof(struct te_request_compat));
650 request->params = (uintptr_t)params;
651 request->params_size = operation->list_count;
653 if (copy_params_from_user_compat(request, operation)) {
655 pr_info("failed to copy params from user\n");
659 te_launch_operation_compat(&cmd_compat.launchop,
662 SET_ANSWER(answer, request->result, request->result_origin);
666 pr_err("Invalid IOCTL Cmd\n");
670 if (ptr_user_answer && !err) {
671 if (copy_to_user(ptr_user_answer, &answer,
672 sizeof(struct te_answer))) {
673 pr_err("Failed to copy answer\n");
677 if (request->params && !err) {
678 if (copy_params_to_user_compat(request, operation)) {
679 pr_err("Failed to copy return params\n");
686 te_put_used_cmd_desc_compat(dev, cmd_desc);
688 te_put_free_params_compat(dev, params, operation->list_count);
692 static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num,
693 unsigned long ioctl_param)
698 case TE_IOCTL_OPEN_CLIENT_SESSION:
699 case TE_IOCTL_CLOSE_CLIENT_SESSION:
700 case TE_IOCTL_LAUNCH_OPERATION:
701 mutex_lock(&smc_lock);
702 err = te_handle_trustedapp_ioctl(file, ioctl_num, ioctl_param);
703 mutex_unlock(&smc_lock);
706 case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT:
707 case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT:
708 case TE_IOCTL_LAUNCH_OPERATION_COMPAT:
709 mutex_lock(&smc_lock);
710 err = te_handle_trustedapp_ioctl_compat(file, ioctl_num,
712 mutex_unlock(&smc_lock);
715 case TE_IOCTL_SS_NEW_REQ_LEGACY:
716 case TE_IOCTL_SS_REQ_COMPLETE_LEGACY:
717 err = te_handle_ss_ioctl_legacy(file, ioctl_num, ioctl_param);
720 case TE_IOCTL_SS_NEW_REQ:
721 case TE_IOCTL_SS_REQ_COMPLETE:
722 err = te_handle_ss_ioctl(file, ioctl_num, ioctl_param);
726 pr_err("%s: Invalid IOCTL (0x%x) id 0x%x max 0x%lx\n",
727 __func__, ioctl_num, _IOC_NR(ioctl_num),
728 (unsigned long)TE_IOCTL_MAX_NR);
737 * tlk_driver function definitions.
739 static const struct file_operations tlk_device_fops = {
740 .owner = THIS_MODULE,
741 .open = tlk_device_open,
742 .release = tlk_device_release,
743 .unlocked_ioctl = tlk_device_ioctl,
745 .compat_ioctl = tlk_device_ioctl,
749 struct miscdevice tlk_misc_device = {
750 .minor = MISC_DYNAMIC_MINOR,
751 .name = "tlk_device",
752 .fops = &tlk_device_fops,
755 static int __init tlk_init(void)
759 INIT_LIST_HEAD(&(tlk_dev.used_cmd_list));
760 INIT_LIST_HEAD(&(tlk_dev.free_cmd_list));
762 ret = te_create_free_cmd_list(&tlk_dev);
766 return misc_register(&tlk_misc_device);
769 module_init(tlk_init);