blob: c60537a736e2dbb9c45dc1840b80f0cf6b09a7cb [file] [log] [blame]
Mona Hossaind44a3842012-10-15 09:41:35 -07001/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
Mona Hossain2892b6b2012-02-17 13:53:11 -08002 *
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08003 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Mona Hossain2892b6b2012-02-17 13:53:11 -08004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/platform_device.h>
22#include <linux/debugfs.h>
23#include <linux/cdev.h>
24#include <linux/uaccess.h>
25#include <linux/sched.h>
26#include <linux/list.h>
27#include <linux/mutex.h>
28#include <linux/io.h>
Mitchel Humpherys4f8be2e2012-09-06 10:41:41 -070029#include <linux/msm_ion.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080030#include <linux/types.h>
31#include <linux/clk.h>
32#include <linux/qseecom.h>
Mona Hossaind44a3842012-10-15 09:41:35 -070033#include <linux/elf.h>
34#include <linux/firmware.h>
Mona Hossainacea1022012-04-09 13:37:27 -070035#include <linux/freezer.h>
Mona Hossainf1f2ed62012-11-15 19:51:33 -080036#include <linux/scatterlist.h>
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070037#include <mach/board.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080038#include <mach/msm_bus.h>
39#include <mach/msm_bus_board.h>
40#include <mach/scm.h>
Stephen Boyd77db8bb2012-06-27 15:15:16 -070041#include <mach/subsystem_restart.h>
Ramesh Masavarapuff377032012-09-14 12:11:32 -070042#include <mach/socinfo.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080043#include <mach/qseecomi.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080044#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070045#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080046
47#define QSEECOM_DEV "qseecom"
Mona Hossain2892b6b2012-02-17 13:53:11 -080048#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070049#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080050#define QSEE_VERSION_01 0x401000
51#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080052#define QSEE_VERSION_03 0x403000
Amir Samuelovd1fc7412013-03-10 16:56:13 +020053#define QSEE_VERSION_04 0x404000
Zhen Kong336636e2013-04-15 11:04:54 -070054#define QSEE_VERSION_05 0x405000
55
Mona Hossain5b76a622012-11-15 20:09:08 -080056
Mona Hossain05c73562012-10-29 17:49:01 -070057
58#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080059
Mona Hossaind39e33b2012-11-05 13:36:40 -080060#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080061
Mona Hossain13dd8922013-01-03 06:11:09 -080062#define QSEECOM_MAX_SG_ENTRY 512
Mona Hossain4cf78a92013-02-14 12:06:41 -080063#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
Mona Hossainf1f2ed62012-11-15 19:51:33 -080064
Amir Samuelovd1fc7412013-03-10 16:56:13 +020065/* Save partition image hash for authentication check */
66#define SCM_SAVE_PARTITION_HASH_ID 0x01
67
68/* Check if enterprise security is activate */
69#define SCM_IS_ACTIVATED_ID 0x02
70
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070071enum qseecom_clk_definitions {
72 CLK_DFAB = 0,
73 CLK_SFPB,
74};
75
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080076enum qseecom_client_handle_type {
77 QSEECOM_CLIENT_APP = 0,
78 QSEECOM_LISTENER_SERVICE,
79 QSEECOM_SECURE_SERVICE,
80 QSEECOM_GENERIC,
81};
82
Mona Hossainc92629e2013-04-01 13:37:46 -070083enum qseecom_ce_hw_instance {
84 CLK_QSEE = 0,
85 CLK_CE_DRV,
86};
87
Mona Hossain2892b6b2012-02-17 13:53:11 -080088static struct class *driver_class;
89static dev_t qseecom_device_no;
90static struct cdev qseecom_cdev;
91
Mona Hossain2892b6b2012-02-17 13:53:11 -080092static DEFINE_MUTEX(qsee_bw_mutex);
93static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -070094static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -080095
Mona Hossain2892b6b2012-02-17 13:53:11 -080096struct qseecom_registered_listener_list {
97 struct list_head list;
98 struct qseecom_register_listener_req svc;
99 u8 *sb_reg_req;
100 u8 *sb_virt;
101 s32 sb_phys;
102 size_t sb_length;
103 struct ion_handle *ihandle; /* Retrieve phy addr */
104
105 wait_queue_head_t rcv_req_wq;
106 int rcv_req_flag;
107};
108
109struct qseecom_registered_app_list {
110 struct list_head list;
111 u32 app_id;
112 u32 ref_cnt;
113};
114
Mona Hossaind44a3842012-10-15 09:41:35 -0700115struct qseecom_registered_kclient_list {
116 struct list_head list;
117 struct qseecom_handle *handle;
118};
119
Mona Hossain4cf78a92013-02-14 12:06:41 -0800120struct ce_hw_usage_info {
121 uint32_t qsee_ce_hw_instance;
122 uint32_t hlos_ce_hw_instance;
123 uint32_t disk_encrypt_pipe;
124};
125
Mona Hossain17a4faf2013-03-22 16:40:56 -0700126struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700127 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700128 struct clk *ce_core_clk;
129 struct clk *ce_clk;
130 struct clk *ce_core_src_clk;
131 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700132 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700133};
134
Mona Hossain2892b6b2012-02-17 13:53:11 -0800135struct qseecom_control {
136 struct ion_client *ion_clnt; /* Ion client */
137 struct list_head registered_listener_list_head;
138 spinlock_t registered_listener_list_lock;
139
140 struct list_head registered_app_list_head;
141 spinlock_t registered_app_list_lock;
142
Mona Hossaind44a3842012-10-15 09:41:35 -0700143 struct list_head registered_kclient_list_head;
144 spinlock_t registered_kclient_list_lock;
145
Mona Hossain2892b6b2012-02-17 13:53:11 -0800146 wait_queue_head_t send_resp_wq;
147 int send_resp_flag;
148
149 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700150 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700151 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700152 bool commonlib_loaded;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800153 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700154
155 int qsee_bw_count;
156 int qsee_sfpb_bw_count;
157
158 uint32_t qsee_perf_client;
159 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700160 struct qseecom_clk ce_drv;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800161};
162
163struct qseecom_client_handle {
164 u32 app_id;
165 u8 *sb_virt;
166 s32 sb_phys;
167 uint32_t user_virt_sb_base;
168 size_t sb_length;
169 struct ion_handle *ihandle; /* Retrieve phy addr */
170};
171
172struct qseecom_listener_handle {
173 u32 id;
174};
175
176static struct qseecom_control qseecom;
177
178struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800179 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800180 union {
181 struct qseecom_client_handle client;
182 struct qseecom_listener_handle listener;
183 };
184 bool released;
185 int abort;
186 wait_queue_head_t abort_wq;
187 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700188 bool perf_enabled;
189 bool fast_load_enabled;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800190};
191
Mona Hossain4cf78a92013-02-14 12:06:41 -0800192enum qseecom_set_clear_key_flag {
193 QSEECOM_CLEAR_CE_KEY_CMD = 0,
194 QSEECOM_SET_CE_KEY_CMD,
195};
196
197struct qseecom_set_key_parameter {
198 uint32_t ce_hw;
199 uint32_t pipe;
200 uint32_t flags;
201 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
202 unsigned char hash32[QSEECOM_HASH_SIZE];
203 enum qseecom_set_clear_key_flag set_clear_key_flag;
204};
205
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800206struct qseecom_sg_entry {
207 uint32_t phys_addr;
208 uint32_t len;
209};
210
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700211/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800212static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
213static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700214
Mona Hossain2892b6b2012-02-17 13:53:11 -0800215static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800216 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800217{
218 struct qseecom_registered_listener_list *ptr;
219 int unique = 1;
220 unsigned long flags;
221
222 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
223 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800224 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800225 pr_err("Service id: %u is already registered\n",
226 ptr->svc.listener_id);
227 unique = 0;
228 break;
229 }
230 }
231 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
232 return unique;
233}
234
235static struct qseecom_registered_listener_list *__qseecom_find_svc(
236 int32_t listener_id)
237{
238 struct qseecom_registered_listener_list *entry = NULL;
239 unsigned long flags;
240
241 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
242 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
243 {
244 if (entry->svc.listener_id == listener_id)
245 break;
246 }
247 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
248 return entry;
249}
250
251static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
252 struct qseecom_dev_handle *handle,
253 struct qseecom_register_listener_req *listener)
254{
255 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800256 struct qseecom_register_listener_ireq req;
257 struct qseecom_command_scm_resp resp;
258 ion_phys_addr_t pa;
259
260 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800261 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
262 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800263 if (svc->ihandle == NULL) {
264 pr_err("Ion client could not retrieve the handle\n");
265 return -ENOMEM;
266 }
267
268 /* Get the physical address of the ION BUF */
269 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
270
271 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700272 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800273 svc->sb_phys = pa;
274
Mona Hossaind4613de2013-05-15 16:49:29 -0700275 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
276 req.listener_id = svc->svc.listener_id;
277 req.sb_len = svc->sb_length;
278 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800279
Mona Hossaind4613de2013-05-15 16:49:29 -0700280 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800281
Mona Hossaind4613de2013-05-15 16:49:29 -0700282 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800283 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700284 if (ret) {
285 pr_err("qseecom_scm_call failed with err: %d\n", ret);
286 return -EINVAL;
287 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800288
Mona Hossaind4613de2013-05-15 16:49:29 -0700289 if (resp.result != QSEOS_RESULT_SUCCESS) {
290 pr_err("Error SB registration req: resp.result = %d\n",
291 resp.result);
292 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800293 }
294 return 0;
295}
296
297static int qseecom_register_listener(struct qseecom_dev_handle *data,
298 void __user *argp)
299{
300 int ret = 0;
301 unsigned long flags;
302 struct qseecom_register_listener_req rcvd_lstnr;
303 struct qseecom_registered_listener_list *new_entry;
304
305 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
306 if (ret) {
307 pr_err("copy_from_user failed\n");
308 return ret;
309 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800310 data->listener.id = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800311 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800312 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800313 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800314 data->released = true;
315 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800316 }
317
318 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
319 if (!new_entry) {
320 pr_err("kmalloc failed\n");
321 return -ENOMEM;
322 }
323 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
324 new_entry->rcv_req_flag = 0;
325
326 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
327 new_entry->sb_length = rcvd_lstnr.sb_size;
328 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
329 pr_err("qseecom_set_sb_memoryfailed\n");
330 kzfree(new_entry);
331 return -ENOMEM;
332 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800333
Mona Hossain2892b6b2012-02-17 13:53:11 -0800334 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800335 init_waitqueue_head(&new_entry->rcv_req_wq);
336
337 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
338 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
339 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800340
Mona Hossain2892b6b2012-02-17 13:53:11 -0800341 return ret;
342}
343
344static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
345{
346 int ret = 0;
347 unsigned long flags;
348 uint32_t unmap_mem = 0;
349 struct qseecom_register_listener_ireq req;
350 struct qseecom_registered_listener_list *ptr_svc = NULL;
351 struct qseecom_command_scm_resp resp;
352 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
353
Mona Hossaind4613de2013-05-15 16:49:29 -0700354 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
355 req.listener_id = data->listener.id;
356 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800357
Mona Hossaind4613de2013-05-15 16:49:29 -0700358 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800359 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700360 if (ret) {
361 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
362 ret, data->listener.id);
363 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800364 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700365
366 if (resp.result != QSEOS_RESULT_SUCCESS) {
367 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
368 resp.result, data->listener.id);
369 return -EPERM;
370 }
371
Mona Hossain2892b6b2012-02-17 13:53:11 -0800372 data->abort = 1;
373 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
374 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
375 list) {
376 if (ptr_svc->svc.listener_id == data->listener.id) {
377 wake_up_all(&ptr_svc->rcv_req_wq);
378 break;
379 }
380 }
381 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
382
383 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700384 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800385 atomic_read(&data->ioctl_count) <= 1)) {
386 pr_err("Interrupted from abort\n");
387 ret = -ERESTARTSYS;
388 break;
389 }
390 }
391
392 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
393 list_for_each_entry(ptr_svc,
394 &qseecom.registered_listener_list_head,
395 list)
396 {
397 if (ptr_svc->svc.listener_id == data->listener.id) {
398 if (ptr_svc->sb_virt) {
399 unmap_mem = 1;
400 ihandle = ptr_svc->ihandle;
401 }
402 list_del(&ptr_svc->list);
403 kzfree(ptr_svc);
404 break;
405 }
406 }
407 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
408
409 /* Unmap the memory */
410 if (unmap_mem) {
411 if (!IS_ERR_OR_NULL(ihandle)) {
412 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
413 ion_free(qseecom.ion_clnt, ihandle);
414 }
415 }
416 data->released = true;
417 return ret;
418}
419
420static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
421 void __user *argp)
422{
423 ion_phys_addr_t pa;
424 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800425 struct qseecom_set_sb_mem_param_req req;
426 uint32_t len;
427
428 /* Copy the relevant information needed for loading the image */
429 if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
430 return -EFAULT;
431
Mona Hossain2892b6b2012-02-17 13:53:11 -0800432 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800433 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
434 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800435 if (IS_ERR_OR_NULL(data->client.ihandle)) {
436 pr_err("Ion client could not retrieve the handle\n");
437 return -ENOMEM;
438 }
439 /* Get the physical address of the ION BUF */
440 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
441 /* Populate the structure for sending scm call to load image */
442 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700443 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800444 data->client.sb_phys = pa;
445 data->client.sb_length = req.sb_len;
446 data->client.user_virt_sb_base = req.virt_sb_base;
447 return 0;
448}
449
Mona Hossain2892b6b2012-02-17 13:53:11 -0800450static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
451{
452 int ret;
453 ret = (qseecom.send_resp_flag != 0);
454 return ret || data->abort;
455}
456
457static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
458 struct qseecom_command_scm_resp *resp)
459{
460 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800461 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800462 uint32_t lstnr;
463 unsigned long flags;
464 struct qseecom_client_listener_data_irsp send_data_rsp;
465 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700466 sigset_t new_sigset;
467 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800468
Mona Hossain2892b6b2012-02-17 13:53:11 -0800469 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
470 lstnr = resp->data;
471 /*
472 * Wake up blocking lsitener service with the lstnr id
473 */
474 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
475 flags);
476 list_for_each_entry(ptr_svc,
477 &qseecom.registered_listener_list_head, list) {
478 if (ptr_svc->svc.listener_id == lstnr) {
479 ptr_svc->rcv_req_flag = 1;
480 wake_up_interruptible(&ptr_svc->rcv_req_wq);
481 break;
482 }
483 }
484 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
485 flags);
486 if (ptr_svc->svc.listener_id != lstnr) {
487 pr_warning("Service requested for does on exist\n");
488 return -ERESTARTSYS;
489 }
490 pr_debug("waking up rcv_req_wq and "
491 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800492
Mona Hossain91da2c52013-03-29 17:28:31 -0700493 /* initialize the new signal mask with all signals*/
494 sigfillset(&new_sigset);
495 /* block all signals */
496 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
497
498 do {
499 if (!wait_event_freezable(qseecom.send_resp_wq,
500 __qseecom_listener_has_sent_rsp(data)))
501 break;
502 } while (1);
503
504 /* restore signal mask */
505 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
506 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700507 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
508 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700509 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800510 send_data_rsp.status = QSEOS_RESULT_FAILURE;
511 } else {
512 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800513 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800514
Mona Hossain2892b6b2012-02-17 13:53:11 -0800515 qseecom.send_resp_flag = 0;
516 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
517 send_data_rsp.listener_id = lstnr ;
518
519 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
520 (const void *)&send_data_rsp,
521 sizeof(send_data_rsp), resp,
522 sizeof(*resp));
523 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700524 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800525 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800526 return ret;
527 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800528 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
529 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
530 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
531 resp->result, data->client.app_id, lstnr);
532 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700533 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800534 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800535 if (rc)
536 return rc;
537
Mona Hossain2892b6b2012-02-17 13:53:11 -0800538 return ret;
539}
540
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700541static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
542{
543 int32_t ret;
544 struct qseecom_command_scm_resp resp;
545
546 /* SCM_CALL to check if app_id for the mentioned app exists */
547 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
548 sizeof(struct qseecom_check_app_ireq),
549 &resp, sizeof(resp));
550 if (ret) {
551 pr_err("scm_call to check if app is already loaded failed\n");
552 return -EINVAL;
553 }
554
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700555 if (resp.result == QSEOS_RESULT_FAILURE) {
556 return 0;
557 } else {
558 switch (resp.resp_type) {
559 /*qsee returned listener type response */
560 case QSEOS_LISTENER_ID:
561 pr_err("resp type is of listener type instead of app");
562 return -EINVAL;
563 break;
564 case QSEOS_APP_ID:
565 return resp.data;
566 default:
567 pr_err("invalid resp type (%d) from qsee",
568 resp.resp_type);
569 return -ENODEV;
570 break;
571 }
572 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700573}
574
Mona Hossain2892b6b2012-02-17 13:53:11 -0800575static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
576{
577 struct qseecom_registered_app_list *entry = NULL;
578 unsigned long flags = 0;
579 u32 app_id = 0;
580 struct ion_handle *ihandle; /* Ion handle */
581 struct qseecom_load_img_req load_img_req;
582 int32_t ret;
583 ion_phys_addr_t pa = 0;
584 uint32_t len;
585 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800586 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700587 struct qseecom_load_app_ireq load_req;
588
Mona Hossain2892b6b2012-02-17 13:53:11 -0800589 /* Copy the relevant information needed for loading the image */
590 if (__copy_from_user(&load_img_req,
591 (void __user *)argp,
592 sizeof(struct qseecom_load_img_req))) {
593 pr_err("copy_from_user failed\n");
594 return -EFAULT;
595 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700596 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800597 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700598 if (ret)
599 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800600 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
601 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800602
Mona Hossain436b75f2012-11-20 17:10:40 -0800603 ret = __qseecom_check_app_exists(req);
604 if (ret < 0)
605 return ret;
606 else
607 app_id = ret;
608
609 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700610 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800611 (char *)(req.app_name));
612 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
613 list_for_each_entry(entry,
614 &qseecom.registered_app_list_head, list){
615 if (entry->app_id == app_id) {
616 entry->ref_cnt++;
617 break;
618 }
619 }
620 spin_unlock_irqrestore(
621 &qseecom.registered_app_list_lock, flags);
622 } else {
623 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700624 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800625 /* Get the handle of the shared fd */
626 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800627 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800628 if (IS_ERR_OR_NULL(ihandle)) {
629 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800630 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800631 return -ENOMEM;
632 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800633
Mona Hossain436b75f2012-11-20 17:10:40 -0800634 /* Get the physical address of the ION BUF */
635 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800636
Mona Hossain436b75f2012-11-20 17:10:40 -0800637 /* Populate the structure for sending scm call to load image */
638 memcpy(load_req.app_name, load_img_req.img_name,
639 MAX_APP_NAME_SIZE);
640 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
641 load_req.mdt_len = load_img_req.mdt_len;
642 load_req.img_len = load_img_req.img_len;
643 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800644
Mona Hossain436b75f2012-11-20 17:10:40 -0800645 /* SCM_CALL to load the app and get the app_id back */
646 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700647 sizeof(struct qseecom_load_app_ireq),
648 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700649 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800650 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800651 if (!IS_ERR_OR_NULL(ihandle))
652 ion_free(qseecom.ion_clnt, ihandle);
653 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800654 return -EINVAL;
655 }
656
657 if (resp.result == QSEOS_RESULT_FAILURE) {
658 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700659 if (!IS_ERR_OR_NULL(ihandle))
660 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800661 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800662 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700663 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700664
Mona Hossain436b75f2012-11-20 17:10:40 -0800665 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
666 ret = __qseecom_process_incomplete_cmd(data, &resp);
667 if (ret) {
668 pr_err("process_incomplete_cmd failed err: %d\n",
669 ret);
670 if (!IS_ERR_OR_NULL(ihandle))
671 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800672 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800673 return ret;
674 }
675 }
676
677 if (resp.result != QSEOS_RESULT_SUCCESS) {
678 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700679 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800680 if (!IS_ERR_OR_NULL(ihandle))
681 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800682 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800683 return -EFAULT;
684 }
685
686 app_id = resp.data;
687
688 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
689 if (!entry) {
690 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800691 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800692 return -ENOMEM;
693 }
694 entry->app_id = app_id;
695 entry->ref_cnt = 1;
696
697 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700698 if (!IS_ERR_OR_NULL(ihandle))
699 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700700
Mona Hossain436b75f2012-11-20 17:10:40 -0800701 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
702 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
703 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
704 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700705
Mona Hossain436b75f2012-11-20 17:10:40 -0800706 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700707 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800708 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800709 data->client.app_id = app_id;
710 load_img_req.app_id = app_id;
711 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
712 pr_err("copy_to_user failed\n");
713 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800714 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800715 return -EFAULT;
716 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800717 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800718 return 0;
719}
720
721static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
722{
723 wake_up_all(&qseecom.send_resp_wq);
724 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700725 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800726 atomic_read(&data->ioctl_count) <= 1)) {
727 pr_err("Interrupted from abort\n");
728 return -ERESTARTSYS;
729 break;
730 }
731 }
732 /* Set unload app */
733 return 1;
734}
735
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800736static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
737{
738 int ret = 0;
739 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
740 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
741 ion_free(qseecom.ion_clnt, data->client.ihandle);
742 data->client.ihandle = NULL;
743 }
744 return ret;
745}
746
Mona Hossain2892b6b2012-02-17 13:53:11 -0800747static int qseecom_unload_app(struct qseecom_dev_handle *data)
748{
749 unsigned long flags;
750 int ret = 0;
751 struct qseecom_command_scm_resp resp;
752 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700753 bool unload = false;
754 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800755
Mona Hossaind4613de2013-05-15 16:49:29 -0700756 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800757 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
758 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
759 list) {
760 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700761 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800762 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700763 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800764 break;
765 } else {
766 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700767 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700768 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800769 break;
770 }
771 }
772 }
773 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
774 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700775 if (found_app == false) {
776 pr_err("Cannot find app with id = %d\n",
777 data->client.app_id);
778 return -EINVAL;
779 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800780 }
781
Mona Hossaind4613de2013-05-15 16:49:29 -0700782 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800783 struct qseecom_unload_app_ireq req;
784
Mona Hossain340dba82012-08-07 19:54:46 -0700785 __qseecom_cleanup_app(data);
786 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
787 list_del(&ptr_app->list);
788 kzfree(ptr_app);
789 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
790 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800791 /* Populate the structure for sending scm call to load image */
792 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
793 req.app_id = data->client.app_id;
794
795 /* SCM_CALL to unload the app */
796 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
797 sizeof(struct qseecom_unload_app_ireq),
798 &resp, sizeof(resp));
799 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700800 pr_err("scm_call to unload app (id = %d) failed\n",
801 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800802 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700803 } else {
804 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800805 }
806 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
807 ret = __qseecom_process_incomplete_cmd(data, &resp);
808 if (ret) {
809 pr_err("process_incomplete_cmd fail err: %d\n",
810 ret);
811 return ret;
812 }
813 }
814 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800815 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800816 data->released = true;
817 return ret;
818}
819
820static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
821 uint32_t virt)
822{
823 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
824}
825
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800826int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
827 struct qseecom_send_svc_cmd_req *req_ptr,
828 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
829{
830 int ret = 0;
831 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
832 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
833 req_ptr, send_svc_ireq_ptr);
834 return -EINVAL;
835 }
836 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
837 send_svc_ireq_ptr->key_type =
838 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
839 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
840 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
841 (uint32_t)req_ptr->resp_buf));
842 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
843
844 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
845 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
846 return ret;
847}
848
849static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
850 void __user *argp)
851{
852 int ret = 0;
853 struct qseecom_client_send_service_ireq send_svc_ireq;
854 struct qseecom_command_scm_resp resp;
855 struct qseecom_send_svc_cmd_req req;
856 /*struct qseecom_command_scm_resp resp;*/
857
858 if (__copy_from_user(&req,
859 (void __user *)argp,
860 sizeof(req))) {
861 pr_err("copy_from_user failed\n");
862 return -EFAULT;
863 }
864
865 if (req.resp_buf == NULL) {
866 pr_err("cmd buffer or response buffer is null\n");
867 return -EINVAL;
868 }
869
870 data->type = QSEECOM_SECURE_SERVICE;
871
872 switch (req.cmd_id) {
873 case QSEE_RPMB_PROVISION_KEY_COMMAND:
874 case QSEE_RPMB_ERASE_COMMAND:
875 if (__qseecom_process_rpmb_svc_cmd(data, &req,
876 &send_svc_ireq))
877 return -EINVAL;
878 break;
879 default:
880 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
881 return -EINVAL;
882 }
883
884 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
885 sizeof(send_svc_ireq),
886 &resp, sizeof(resp));
887 if (ret) {
888 pr_err("qseecom_scm_call failed with err: %d\n", ret);
889 return ret;
890 }
891
892 switch (resp.result) {
893 case QSEOS_RESULT_SUCCESS:
894 break;
895 case QSEOS_RESULT_INCOMPLETE:
896 pr_err("qseos_result_incomplete\n");
897 ret = __qseecom_process_incomplete_cmd(data, &resp);
898 if (ret) {
899 pr_err("process_incomplete_cmd fail: err: %d\n",
900 ret);
901 }
902 break;
903 case QSEOS_RESULT_FAILURE:
904 pr_err("process_incomplete_cmd failed err: %d\n", ret);
905 break;
906 default:
907 pr_err("Response result %d not supported\n",
908 resp.result);
909 ret = -EINVAL;
910 break;
911 }
912 return ret;
913
914}
915
Mona Hossain2892b6b2012-02-17 13:53:11 -0800916static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
917 struct qseecom_send_cmd_req *req)
918{
919 int ret = 0;
920 u32 reqd_len_sb_in = 0;
921 struct qseecom_client_send_data_ireq send_data_req;
922 struct qseecom_command_scm_resp resp;
923
924 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
925 pr_err("cmd buffer or response buffer is null\n");
926 return -EINVAL;
927 }
928
929 if (req->cmd_req_len <= 0 ||
930 req->resp_len <= 0 ||
931 req->cmd_req_len > data->client.sb_length ||
932 req->resp_len > data->client.sb_length) {
933 pr_err("cmd buffer length or "
934 "response buffer length not valid\n");
935 return -EINVAL;
936 }
937
938 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
939 if (reqd_len_sb_in > data->client.sb_length) {
940 pr_debug("Not enough memory to fit cmd_buf and "
941 "resp_buf. Required: %u, Available: %u\n",
942 reqd_len_sb_in, data->client.sb_length);
943 return -ENOMEM;
944 }
945
946 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
947 send_data_req.app_id = data->client.app_id;
948 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
949 (uint32_t)req->cmd_req_buf));
950 send_data_req.req_len = req->cmd_req_len;
951 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
952 (uint32_t)req->resp_buf));
953 send_data_req.rsp_len = req->resp_len;
954
955 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
956 sizeof(send_data_req),
957 &resp, sizeof(resp));
958 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700959 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
960 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800961 return ret;
962 }
963
964 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
965 ret = __qseecom_process_incomplete_cmd(data, &resp);
966 if (ret) {
967 pr_err("process_incomplete_cmd failed err: %d\n", ret);
968 return ret;
969 }
Mona Hossainbb0bca12012-04-12 11:47:45 -0700970 } else {
971 if (resp.result != QSEOS_RESULT_SUCCESS) {
972 pr_err("Response result %d not supported\n",
973 resp.result);
974 ret = -EINVAL;
975 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800976 }
977 return ret;
978}
979
980
981static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
982{
983 int ret = 0;
984 struct qseecom_send_cmd_req req;
985
986 ret = copy_from_user(&req, argp, sizeof(req));
987 if (ret) {
988 pr_err("copy_from_user failed\n");
989 return ret;
990 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700991 ret = __qseecom_send_cmd(data, &req);
992
Mona Hossain2892b6b2012-02-17 13:53:11 -0800993 if (ret)
994 return ret;
995
996 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
997 req.resp_len, req.resp_buf);
998 return ret;
999}
1000
Mona Hossainc56584d2013-05-28 09:06:26 -07001001static int __qseecom_update_cmd_buf(struct qseecom_send_modfd_cmd_req *req,
1002 bool cleanup)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001003{
1004 struct ion_handle *ihandle;
1005 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001006 int ret = 0;
1007 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001008
1009 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001010 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001011 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001012 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001013 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001014 req->ifd_data[i].fd);
1015 if (IS_ERR_OR_NULL(ihandle)) {
1016 pr_err("Ion client can't retrieve the handle\n");
1017 return -ENOMEM;
1018 }
1019 field = (char *) req->cmd_req_buf +
1020 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001021
1022 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001023 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1024 if (sg_ptr == NULL) {
1025 pr_err("IOn client could not retrieve sg table\n");
1026 goto err;
1027 }
1028 if (sg_ptr->nents == 0) {
1029 pr_err("Num of scattered entries is 0\n");
1030 goto err;
1031 }
1032 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1033 pr_err("Num of scattered entries");
1034 pr_err(" (%d) is greater than max supported %d\n",
1035 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1036 goto err;
1037 }
1038 if (sg_ptr->nents == 1) {
1039 uint32_t *update;
1040 update = (uint32_t *) field;
Mona Hossainc56584d2013-05-28 09:06:26 -07001041 if (cleanup)
1042 *update = 0;
1043 else
1044 *update = (uint32_t)sg_dma_address(
1045 sg_ptr->sgl);
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001046 } else {
1047 struct qseecom_sg_entry *update;
1048 struct scatterlist *sg;
1049 int j = 0;
1050 update = (struct qseecom_sg_entry *) field;
1051 sg = sg_ptr->sgl;
1052 for (j = 0; j < sg_ptr->nents; j++) {
Mona Hossainc56584d2013-05-28 09:06:26 -07001053 if (cleanup) {
1054 update->phys_addr = 0;
1055 update->len = 0;
1056 } else {
1057 update->phys_addr = (uint32_t)
1058 sg_dma_address(sg);
1059 update->len = sg->length;
1060 }
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001061 update++;
1062 sg = sg_next(sg);
1063 }
1064 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001065 /* Deallocate the handle */
1066 if (!IS_ERR_OR_NULL(ihandle))
1067 ion_free(qseecom.ion_clnt, ihandle);
1068 }
1069 }
1070 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001071err:
1072 if (!IS_ERR_OR_NULL(ihandle))
1073 ion_free(qseecom.ion_clnt, ihandle);
1074 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001075}
1076
1077static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1078 void __user *argp)
1079{
1080 int ret = 0;
1081 struct qseecom_send_modfd_cmd_req req;
1082 struct qseecom_send_cmd_req send_cmd_req;
1083
1084 ret = copy_from_user(&req, argp, sizeof(req));
1085 if (ret) {
1086 pr_err("copy_from_user failed\n");
1087 return ret;
1088 }
1089 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1090 send_cmd_req.cmd_req_len = req.cmd_req_len;
1091 send_cmd_req.resp_buf = req.resp_buf;
1092 send_cmd_req.resp_len = req.resp_len;
1093
Mona Hossainc56584d2013-05-28 09:06:26 -07001094 ret = __qseecom_update_cmd_buf(&req, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001095 if (ret)
1096 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001097 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001098 if (ret)
1099 return ret;
Mona Hossainc56584d2013-05-28 09:06:26 -07001100 ret = __qseecom_update_cmd_buf(&req, true);
1101 if (ret)
1102 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001103 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1104 req.resp_len, req.resp_buf);
1105 return ret;
1106}
1107
1108static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1109 struct qseecom_registered_listener_list *svc)
1110{
1111 int ret;
1112 ret = (svc->rcv_req_flag != 0);
1113 return ret || data->abort;
1114}
1115
1116static int qseecom_receive_req(struct qseecom_dev_handle *data)
1117{
1118 int ret = 0;
1119 struct qseecom_registered_listener_list *this_lstnr;
1120
1121 this_lstnr = __qseecom_find_svc(data->listener.id);
1122 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001123 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001124 __qseecom_listener_has_rcvd_req(data,
1125 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001126 pr_warning("Interrupted: exiting Listener Service = %d\n",
1127 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001128 /* woken up for different reason */
1129 return -ERESTARTSYS;
1130 }
1131
1132 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001133 pr_err("Aborting Listener Service = %d\n",
1134 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001135 return -ENODEV;
1136 }
1137 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001138 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001139 }
1140 return ret;
1141}
1142
Mona Hossaind44a3842012-10-15 09:41:35 -07001143static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1144{
1145 struct elf32_hdr *ehdr;
1146
1147 if (fw_entry->size < sizeof(*ehdr)) {
1148 pr_err("%s: Not big enough to be an elf header\n",
1149 qseecom.pdev->init_name);
1150 return false;
1151 }
1152 ehdr = (struct elf32_hdr *)fw_entry->data;
1153 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1154 pr_err("%s: Not an elf header\n",
1155 qseecom.pdev->init_name);
1156 return false;
1157 }
1158
1159 if (ehdr->e_phnum == 0) {
1160 pr_err("%s: No loadable segments\n",
1161 qseecom.pdev->init_name);
1162 return false;
1163 }
1164 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1165 sizeof(struct elf32_hdr) > fw_entry->size) {
1166 pr_err("%s: Program headers not within mdt\n",
1167 qseecom.pdev->init_name);
1168 return false;
1169 }
1170 return true;
1171}
1172
1173static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1174{
1175 int ret = -1;
1176 int i = 0, rc = 0;
1177 const struct firmware *fw_entry = NULL;
1178 struct elf32_phdr *phdr;
1179 char fw_name[MAX_APP_NAME_SIZE];
1180 struct elf32_hdr *ehdr;
1181 int num_images = 0;
1182
1183 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1184 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1185 if (rc) {
1186 pr_err("error with request_firmware\n");
1187 ret = -EIO;
1188 goto err;
1189 }
1190 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1191 ret = -EIO;
1192 goto err;
1193 }
1194 *fw_size = fw_entry->size;
1195 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1196 ehdr = (struct elf32_hdr *)fw_entry->data;
1197 num_images = ehdr->e_phnum;
1198 release_firmware(fw_entry);
1199 for (i = 0; i < num_images; i++, phdr++) {
1200 memset(fw_name, 0, sizeof(fw_name));
1201 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1202 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1203 if (ret)
1204 goto err;
1205 *fw_size += fw_entry->size;
1206 release_firmware(fw_entry);
1207 }
1208 return ret;
1209err:
1210 if (fw_entry)
1211 release_firmware(fw_entry);
1212 *fw_size = 0;
1213 return ret;
1214}
1215
1216static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1217 struct qseecom_load_app_ireq *load_req)
1218{
1219 int ret = -1;
1220 int i = 0, rc = 0;
1221 const struct firmware *fw_entry = NULL;
1222 char fw_name[MAX_APP_NAME_SIZE];
1223 u8 *img_data_ptr = img_data;
1224 struct elf32_hdr *ehdr;
1225 int num_images = 0;
1226
1227 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1228 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1229 if (rc) {
1230 ret = -EIO;
1231 goto err;
1232 }
1233 load_req->img_len = fw_entry->size;
1234 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1235 img_data_ptr = img_data_ptr + fw_entry->size;
1236 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1237 ehdr = (struct elf32_hdr *)fw_entry->data;
1238 num_images = ehdr->e_phnum;
1239 release_firmware(fw_entry);
1240 for (i = 0; i < num_images; i++) {
1241 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1242 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1243 if (ret) {
1244 pr_err("Failed to locate blob %s\n", fw_name);
1245 goto err;
1246 }
1247 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1248 img_data_ptr = img_data_ptr + fw_entry->size;
1249 load_req->img_len += fw_entry->size;
1250 release_firmware(fw_entry);
1251 }
1252 load_req->phy_addr = virt_to_phys(img_data);
1253 return ret;
1254err:
1255 release_firmware(fw_entry);
1256 return ret;
1257}
1258
1259static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1260{
1261 int ret = -1;
1262 uint32_t fw_size = 0;
1263 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1264 struct qseecom_command_scm_resp resp;
1265 u8 *img_data = NULL;
1266
1267 if (__qseecom_get_fw_size(appname, &fw_size))
1268 return -EIO;
1269
1270 img_data = kzalloc(fw_size, GFP_KERNEL);
1271 if (!img_data) {
1272 pr_err("Failied to allocate memory for copying image data\n");
1273 return -ENOMEM;
1274 }
1275 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1276 if (ret) {
1277 kzfree(img_data);
1278 return -EIO;
1279 }
1280
1281 /* Populate the remaining parameters */
1282 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1283 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001284 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001285 if (ret) {
1286 kzfree(img_data);
1287 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001288 return -EIO;
1289 }
1290
Mona Hossaind44a3842012-10-15 09:41:35 -07001291 /* SCM_CALL to load the image */
1292 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1293 sizeof(struct qseecom_load_app_ireq),
1294 &resp, sizeof(resp));
1295 kzfree(img_data);
1296 if (ret) {
1297 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001298 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001299 return -EIO;
1300 }
1301
1302 switch (resp.result) {
1303 case QSEOS_RESULT_SUCCESS:
1304 ret = resp.data;
1305 break;
1306 case QSEOS_RESULT_INCOMPLETE:
1307 ret = __qseecom_process_incomplete_cmd(data, &resp);
1308 if (ret)
1309 pr_err("process_incomplete_cmd FAILED\n");
1310 else
1311 ret = resp.data;
1312 break;
1313 case QSEOS_RESULT_FAILURE:
1314 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1315 break;
1316 default:
1317 pr_err("scm call return unknown response %d\n", resp.result);
1318 ret = -EINVAL;
1319 break;
1320 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001321 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001322
Mona Hossaind44a3842012-10-15 09:41:35 -07001323 return ret;
1324}
1325
Mona Hossain9498f5e2013-01-23 18:08:45 -08001326static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001327{
1328 int32_t ret = 0;
1329 uint32_t fw_size = 0;
1330 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1331 struct qseecom_command_scm_resp resp;
1332 u8 *img_data = NULL;
1333
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001334 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001335 return -EIO;
1336
1337 img_data = kzalloc(fw_size, GFP_KERNEL);
1338 if (!img_data) {
1339 pr_err("Mem allocation for lib image data failed\n");
1340 return -ENOMEM;
1341 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001342 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001343 if (ret) {
1344 kzfree(img_data);
1345 return -EIO;
1346 }
1347 /* Populate the remaining parameters */
1348 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001349 /* Vote for the SFPB clock */
1350 ret = qsee_vote_for_clock(data, CLK_SFPB);
1351 if (ret) {
1352 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1353 kzfree(img_data);
1354 return -EIO;
1355 }
1356
Mona Hossain05c73562012-10-29 17:49:01 -07001357 /* SCM_CALL to load the image */
1358 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1359 sizeof(struct qseecom_load_lib_image_ireq),
1360 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001361 if (ret) {
1362 pr_err("scm_call to load failed : ret %d\n", ret);
1363 ret = -EIO;
1364 } else {
1365 switch (resp.result) {
1366 case QSEOS_RESULT_SUCCESS:
1367 break;
1368 case QSEOS_RESULT_FAILURE:
1369 pr_err("scm call failed w/response result%d\n",
1370 resp.result);
1371 ret = -EINVAL;
1372 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001373 case QSEOS_RESULT_INCOMPLETE:
1374 ret = __qseecom_process_incomplete_cmd(data, &resp);
1375 if (ret)
1376 pr_err("process_incomplete_cmd failed err: %d\n",
1377 ret);
1378 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001379 default:
1380 pr_err("scm call return unknown response %d\n",
1381 resp.result);
1382 ret = -EINVAL;
1383 break;
1384 }
1385 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001386 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001387 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001388 return ret;
1389}
1390
1391static int qseecom_unload_commonlib_image(void)
1392{
1393 int ret = -EINVAL;
1394 struct qseecom_unload_lib_image_ireq unload_req = {0};
1395 struct qseecom_command_scm_resp resp;
1396
1397 /* Populate the remaining parameters */
1398 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1399 /* SCM_CALL to load the image */
1400 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1401 sizeof(struct qseecom_unload_lib_image_ireq),
1402 &resp, sizeof(resp));
1403 if (ret) {
1404 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1405 ret = -EIO;
1406 } else {
1407 switch (resp.result) {
1408 case QSEOS_RESULT_SUCCESS:
1409 break;
1410 case QSEOS_RESULT_FAILURE:
1411 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1412 break;
1413 default:
1414 pr_err("scm call return unknown response %d\n",
1415 resp.result);
1416 ret = -EINVAL;
1417 break;
1418 }
1419 }
1420 return ret;
1421}
1422
Mona Hossaind44a3842012-10-15 09:41:35 -07001423int qseecom_start_app(struct qseecom_handle **handle,
1424 char *app_name, uint32_t size)
1425{
Mona Hossain05c73562012-10-29 17:49:01 -07001426 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001427 unsigned long flags = 0;
1428 struct qseecom_dev_handle *data = NULL;
1429 struct qseecom_check_app_ireq app_ireq;
1430 struct qseecom_registered_app_list *entry = NULL;
1431 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1432 bool found_app = false;
1433 uint32_t len;
1434 ion_phys_addr_t pa;
1435
Mona Hossain823f9882012-11-23 14:42:20 -08001436 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1437 if (!(*handle)) {
1438 pr_err("failed to allocate memory for kernel client handle\n");
1439 return -ENOMEM;
1440 }
1441
Mona Hossaind44a3842012-10-15 09:41:35 -07001442 data = kzalloc(sizeof(*data), GFP_KERNEL);
1443 if (!data) {
1444 pr_err("kmalloc failed\n");
1445 if (ret == 0) {
1446 kfree(*handle);
1447 *handle = NULL;
1448 }
1449 return -ENOMEM;
1450 }
1451 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001452 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001453 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001454 data->client.sb_length = size;
1455 data->client.user_virt_sb_base = 0;
1456 data->client.ihandle = NULL;
1457
1458 init_waitqueue_head(&data->abort_wq);
1459 atomic_set(&data->ioctl_count, 0);
1460
1461 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1462 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1463 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1464 pr_err("Ion client could not retrieve the handle\n");
1465 kfree(data);
1466 kfree(*handle);
1467 *handle = NULL;
1468 return -EINVAL;
1469 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001470 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001471 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001472 if (qseecom.commonlib_loaded == false) {
1473 ret = qseecom_load_commonlib_image(data);
1474 if (ret == 0)
1475 qseecom.commonlib_loaded = true;
1476 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001477 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001478 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001479 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001480 ret = -EIO;
1481 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001482 }
1483
1484 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1485 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1486 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001487 if (ret < 0)
1488 goto err;
1489
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001490 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001491 if (ret > 0) {
1492 pr_warn("App id %d for [%s] app exists\n", ret,
1493 (char *)app_ireq.app_name);
1494 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1495 list_for_each_entry(entry,
1496 &qseecom.registered_app_list_head, list){
1497 if (entry->app_id == ret) {
1498 entry->ref_cnt++;
1499 found_app = true;
1500 break;
1501 }
1502 }
1503 spin_unlock_irqrestore(
1504 &qseecom.registered_app_list_lock, flags);
1505 if (!found_app)
1506 pr_warn("App_id %d [%s] was loaded but not registered\n",
1507 ret, (char *)app_ireq.app_name);
1508 } else {
1509 /* load the app and get the app_id */
1510 pr_debug("%s: Loading app for the first time'\n",
1511 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001512 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001513 if (ret < 0)
1514 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001515 data->client.app_id = ret;
1516 }
1517 if (!found_app) {
1518 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1519 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001520 pr_err("kmalloc for app entry failed\n");
1521 ret = -ENOMEM;
1522 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001523 }
1524 entry->app_id = ret;
1525 entry->ref_cnt = 1;
1526
1527 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1528 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1529 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1530 flags);
1531 }
1532
1533 /* Get the physical address of the ION BUF */
1534 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1535 /* Populate the structure for sending scm call to load image */
1536 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1537 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001538 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001539 data->client.sb_phys = pa;
1540 (*handle)->dev = (void *)data;
1541 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1542 (*handle)->sbuf_len = data->client.sb_length;
1543
1544 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1545 if (!kclient_entry) {
1546 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001547 ret = -ENOMEM;
1548 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001549 }
1550 kclient_entry->handle = *handle;
1551
1552 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1553 list_add_tail(&kclient_entry->list,
1554 &qseecom.registered_kclient_list_head);
1555 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1556
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001557 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001558 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001559
1560err:
1561 kfree(data);
1562 kfree(*handle);
1563 *handle = NULL;
1564 mutex_unlock(&app_access_lock);
1565 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001566}
1567EXPORT_SYMBOL(qseecom_start_app);
1568
1569int qseecom_shutdown_app(struct qseecom_handle **handle)
1570{
1571 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001572 struct qseecom_dev_handle *data;
1573
Mona Hossaind44a3842012-10-15 09:41:35 -07001574 struct qseecom_registered_kclient_list *kclient = NULL;
1575 unsigned long flags = 0;
1576 bool found_handle = false;
1577
Mona Hossain33824022013-02-25 09:32:33 -08001578 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001579 pr_err("Handle is not initialized\n");
1580 return -EINVAL;
1581 }
Mona Hossain33824022013-02-25 09:32:33 -08001582 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001583 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1584 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1585 list) {
1586 if (kclient->handle == (*handle)) {
1587 list_del(&kclient->list);
1588 found_handle = true;
1589 break;
1590 }
1591 }
1592 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1593 if (!found_handle)
1594 pr_err("Unable to find the handle, exiting\n");
1595 else
1596 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001597 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001598 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001599 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001600 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001601 if (ret == 0) {
1602 kzfree(data);
1603 kzfree(*handle);
1604 kzfree(kclient);
1605 *handle = NULL;
1606 }
1607 return ret;
1608}
1609EXPORT_SYMBOL(qseecom_shutdown_app);
1610
1611int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1612 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1613{
1614 int ret = 0;
1615 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1616 struct qseecom_dev_handle *data;
1617
Mona Hossaind44a3842012-10-15 09:41:35 -07001618 if (handle == NULL) {
1619 pr_err("Handle is not initialized\n");
1620 return -EINVAL;
1621 }
1622 data = handle->dev;
1623
1624 req.cmd_req_len = sbuf_len;
1625 req.resp_len = rbuf_len;
1626 req.cmd_req_buf = send_buf;
1627 req.resp_buf = resp_buf;
1628
1629 mutex_lock(&app_access_lock);
1630 atomic_inc(&data->ioctl_count);
1631
1632 ret = __qseecom_send_cmd(data, &req);
1633
1634 atomic_dec(&data->ioctl_count);
1635 mutex_unlock(&app_access_lock);
1636
1637 if (ret)
1638 return ret;
1639
1640 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1641 req.resp_len, req.resp_buf);
1642 return ret;
1643}
1644EXPORT_SYMBOL(qseecom_send_command);
1645
Mona Hossain91a8fc92012-11-07 19:58:30 -08001646int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1647{
Mona Hossainfca6f422013-01-12 13:00:35 -08001648 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001649 if ((handle == NULL) || (handle->dev == NULL)) {
1650 pr_err("No valid kernel client\n");
1651 return -EINVAL;
1652 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001653 if (high) {
1654 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1655 if (ret)
1656 pr_err("Failed to vote for DFAB clock%d\n", ret);
1657 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1658 if (ret) {
1659 pr_err("Failed to vote for SFPB clock%d\n", ret);
1660 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1661 }
1662 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001663 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001664 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001665 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001666 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001667}
1668EXPORT_SYMBOL(qseecom_set_bandwidth);
1669
Mona Hossain2892b6b2012-02-17 13:53:11 -08001670static int qseecom_send_resp(void)
1671{
1672 qseecom.send_resp_flag = 1;
1673 wake_up_interruptible(&qseecom.send_resp_wq);
1674 return 0;
1675}
1676
1677static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1678 void __user *argp)
1679{
1680 struct qseecom_qseos_version_req req;
1681
1682 if (copy_from_user(&req, argp, sizeof(req))) {
1683 pr_err("copy_from_user failed");
1684 return -EINVAL;
1685 }
1686 req.qseos_version = qseecom.qseos_version;
1687 if (copy_to_user(argp, &req, sizeof(req))) {
1688 pr_err("copy_to_user failed");
1689 return -EINVAL;
1690 }
1691 return 0;
1692}
1693
Mona Hossainc92629e2013-04-01 13:37:46 -07001694static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001695{
1696 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001697 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001698
Mona Hossainc92629e2013-04-01 13:37:46 -07001699 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001700 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001701 else
1702 qclk = &qseecom.ce_drv;
1703
1704 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001705
1706 if (qclk->clk_access_cnt == ULONG_MAX)
1707 goto err;
1708
Mona Hossainc92629e2013-04-01 13:37:46 -07001709 if (qclk->clk_access_cnt > 0) {
1710 qclk->clk_access_cnt++;
1711 mutex_unlock(&clk_access_lock);
1712 return rc;
1713 }
1714
Mona Hossain6311d572013-03-01 15:54:02 -08001715 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001716 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001717 if (rc) {
1718 pr_err("Unable to enable/prepare CE core clk\n");
1719 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001720 }
1721 /* Enable CE clk */
1722 rc = clk_prepare_enable(qclk->ce_clk);
1723 if (rc) {
1724 pr_err("Unable to enable/prepare CE iface clk\n");
1725 goto ce_clk_err;
1726 }
1727 /* Enable AXI clk */
1728 rc = clk_prepare_enable(qclk->ce_bus_clk);
1729 if (rc) {
1730 pr_err("Unable to enable/prepare CE bus clk\n");
1731 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001732 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001733 qclk->clk_access_cnt++;
1734 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001735 return 0;
1736
1737ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001738 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001739ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001740 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001741err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001742 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001743 return -EIO;
1744}
1745
Mona Hossainc92629e2013-04-01 13:37:46 -07001746static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001747{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001748 struct qseecom_clk *qclk;
1749
Mona Hossainc92629e2013-04-01 13:37:46 -07001750 if (ce == CLK_QSEE)
1751 qclk = &qseecom.qsee;
1752 else
1753 qclk = &qseecom.ce_drv;
1754
1755 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001756
1757 if (qclk->clk_access_cnt == 0) {
1758 mutex_unlock(&clk_access_lock);
1759 return;
1760 }
1761
Mona Hossainc92629e2013-04-01 13:37:46 -07001762 if (qclk->clk_access_cnt == 1) {
1763 if (qclk->ce_clk != NULL)
1764 clk_disable_unprepare(qclk->ce_clk);
1765 if (qclk->ce_core_clk != NULL)
1766 clk_disable_unprepare(qclk->ce_core_clk);
1767 if (qclk->ce_bus_clk != NULL)
1768 clk_disable_unprepare(qclk->ce_bus_clk);
1769 }
1770 qclk->clk_access_cnt--;
1771 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001772}
1773
Mona Hossain04d3fac2012-12-03 10:10:37 -08001774static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1775 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001776{
1777 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001778 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001779
Mona Hossain17a4faf2013-03-22 16:40:56 -07001780 qclk = &qseecom.qsee;
1781 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001782 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001783
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001784 switch (clk_type) {
1785 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001786 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001787 if (!qseecom.qsee_bw_count) {
1788 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001789 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001790 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001791 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001792 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07001793 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001794 if (!ret) {
1795 ret =
1796 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001797 qseecom.qsee_perf_client, 1);
1798 if ((ret) &&
1799 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07001800 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001801 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08001802 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001803 if (ret)
1804 pr_err("DFAB Bandwidth req failed (%d)\n",
1805 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001806 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001807 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001808 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001809 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001810 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001811 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001812 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001813 }
1814 mutex_unlock(&qsee_bw_mutex);
1815 break;
1816 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001817 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001818 if (!qseecom.qsee_sfpb_bw_count) {
1819 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001820 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001821 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001822 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001823 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07001824 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001825 if (!ret) {
1826 ret =
1827 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001828 qseecom.qsee_perf_client, 2);
1829 if ((ret) &&
1830 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07001831 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001832 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08001833 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001834
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001835 if (ret)
1836 pr_err("SFPB Bandwidth req failed (%d)\n",
1837 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001838 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001839 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001840 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001841 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001842 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001843 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001844 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001845 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001846 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001847 break;
1848 default:
1849 pr_err("Clock type not defined\n");
1850 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001851 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001852 return ret;
1853}
1854
Mona Hossain04d3fac2012-12-03 10:10:37 -08001855static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
1856 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001857{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001858 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001859 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08001860
Mona Hossain17a4faf2013-03-22 16:40:56 -07001861 qclk = &qseecom.qsee;
1862 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08001863 return;
1864
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001865 switch (clk_type) {
1866 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001867 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001868 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001869 pr_err("Client error.Extra call to disable DFAB clk\n");
1870 mutex_unlock(&qsee_bw_mutex);
1871 return;
1872 }
1873
Mona Hossain17a4faf2013-03-22 16:40:56 -07001874 if (qseecom.qsee_bw_count == 1) {
1875 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001876 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001877 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001878 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001879 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001880 qseecom.qsee_perf_client, 0);
1881 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07001882 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001883 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001884 if (ret)
1885 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001886 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001887 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001888 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001889 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001890 }
1891 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001892 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001893 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001894 }
1895 mutex_unlock(&qsee_bw_mutex);
1896 break;
1897 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001898 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001899 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001900 pr_err("Client error.Extra call to disable SFPB clk\n");
1901 mutex_unlock(&qsee_bw_mutex);
1902 return;
1903 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07001904 if (qseecom.qsee_sfpb_bw_count == 1) {
1905 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001906 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001907 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001908 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001909 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001910 qseecom.qsee_perf_client, 0);
1911 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07001912 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001913 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001914 if (ret)
1915 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001916 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001917 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001918 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001919 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001920 }
1921 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001922 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001923 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001924 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001925 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001926 break;
1927 default:
1928 pr_err("Clock type not defined\n");
1929 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001930 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001931
Mona Hossain2892b6b2012-02-17 13:53:11 -08001932}
1933
Mona Hossain5ab9d772012-04-11 21:00:40 -07001934static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
1935 void __user *argp)
1936{
1937 struct ion_handle *ihandle; /* Ion handle */
1938 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001939 int ret;
1940 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07001941 ion_phys_addr_t pa = 0;
1942 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001943 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07001944 struct qseecom_load_app_ireq load_req;
1945 struct qseecom_command_scm_resp resp;
1946
1947 /* Copy the relevant information needed for loading the image */
1948 if (__copy_from_user(&load_img_req,
1949 (void __user *)argp,
1950 sizeof(struct qseecom_load_img_req))) {
1951 pr_err("copy_from_user failed\n");
1952 return -EFAULT;
1953 }
1954
1955 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001956 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07001957 load_img_req.ifd_data_fd);
1958 if (IS_ERR_OR_NULL(ihandle)) {
1959 pr_err("Ion client could not retrieve the handle\n");
1960 return -ENOMEM;
1961 }
1962
1963 /* Get the physical address of the ION BUF */
1964 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
1965
1966 /* Populate the structure for sending scm call to load image */
1967 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
1968 load_req.mdt_len = load_img_req.mdt_len;
1969 load_req.img_len = load_img_req.img_len;
1970 load_req.phy_addr = pa;
1971
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001972 /* SCM_CALL tied to Core0 */
1973 mask = CPU_MASK_CPU0;
1974 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
1975 if (set_cpu_ret) {
1976 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
1977 set_cpu_ret);
1978 ret = -EFAULT;
1979 goto qseecom_load_external_elf_set_cpu_err;
1980 }
Mona Hossain6311d572013-03-01 15:54:02 -08001981 /* Vote for the SFPB clock */
1982 ret = qsee_vote_for_clock(data, CLK_SFPB);
1983 if (ret) {
1984 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1985 ret = -EIO;
1986 goto qseecom_load_external_elf_set_cpu_err;
1987 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001988
Mona Hossain5ab9d772012-04-11 21:00:40 -07001989 /* SCM_CALL to load the external elf */
1990 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1991 sizeof(struct qseecom_load_app_ireq),
1992 &resp, sizeof(resp));
1993 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001994 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07001995 ret);
1996 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07001997 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07001998 }
1999
2000 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2001 ret = __qseecom_process_incomplete_cmd(data, &resp);
2002 if (ret)
2003 pr_err("process_incomplete_cmd failed err: %d\n",
2004 ret);
2005 } else {
2006 if (resp.result != QSEOS_RESULT_SUCCESS) {
2007 pr_err("scm_call to load image failed resp.result =%d\n",
2008 resp.result);
2009 ret = -EFAULT;
2010 }
2011 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002012
2013qseecom_load_external_elf_scm_err:
2014 /* Restore the CPU mask */
2015 mask = CPU_MASK_ALL;
2016 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2017 if (set_cpu_ret) {
2018 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2019 set_cpu_ret);
2020 ret = -EFAULT;
2021 }
2022
2023qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002024 /* Deallocate the handle */
2025 if (!IS_ERR_OR_NULL(ihandle))
2026 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002027 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002028 return ret;
2029}
2030
2031static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2032{
2033 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002034 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002035 struct qseecom_command_scm_resp resp;
2036 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002037 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002038
2039 /* Populate the structure for sending scm call to unload image */
2040 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002041
2042 /* SCM_CALL tied to Core0 */
2043 mask = CPU_MASK_CPU0;
2044 ret = set_cpus_allowed_ptr(current, &mask);
2045 if (ret) {
2046 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2047 ret);
2048 return -EFAULT;
2049 }
2050
Mona Hossain5ab9d772012-04-11 21:00:40 -07002051 /* SCM_CALL to unload the external elf */
2052 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2053 sizeof(struct qseecom_unload_app_ireq),
2054 &resp, sizeof(resp));
2055 if (ret) {
2056 pr_err("scm_call to unload failed : ret %d\n",
2057 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002058 ret = -EFAULT;
2059 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002060 }
2061 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2062 ret = __qseecom_process_incomplete_cmd(data, &resp);
2063 if (ret)
2064 pr_err("process_incomplete_cmd fail err: %d\n",
2065 ret);
2066 } else {
2067 if (resp.result != QSEOS_RESULT_SUCCESS) {
2068 pr_err("scm_call to unload image failed resp.result =%d\n",
2069 resp.result);
2070 ret = -EFAULT;
2071 }
2072 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002073
2074qseecom_unload_external_elf_scm_err:
2075 /* Restore the CPU mask */
2076 mask = CPU_MASK_ALL;
2077 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2078 if (set_cpu_ret) {
2079 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2080 set_cpu_ret);
2081 ret = -EFAULT;
2082 }
2083
Mona Hossain5ab9d772012-04-11 21:00:40 -07002084 return ret;
2085}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002086
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002087static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2088 void __user *argp)
2089{
2090
2091 int32_t ret;
2092 struct qseecom_qseos_app_load_query query_req;
2093 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002094 struct qseecom_registered_app_list *entry = NULL;
2095 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002096
2097 /* Copy the relevant information needed for loading the image */
2098 if (__copy_from_user(&query_req,
2099 (void __user *)argp,
2100 sizeof(struct qseecom_qseos_app_load_query))) {
2101 pr_err("copy_from_user failed\n");
2102 return -EFAULT;
2103 }
2104
2105 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2106 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2107
2108 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002109
2110 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002111 pr_err(" scm call to check if app is loaded failed");
2112 return ret; /* scm call failed */
2113 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002114 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002115 (char *)(req.app_name));
2116 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2117 list_for_each_entry(entry,
2118 &qseecom.registered_app_list_head, list){
2119 if (entry->app_id == ret) {
2120 entry->ref_cnt++;
2121 break;
2122 }
2123 }
2124 spin_unlock_irqrestore(
2125 &qseecom.registered_app_list_lock, flags);
2126 data->client.app_id = ret;
2127 query_req.app_id = ret;
2128
2129 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2130 pr_err("copy_to_user failed\n");
2131 return -EFAULT;
2132 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002133 return -EEXIST; /* app already loaded */
2134 } else {
2135 return 0; /* app not loaded */
2136 }
2137}
2138
Mona Hossain4cf78a92013-02-14 12:06:41 -08002139static int __qseecom_get_ce_pipe_info(
2140 enum qseecom_key_management_usage_type usage,
2141 uint32_t *pipe, uint32_t *ce_hw)
2142{
2143 int ret;
2144 switch (usage) {
2145 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2146 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2147 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2148 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2149 qseecom.ce_info.disk_encrypt_pipe,
2150 qseecom.ce_info.hlos_ce_hw_instance);
2151 ret = -EINVAL;
2152 } else {
2153 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2154 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2155 ret = 0;
2156 }
2157 break;
2158 default:
2159 ret = -EINVAL;
2160 break;
2161 }
2162 return ret;
2163}
2164
2165static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2166 enum qseecom_key_management_usage_type usage,
2167 uint8_t *key_id, uint32_t flags)
2168{
2169 struct qseecom_key_generate_ireq ireq;
2170 struct qseecom_command_scm_resp resp;
2171 int ret;
2172
2173 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2174 pr_err("Error:: unsupported usage %d\n", usage);
2175 return -EFAULT;
2176 }
2177
2178 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2179 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002180 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002181
Mona Hossainc92629e2013-04-01 13:37:46 -07002182 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002183
2184 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002185 &ireq, sizeof(struct qseecom_key_generate_ireq),
2186 &resp, sizeof(resp));
2187 if (ret) {
2188 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002189 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002190 return ret;
2191 }
2192
2193 switch (resp.result) {
2194 case QSEOS_RESULT_SUCCESS:
2195 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002196 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002197 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002198 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002199 case QSEOS_RESULT_INCOMPLETE:
2200 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002201 if (ret) {
2202 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002203 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002204 ret = 0;
2205 } else {
2206 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2207 resp.result);
2208 }
2209 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002210 break;
2211 case QSEOS_RESULT_FAILURE:
2212 default:
2213 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2214 ret = -EINVAL;
2215 break;
2216 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002217 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002218 return ret;
2219}
2220
2221static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2222 enum qseecom_key_management_usage_type usage,
2223 uint8_t *key_id, uint32_t flags)
2224{
2225 struct qseecom_key_delete_ireq ireq;
2226 struct qseecom_command_scm_resp resp;
2227 int ret;
2228
2229 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2230 pr_err("Error:: unsupported usage %d\n", usage);
2231 return -EFAULT;
2232 }
2233
2234 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2235 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002236 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002237
Mona Hossainc92629e2013-04-01 13:37:46 -07002238 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002239
2240 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002241 &ireq, sizeof(struct qseecom_key_delete_ireq),
2242 &resp, sizeof(struct qseecom_command_scm_resp));
2243 if (ret) {
2244 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002245 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002246 return ret;
2247 }
2248
2249 switch (resp.result) {
2250 case QSEOS_RESULT_SUCCESS:
2251 break;
2252 case QSEOS_RESULT_INCOMPLETE:
2253 ret = __qseecom_process_incomplete_cmd(data, &resp);
2254 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002255 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2256 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002257 break;
2258 case QSEOS_RESULT_FAILURE:
2259 default:
2260 pr_err("Delete key scm call failed resp.result %d\n",
2261 resp.result);
2262 ret = -EINVAL;
2263 break;
2264 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002265 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002266 return ret;
2267}
2268
2269static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2270 enum qseecom_key_management_usage_type usage,
2271 struct qseecom_set_key_parameter *set_key_para)
2272{
2273 struct qseecom_key_select_ireq ireq;
2274 struct qseecom_command_scm_resp resp;
2275 int ret;
2276
2277 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2278 pr_err("Error:: unsupported usage %d\n", usage);
2279 return -EFAULT;
2280 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002281
Zhen Kongdb2bf742013-05-13 23:55:42 -07002282 __qseecom_enable_clk(CLK_QSEE);
2283 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002284 __qseecom_enable_clk(CLK_CE_DRV);
2285
Mona Hossain4cf78a92013-02-14 12:06:41 -08002286 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002287 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002288 ireq.ce = set_key_para->ce_hw;
2289 ireq.pipe = set_key_para->pipe;
2290 ireq.flags = set_key_para->flags;
2291
Zhen Kong1f09c7692013-05-03 17:50:32 -07002292 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2293 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002294
Mona Hossain4cf78a92013-02-14 12:06:41 -08002295 if (set_key_para->set_clear_key_flag ==
2296 QSEECOM_SET_CE_KEY_CMD)
2297 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2298 QSEECOM_HASH_SIZE);
2299 else
2300 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2301
Zhen Kong336636e2013-04-15 11:04:54 -07002302 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002303 &ireq, sizeof(struct qseecom_key_select_ireq),
2304 &resp, sizeof(struct qseecom_command_scm_resp));
2305 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002306 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002307 __qseecom_disable_clk(CLK_QSEE);
2308 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2309 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kong336636e2013-04-15 11:04:54 -07002310 return ret;
2311 }
2312
Mona Hossain4cf78a92013-02-14 12:06:41 -08002313 switch (resp.result) {
2314 case QSEOS_RESULT_SUCCESS:
2315 break;
2316 case QSEOS_RESULT_INCOMPLETE:
2317 ret = __qseecom_process_incomplete_cmd(data, &resp);
2318 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002319 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2320 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002321 break;
2322 case QSEOS_RESULT_FAILURE:
2323 default:
2324 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2325 ret = -EINVAL;
2326 break;
2327 }
2328
Zhen Kongdb2bf742013-05-13 23:55:42 -07002329 __qseecom_disable_clk(CLK_QSEE);
2330 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002331 __qseecom_disable_clk(CLK_CE_DRV);
2332
Mona Hossain4cf78a92013-02-14 12:06:41 -08002333 return ret;
2334}
2335
2336static int qseecom_create_key(struct qseecom_dev_handle *data,
2337 void __user *argp)
2338{
2339 uint32_t ce_hw = 0;
2340 uint32_t pipe = 0;
2341 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2342 int ret = 0;
2343 uint32_t flags = 0;
2344 struct qseecom_set_key_parameter set_key_para;
2345 struct qseecom_create_key_req create_key_req;
2346
2347 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2348 if (ret) {
2349 pr_err("copy_from_user failed\n");
2350 return ret;
2351 }
2352
2353 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2354 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2355 return -EFAULT;
2356 }
2357
2358 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2359 if (ret) {
2360 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2361 return -EINVAL;
2362 }
2363
2364 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2365 key_id, flags);
2366 if (ret) {
2367 pr_err("Failed to generate key on storage: %d\n", ret);
2368 return -EFAULT;
2369 }
2370
2371 set_key_para.ce_hw = ce_hw;
2372 set_key_para.pipe = pipe;
2373 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2374 set_key_para.flags = flags;
2375 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2376 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2377 QSEECOM_HASH_SIZE);
2378
2379 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2380 &set_key_para);
2381 if (ret) {
2382 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2383 pipe, ce_hw, ret);
2384 return -EFAULT;
2385 }
2386
2387 return ret;
2388}
2389
2390static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2391 void __user *argp)
2392{
2393 uint32_t ce_hw = 0;
2394 uint32_t pipe = 0;
2395 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2396 int ret = 0;
2397 uint32_t flags = 0;
2398 int i;
2399 struct qseecom_wipe_key_req wipe_key_req;
2400 struct qseecom_set_key_parameter clear_key_para;
2401
2402 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2403 if (ret) {
2404 pr_err("copy_from_user failed\n");
2405 return ret;
2406 }
2407
2408 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2409 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2410 return -EFAULT;
2411 }
2412
2413 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2414 if (ret) {
2415 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2416 return -EINVAL;
2417 }
2418
2419 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2420 flags);
2421 if (ret) {
2422 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2423 return -EFAULT;
2424 }
2425
2426 /* an invalid key_id 0xff is used to indicate clear key*/
2427 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2428 clear_key_para.key_id[i] = 0xff;
2429 clear_key_para.ce_hw = ce_hw;
2430 clear_key_para.pipe = pipe;
2431 clear_key_para.flags = flags;
2432 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2433 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2434 &clear_key_para);
2435 if (ret) {
2436 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2437 pipe, ce_hw, ret);
2438 return -EFAULT;
2439 }
2440
2441 return ret;
2442}
2443
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002444static int qseecom_is_es_activated(void __user *argp)
2445{
2446 struct qseecom_is_es_activated_req req;
2447 int ret;
2448 int resp_buf;
2449
2450 if (qseecom.qsee_version < QSEE_VERSION_04) {
2451 pr_err("invalid qsee version");
2452 return -ENODEV;
2453 }
2454
2455 if (argp == NULL) {
2456 pr_err("arg is null");
2457 return -EINVAL;
2458 }
2459
2460 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2461 (void *) &resp_buf, sizeof(resp_buf));
2462 if (ret) {
2463 pr_err("scm_call failed");
2464 return ret;
2465 }
2466
2467 req.is_activated = resp_buf;
2468 ret = copy_to_user(argp, &req, sizeof(req));
2469 if (ret) {
2470 pr_err("copy_to_user failed");
2471 return ret;
2472 }
2473
2474 return 0;
2475}
2476
2477static int qseecom_save_partition_hash(void __user *argp)
2478{
2479 struct qseecom_save_partition_hash_req req;
2480 int ret;
2481
2482 if (qseecom.qsee_version < QSEE_VERSION_04) {
2483 pr_err("invalid qsee version ");
2484 return -ENODEV;
2485 }
2486
2487 if (argp == NULL) {
2488 pr_err("arg is null");
2489 return -EINVAL;
2490 }
2491
2492 ret = copy_from_user(&req, argp, sizeof(req));
2493 if (ret) {
2494 pr_err("copy_from_user failed");
2495 return ret;
2496 }
2497
2498 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2499 (void *) &req, sizeof(req), NULL, 0);
2500 if (ret) {
2501 pr_err("scm_call failed");
2502 return ret;
2503 }
2504
2505 return 0;
2506}
2507
Mona Hossain2892b6b2012-02-17 13:53:11 -08002508static long qseecom_ioctl(struct file *file, unsigned cmd,
2509 unsigned long arg)
2510{
2511 int ret = 0;
2512 struct qseecom_dev_handle *data = file->private_data;
2513 void __user *argp = (void __user *) arg;
2514
2515 if (data->abort) {
2516 pr_err("Aborting qseecom driver\n");
2517 return -ENODEV;
2518 }
2519
2520 switch (cmd) {
2521 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2522 pr_debug("ioctl register_listener_req()\n");
2523 atomic_inc(&data->ioctl_count);
2524 ret = qseecom_register_listener(data, argp);
2525 atomic_dec(&data->ioctl_count);
2526 wake_up_all(&data->abort_wq);
2527 if (ret)
2528 pr_err("failed qseecom_register_listener: %d\n", ret);
2529 break;
2530 }
2531 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2532 pr_debug("ioctl unregister_listener_req()\n");
2533 atomic_inc(&data->ioctl_count);
2534 ret = qseecom_unregister_listener(data);
2535 atomic_dec(&data->ioctl_count);
2536 wake_up_all(&data->abort_wq);
2537 if (ret)
2538 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2539 break;
2540 }
2541 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2542 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002543 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002544 atomic_inc(&data->ioctl_count);
2545 ret = qseecom_send_cmd(data, argp);
2546 atomic_dec(&data->ioctl_count);
2547 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002548 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002549 if (ret)
2550 pr_err("failed qseecom_send_cmd: %d\n", ret);
2551 break;
2552 }
2553 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2554 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002555 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002556 atomic_inc(&data->ioctl_count);
2557 ret = qseecom_send_modfd_cmd(data, argp);
2558 atomic_dec(&data->ioctl_count);
2559 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002560 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002561 if (ret)
2562 pr_err("failed qseecom_send_cmd: %d\n", ret);
2563 break;
2564 }
2565 case QSEECOM_IOCTL_RECEIVE_REQ: {
2566 atomic_inc(&data->ioctl_count);
2567 ret = qseecom_receive_req(data);
2568 atomic_dec(&data->ioctl_count);
2569 wake_up_all(&data->abort_wq);
2570 if (ret)
2571 pr_err("failed qseecom_receive_req: %d\n", ret);
2572 break;
2573 }
2574 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2575 atomic_inc(&data->ioctl_count);
2576 ret = qseecom_send_resp();
2577 atomic_dec(&data->ioctl_count);
2578 wake_up_all(&data->abort_wq);
2579 if (ret)
2580 pr_err("failed qseecom_send_resp: %d\n", ret);
2581 break;
2582 }
2583 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2584 ret = qseecom_set_client_mem_param(data, argp);
2585 if (ret)
2586 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2587 ret);
2588 break;
2589 }
2590 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2591 mutex_lock(&app_access_lock);
2592 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002593 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2594 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002595 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002596 if (ret == 0)
2597 qseecom.commonlib_loaded = true;
2598 }
2599 }
2600 if (ret == 0)
2601 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002602 atomic_dec(&data->ioctl_count);
2603 mutex_unlock(&app_access_lock);
2604 if (ret)
2605 pr_err("failed load_app request: %d\n", ret);
2606 break;
2607 }
2608 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2609 mutex_lock(&app_access_lock);
2610 atomic_inc(&data->ioctl_count);
2611 ret = qseecom_unload_app(data);
2612 atomic_dec(&data->ioctl_count);
2613 mutex_unlock(&app_access_lock);
2614 if (ret)
2615 pr_err("failed unload_app request: %d\n", ret);
2616 break;
2617 }
2618 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2619 atomic_inc(&data->ioctl_count);
2620 ret = qseecom_get_qseos_version(data, argp);
2621 if (ret)
2622 pr_err("qseecom_get_qseos_version: %d\n", ret);
2623 atomic_dec(&data->ioctl_count);
2624 break;
2625 }
2626 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2627 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002628 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002629 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002630 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002631 ret = qsee_vote_for_clock(data, CLK_SFPB);
2632 if (ret)
2633 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002634 atomic_dec(&data->ioctl_count);
2635 break;
2636 }
2637 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2638 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002639 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002640 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002641 atomic_dec(&data->ioctl_count);
2642 break;
2643 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002644 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2645 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002646 mutex_lock(&app_access_lock);
2647 atomic_inc(&data->ioctl_count);
2648 ret = qseecom_load_external_elf(data, argp);
2649 atomic_dec(&data->ioctl_count);
2650 mutex_unlock(&app_access_lock);
2651 if (ret)
2652 pr_err("failed load_external_elf request: %d\n", ret);
2653 break;
2654 }
2655 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2656 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002657 mutex_lock(&app_access_lock);
2658 atomic_inc(&data->ioctl_count);
2659 ret = qseecom_unload_external_elf(data);
2660 atomic_dec(&data->ioctl_count);
2661 mutex_unlock(&app_access_lock);
2662 if (ret)
2663 pr_err("failed unload_app request: %d\n", ret);
2664 break;
2665 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002666 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2667 mutex_lock(&app_access_lock);
2668 atomic_inc(&data->ioctl_count);
2669 ret = qseecom_query_app_loaded(data, argp);
2670 atomic_dec(&data->ioctl_count);
2671 mutex_unlock(&app_access_lock);
2672 break;
2673 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002674 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2675 if (qseecom.qsee_version < QSEE_VERSION_03) {
2676 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2677 qseecom.qsee_version);
2678 return -EINVAL;
2679 }
2680 mutex_lock(&app_access_lock);
2681 atomic_inc(&data->ioctl_count);
2682 ret = qseecom_send_service_cmd(data, argp);
2683 atomic_dec(&data->ioctl_count);
2684 mutex_unlock(&app_access_lock);
2685 break;
2686 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002687 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002688 if (qseecom.qsee_version < QSEE_VERSION_05) {
2689 pr_err("Create Key feature not supported in qsee version %u\n",
2690 qseecom.qsee_version);
2691 return -EINVAL;
2692 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002693 data->released = true;
2694 mutex_lock(&app_access_lock);
2695 atomic_inc(&data->ioctl_count);
2696 ret = qseecom_create_key(data, argp);
2697 if (ret)
2698 pr_err("failed to create encryption key: %d\n", ret);
2699
2700 atomic_dec(&data->ioctl_count);
2701 mutex_unlock(&app_access_lock);
2702 break;
2703 }
2704 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002705 if (qseecom.qsee_version < QSEE_VERSION_05) {
2706 pr_err("Wipe Key feature not supported in qsee version %u\n",
2707 qseecom.qsee_version);
2708 return -EINVAL;
2709 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002710 data->released = true;
2711 mutex_lock(&app_access_lock);
2712 atomic_inc(&data->ioctl_count);
2713 ret = qseecom_wipe_key(data, argp);
2714 if (ret)
2715 pr_err("failed to wipe encryption key: %d\n", ret);
2716 atomic_dec(&data->ioctl_count);
2717 mutex_unlock(&app_access_lock);
2718 break;
2719 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002720 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
2721 data->released = true;
2722 mutex_lock(&app_access_lock);
2723 atomic_inc(&data->ioctl_count);
2724 ret = qseecom_save_partition_hash(argp);
2725 atomic_dec(&data->ioctl_count);
2726 mutex_unlock(&app_access_lock);
2727 break;
2728 }
2729 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
2730 data->released = true;
2731 mutex_lock(&app_access_lock);
2732 atomic_inc(&data->ioctl_count);
2733 ret = qseecom_is_es_activated(argp);
2734 atomic_dec(&data->ioctl_count);
2735 mutex_unlock(&app_access_lock);
2736 break;
2737 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002738 default:
2739 return -EINVAL;
2740 }
2741 return ret;
2742}
2743
2744static int qseecom_open(struct inode *inode, struct file *file)
2745{
2746 int ret = 0;
2747 struct qseecom_dev_handle *data;
2748
2749 data = kzalloc(sizeof(*data), GFP_KERNEL);
2750 if (!data) {
2751 pr_err("kmalloc failed\n");
2752 return -ENOMEM;
2753 }
2754 file->private_data = data;
2755 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002756 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002757 data->released = false;
2758 init_waitqueue_head(&data->abort_wq);
2759 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07002760
Mona Hossain2892b6b2012-02-17 13:53:11 -08002761 return ret;
2762}
2763
2764static int qseecom_release(struct inode *inode, struct file *file)
2765{
2766 struct qseecom_dev_handle *data = file->private_data;
2767 int ret = 0;
2768
2769 if (data->released == false) {
2770 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002771 switch (data->type) {
2772 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002773 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002774 break;
2775 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002776 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002777 break;
2778 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07002779 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002780 ret = qseecom_unmap_ion_allocated_memory(data);
2781 if (ret) {
2782 pr_err("Close failed\n");
2783 return ret;
2784 }
2785 break;
2786 default:
2787 pr_err("Unsupported clnt_handle_type %d",
2788 data->type);
2789 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002790 }
2791 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002792
Mona Hossainc9c83c72013-04-11 12:43:48 -07002793 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002794 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07002795 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002796 qsee_disable_clock_vote(data, CLK_DFAB);
2797
Mona Hossain2892b6b2012-02-17 13:53:11 -08002798 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002799
Mona Hossain2892b6b2012-02-17 13:53:11 -08002800 return ret;
2801}
2802
Mona Hossain2892b6b2012-02-17 13:53:11 -08002803static const struct file_operations qseecom_fops = {
2804 .owner = THIS_MODULE,
2805 .unlocked_ioctl = qseecom_ioctl,
2806 .open = qseecom_open,
2807 .release = qseecom_release
2808};
2809
Mona Hossainc92629e2013-04-01 13:37:46 -07002810static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002811{
2812 int rc = 0;
2813 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002814 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07002815 char *core_clk_src = NULL;
2816 char *core_clk = NULL;
2817 char *iface_clk = NULL;
2818 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002819
Mona Hossainc92629e2013-04-01 13:37:46 -07002820 switch (ce) {
2821 case CLK_QSEE: {
2822 core_clk_src = "core_clk_src";
2823 core_clk = "core_clk";
2824 iface_clk = "iface_clk";
2825 bus_clk = "bus_clk";
2826 qclk = &qseecom.qsee;
2827 qclk->instance = CLK_QSEE;
2828 break;
2829 };
2830 case CLK_CE_DRV: {
2831 core_clk_src = "ce_drv_core_clk_src";
2832 core_clk = "ce_drv_core_clk";
2833 iface_clk = "ce_drv_iface_clk";
2834 bus_clk = "ce_drv_bus_clk";
2835 qclk = &qseecom.ce_drv;
2836 qclk->instance = CLK_CE_DRV;
2837 break;
2838 };
2839 default:
2840 pr_err("Invalid ce hw instance: %d!\n", ce);
2841 return -EIO;
2842 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002843 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002844
Mona Hossainc92629e2013-04-01 13:37:46 -07002845 /* Get CE3 src core clk. */
2846 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002847 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08002848 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002849 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002850 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002851 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002852 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08002853 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002854 }
2855 } else {
2856 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002857 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002858 }
2859
2860 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07002861 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002862 if (IS_ERR(qclk->ce_core_clk)) {
2863 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002864 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002865 if (qclk->ce_core_src_clk != NULL)
2866 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002867 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002868 }
2869
2870 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07002871 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002872 if (IS_ERR(qclk->ce_clk)) {
2873 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002874 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002875 if (qclk->ce_core_src_clk != NULL)
2876 clk_put(qclk->ce_core_src_clk);
2877 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002878 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002879 }
2880
2881 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07002882 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002883 if (IS_ERR(qclk->ce_bus_clk)) {
2884 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002885 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07002886 if (qclk->ce_core_src_clk != NULL)
2887 clk_put(qclk->ce_core_src_clk);
2888 clk_put(qclk->ce_core_clk);
2889 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002890 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002891 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002892 return rc;
2893}
2894
Mona Hossainc92629e2013-04-01 13:37:46 -07002895static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002896{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002897 struct qseecom_clk *qclk;
2898
Mona Hossainc92629e2013-04-01 13:37:46 -07002899 if (ce == CLK_QSEE)
2900 qclk = &qseecom.qsee;
2901 else
2902 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002903
2904 if (qclk->ce_clk != NULL) {
2905 clk_put(qclk->ce_clk);
2906 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002907 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002908 if (qclk->ce_core_clk != NULL) {
2909 clk_put(qclk->ce_core_clk);
2910 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002911 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002912 if (qclk->ce_bus_clk != NULL) {
2913 clk_put(qclk->ce_bus_clk);
2914 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002915 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002916 if (qclk->ce_core_src_clk != NULL) {
2917 clk_put(qclk->ce_core_src_clk);
2918 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002919 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07002920}
2921
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002922static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002923{
2924 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002925 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002926 struct device *class_dev;
2927 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002928 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002929 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
2930
Mona Hossain17a4faf2013-03-22 16:40:56 -07002931 qseecom.qsee_bw_count = 0;
2932 qseecom.qsee_perf_client = 0;
2933 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08002934
Mona Hossain17a4faf2013-03-22 16:40:56 -07002935 qseecom.qsee.ce_core_clk = NULL;
2936 qseecom.qsee.ce_clk = NULL;
2937 qseecom.qsee.ce_core_src_clk = NULL;
2938 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002939
Mona Hossainc92629e2013-04-01 13:37:46 -07002940 qseecom.ce_drv.ce_core_clk = NULL;
2941 qseecom.ce_drv.ce_clk = NULL;
2942 qseecom.ce_drv.ce_core_src_clk = NULL;
2943 qseecom.ce_drv.ce_bus_clk = NULL;
2944
Mona Hossain2892b6b2012-02-17 13:53:11 -08002945 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
2946 if (rc < 0) {
2947 pr_err("alloc_chrdev_region failed %d\n", rc);
2948 return rc;
2949 }
2950
2951 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
2952 if (IS_ERR(driver_class)) {
2953 rc = -ENOMEM;
2954 pr_err("class_create failed %d\n", rc);
2955 goto unregister_chrdev_region;
2956 }
2957
2958 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
2959 QSEECOM_DEV);
2960 if (!class_dev) {
2961 pr_err("class_device_create failed %d\n", rc);
2962 rc = -ENOMEM;
2963 goto class_destroy;
2964 }
2965
2966 cdev_init(&qseecom_cdev, &qseecom_fops);
2967 qseecom_cdev.owner = THIS_MODULE;
2968
2969 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
2970 if (rc < 0) {
2971 pr_err("cdev_add failed %d\n", rc);
2972 goto err;
2973 }
2974
2975 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
2976 spin_lock_init(&qseecom.registered_listener_list_lock);
2977 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
2978 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002979 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
2980 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002981 init_waitqueue_head(&qseecom.send_resp_wq);
2982 qseecom.send_resp_flag = 0;
2983
2984 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
2985 &qsee_not_legacy, sizeof(qsee_not_legacy));
2986 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07002987 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002988 goto err;
2989 }
Mona Hossain05c73562012-10-29 17:49:01 -07002990 if (qsee_not_legacy) {
2991 uint32_t feature = 10;
2992
2993 qseecom.qsee_version = QSEEE_VERSION_00;
2994 rc = scm_call(6, 3, &feature, sizeof(feature),
2995 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
2996 if (rc) {
2997 pr_err("Failed to get QSEE version info %d\n", rc);
2998 goto err;
2999 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003000 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003001 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003002 pr_err("QSEE legacy version is not supported:");
3003 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3004 rc = -EINVAL;
3005 goto err;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003006 }
Mona Hossain05c73562012-10-29 17:49:01 -07003007 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003008 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003009 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003010 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003011 if (qseecom.ion_clnt == NULL) {
3012 pr_err("Ion client cannot be created\n");
3013 rc = -ENOMEM;
3014 goto err;
3015 }
3016
3017 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003018 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003019
Mona Hossain4cf78a92013-02-14 12:06:41 -08003020 if (of_property_read_u32((&pdev->dev)->of_node,
3021 "qcom,disk-encrypt-pipe-pair",
3022 &qseecom.ce_info.disk_encrypt_pipe)) {
3023 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3024 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3025 rc = -EINVAL;
3026 goto err;
3027 } else {
3028 pr_warn("bam_pipe_pair=0x%x",
3029 qseecom.ce_info.disk_encrypt_pipe);
3030 }
3031
3032 if (of_property_read_u32((&pdev->dev)->of_node,
3033 "qcom,qsee-ce-hw-instance",
3034 &qseecom.ce_info.qsee_ce_hw_instance)) {
3035 pr_err("Fail to get qsee ce hw instance information.\n");
3036 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3037 rc = -EINVAL;
3038 goto err;
3039 } else {
3040 pr_warn("qsee-ce-hw-instance=0x%x",
3041 qseecom.ce_info.qsee_ce_hw_instance);
3042 }
3043
3044 if (of_property_read_u32((&pdev->dev)->of_node,
3045 "qcom,hlos-ce-hw-instance",
3046 &qseecom.ce_info.hlos_ce_hw_instance)) {
3047 pr_err("Fail to get hlos ce hw instance information.\n");
3048 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3049 rc = -EINVAL;
3050 goto err;
3051 } else {
3052 pr_warn("hlos-ce-hw-instance=0x%x",
3053 qseecom.ce_info.hlos_ce_hw_instance);
3054 }
3055
Mona Hossainc92629e2013-04-01 13:37:46 -07003056 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3057 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3058
3059 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003060 if (ret)
3061 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003062
Mona Hossainc92629e2013-04-01 13:37:46 -07003063 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3064 ret = __qseecom_init_clk(CLK_CE_DRV);
3065 if (ret) {
3066 __qseecom_deinit_clk(CLK_QSEE);
3067 goto err;
3068 }
3069 } else {
3070 struct qseecom_clk *qclk;
3071
3072 qclk = &qseecom.qsee;
3073 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3074 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3075 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3076 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3077 }
3078
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003079 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3080 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003081 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3082 struct resource *resource = NULL;
3083 struct qsee_apps_region_info_ireq req;
3084 struct qseecom_command_scm_resp resp;
3085
3086 resource = platform_get_resource_byname(pdev,
3087 IORESOURCE_MEM, "secapp-region");
3088 if (resource) {
3089 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3090 req.addr = resource->start;
3091 req.size = resource_size(resource);
3092 pr_warn("secure app region addr=0x%x size=0x%x",
3093 req.addr, req.size);
3094 } else {
3095 pr_err("Fail to get secure app region info\n");
3096 rc = -EINVAL;
3097 goto err;
3098 }
3099 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3100 &resp, sizeof(resp));
3101 if (rc) {
3102 pr_err("Failed to send secapp region info %d\n",
3103 rc);
3104 goto err;
3105 }
3106 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003107 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003108 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3109 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003110 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003111
Mona Hossain17a4faf2013-03-22 16:40:56 -07003112 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003113 qseecom_platform_support);
3114
Mona Hossain17a4faf2013-03-22 16:40:56 -07003115 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003116 pr_err("Unable to register bus client\n");
3117 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003118err:
3119 device_destroy(driver_class, qseecom_device_no);
3120class_destroy:
3121 class_destroy(driver_class);
3122unregister_chrdev_region:
3123 unregister_chrdev_region(qseecom_device_no, 1);
3124 return rc;
3125}
3126
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003127static int __devinit qseecom_remove(struct platform_device *pdev)
3128{
Mona Hossaind44a3842012-10-15 09:41:35 -07003129 struct qseecom_registered_kclient_list *kclient = NULL;
3130 unsigned long flags = 0;
3131 int ret = 0;
3132
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003133 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003134 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003135
3136 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3137 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3138 struct qseecom_registered_kclient_list, list);
3139 if (list_empty(&kclient->list)) {
3140 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3141 flags);
3142 return 0;
3143 }
3144 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3145 list) {
3146 if (kclient)
3147 list_del(&kclient->list);
3148 break;
3149 }
3150 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3151
3152
3153 while (kclient->handle != NULL) {
3154 ret = qseecom_unload_app(kclient->handle->dev);
3155 if (ret == 0) {
3156 kzfree(kclient->handle->dev);
3157 kzfree(kclient->handle);
3158 kzfree(kclient);
3159 }
3160 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3161 kclient = list_entry(
3162 (&qseecom.registered_kclient_list_head)->next,
3163 struct qseecom_registered_kclient_list, list);
3164 if (list_empty(&kclient->list)) {
3165 spin_unlock_irqrestore(
3166 &qseecom.registered_kclient_list_lock, flags);
3167 return 0;
3168 }
3169 list_for_each_entry(kclient,
3170 &qseecom.registered_kclient_list_head, list) {
3171 if (kclient)
3172 list_del(&kclient->list);
3173 break;
3174 }
3175 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3176 flags);
3177 if (!kclient) {
3178 ret = 0;
3179 break;
3180 }
3181 }
Mona Hossain05c73562012-10-29 17:49:01 -07003182 if (qseecom.qseos_version > QSEEE_VERSION_00)
3183 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003184
Mona Hossain17a4faf2013-03-22 16:40:56 -07003185 if (qseecom.qsee_perf_client)
3186 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3187 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003188 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003189 if (pdev->dev.of_node) {
3190 __qseecom_deinit_clk(CLK_QSEE);
3191 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3192 __qseecom_deinit_clk(CLK_CE_DRV);
3193 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003194 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003195};
3196
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003197static struct of_device_id qseecom_match[] = {
3198 {
3199 .compatible = "qcom,qseecom",
3200 },
3201 {}
3202};
3203
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003204static struct platform_driver qseecom_plat_driver = {
3205 .probe = qseecom_probe,
3206 .remove = qseecom_remove,
3207 .driver = {
3208 .name = "qseecom",
3209 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003210 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003211 },
3212};
3213
3214static int __devinit qseecom_init(void)
3215{
3216 return platform_driver_register(&qseecom_plat_driver);
3217}
3218
3219static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003220{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003221 device_destroy(driver_class, qseecom_device_no);
3222 class_destroy(driver_class);
3223 unregister_chrdev_region(qseecom_device_no, 1);
3224 ion_client_destroy(qseecom.ion_clnt);
3225}
3226
3227MODULE_LICENSE("GPL v2");
3228MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3229
3230module_init(qseecom_init);
3231module_exit(qseecom_exit);