tlk_driver: 5/22 update
[tegra/ote_partner/tlk_driver.git] / ote_comms.c
1 /*
2  * Copyright (c) 2012-2014 NVIDIA Corporation. All rights reserved.
3  *
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.
8  *
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
12  * more details.
13  *
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.
17  */
18
19 #include <linux/atomic.h>
20 #include <linux/uaccess.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/fs.h>
24 #include <linux/printk.h>
25 #include <linux/ioctl.h>
26 #include <linux/sched.h>
27 #include <linux/mm.h>
28 #include <linux/pagemap.h>
29 #include <asm/smp_plat.h>
30
31 #include "ote_protocol.h"
32
33 bool verbose_smc;
34 core_param(verbose_smc, verbose_smc, bool, 0644);
35
36 #define SET_RESULT(req, r, ro)  { req->result = r; req->result_origin = ro; }
37
38 static struct te_shmem_desc *te_add_shmem_desc(void *buffer, size_t size,
39                 struct tlk_context *context)
40 {
41         struct te_shmem_desc *shmem_desc = NULL;
42         shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL);
43         if (shmem_desc) {
44                 INIT_LIST_HEAD(&(shmem_desc->list));
45                 shmem_desc->buffer = buffer;
46                 shmem_desc->size = size;
47                 list_add_tail(&shmem_desc->list, &(context->shmem_alloc_list));
48         }
49
50         return shmem_desc;
51 }
52
53 static int te_pin_mem_buffers(void *buffer, size_t size,
54                 struct tlk_context *context)
55 {
56         struct te_shmem_desc *shmem_desc = NULL;
57         int ret = 0;
58
59         shmem_desc = te_add_shmem_desc(buffer, size, context);
60         if (!shmem_desc) {
61                 pr_err("%s: te_add_shmem_desc Failed\n", __func__);
62                 ret = OTE_ERROR_OUT_OF_MEMORY;
63                 goto error;
64         }
65
66         return OTE_SUCCESS;
67 error:
68         return ret;
69 }
70
71 static int te_setup_temp_buffers(struct te_request *request,
72                 struct tlk_context *context)
73 {
74         uint32_t i;
75         int ret = OTE_SUCCESS;
76         struct te_oper_param *params = request->params;
77
78         for (i = 0; i < request->params_size; i++) {
79                 switch (params[i].type) {
80                 case TE_PARAM_TYPE_NONE:
81                 case TE_PARAM_TYPE_INT_RO:
82                 case TE_PARAM_TYPE_INT_RW:
83                         break;
84                 case TE_PARAM_TYPE_MEM_RO:
85                 case TE_PARAM_TYPE_MEM_RW:
86                         ret = te_pin_mem_buffers(
87                                 params[i].u.Mem.base,
88                                 params[i].u.Mem.len,
89                                 context);
90                         if (ret < 0) {
91                                 pr_err("%s failed with err (%d)\n",
92                                         __func__, ret);
93                                 ret = OTE_ERROR_BAD_PARAMETERS;
94                                 break;
95                         }
96                         break;
97                 default:
98                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
99                         ret = OTE_ERROR_BAD_PARAMETERS;
100                         break;
101                 }
102         }
103         return ret;
104 }
105
106 static int te_setup_temp_buffers_compat(struct te_request_compat *request,
107                 struct tlk_context *context)
108 {
109         uint32_t i;
110         int ret = OTE_SUCCESS;
111         struct te_oper_param_compat *params;
112
113         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
114         for (i = 0; i < request->params_size; i++) {
115                 switch (params[i].type) {
116                 case TE_PARAM_TYPE_NONE:
117                 case TE_PARAM_TYPE_INT_RO:
118                 case TE_PARAM_TYPE_INT_RW:
119                         break;
120                 case TE_PARAM_TYPE_MEM_RO:
121                 case TE_PARAM_TYPE_MEM_RW:
122                         ret = te_pin_mem_buffers(
123                                 (void *)(uintptr_t)params[i].u.Mem.base,
124                                 params[i].u.Mem.len,
125                                 context);
126                         if (ret < 0) {
127                                 pr_err("%s failed with err (%d)\n",
128                                         __func__, ret);
129                                 ret = OTE_ERROR_BAD_PARAMETERS;
130                                 break;
131                         }
132                         break;
133                 default:
134                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
135                         ret = OTE_ERROR_BAD_PARAMETERS;
136                         break;
137                 }
138         }
139         return ret;
140 }
141
142 static void te_del_shmem_desc(void *buffer, struct tlk_context *context)
143 {
144         struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
145
146         list_for_each_entry_safe(shmem_desc, tmp_shmem_desc,
147                 &(context->shmem_alloc_list), list) {
148                 if (shmem_desc->buffer == buffer) {
149                         list_del(&shmem_desc->list);
150                         kfree(shmem_desc);
151                 }
152         }
153 }
154
155 /*
156  * Deregister previously initialized shared memory
157  */
158 void te_unregister_memory(void *buffer,
159         struct tlk_context *context)
160 {
161         if (!(list_empty(&(context->shmem_alloc_list))))
162                 te_del_shmem_desc(buffer, context);
163         else
164                 pr_err("No buffers to unpin\n");
165 }
166
167 static void te_unpin_temp_buffers(struct te_request *request,
168         struct tlk_context *context)
169 {
170         uint32_t i;
171         struct te_oper_param *params = request->params;
172
173         for (i = 0; i < request->params_size; i++) {
174                 switch (params[i].type) {
175                 case TE_PARAM_TYPE_NONE:
176                 case TE_PARAM_TYPE_INT_RO:
177                 case TE_PARAM_TYPE_INT_RW:
178                         break;
179                 case TE_PARAM_TYPE_MEM_RO:
180                 case TE_PARAM_TYPE_MEM_RW:
181                         te_unregister_memory(params[i].u.Mem.base, context);
182                         break;
183                 default:
184                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
185                         break;
186                 }
187         }
188 }
189
190 static void te_unpin_temp_buffers_compat(struct te_request_compat *request,
191         struct tlk_context *context)
192 {
193         uint32_t i;
194         struct te_oper_param_compat *params;
195
196         params = (struct te_oper_param_compat *)(uintptr_t)request->params;
197         for (i = 0; i < request->params_size; i++) {
198                 switch (params[i].type) {
199                 case TE_PARAM_TYPE_NONE:
200                 case TE_PARAM_TYPE_INT_RO:
201                 case TE_PARAM_TYPE_INT_RW:
202                         break;
203                 case TE_PARAM_TYPE_MEM_RO:
204                 case TE_PARAM_TYPE_MEM_RW:
205                         te_unregister_memory(
206                                 (void *)(uintptr_t)params[i].u.Mem.base,
207                                 context);
208                         break;
209                 default:
210                         pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
211                         break;
212                 }
213         }
214 }
215
216 #ifdef CONFIG_SMP
217 cpumask_t saved_cpu_mask;
218 static void switch_cpumask_to_cpu0(void)
219 {
220         long ret;
221         cpumask_t local_cpu_mask = CPU_MASK_NONE;
222
223         cpu_set(0, local_cpu_mask);
224         cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current));
225         ret = sched_setaffinity(0, &local_cpu_mask);
226         if (ret)
227                 pr_err("sched_setaffinity #1 -> 0x%lX", ret);
228 }
229
230 static void restore_cpumask(void)
231 {
232         long ret = sched_setaffinity(0, &saved_cpu_mask);
233         if (ret)
234                 pr_err("sched_setaffinity #2 -> 0x%lX", ret);
235 }
236 #else
237 static inline void switch_cpumask_to_cpu0(void) {};
238 static inline void restore_cpumask(void) {};
239 #endif
240
241 uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
242 {
243         uint32_t retval;
244
245         switch_cpumask_to_cpu0();
246
247         retval = _tlk_generic_smc(arg0, arg1, arg2);
248         while (retval == TE_ERROR_PREEMPT_BY_IRQ ||
249                retval == TE_ERROR_PREEMPT_BY_FS) {
250                 if (retval == TE_ERROR_PREEMPT_BY_IRQ) {
251                         retval = _tlk_generic_smc((60 << 24), 0, 0);
252                 } else {
253                         tlk_ss_op();
254                         retval = _tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0);
255                 }
256         }
257
258         restore_cpumask();
259
260         /* Print TLK logs if any */
261         ote_print_logs();
262
263         return retval;
264 }
265
266 uint32_t tlk_extended_smc(uintptr_t *regs)
267 {
268         uint32_t retval;
269
270         switch_cpumask_to_cpu0();
271
272         retval = _tlk_extended_smc(regs);
273         while (retval == 0xFFFFFFFD)
274                 retval = _tlk_generic_smc((60 << 24), 0, 0);
275
276         restore_cpumask();
277
278         /* Print TLK logs if any */
279         ote_print_logs();
280
281         return retval;
282 }
283
284 /*
285  * Do an SMC call
286  */
287 static void do_smc(struct te_request *request, struct tlk_device *dev)
288 {
289         uint32_t smc_args;
290         uint32_t smc_params = 0;
291
292         if (dev->req_param_buf) {
293                 smc_args = (char *)request - dev->req_param_buf;
294                 if (request->params)
295                         smc_params = (char *)request->params -
296                                                 dev->req_param_buf;
297         } else {
298                 smc_args = (uint32_t)virt_to_phys(request);
299                 if (request->params)
300                         smc_params = (uint32_t)virt_to_phys(request->params);
301         }
302
303         tlk_generic_smc(request->type, smc_args, smc_params);
304 }
305
306 /*
307  * Do an SMC call
308  */
309 static void do_smc_compat(struct te_request_compat *request,
310                           struct tlk_device *dev)
311 {
312         uint32_t smc_args;
313         uint32_t smc_params = 0;
314
315         smc_args = (char *)request - dev->req_param_buf;
316         if (request->params) {
317                 smc_params =
318                         (char *)(uintptr_t)request->params - dev->req_param_buf;
319         }
320
321         tlk_generic_smc(request->type, smc_args, smc_params);
322 }
323
324 struct tlk_smc_work_args {
325         uint32_t arg0;
326         uint32_t arg1;
327         uint32_t arg2;
328 };
329
330 static long tlk_generic_smc_on_cpu0(void *args)
331 {
332         struct tlk_smc_work_args *work;
333         int cpu = cpu_logical_map(smp_processor_id());
334         uint32_t retval;
335
336         BUG_ON(cpu != 0);
337
338         work = (struct tlk_smc_work_args *)args;
339         retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
340         while (retval == 0xFFFFFFFD)
341                 retval = _tlk_generic_smc((60 << 24), 0, 0);
342         return retval;
343 }
344
345 /*
346  * VPR programming SMC
347  *
348  * This routine is called both from normal threads and worker threads.
349  * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
350  * any calls to sched_setaffinity will fail.
351  *
352  * If it's a worker thread on CPU0, just invoke the SMC directly. If
353  * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
354  * on CPU0.
355  */
356 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
357 {
358         uint32_t retval;
359
360         /* Share the same lock used when request is send from user side */
361         mutex_lock(&smc_lock);
362
363         if (current->flags &
364             (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
365                 struct tlk_smc_work_args work_args;
366                 int cpu = cpu_logical_map(smp_processor_id());
367
368                 work_args.arg0 = TE_SMC_PROGRAM_VPR;
369                 work_args.arg1 = (uint32_t)vpr_base;
370                 work_args.arg2 = vpr_size;
371
372                 /* workers don't change CPU. depending on the CPU, execute
373                  * directly or sched work */
374                 if (cpu == 0 && (current->flags & PF_WQ_WORKER))
375                         retval = tlk_generic_smc_on_cpu0(&work_args);
376                 else
377                         retval = work_on_cpu(0,
378                                         tlk_generic_smc_on_cpu0, &work_args);
379         } else {
380                 retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
381                                         (uintptr_t)vpr_base, vpr_size);
382         }
383
384         mutex_unlock(&smc_lock);
385
386         if (retval != OTE_SUCCESS) {
387                 pr_err("te_set_vpr_params failed err (0x%x)\n", retval);
388                 return -EINVAL;
389         }
390         return 0;
391 }
392 EXPORT_SYMBOL(te_set_vpr_params);
393
394 /*
395  * Open session SMC (supporting client-based te_open_session() calls)
396  */
397 void te_open_session(struct te_opensession *cmd,
398                      struct te_request *request,
399                      struct tlk_context *context)
400 {
401         int ret;
402
403         ret = te_setup_temp_buffers(request, context);
404         if (ret != OTE_SUCCESS) {
405                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
406                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
407                 return;
408         }
409
410         memcpy(&request->dest_uuid,
411                &cmd->dest_uuid,
412                sizeof(struct te_service_id));
413
414         pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
415                 request->dest_uuid[0],
416                 request->dest_uuid[1],
417                 request->dest_uuid[2],
418                 request->dest_uuid[3]);
419
420         request->type = TE_SMC_OPEN_SESSION;
421
422         do_smc(request, context->dev);
423
424         te_unpin_temp_buffers(request, context);
425 }
426
427 /*
428  * Close session SMC (supporting client-based te_close_session() calls)
429  */
430 void te_close_session(struct te_closesession *cmd,
431                       struct te_request *request,
432                       struct tlk_context *context)
433 {
434         request->session_id = cmd->session_id;
435         request->type = TE_SMC_CLOSE_SESSION;
436
437         do_smc(request, context->dev);
438         if (request->result)
439                 pr_info("Error closing session: %08x\n", request->result);
440 }
441
442 /*
443  * Launch operation SMC (supporting client-based te_launch_operation() calls)
444  */
445 void te_launch_operation(struct te_launchop *cmd,
446                          struct te_request *request,
447                          struct tlk_context *context)
448 {
449         int ret;
450
451         ret = te_setup_temp_buffers(request, context);
452         if (ret != OTE_SUCCESS) {
453                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
454                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
455                 return;
456         }
457
458         request->session_id = cmd->session_id;
459         request->command_id = cmd->operation.command;
460         request->type = TE_SMC_LAUNCH_OPERATION;
461
462         do_smc(request, context->dev);
463
464         te_unpin_temp_buffers(request, context);
465 }
466
467 /*
468  * Open session SMC (supporting client-based te_open_session() calls)
469  */
470 void te_open_session_compat(struct te_opensession_compat *cmd,
471                             struct te_request_compat *request,
472                             struct tlk_context *context)
473 {
474         int ret;
475
476         ret = te_setup_temp_buffers_compat(request, context);
477         if (ret != OTE_SUCCESS) {
478                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
479                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
480                 return;
481         }
482
483         memcpy(&request->dest_uuid,
484                &cmd->dest_uuid,
485                sizeof(struct te_service_id));
486
487         pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
488                 request->dest_uuid[0],
489                 request->dest_uuid[1],
490                 request->dest_uuid[2],
491                 request->dest_uuid[3]);
492
493         request->type = TE_SMC_OPEN_SESSION;
494
495         do_smc_compat(request, context->dev);
496
497         te_unpin_temp_buffers_compat(request, context);
498 }
499
500 /*
501  * Close session SMC (supporting client-based te_close_session() calls)
502  */
503 void te_close_session_compat(struct te_closesession_compat *cmd,
504                              struct te_request_compat *request,
505                              struct tlk_context *context)
506 {
507         request->session_id = cmd->session_id;
508         request->type = TE_SMC_CLOSE_SESSION;
509
510         do_smc_compat(request, context->dev);
511         if (request->result)
512                 pr_info("Error closing session: %08x\n", request->result);
513 }
514
515 /*
516  * Launch operation SMC (supporting client-based te_launch_operation() calls)
517  */
518 void te_launch_operation_compat(struct te_launchop_compat *cmd,
519                                 struct te_request_compat *request,
520                                 struct tlk_context *context)
521 {
522         int ret;
523
524         ret = te_setup_temp_buffers_compat(request, context);
525         if (ret != OTE_SUCCESS) {
526                 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
527                 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
528                 return;
529         }
530
531         request->session_id = cmd->session_id;
532         request->command_id = cmd->operation.command;
533         request->type = TE_SMC_LAUNCH_OPERATION;
534
535         do_smc_compat(request, context->dev);
536
537         te_unpin_temp_buffers_compat(request, context);
538 }
539
540 static int __init tlk_register_irq_handler(void)
541 {
542         tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER,
543                 (uintptr_t)tlk_irq_handler, 0);
544         return 0;
545 }
546
547 arch_initcall(tlk_register_irq_handler);