security: tlk_driver: shared req/param reg SMC
Chris Johnson [Wed, 4 Sep 2013 00:48:59 +0000 (17:48 -0700)]
Add support for attempting to register the req/param buffers with
TLK. If it fails, we know we're on an older TLK and have to use
phys address to indicate where the buffers are.

If the SMC succeeds, we pass the virtual pointers to the buffers
knowing TLK will map them in and use them directly. This takes
care of the coherency and reduces our dependence on phys addrs.

Once both TLK and kernel changes have been synced up, we'll remove
the legacy support.

Bug 1353314

Change-Id: I1a73ddc66f002f966e80579ac49bbbd3e64a1f72
Signed-off-by: Chris Johnson <cwj@nvidia.com>
Reviewed-on: http://git-master/r/269802
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

security/tlk_driver/ote_comms.c
security/tlk_driver/ote_device.c
security/tlk_driver/ote_fs.c
security/tlk_driver/ote_irq.S
security/tlk_driver/ote_protocol.h

index d31cd24..6e3eb0a 100644 (file)
@@ -36,13 +36,6 @@ static unsigned long saved_regs[16];
 
 #define SET_RESULT(req, r, ro) { req->result = r; req->result_origin = ro; }
 
-#define TLK_GENERIC_SMC(arg0, arg1, arg2) \
-       do { \
-               switch_cpumask_to_cpu0(); \
-               tlk_generic_smc(arg0, arg1, arg2); \
-               restore_cpumask(); \
-       } while (0)
-
 static int te_pin_user_pages(void *buffer, size_t size,
                unsigned long *pages_ptr)
 {
@@ -278,13 +271,21 @@ uint32_t tlk_extended_smc(uint32_t *regs)
 /*
  * Do an SMC call
  */
-static void do_smc(struct te_request *request)
+static void do_smc(struct te_request *request, struct tlk_device *dev)
 {
-       phys_addr_t smc_args = virt_to_phys(request);
-       phys_addr_t smc_params = 0;
-
-       if (request->params)
-               smc_params = virt_to_phys(request->params);
+       uint32_t smc_args;
+       uint32_t smc_params = 0;
+
+       if (dev->req_param_buf) {
+               smc_args = (char *)request - dev->req_param_buf;
+               if (request->params)
+                       smc_params = (char *)request->params -
+                                               dev->req_param_buf;
+       } else {
+               smc_args = (uint32_t)virt_to_phys(request);
+               if (request->params)
+                       smc_params = (uint32_t)virt_to_phys(request->params);
+       }
 
        TLK_GENERIC_SMC(request->type, smc_args, smc_params);
 }
@@ -317,7 +318,7 @@ void te_open_session(struct te_opensession *cmd,
 
        request->type = TE_SMC_OPEN_SESSION;
 
-       do_smc(request);
+       do_smc(request, context->dev);
 
        te_unpin_temp_buffers(request, context);
 }
@@ -326,12 +327,13 @@ void te_open_session(struct te_opensession *cmd,
  * Close session SMC (supporting client-based te_close_session() calls)
  */
 void te_close_session(struct te_closesession *cmd,
-                     struct te_request *request)
+                     struct te_request *request,
+                     struct tlk_context *context)
 {
        request->session_id = cmd->session_id;
        request->type = TE_SMC_CLOSE_SESSION;
 
-       do_smc(request);
+       do_smc(request, context->dev);
        if (request->result)
                pr_info("Error closing session: %08x\n", request->result);
 }
@@ -356,7 +358,7 @@ void te_launch_operation(struct te_launchop *cmd,
        request->command_id = cmd->operation.command;
        request->type = TE_SMC_LAUNCH_OPERATION;
 
-       do_smc(request);
+       do_smc(request, context->dev);
 
        te_unpin_temp_buffers(request, context);
 }
index f9b0e56..6292432 100644 (file)
@@ -48,22 +48,44 @@ u32 notrace tegra_read_cycle(void)
        return cycle_count;
 }
 
-/*
- * The maximum number of outstanding command requests.
- */
-#define TE_CMD_DESC_MAX                (PAGE_SIZE / sizeof(struct te_request))
-#define TE_PARAM_MAX           (PAGE_SIZE / sizeof(struct te_oper_param))
-
 static int te_create_free_cmd_list(struct tlk_device *dev)
 {
        int cmd_desc_count, ret = 0;
        struct te_cmd_req_desc *req_desc;
        int bitmap_size;
+       bool use_reqbuf;
+
+       /*
+        * Check if new shared req/param register SMC is supported.
+        *
+        * If it is, TLK can map in the shared req/param buffers and do_smc
+        * only needs to send the offsets within each (with cache coherency
+        * being maintained by HW through an NS mapping).
+        *
+        * If the SMC support is not yet present, then fallback to the old
+        * mode of writing to an uncached buffer to maintain coherency (and
+        * phys addresses are passed in do_smc).
+        */
+       dev->req_param_buf = NULL;
+       use_reqbuf = !TLK_GENERIC_SMC(TE_SMC_REGISTER_REQ_BUF, 0, 0);
+
+       if (use_reqbuf) {
+               dev->req_param_buf = kmalloc((2 * PAGE_SIZE), GFP_KERNEL);
+
+               /* requests in the first page, params in the second */
+               dev->req_addr   = (struct te_request *) dev->req_param_buf;
+               dev->param_addr = (struct te_oper_param *)
+                                       (dev->req_param_buf + PAGE_SIZE);
+
+               TLK_GENERIC_SMC(TE_SMC_REGISTER_REQ_BUF,
+                               (uint32_t)dev->req_addr, (2 * PAGE_SIZE));
+       } else {
+               dev->req_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
+                                       &dev->req_addr_phys, GFP_KERNEL);
+               dev->param_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
+                                       &dev->param_addr_phys, GFP_KERNEL);
+       }
 
-       dev->req_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
-                               &dev->req_addr_phys, GFP_KERNEL);
-       dev->param_addr = dma_alloc_coherent(NULL, PAGE_SIZE,
-                               &dev->param_addr_phys, GFP_KERNEL);
        if ((dev->req_addr == NULL) || (dev->param_addr == NULL)) {
                ret = -ENOMEM;
                goto error;
@@ -90,7 +112,6 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
        }
 error:
        return ret;
-
 }
 
 static struct te_oper_param *te_get_free_params(struct tlk_device *dev,
@@ -331,7 +352,7 @@ static long te_handle_trustedapp_ioctl(struct file *file,
                memset(request, 0, sizeof(struct te_request));
 
                /* close session cannot fail */
-               te_close_session(&cmd.closesession, request);
+               te_close_session(&cmd.closesession, request, context);
                break;
 
        case TE_IOCTL_LAUNCH_OPERATION:
index b3524bd..cf02e8c 100644 (file)
@@ -44,13 +44,6 @@ static DECLARE_COMPLETION(req_ready);
 static DECLARE_COMPLETION(req_complete);
 static unsigned long secure_error;
 
-#define TLK_EXTENDED_SMC(arg0) \
-       do { \
-               switch_cpumask_to_cpu0(); \
-               tlk_extended_smc(arg0); \
-               restore_cpumask(); \
-       } while (0)
-
 static void indicate_complete(unsigned long ret)
 {
        tlk_generic_smc(TE_SMC_FS_OP_DONE, ret, 0);
index 7bfda88..6305e07 100644 (file)
@@ -16,6 +16,6 @@
 
 ENTRY(tlk_irq_handler)
        movw    r0, #0x1FF1
-       movt    r0, #0xFFFF
+       movt    r0, #0xFFFF     @ TE_SMC_NS_IRQ_DONE
        smc     #0
 ENDPROC(tlk_irq_handler)
index d3b4dd4..4efade0 100644 (file)
 #define TE_IOCTL_MIN_NR        _IOC_NR(TE_IOCTL_OPEN_CLIENT_SESSION)
 #define TE_IOCTL_MAX_NR        _IOC_NR(TE_IOCTL_FILE_REQ_COMPLETE)
 
+/* shared buffer is 2 pages: 1st are requests, 2nd are params */
+#define TE_CMD_DESC_MAX        (PAGE_SIZE / sizeof(struct te_request))
+#define TE_PARAM_MAX   (PAGE_SIZE / sizeof(struct te_oper_param))
+
 #define MAX_EXT_SMC_ARGS       12
 
 uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2);
@@ -52,12 +56,38 @@ static inline void switch_cpumask_to_cpu0(void) {};
 static inline void restore_cpumask(void) {};
 #endif
 
+static inline uint32_t
+TLK_GENERIC_SMC(uint32_t arg0, uint32_t arg1, uint32_t arg2)
+{
+       uint32_t retval;
+
+       switch_cpumask_to_cpu0();
+       retval = tlk_generic_smc(arg0, arg1, arg2);
+       restore_cpumask();
+
+       return retval;
+}
+
+static inline uint32_t
+TLK_EXTENDED_SMC(uint32_t *args)
+{
+       uint32_t retval;
+
+       switch_cpumask_to_cpu0();
+       retval = tlk_extended_smc(args);
+       restore_cpumask();
+
+       return retval;
+}
+
 struct tlk_device {
        struct te_request *req_addr;
        dma_addr_t req_addr_phys;
        struct te_oper_param *param_addr;
        dma_addr_t param_addr_phys;
 
+       char *req_param_buf;
+
        unsigned long *param_bitmap;
 
        struct list_head used_cmd_list;
@@ -90,6 +120,7 @@ enum {
        TE_SMC_REGISTER_IRQ_HANDLER     = 0xFFFF1FF0,
        TE_SMC_NS_IRQ_DONE              = 0xFFFF1FF1,
        TE_SMC_REGISTER_FS_HANDLERS     = 0xFFFF1FF2,
+       TE_SMC_REGISTER_REQ_BUF         = 0xFFFF1FF3,
        TE_SMC_FS_OP_DONE               = 0xFFFF1FFF,
 };
 
@@ -187,7 +218,8 @@ void te_open_session(struct te_opensession *cmd,
        struct tlk_context *context);
 
 void te_close_session(struct te_closesession *cmd,
-       struct te_request *request);
+       struct te_request *request,
+       struct tlk_context *context);
 
 void te_launch_operation(struct te_launchop *cmd,
        struct te_request *request,