[FOSS_TLK]security: tlk: common function to switch to CPU0
Varun Wadekar [Thu, 11 Dec 2014 01:16:40 +0000 (06:16 +0530)]
TLK runs only on CPU0 so we have to switch CPUs before we
issue any request to the secure world. There are instances
when the requests are sent from workqueues which need some
extra code before we can run on CPU0. Previously, we used
this code only for resizing VPR regions. But it seems that
the requests for TAs can also benefit from this approach.

Encapsulate the logic in a common function, send_smc(), and
remove tlk_generic_smc(), tlk_extended_smc() functions. For
non-PF_NO_SETAFFINITY scnearios, check we can switch the
CPU mask to run on CPU0. If for some reason the CPU switch
fails, then we schedule work on CPU0 instead. This takes care
of the previous corner cases when the CPU switch failed and
we continued on the same CPU.

Change-Id: I3797bb50acbf379a4ddc49c90206d6d697549471
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/755006
Reviewed-by: Automatic_Commit_Validation_User

security/tlk_driver/ote_asm.S
security/tlk_driver/ote_comms.c
security/tlk_driver/ote_device.c
security/tlk_driver/ote_fiq_glue.c
security/tlk_driver/ote_fs.c
security/tlk_driver/ote_log.c
security/tlk_driver/ote_protocol.h

index 684f8ea..fd63d07 100644 (file)
@@ -24,25 +24,6 @@ ENTRY(_tlk_generic_smc)
        ret
 ENDPROC(_tlk_generic_smc)
 
-       /* allows MAX_EXT_SMC_ARGS (r0-r11) to be passed in registers */
-
-/* uint32_t tlk_extended_smc(uint32_t *regs) */
-ENTRY(_tlk_extended_smc)
-       /*
-        * Allows MAX_EXT_SMC_ARGS (r0-r11) to be passed in registers
-        * (for aarch64, these are scratch, so no need to save them)
-        */
-       mov     x12, x0
-       ldp     x0, x1, [x12], #16
-       ldp     x2, x3, [x12], #16
-       ldp     x4, x5, [x12], #16
-       ldp     x6, x7, [x12], #16
-       ldp     x8, x9, [x12], #16
-       ldp     x10, x11, [x12], #16
-       smc     #0
-       ret
-ENDPROC(_tlk_extended_smc)
-
 ENTRY(tlk_fiq_glue_aarch64)
        sub     sp, sp, #S_FRAME_SIZE - S_LR
        stp     x0, x1, [sp, #-16]!
@@ -79,12 +60,4 @@ ENTRY(_tlk_generic_smc)
        mov     pc, lr
 ENDPROC(_tlk_generic_smc)
 
-ENTRY(_tlk_extended_smc)
-       stmfd   sp!, {r4-r12}   @ save reg state
-       mov     r12, r0         @ reg ptr to r12
-       ldmia   r12, {r0-r11}   @ load arg regs
-       smc     #0
-       ldmfd   sp!, {r4-r12}   @ restore saved regs
-ENDPROC(_tlk_extended_smc)
-
 #endif
index 1a3c3fa..4d4c7e6 100644 (file)
@@ -203,7 +203,7 @@ static struct te_session *te_get_session(struct tlk_context *context,
 
 #ifdef CONFIG_SMP
 cpumask_t saved_cpu_mask;
-static void switch_cpumask_to_cpu0(void)
+static long switch_cpumask_to_cpu0(void)
 {
        long ret;
        cpumask_t local_cpu_mask = CPU_MASK_NONE;
@@ -213,6 +213,8 @@ static void switch_cpumask_to_cpu0(void)
        ret = sched_setaffinity(0, &local_cpu_mask);
        if (ret)
                pr_err("%s: sched_setaffinity #1 -> 0x%lX", __func__, ret);
+
+       return ret;
 }
 
 static void restore_cpumask(void)
@@ -222,17 +224,24 @@ static void restore_cpumask(void)
                pr_err("%s: sched_setaffinity #2 -> 0x%lX", __func__, ret);
 }
 #else
-static inline void switch_cpumask_to_cpu0(void) {};
+static inline long switch_cpumask_to_cpu0(void) { return 0; };
 static inline void restore_cpumask(void) {};
 #endif
 
-uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
+struct tlk_smc_work_args {
+       uint32_t arg0;
+       uintptr_t arg1;
+       uint32_t arg2;
+};
+
+static long tlk_generic_smc_on_cpu0(void *args)
 {
+       struct tlk_smc_work_args *work;
        uint32_t retval;
 
-       switch_cpumask_to_cpu0();
+       work = (struct tlk_smc_work_args *)args;
+       retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
 
-       retval = _tlk_generic_smc(arg0, arg1, arg2);
        while (retval == TE_ERROR_PREEMPT_BY_IRQ ||
               retval == TE_ERROR_PREEMPT_BY_FS) {
                if (retval == TE_ERROR_PREEMPT_BY_FS)
@@ -240,30 +249,47 @@ uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
                retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
        }
 
-       restore_cpumask();
-
        /* Print TLK logs if any */
        ote_print_logs();
 
        return retval;
 }
 
-uint32_t tlk_extended_smc(uintptr_t *regs)
+uint32_t send_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
 {
-       uint32_t retval;
+       long ret;
+       struct tlk_smc_work_args work_args;
 
-       switch_cpumask_to_cpu0();
+       work_args.arg0 = arg0;
+       work_args.arg1 = arg1;
+       work_args.arg2 = arg2;
 
-       retval = _tlk_extended_smc(regs);
-       while (retval == TE_ERROR_PREEMPT_BY_IRQ)
-               retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
+       if (current->flags &
+           (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
+               int cpu = cpu_logical_map(get_cpu());
+               put_cpu();
 
-       restore_cpumask();
+               /* workers don't change CPU. depending on the CPU, execute
+                * directly or sched work */
+               if (cpu == 0 && (current->flags & PF_WQ_WORKER))
+                       return tlk_generic_smc_on_cpu0(&work_args);
+               else
+                       return work_on_cpu(0,
+                                       tlk_generic_smc_on_cpu0, &work_args);
+       }
 
-       /* Print TLK logs if any */
-       ote_print_logs();
+       /* switch to CPU0 */
+       ret = switch_cpumask_to_cpu0();
+       if (ret) {
+               /* not able to switch, schedule work on CPU0 */
+               ret = work_on_cpu(0, tlk_generic_smc_on_cpu0, &work_args);
+       } else {
+               /* switched to CPU0 */
+               ret = tlk_generic_smc_on_cpu0(&work_args);
+               restore_cpumask();
+       }
 
-       return retval;
+       return ret;
 }
 
 /*
@@ -280,28 +306,7 @@ static void do_smc(struct te_request *request, struct tlk_device *dev)
                        (char *)(uintptr_t)request->params - dev->req_param_buf;
        }
 
-       tlk_generic_smc(request->type, smc_args, smc_params);
-}
-
-struct tlk_smc_work_args {
-       uint32_t arg0;
-       uintptr_t arg1;
-       uint32_t arg2;
-};
-
-static long tlk_generic_smc_on_cpu0(void *args)
-{
-       struct tlk_smc_work_args *work;
-       int cpu = cpu_logical_map(smp_processor_id());
-       uint32_t retval;
-
-       BUG_ON(cpu != 0);
-
-       work = (struct tlk_smc_work_args *)args;
-       retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2);
-       while (retval == TE_ERROR_PREEMPT_BY_IRQ)
-               retval = _tlk_generic_smc(TE_SMC_RESTART, 0, 0);
-       return retval;
+       (void)send_smc(request->type, smc_args, smc_params);
 }
 
 /*
@@ -322,27 +327,7 @@ int te_set_vpr_params(void *vpr_base, size_t vpr_size)
        /* Share the same lock used when request is send from user side */
        mutex_lock(&smc_lock);
 
-       if (current->flags &
-           (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
-               struct tlk_smc_work_args work_args;
-               int cpu = cpu_logical_map(get_cpu());
-
-               put_cpu();
-               work_args.arg0 = TE_SMC_PROGRAM_VPR;
-               work_args.arg1 = (uintptr_t)vpr_base;
-               work_args.arg2 = vpr_size;
-
-               /* workers don't change CPU. depending on the CPU, execute
-                * directly or sched work */
-               if (cpu == 0 && (current->flags & PF_WQ_WORKER))
-                       retval = tlk_generic_smc_on_cpu0(&work_args);
-               else
-                       retval = work_on_cpu(0,
-                                       tlk_generic_smc_on_cpu0, &work_args);
-       } else {
-               retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR,
-                                       (uintptr_t)vpr_base, vpr_size);
-       }
+       retval = send_smc(TE_SMC_PROGRAM_VPR, (uintptr_t)vpr_base, vpr_size);
 
        mutex_unlock(&smc_lock);
 
index 8fe6ccd..d0a4d79 100644 (file)
@@ -57,7 +57,7 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
         * phys addresses are passed in do_smc).
         */
        dev->req_param_buf = NULL;
-       use_reqbuf = !tlk_generic_smc(TE_SMC_REGISTER_REQ_BUF, 0, 0);
+       use_reqbuf = !send_smc(TE_SMC_REGISTER_REQ_BUF, 0, 0);
 
        if (use_reqbuf) {
                dev->req_param_buf = kmalloc((2 * PAGE_SIZE), GFP_KERNEL);
@@ -67,7 +67,7 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
                dev->param_addr = (struct te_oper_param *)
                                        (dev->req_param_buf + PAGE_SIZE);
 
-               tlk_generic_smc(TE_SMC_REGISTER_REQ_BUF,
+               send_smc(TE_SMC_REGISTER_REQ_BUF,
                                (uintptr_t)dev->req_addr, (2 * PAGE_SIZE));
        } else {
                dev->req_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
index 69466af..fdfb4bd 100644 (file)
@@ -41,7 +41,7 @@ int fiq_glue_register_handler(struct fiq_glue_handler *handler)
 
        current_handler = handler;
 
-       ret = tlk_generic_smc(TE_SMC_REGISTER_FIQ_GLUE,
+       ret = send_smc(TE_SMC_REGISTER_FIQ_GLUE,
                        (uintptr_t)tlk_fiq_glue_aarch64, 0);
        if (ret)
                pr_err("%s: failed to register FIQ glue\n", __func__);
index 8849879..1c83878 100644 (file)
@@ -93,7 +93,7 @@ static int __init tlk_ss_init(void)
                return -ENOMEM;
        }
 
-       ret = tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER,
+       ret = send_smc(TE_SMC_SS_REGISTER_HANDLER,
                        (uintptr_t)ss_op_shmem, 0);
        if (ret != 0) {
                dma_free_coherent(NULL, sizeof(struct te_ss_op),
index d884060..bb99eee 100644 (file)
@@ -186,7 +186,7 @@ static int __init ote_logger_init(void)
                /* Node is present, but logger is disabled */
                smc_args[0] = TE_SMC_INIT_LOGGER;
                smc_args[1] = 0;
-               tlk_generic_smc(smc_args[0], smc_args[1], 0);
+               send_smc(smc_args[0], smc_args[1], 0);
 
                return ret;
        }
@@ -198,7 +198,7 @@ static int __init ote_logger_init(void)
        smc_args[1] = (uintptr_t)cb;
 
        /* enable logging only if secure firmware supports it */
-       if (!tlk_generic_smc(smc_args[0], smc_args[1], 0))
+       if (!send_smc(smc_args[0], smc_args[1], 0))
                ote_logging_enabled = 1;
 
        ote_print_logs();
index fc9048b..8a36605 100644 (file)
@@ -49,10 +49,8 @@ extern struct mutex smc_lock;
 extern struct tlk_device tlk_dev;
 extern void tlk_fiq_glue_aarch64(void);
 
+uint32_t send_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2);
 uint32_t _tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2);
-uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2);
-uint32_t _tlk_extended_smc(uintptr_t *args);
-uint32_t tlk_extended_smc(uintptr_t *args);
 void tlk_irq_handler(void);
 
 /* errors returned by secure world in reponse to SMC calls */