tlk_driver: 5/22 update
[tegra/ote_partner/tlk_driver.git] / ote_comms.c
index da260a5..11d43b5 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <asm/smp_plat.h>
 
 #include "ote_protocol.h"
 
@@ -244,8 +245,15 @@ uint32_t tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2)
        switch_cpumask_to_cpu0();
 
        retval = _tlk_generic_smc(arg0, arg1, arg2);
-       while (retval == 0xFFFFFFFD)
-               retval = _tlk_generic_smc((60 << 24), 0, 0);
+       while (retval == TE_ERROR_PREEMPT_BY_IRQ ||
+              retval == TE_ERROR_PREEMPT_BY_FS) {
+               if (retval == TE_ERROR_PREEMPT_BY_IRQ) {
+                       retval = _tlk_generic_smc((60 << 24), 0, 0);
+               } else {
+                       tlk_ss_op();
+                       retval = _tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0);
+               }
+       }
 
        restore_cpumask();
 
@@ -313,8 +321,37 @@ static void do_smc_compat(struct te_request_compat *request,
        tlk_generic_smc(request->type, smc_args, smc_params);
 }
 
+struct tlk_smc_work_args {
+       uint32_t arg0;
+       uint32_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 == 0xFFFFFFFD)
+               retval = _tlk_generic_smc((60 << 24), 0, 0);
+       return retval;
+}
+
 /*
  * VPR programming SMC
+ *
+ * This routine is called both from normal threads and worker threads.
+ * The worker threads are per-cpu and have PF_NO_SETAFFINITY set, so
+ * any calls to sched_setaffinity will fail.
+ *
+ * If it's a worker thread on CPU0, just invoke the SMC directly. If
+ * it's running on a non-CPU0, use work_on_cpu() to schedule the SMC
+ * on CPU0.
  */
 int te_set_vpr_params(void *vpr_base, size_t vpr_size)
 {
@@ -323,8 +360,26 @@ 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);
 
-       retval = tlk_generic_smc(TE_SMC_PROGRAM_VPR, (uintptr_t)vpr_base,
-                       vpr_size);
+       if (current->flags &
+           (PF_WQ_WORKER | PF_NO_SETAFFINITY | PF_KTHREAD)) {
+               struct tlk_smc_work_args work_args;
+               int cpu = cpu_logical_map(smp_processor_id());
+
+               work_args.arg0 = TE_SMC_PROGRAM_VPR;
+               work_args.arg1 = (uint32_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);
+       }
 
        mutex_unlock(&smc_lock);