tlk_driver: 5/22 update daily-2014.06.20.0_release-tlk daily-2014.07.14.1_release-tlk daily-2014.07.17.0_release-tlk
Dennis Huang [Thu, 22 May 2014 23:57:28 +0000 (16:57 -0700)]
- ensure VPR SMC occurs on CPU0
- modify secure storage glue

Change-Id: I309733af47a1fbd4fbf6bdba618f2b1de6c83eb2
Reviewed-on: http://git-master/r/413472
Reviewed-by: Dennis Huang <denhuang@nvidia.com>
Tested-by: Dennis Huang <denhuang@nvidia.com>

ote_comms.c
ote_device.c
ote_fs.c
ote_protocol.h

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);
 
index d7dfd7a..32a2b65 100644 (file)
@@ -712,6 +712,11 @@ static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num,
                mutex_unlock(&smc_lock);
                break;
 
+       case TE_IOCTL_SS_NEW_REQ_LEGACY:
+       case TE_IOCTL_SS_REQ_COMPLETE_LEGACY:
+               err = te_handle_ss_ioctl_legacy(file, ioctl_num, ioctl_param);
+               break;
+
        case TE_IOCTL_SS_NEW_REQ:
        case TE_IOCTL_SS_REQ_COMPLETE:
                err = te_handle_ss_ioctl(file, ioctl_num, ioctl_param);
index e3d427a..f58bdd6 100644 (file)
--- a/ote_fs.c
+++ b/ote_fs.c
@@ -30,6 +30,7 @@
 static DECLARE_COMPLETION(req_ready);
 static DECLARE_COMPLETION(req_complete);
 
+static struct te_ss_op_legacy *ss_op_shmem_legacy;
 static struct te_ss_op *ss_op_shmem;
 static uint32_t ss_op_size;
 
@@ -38,26 +39,26 @@ static void indicate_ss_op_complete(void)
        tlk_generic_smc(TE_SMC_SS_REQ_COMPLETE, 0, 0);
 }
 
-int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num,
+int te_handle_ss_ioctl_legacy(struct file *file, unsigned int ioctl_num,
        unsigned long ioctl_param)
 {
        switch (ioctl_num) {
-       case TE_IOCTL_SS_NEW_REQ:
+       case TE_IOCTL_SS_NEW_REQ_LEGACY:
                /* wait for a new request */
                if (wait_for_completion_interruptible(&req_ready))
                        return -ENODATA;
 
                /* transfer pending request to daemon's buffer */
-               if (copy_to_user((void __user *)ioctl_param, ss_op_shmem,
+               if (copy_to_user((void __user *)ioctl_param, ss_op_shmem_legacy,
                                        ss_op_size)) {
                        pr_err("copy_to_user failed for new request\n");
                        return -EFAULT;
                }
                break;
 
-       case TE_IOCTL_SS_REQ_COMPLETE: /* request complete */
-               if (copy_from_user(ss_op_shmem, (void __user *)ioctl_param,
-                                       ss_op_size)) {
+       case TE_IOCTL_SS_REQ_COMPLETE_LEGACY: /* request complete */
+               if (copy_from_user(ss_op_shmem_legacy,
+                       (void __user *)ioctl_param, ss_op_size)) {
                        pr_err("copy_from_user failed for request\n");
                        return -EFAULT;
                }
@@ -70,7 +71,7 @@ int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num,
        return 0;
 }
 
-void tlk_ss_op(uint32_t size)
+void tlk_ss_op_legacy(uint32_t size)
 {
        /* store size of request */
        ss_op_size = size;
@@ -85,9 +86,71 @@ void tlk_ss_op(uint32_t size)
        indicate_ss_op_complete();
 }
 
+static int __init tlk_ss_init_legacy(void)
+{
+       dma_addr_t ss_op_shmem_dma;
+
+       /* allocate shared memory buffer */
+       ss_op_shmem_legacy = dma_alloc_coherent(NULL,
+               sizeof(struct te_ss_op_legacy), &ss_op_shmem_dma, GFP_KERNEL);
+       if (!ss_op_shmem_legacy) {
+               pr_err("%s: no memory available for fs operations\n", __func__);
+               return -ENOMEM;
+       }
+
+       tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER_LEGACY,
+               (uintptr_t)tlk_ss_op_legacy, (uintptr_t)ss_op_shmem_legacy);
+
+       return 0;
+}
+
+arch_initcall(tlk_ss_init_legacy);
+
+int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num,
+       unsigned long ioctl_param)
+{
+       switch (ioctl_num) {
+       case TE_IOCTL_SS_NEW_REQ:
+               /* wait for a new request */
+               if (wait_for_completion_interruptible(&req_ready))
+                       return -ENODATA;
+
+               /* transfer pending request to daemon's buffer */
+               if (copy_to_user((void __user *)ioctl_param, ss_op_shmem->data,
+                                       ss_op_shmem->req_size)) {
+                       pr_err("copy_to_user failed for new request\n");
+                       return -EFAULT;
+               }
+               break;
+
+       case TE_IOCTL_SS_REQ_COMPLETE: /* request complete */
+               if (copy_from_user(ss_op_shmem->data,
+                       (void __user *)ioctl_param, ss_op_shmem->req_size)) {
+                       pr_err("copy_from_user failed for request\n");
+                       return -EFAULT;
+               }
+
+               /* signal the producer */
+               complete(&req_complete);
+               break;
+       }
+
+       return 0;
+}
+
+void tlk_ss_op(void)
+{
+       /* signal consumer */
+       complete(&req_ready);
+
+       /* wait for the consumer's signal */
+       wait_for_completion(&req_complete);
+}
+
 static int __init tlk_ss_init(void)
 {
        dma_addr_t ss_op_shmem_dma;
+       int32_t ret;
 
        /* allocate shared memory buffer */
        ss_op_shmem = dma_alloc_coherent(NULL, sizeof(struct te_ss_op),
@@ -97,8 +160,14 @@ static int __init tlk_ss_init(void)
                return -ENOMEM;
        }
 
-       tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER,
-                       (uintptr_t)tlk_ss_op, (uintptr_t)ss_op_shmem);
+       ret = tlk_generic_smc(TE_SMC_SS_REGISTER_HANDLER,
+                       (uintptr_t)ss_op_shmem, 0);
+       if (ret != 0) {
+               dma_free_coherent(NULL, sizeof(struct te_ss_op),
+                       (void *)ss_op_shmem, ss_op_shmem_dma);
+               ss_op_shmem = NULL;
+               return -ENOTSUPP;
+       }
 
        return 0;
 }
index c5aea3d..608ee89 100644 (file)
 #define TE_IOCTL_LAUNCH_OPERATION_COMPAT \
        _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd_compat)
 
+#define TE_IOCTL_SS_NEW_REQ_LEGACY \
+       _IOR(TE_IOCTL_MAGIC_NUMBER,  0x20, struct te_ss_op_legacy)
+#define TE_IOCTL_SS_REQ_COMPLETE_LEGACY \
+       _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x21, struct te_ss_op_legacy)
+
+/* ioctls using new SS structs (eventually to replace current SS ioctls) */
 #define TE_IOCTL_SS_NEW_REQ \
        _IOR(TE_IOCTL_MAGIC_NUMBER,  0x20, struct te_ss_op)
 #define TE_IOCTL_SS_REQ_COMPLETE \
@@ -65,6 +71,12 @@ 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 */
+enum {
+       TE_ERROR_PREEMPT_BY_IRQ = 0xFFFFFFFD,
+       TE_ERROR_PREEMPT_BY_FS = 0xFFFFFFFE,
+};
+
 struct tlk_device {
        struct te_request *req_addr;
        dma_addr_t req_addr_phys;
@@ -115,8 +127,9 @@ enum {
        TE_SMC_REGISTER_IRQ_HANDLER     = 0x32000004,
        TE_SMC_NS_IRQ_DONE              = 0x32000005,
        TE_SMC_INIT_LOGGER              = 0x32000007,
-       TE_SMC_SS_REGISTER_HANDLER      = 0x32000008,
+       TE_SMC_SS_REGISTER_HANDLER_LEGACY       = 0x32000008,
        TE_SMC_SS_REQ_COMPLETE          = 0x32000009,
+       TE_SMC_SS_REGISTER_HANDLER      = 0x32000010,
 
        /* SIP (SOC specific) calls.  */
        TE_SMC_PROGRAM_VPR              = 0x82000003,
@@ -308,13 +321,21 @@ void te_launch_operation_compat(struct te_launchop_compat *cmd,
 
 #define SS_OP_MAX_DATA_SIZE    0x1000
 struct te_ss_op {
+       uint32_t        req_size;
        uint8_t         data[SS_OP_MAX_DATA_SIZE];
 };
 
+struct te_ss_op_legacy {
+       uint8_t         data[SS_OP_MAX_DATA_SIZE];
+};
+
+int te_handle_ss_ioctl_legacy(struct file *file, unsigned int ioctl_num,
+               unsigned long ioctl_param);
 int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num,
                unsigned long ioctl_param);
 int te_handle_fs_ioctl(struct file *file, unsigned int ioctl_num,
                unsigned long ioctl_param);
 void ote_print_logs(void);
+void tlk_ss_op(void);
 
 #endif