2 * Copyright (c) 2012-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/sched.h>
28 #include <linux/pagemap.h>
29 #include <asm/smp_plat.h>
31 #include "ote_protocol.h"
34 core_param(verbose_smc, verbose_smc, bool, 0644);
36 #define SET_RESULT(req, r, ro) { req->result = r; req->result_origin = ro; }
38 static struct te_shmem_desc *te_add_shmem_desc(void *buffer, size_t size,
39 struct tlk_context *context)
41 struct te_shmem_desc *shmem_desc = NULL;
42 shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL);
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));
53 static int te_pin_mem_buffers(void *buffer, size_t size,
54 struct tlk_context *context)
56 struct te_shmem_desc *shmem_desc = NULL;
59 shmem_desc = te_add_shmem_desc(buffer, size, context);
61 pr_err("%s: te_add_shmem_desc Failed\n", __func__);
62 ret = OTE_ERROR_OUT_OF_MEMORY;
71 static int te_setup_temp_buffers(struct te_request *request,
72 struct tlk_context *context)
75 int ret = OTE_SUCCESS;
76 struct te_oper_param *params = request->params;
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:
84 case TE_PARAM_TYPE_MEM_RO:
85 case TE_PARAM_TYPE_MEM_RW:
86 ret = te_pin_mem_buffers(
91 pr_err("%s failed with err (%d)\n",
93 ret = OTE_ERROR_BAD_PARAMETERS;
98 pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
99 ret = OTE_ERROR_BAD_PARAMETERS;
106 static int te_setup_temp_buffers_compat(struct te_request_compat *request,
107 struct tlk_context *context)
110 int ret = OTE_SUCCESS;
111 struct te_oper_param_compat *params;
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:
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,
127 pr_err("%s failed with err (%d)\n",
129 ret = OTE_ERROR_BAD_PARAMETERS;
134 pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
135 ret = OTE_ERROR_BAD_PARAMETERS;
142 static void te_del_shmem_desc(void *buffer, struct tlk_context *context)
144 struct te_shmem_desc *shmem_desc, *tmp_shmem_desc;
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);
156 * Deregister previously initialized shared memory
158 void te_unregister_memory(void *buffer,
159 struct tlk_context *context)
161 if (!(list_empty(&(context->shmem_alloc_list))))
162 te_del_shmem_desc(buffer, context);
164 pr_err("No buffers to unpin\n");
167 static void te_unpin_temp_buffers(struct te_request *request,
168 struct tlk_context *context)
171 struct te_oper_param *params = request->params;
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:
179 case TE_PARAM_TYPE_MEM_RO:
180 case TE_PARAM_TYPE_MEM_RW:
181 te_unregister_memory(params[i].u.Mem.base, context);
184 pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
190 static void te_unpin_temp_buffers_compat(struct te_request_compat *request,
191 struct tlk_context *context)
194 struct te_oper_param_compat *params;
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:
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,
210 pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__);
217 cpumask_t saved_cpu_mask;
218 static void switch_cpumask_to_cpu0(void)
221 cpumask_t local_cpu_mask = CPU_MASK_NONE;
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);
227 pr_err("sched_setaffinity #1 -> 0x%lX", ret);
230 static void restore_cpumask(void)
232 long ret = sched_setaffinity(0, &saved_cpu_mask);
234 pr_err("sched_setaffinity #2 -> 0x%lX", ret);
237 static inline void switch_cpumask_to_cpu0(void) {};
238 static inline void restore_cpumask(void) {};
241 uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
245 switch_cpumask_to_cpu0();
247 retval = _tlk_generic_smc(arg0, arg1, arg2);
249 while (retval == TE_ERROR_PREEMPT_BY_IRQ ||
250 retval == TE_ERROR_PREEMPT_BY_FS) {
251 if (retval == TE_ERROR_PREEMPT_BY_IRQ) {
252 retval = _tlk_generic_smc((60 << 24), 0, 0);
255 retval = _tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0);
261 /* Print TLK logs if any */
267 uint32_t tlk_extended_smc(uintptr_t *regs)
271 switch_cpumask_to_cpu0();
273 retval = _tlk_extended_smc(regs);
274 while (retval == 0xFFFFFFFD)
275 retval = _tlk_generic_smc((60 << 24), 0, 0);
279 /* Print TLK logs if any */
288 static void do_smc(struct te_request *request, struct tlk_device *dev)
291 uint32_t smc_params = 0;
293 if (dev->req_param_buf) {
294 smc_args = (char *)request - dev->req_param_buf;
296 smc_params = (char *)request->params -
299 smc_args = (uint32_t)virt_to_phys(request);
301 smc_params = (uint32_t)virt_to_phys(request->params);
304 tlk_generic_smc(request->type, smc_args, smc_params);
310 static void do_smc_compat(struct te_request_compat *request,
311 struct tlk_device *dev)
314 uint32_t smc_params = 0;
316 smc_args = (char *)request - dev->req_param_buf;
317 if (request->params) {
319 (char *)(uintptr_t)request->params - dev->req_param_buf;
322 tlk_generic_smc(request->type, smc_args, smc_params);
325 struct tlk_smc_work_args {
331 static long tlk_generic_smc_on_cpu0(void *args)
333 struct tlk_smc_work_args *work;
334 int cpu = cpu_logical_map(smp_processor_id());
339 work = (struct tlk_smc_work_args *)args;
340 retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
341 while (retval == 0xFFFFFFFD)
342 retval = _tlk_generic_smc((60 << 24), 0, 0);
347 * VPR programming SMC
349 * This routine is called both from normal threads and worker threads.
350 * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
351 * any calls to sched_setaffinity will fail.
353 * If it's a worker thread on CPU0, just invoke the SMC directly. If
354 * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
357 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
361 /* Share the same lock used when request is send from user side */
362 mutex_lock(&smc_lock);
365 (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
366 struct tlk_smc_work_args work_args;
367 int cpu = cpu_logical_map(smp_processor_id());
369 work_args.arg0 = TE_SMC_PROGRAM_VPR;
370 work_args.arg1 = (uint32_t)vpr_base;
371 work_args.arg2 = vpr_size;
373 /* workers don't change CPU. depending on the CPU, execute
374 * directly or sched work */
375 if (cpu == 0 && (current->flags & PF_WQ_WORKER))
376 retval = tlk_generic_smc_on_cpu0(&work_args);
378 retval = work_on_cpu(0,
379 tlk_generic_smc_on_cpu0, &work_args);
381 retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
382 (uintptr_t)vpr_base, vpr_size);
385 mutex_unlock(&smc_lock);
387 if (retval != OTE_SUCCESS) {
388 pr_err("te_set_vpr_params failed err (0x%x)\n", retval);
393 EXPORT_SYMBOL(te_set_vpr_params);
396 * Open session SMC (supporting client-based te_open_session() calls)
398 void te_open_session(struct te_opensession *cmd,
399 struct te_request *request,
400 struct tlk_context *context)
404 ret = te_setup_temp_buffers(request, context);
405 if (ret != OTE_SUCCESS) {
406 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
407 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
411 memcpy(&request->dest_uuid,
413 sizeof(struct te_service_id));
415 pr_info("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n",
416 request->dest_uuid[0],
417 request->dest_uuid[1],
418 request->dest_uuid[2],
419 request->dest_uuid[3]);
421 request->type = TE_SMC_OPEN_SESSION;
423 do_smc(request, context->dev);
425 te_unpin_temp_buffers(request, context);
429 * Close session SMC (supporting client-based te_close_session() calls)
431 void te_close_session(struct te_closesession *cmd,
432 struct te_request *request,
433 struct tlk_context *context)
435 request->session_id = cmd->session_id;
436 request->type = TE_SMC_CLOSE_SESSION;
438 do_smc(request, context->dev);
440 pr_info("Error closing session: %08x\n", request->result);
444 * Launch operation SMC (supporting client-based te_launch_operation() calls)
446 void te_launch_operation(struct te_launchop *cmd,
447 struct te_request *request,
448 struct tlk_context *context)
452 ret = te_setup_temp_buffers(request, context);
453 if (ret != OTE_SUCCESS) {
454 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
455 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
459 request->session_id = cmd->session_id;
460 request->command_id = cmd->operation.command;
461 request->type = TE_SMC_LAUNCH_OPERATION;
463 do_smc(request, context->dev);
465 te_unpin_temp_buffers(request, context);
469 * Open session SMC (supporting client-based te_open_session() calls)
471 void te_open_session_compat(struct te_opensession_compat *cmd,
472 struct te_request_compat *request,
473 struct tlk_context *context)
477 ret = te_setup_temp_buffers_compat(request, context);
478 if (ret != OTE_SUCCESS) {
479 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
480 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
484 memcpy(&request->dest_uuid,
486 sizeof(struct te_service_id));
488 pr_info("OPEN_CLIENT_SESSION_COMPAT: 0x%x 0x%x 0x%x 0x%x\n",
489 request->dest_uuid[0],
490 request->dest_uuid[1],
491 request->dest_uuid[2],
492 request->dest_uuid[3]);
494 request->type = TE_SMC_OPEN_SESSION;
496 do_smc_compat(request, context->dev);
498 te_unpin_temp_buffers_compat(request, context);
502 * Close session SMC (supporting client-based te_close_session() calls)
504 void te_close_session_compat(struct te_closesession_compat *cmd,
505 struct te_request_compat *request,
506 struct tlk_context *context)
508 request->session_id = cmd->session_id;
509 request->type = TE_SMC_CLOSE_SESSION;
511 do_smc_compat(request, context->dev);
513 pr_info("Error closing session: %08x\n", request->result);
517 * Launch operation SMC (supporting client-based te_launch_operation() calls)
519 void te_launch_operation_compat(struct te_launchop_compat *cmd,
520 struct te_request_compat *request,
521 struct tlk_context *context)
525 ret = te_setup_temp_buffers_compat(request, context);
526 if (ret != OTE_SUCCESS) {
527 pr_err("te_setup_temp_buffers failed err (0x%x)\n", ret);
528 SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API);
532 request->session_id = cmd->session_id;
533 request->command_id = cmd->operation.command;
534 request->type = TE_SMC_LAUNCH_OPERATION;
536 do_smc_compat(request, context->dev);
538 te_unpin_temp_buffers_compat(request, context);
541 static int __init tlk_register_irq_handler(void)
543 tlk_generic_smc(TE_SMC_REGISTER_IRQ_HANDLER,
544 (uintptr_t)tlk_irq_handler, 0);
548 arch_initcall(tlk_register_irq_handler);