blob: aad7fb319176324435c789eaea6f2ea9bcd16d81 [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>
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -070044#include <asm/cacheflush.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080045#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070046#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080047
48#define QSEECOM_DEV "qseecom"
Mona Hossain2892b6b2012-02-17 13:53:11 -080049#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070050#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080051#define QSEE_VERSION_01 0x401000
52#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080053#define QSEE_VERSION_03 0x403000
Amir Samuelovd1fc7412013-03-10 16:56:13 +020054#define QSEE_VERSION_04 0x404000
Zhen Kong336636e2013-04-15 11:04:54 -070055#define QSEE_VERSION_05 0x405000
56
Mona Hossain5b76a622012-11-15 20:09:08 -080057
Mona Hossain05c73562012-10-29 17:49:01 -070058
59#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080060
Mona Hossaind39e33b2012-11-05 13:36:40 -080061#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080062
Mona Hossain13dd8922013-01-03 06:11:09 -080063#define QSEECOM_MAX_SG_ENTRY 512
Mona Hossain4cf78a92013-02-14 12:06:41 -080064#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
Mona Hossainf1f2ed62012-11-15 19:51:33 -080065
Amir Samuelovd1fc7412013-03-10 16:56:13 +020066/* Save partition image hash for authentication check */
67#define SCM_SAVE_PARTITION_HASH_ID 0x01
68
69/* Check if enterprise security is activate */
70#define SCM_IS_ACTIVATED_ID 0x02
71
Zhen Kong7812dc12013-07-09 17:12:55 -070072#define RPMB_SERVICE 0x2000
73
Zhen Kong2edf90d2013-08-27 12:05:06 -070074#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
75#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
76
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070077enum qseecom_clk_definitions {
78 CLK_DFAB = 0,
79 CLK_SFPB,
80};
81
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080082enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053083 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080084 QSEECOM_LISTENER_SERVICE,
85 QSEECOM_SECURE_SERVICE,
86 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053087 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080088};
89
Mona Hossainc92629e2013-04-01 13:37:46 -070090enum qseecom_ce_hw_instance {
91 CLK_QSEE = 0,
92 CLK_CE_DRV,
93};
94
Mona Hossain2892b6b2012-02-17 13:53:11 -080095static struct class *driver_class;
96static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -080097
Mona Hossain2892b6b2012-02-17 13:53:11 -080098static DEFINE_MUTEX(qsee_bw_mutex);
99static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -0700100static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800101
Mona Hossain2892b6b2012-02-17 13:53:11 -0800102struct qseecom_registered_listener_list {
103 struct list_head list;
104 struct qseecom_register_listener_req svc;
Zhen Kongf4948192013-11-25 13:05:35 -0800105 uint32_t user_virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800106 u8 *sb_virt;
107 s32 sb_phys;
108 size_t sb_length;
109 struct ion_handle *ihandle; /* Retrieve phy addr */
110
111 wait_queue_head_t rcv_req_wq;
112 int rcv_req_flag;
113};
114
115struct qseecom_registered_app_list {
116 struct list_head list;
117 u32 app_id;
118 u32 ref_cnt;
119};
120
Mona Hossaind44a3842012-10-15 09:41:35 -0700121struct qseecom_registered_kclient_list {
122 struct list_head list;
123 struct qseecom_handle *handle;
124};
125
Mona Hossain4cf78a92013-02-14 12:06:41 -0800126struct ce_hw_usage_info {
127 uint32_t qsee_ce_hw_instance;
128 uint32_t hlos_ce_hw_instance;
129 uint32_t disk_encrypt_pipe;
130};
131
Mona Hossain17a4faf2013-03-22 16:40:56 -0700132struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700133 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700134 struct clk *ce_core_clk;
135 struct clk *ce_clk;
136 struct clk *ce_core_src_clk;
137 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700138 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700139};
140
Mona Hossain2892b6b2012-02-17 13:53:11 -0800141struct qseecom_control {
142 struct ion_client *ion_clnt; /* Ion client */
143 struct list_head registered_listener_list_head;
144 spinlock_t registered_listener_list_lock;
145
146 struct list_head registered_app_list_head;
147 spinlock_t registered_app_list_lock;
148
Mona Hossaind44a3842012-10-15 09:41:35 -0700149 struct list_head registered_kclient_list_head;
150 spinlock_t registered_kclient_list_lock;
151
Mona Hossain2892b6b2012-02-17 13:53:11 -0800152 wait_queue_head_t send_resp_wq;
153 int send_resp_flag;
154
155 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700156 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700157 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700158 bool commonlib_loaded;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800159 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700160
161 int qsee_bw_count;
162 int qsee_sfpb_bw_count;
163
164 uint32_t qsee_perf_client;
165 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700166 struct qseecom_clk ce_drv;
AnilKumar Chimataa253a032013-10-04 18:53:42 +0530167 struct cdev cdev;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700168
169 bool support_bus_scaling;
170 uint32_t cumulative_mode;
171 enum qseecom_bandwidth_request_mode current_mode;
172 struct timer_list bw_scale_down_timer;
173 struct work_struct bw_inactive_req_ws;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800174};
175
176struct qseecom_client_handle {
177 u32 app_id;
178 u8 *sb_virt;
179 s32 sb_phys;
180 uint32_t user_virt_sb_base;
181 size_t sb_length;
182 struct ion_handle *ihandle; /* Retrieve phy addr */
183};
184
185struct qseecom_listener_handle {
186 u32 id;
187};
188
189static struct qseecom_control qseecom;
190
191struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800192 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800193 union {
194 struct qseecom_client_handle client;
195 struct qseecom_listener_handle listener;
196 };
197 bool released;
198 int abort;
199 wait_queue_head_t abort_wq;
200 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700201 bool perf_enabled;
202 bool fast_load_enabled;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700203 enum qseecom_bandwidth_request_mode mode;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800204};
205
Mona Hossain4cf78a92013-02-14 12:06:41 -0800206enum qseecom_set_clear_key_flag {
207 QSEECOM_CLEAR_CE_KEY_CMD = 0,
208 QSEECOM_SET_CE_KEY_CMD,
209};
210
211struct qseecom_set_key_parameter {
212 uint32_t ce_hw;
213 uint32_t pipe;
214 uint32_t flags;
215 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
216 unsigned char hash32[QSEECOM_HASH_SIZE];
217 enum qseecom_set_clear_key_flag set_clear_key_flag;
218};
219
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800220struct qseecom_sg_entry {
221 uint32_t phys_addr;
222 uint32_t len;
223};
224
Zhen Kong9730ddf2013-12-17 16:49:43 -0800225uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = {
226 "Disk Encryption"
227};
228
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700229/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800230static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
231static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700232static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
233static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700234
Mona Hossain2892b6b2012-02-17 13:53:11 -0800235static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800236 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800237{
238 struct qseecom_registered_listener_list *ptr;
239 int unique = 1;
240 unsigned long flags;
241
242 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
243 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800244 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800245 pr_err("Service id: %u is already registered\n",
246 ptr->svc.listener_id);
247 unique = 0;
248 break;
249 }
250 }
251 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
252 return unique;
253}
254
255static struct qseecom_registered_listener_list *__qseecom_find_svc(
256 int32_t listener_id)
257{
258 struct qseecom_registered_listener_list *entry = NULL;
259 unsigned long flags;
260
261 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
262 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
263 {
264 if (entry->svc.listener_id == listener_id)
265 break;
266 }
267 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530268
269 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
270 pr_err("Service id: %u is not found\n", listener_id);
271 return NULL;
272 }
273
Mona Hossain2892b6b2012-02-17 13:53:11 -0800274 return entry;
275}
276
277static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
278 struct qseecom_dev_handle *handle,
279 struct qseecom_register_listener_req *listener)
280{
281 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800282 struct qseecom_register_listener_ireq req;
283 struct qseecom_command_scm_resp resp;
284 ion_phys_addr_t pa;
285
286 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800287 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
288 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800289 if (svc->ihandle == NULL) {
290 pr_err("Ion client could not retrieve the handle\n");
291 return -ENOMEM;
292 }
293
294 /* Get the physical address of the ION BUF */
295 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
296
297 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700298 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800299 svc->sb_phys = pa;
300
Mona Hossaind4613de2013-05-15 16:49:29 -0700301 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
302 req.listener_id = svc->svc.listener_id;
303 req.sb_len = svc->sb_length;
304 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800305
Mona Hossaind4613de2013-05-15 16:49:29 -0700306 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800307
Mona Hossaind4613de2013-05-15 16:49:29 -0700308 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800309 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700310 if (ret) {
311 pr_err("qseecom_scm_call failed with err: %d\n", ret);
312 return -EINVAL;
313 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800314
Mona Hossaind4613de2013-05-15 16:49:29 -0700315 if (resp.result != QSEOS_RESULT_SUCCESS) {
316 pr_err("Error SB registration req: resp.result = %d\n",
317 resp.result);
318 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800319 }
320 return 0;
321}
322
323static int qseecom_register_listener(struct qseecom_dev_handle *data,
324 void __user *argp)
325{
326 int ret = 0;
327 unsigned long flags;
328 struct qseecom_register_listener_req rcvd_lstnr;
329 struct qseecom_registered_listener_list *new_entry;
330
331 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
332 if (ret) {
333 pr_err("copy_from_user failed\n");
334 return ret;
335 }
Zhen Kongf4948192013-11-25 13:05:35 -0800336 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
337 rcvd_lstnr.sb_size))
338 return -EFAULT;
339
Mona Hossain0af10ab2012-02-28 18:26:41 -0800340 data->listener.id = 0;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700341 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800342 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800343 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800344 data->released = true;
345 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800346 }
347
348 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
349 if (!new_entry) {
350 pr_err("kmalloc failed\n");
351 return -ENOMEM;
352 }
353 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
354 new_entry->rcv_req_flag = 0;
355
356 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
357 new_entry->sb_length = rcvd_lstnr.sb_size;
Zhen Kongf4948192013-11-25 13:05:35 -0800358 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800359 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
360 pr_err("qseecom_set_sb_memoryfailed\n");
361 kzfree(new_entry);
362 return -ENOMEM;
363 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800364
Mona Hossain2892b6b2012-02-17 13:53:11 -0800365 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800366 init_waitqueue_head(&new_entry->rcv_req_wq);
367
368 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
369 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
370 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800371
Mona Hossain2892b6b2012-02-17 13:53:11 -0800372 return ret;
373}
374
375static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
376{
377 int ret = 0;
378 unsigned long flags;
379 uint32_t unmap_mem = 0;
380 struct qseecom_register_listener_ireq req;
381 struct qseecom_registered_listener_list *ptr_svc = NULL;
382 struct qseecom_command_scm_resp resp;
383 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
384
Mona Hossaind4613de2013-05-15 16:49:29 -0700385 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
386 req.listener_id = data->listener.id;
387 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800388
Mona Hossaind4613de2013-05-15 16:49:29 -0700389 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800390 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700391 if (ret) {
392 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
393 ret, data->listener.id);
394 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800395 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700396
397 if (resp.result != QSEOS_RESULT_SUCCESS) {
398 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
399 resp.result, data->listener.id);
400 return -EPERM;
401 }
402
Mona Hossain2892b6b2012-02-17 13:53:11 -0800403 data->abort = 1;
404 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
405 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
406 list) {
407 if (ptr_svc->svc.listener_id == data->listener.id) {
408 wake_up_all(&ptr_svc->rcv_req_wq);
409 break;
410 }
411 }
412 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
413
414 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700415 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800416 atomic_read(&data->ioctl_count) <= 1)) {
417 pr_err("Interrupted from abort\n");
418 ret = -ERESTARTSYS;
419 break;
420 }
421 }
422
423 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
424 list_for_each_entry(ptr_svc,
425 &qseecom.registered_listener_list_head,
426 list)
427 {
428 if (ptr_svc->svc.listener_id == data->listener.id) {
429 if (ptr_svc->sb_virt) {
430 unmap_mem = 1;
431 ihandle = ptr_svc->ihandle;
432 }
433 list_del(&ptr_svc->list);
434 kzfree(ptr_svc);
435 break;
436 }
437 }
438 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
439
440 /* Unmap the memory */
441 if (unmap_mem) {
442 if (!IS_ERR_OR_NULL(ihandle)) {
443 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
444 ion_free(qseecom.ion_clnt, ihandle);
445 }
446 }
447 data->released = true;
448 return ret;
449}
450
Zhen Kong2edf90d2013-08-27 12:05:06 -0700451static int __qseecom_set_msm_bus_request(uint32_t mode)
452{
453 int ret = 0;
454 struct qseecom_clk *qclk;
455
456 qclk = &qseecom.qsee;
457 if (qclk->ce_core_src_clk != NULL) {
458 if (mode == INACTIVE) {
459 __qseecom_disable_clk(CLK_QSEE);
460 } else {
461 ret = __qseecom_enable_clk(CLK_QSEE);
462 if (ret)
463 pr_err("CLK enabling failed (%d) MODE (%d)\n",
464 ret, mode);
465 }
466 }
467
468 if ((!ret) && (qseecom.current_mode != mode)) {
469 ret = msm_bus_scale_client_update_request(
470 qseecom.qsee_perf_client, mode);
471 if (ret) {
472 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
473 ret, mode);
474 if (qclk->ce_core_src_clk != NULL) {
475 if (mode == INACTIVE)
476 __qseecom_enable_clk(CLK_QSEE);
477 else
478 __qseecom_disable_clk(CLK_QSEE);
479 }
480 }
481 qseecom.current_mode = mode;
482 }
483 return ret;
484}
485
486static void qseecom_bw_inactive_req_work(struct work_struct *work)
487{
488 mutex_lock(&app_access_lock);
489 mutex_lock(&qsee_bw_mutex);
490 __qseecom_set_msm_bus_request(INACTIVE);
491 pr_debug("current_mode = %d, cumulative_mode = %d\n",
492 qseecom.current_mode, qseecom.cumulative_mode);
493 mutex_unlock(&qsee_bw_mutex);
494 mutex_unlock(&app_access_lock);
495 return;
496}
497
498static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
499{
500 schedule_work(&qseecom.bw_inactive_req_ws);
501 return;
502}
503
504static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
505{
506 int32_t ret = 0;
507 int32_t request_mode = INACTIVE;
508
509 mutex_lock(&qsee_bw_mutex);
510 if (mode == 0) {
511 if (qseecom.cumulative_mode > MEDIUM)
512 request_mode = HIGH;
513 else
514 request_mode = qseecom.cumulative_mode;
515 } else {
516 request_mode = mode;
517 }
518 __qseecom_set_msm_bus_request(request_mode);
519
520 del_timer_sync(&(qseecom.bw_scale_down_timer));
521 qseecom.bw_scale_down_timer.expires = jiffies +
522 msecs_to_jiffies(duration);
523 add_timer(&(qseecom.bw_scale_down_timer));
524
525 mutex_unlock(&qsee_bw_mutex);
526 return ret;
527}
528
529
530static int qseecom_unregister_bus_bandwidth_needs(
531 struct qseecom_dev_handle *data)
532{
533 int32_t ret = 0;
534
535 qseecom.cumulative_mode -= data->mode;
536 data->mode = INACTIVE;
537
538 return ret;
539}
540
541static int __qseecom_register_bus_bandwidth_needs(
542 struct qseecom_dev_handle *data, uint32_t request_mode)
543{
544 int32_t ret = 0;
545
546 if (data->mode == INACTIVE) {
547 qseecom.cumulative_mode += request_mode;
548 data->mode = request_mode;
549 } else {
550 if (data->mode != request_mode) {
551 qseecom.cumulative_mode -= data->mode;
552 qseecom.cumulative_mode += request_mode;
553 data->mode = request_mode;
554 }
555 }
556 return ret;
557}
558
559static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
560 void __user *argp)
561{
562 int32_t ret = 0;
563 int32_t req_mode;
564
565 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
566 if (ret) {
567 pr_err("copy_from_user failed\n");
568 return ret;
569 }
570 if (req_mode > HIGH) {
571 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
572 return ret;
573 }
574 mutex_lock(&qsee_bw_mutex);
575 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
576 mutex_unlock(&qsee_bw_mutex);
577
578 return ret;
579}
580
581static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
582{
583 if (!qseecom.support_bus_scaling)
584 qsee_disable_clock_vote(data, CLK_SFPB);
585 return;
586}
587
588static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
589{
590 int ret = 0;
591 if (qseecom.support_bus_scaling) {
592 qseecom_scale_bus_bandwidth_timer(
593 MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
594 } else {
595 ret = qsee_vote_for_clock(data, CLK_SFPB);
596 if (ret)
597 pr_err("Fail vote for clk SFPB ret %d\n", ret);
598 }
599 return ret;
600}
601
Mona Hossain2892b6b2012-02-17 13:53:11 -0800602static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
603 void __user *argp)
604{
605 ion_phys_addr_t pa;
606 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800607 struct qseecom_set_sb_mem_param_req req;
608 uint32_t len;
609
610 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700611 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800612 return -EFAULT;
613
Mona Hossaina1124de2013-10-01 13:41:09 -0700614 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
615 (req.sb_len == 0)) {
616 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
617 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
618 return -EFAULT;
619 }
Zhen Kongf4948192013-11-25 13:05:35 -0800620 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
621 req.sb_len))
622 return -EFAULT;
623
Mona Hossain2892b6b2012-02-17 13:53:11 -0800624 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800625 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
626 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800627 if (IS_ERR_OR_NULL(data->client.ihandle)) {
628 pr_err("Ion client could not retrieve the handle\n");
629 return -ENOMEM;
630 }
631 /* Get the physical address of the ION BUF */
632 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
633 /* Populate the structure for sending scm call to load image */
634 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700635 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800636 data->client.sb_phys = pa;
637 data->client.sb_length = req.sb_len;
638 data->client.user_virt_sb_base = req.virt_sb_base;
639 return 0;
640}
641
Mona Hossain2892b6b2012-02-17 13:53:11 -0800642static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
643{
644 int ret;
645 ret = (qseecom.send_resp_flag != 0);
646 return ret || data->abort;
647}
648
649static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
650 struct qseecom_command_scm_resp *resp)
651{
652 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800653 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800654 uint32_t lstnr;
655 unsigned long flags;
656 struct qseecom_client_listener_data_irsp send_data_rsp;
657 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700658 sigset_t new_sigset;
659 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800660
Mona Hossain2892b6b2012-02-17 13:53:11 -0800661 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
662 lstnr = resp->data;
663 /*
664 * Wake up blocking lsitener service with the lstnr id
665 */
666 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
667 flags);
668 list_for_each_entry(ptr_svc,
669 &qseecom.registered_listener_list_head, list) {
670 if (ptr_svc->svc.listener_id == lstnr) {
671 ptr_svc->rcv_req_flag = 1;
672 wake_up_interruptible(&ptr_svc->rcv_req_wq);
673 break;
674 }
675 }
676 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
677 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700678
679 if (ptr_svc == NULL) {
680 pr_err("Listener Svc %d does not exist\n", lstnr);
681 return -EINVAL;
682 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800683 if (ptr_svc->svc.listener_id != lstnr) {
684 pr_warning("Service requested for does on exist\n");
685 return -ERESTARTSYS;
686 }
687 pr_debug("waking up rcv_req_wq and "
688 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800689
Mona Hossain91da2c52013-03-29 17:28:31 -0700690 /* initialize the new signal mask with all signals*/
691 sigfillset(&new_sigset);
692 /* block all signals */
693 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
694
695 do {
696 if (!wait_event_freezable(qseecom.send_resp_wq,
697 __qseecom_listener_has_sent_rsp(data)))
698 break;
699 } while (1);
700
701 /* restore signal mask */
702 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
703 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700704 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
705 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700706 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800707 send_data_rsp.status = QSEOS_RESULT_FAILURE;
708 } else {
709 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800710 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800711
Mona Hossain2892b6b2012-02-17 13:53:11 -0800712 qseecom.send_resp_flag = 0;
713 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
714 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700715 if (ptr_svc)
716 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
717 ptr_svc->sb_virt, ptr_svc->sb_length,
718 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700719
720 if (lstnr == RPMB_SERVICE)
721 __qseecom_enable_clk(CLK_QSEE);
722
Mona Hossain2892b6b2012-02-17 13:53:11 -0800723 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
724 (const void *)&send_data_rsp,
725 sizeof(send_data_rsp), resp,
726 sizeof(*resp));
727 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700728 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800729 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700730 if (lstnr == RPMB_SERVICE)
731 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800732 return ret;
733 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800734 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
735 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
736 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
737 resp->result, data->client.app_id, lstnr);
738 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700739 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700740 if (lstnr == RPMB_SERVICE)
741 __qseecom_disable_clk(CLK_QSEE);
742
Mona Hossain2892b6b2012-02-17 13:53:11 -0800743 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800744 if (rc)
745 return rc;
746
Mona Hossain2892b6b2012-02-17 13:53:11 -0800747 return ret;
748}
749
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700750static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
751{
752 int32_t ret;
753 struct qseecom_command_scm_resp resp;
754
755 /* SCM_CALL to check if app_id for the mentioned app exists */
756 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
757 sizeof(struct qseecom_check_app_ireq),
758 &resp, sizeof(resp));
759 if (ret) {
760 pr_err("scm_call to check if app is already loaded failed\n");
761 return -EINVAL;
762 }
763
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700764 if (resp.result == QSEOS_RESULT_FAILURE) {
765 return 0;
766 } else {
767 switch (resp.resp_type) {
768 /*qsee returned listener type response */
769 case QSEOS_LISTENER_ID:
770 pr_err("resp type is of listener type instead of app");
771 return -EINVAL;
772 break;
773 case QSEOS_APP_ID:
774 return resp.data;
775 default:
776 pr_err("invalid resp type (%d) from qsee",
777 resp.resp_type);
778 return -ENODEV;
779 break;
780 }
781 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700782}
783
Mona Hossain2892b6b2012-02-17 13:53:11 -0800784static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
785{
786 struct qseecom_registered_app_list *entry = NULL;
787 unsigned long flags = 0;
788 u32 app_id = 0;
789 struct ion_handle *ihandle; /* Ion handle */
790 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700791 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800792 ion_phys_addr_t pa = 0;
793 uint32_t len;
794 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800795 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700796 struct qseecom_load_app_ireq load_req;
797
Mona Hossain2892b6b2012-02-17 13:53:11 -0800798 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700799 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800800 (void __user *)argp,
801 sizeof(struct qseecom_load_img_req))) {
802 pr_err("copy_from_user failed\n");
803 return -EFAULT;
804 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700805 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700806 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700807 if (ret)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700808 return ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800809 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700810 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800811 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800812
Mona Hossain436b75f2012-11-20 17:10:40 -0800813 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530814 if (ret < 0) {
Zhen Kong2edf90d2013-08-27 12:05:06 -0700815 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800816 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530817 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800818
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530819 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800820 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700821 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800822 (char *)(req.app_name));
823 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
824 list_for_each_entry(entry,
825 &qseecom.registered_app_list_head, list){
826 if (entry->app_id == app_id) {
827 entry->ref_cnt++;
828 break;
829 }
830 }
831 spin_unlock_irqrestore(
832 &qseecom.registered_app_list_lock, flags);
833 } else {
834 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700835 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800836 /* Get the handle of the shared fd */
837 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800838 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800839 if (IS_ERR_OR_NULL(ihandle)) {
840 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700841 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800842 return -ENOMEM;
843 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800844
Mona Hossain436b75f2012-11-20 17:10:40 -0800845 /* Get the physical address of the ION BUF */
846 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800847
Mona Hossain436b75f2012-11-20 17:10:40 -0800848 /* Populate the structure for sending scm call to load image */
849 memcpy(load_req.app_name, load_img_req.img_name,
850 MAX_APP_NAME_SIZE);
851 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
852 load_req.mdt_len = load_img_req.mdt_len;
853 load_req.img_len = load_img_req.img_len;
854 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700855 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
856 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800857
Mona Hossain436b75f2012-11-20 17:10:40 -0800858 /* SCM_CALL to load the app and get the app_id back */
859 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700860 sizeof(struct qseecom_load_app_ireq),
861 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700862 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800863 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800864 if (!IS_ERR_OR_NULL(ihandle))
865 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700866 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800867 return -EINVAL;
868 }
869
870 if (resp.result == QSEOS_RESULT_FAILURE) {
871 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700872 if (!IS_ERR_OR_NULL(ihandle))
873 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700874 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800875 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700876 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700877
Mona Hossain436b75f2012-11-20 17:10:40 -0800878 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
879 ret = __qseecom_process_incomplete_cmd(data, &resp);
880 if (ret) {
881 pr_err("process_incomplete_cmd failed err: %d\n",
882 ret);
883 if (!IS_ERR_OR_NULL(ihandle))
884 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700885 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800886 return ret;
887 }
888 }
889
890 if (resp.result != QSEOS_RESULT_SUCCESS) {
891 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700892 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800893 if (!IS_ERR_OR_NULL(ihandle))
894 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700895 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800896 return -EFAULT;
897 }
898
899 app_id = resp.data;
900
901 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
902 if (!entry) {
903 pr_err("kmalloc failed\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700904 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800905 return -ENOMEM;
906 }
907 entry->app_id = app_id;
908 entry->ref_cnt = 1;
909
910 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700911 if (!IS_ERR_OR_NULL(ihandle))
912 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700913
Mona Hossain436b75f2012-11-20 17:10:40 -0800914 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
915 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
916 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
917 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700918
Mona Hossain436b75f2012-11-20 17:10:40 -0800919 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700920 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800921 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800922 data->client.app_id = app_id;
923 load_img_req.app_id = app_id;
924 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
925 pr_err("copy_to_user failed\n");
926 kzfree(entry);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700927 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800928 return -EFAULT;
929 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700930 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800931 return 0;
932}
933
934static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
935{
936 wake_up_all(&qseecom.send_resp_wq);
937 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700938 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800939 atomic_read(&data->ioctl_count) <= 1)) {
940 pr_err("Interrupted from abort\n");
941 return -ERESTARTSYS;
942 break;
943 }
944 }
945 /* Set unload app */
946 return 1;
947}
948
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800949static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
950{
951 int ret = 0;
952 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
953 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
954 ion_free(qseecom.ion_clnt, data->client.ihandle);
955 data->client.ihandle = NULL;
956 }
957 return ret;
958}
959
Mona Hossain2892b6b2012-02-17 13:53:11 -0800960static int qseecom_unload_app(struct qseecom_dev_handle *data)
961{
962 unsigned long flags;
963 int ret = 0;
964 struct qseecom_command_scm_resp resp;
965 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700966 bool unload = false;
967 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800968
Mona Hossaind4613de2013-05-15 16:49:29 -0700969 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800970 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
971 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
972 list) {
973 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700974 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800975 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700976 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800977 break;
978 } else {
979 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700980 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700981 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800982 break;
983 }
984 }
985 }
986 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
987 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700988 if (found_app == false) {
989 pr_err("Cannot find app with id = %d\n",
990 data->client.app_id);
991 return -EINVAL;
992 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800993 }
994
Mona Hossaind4613de2013-05-15 16:49:29 -0700995 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800996 struct qseecom_unload_app_ireq req;
997
Mona Hossain340dba82012-08-07 19:54:46 -0700998 __qseecom_cleanup_app(data);
999 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1000 list_del(&ptr_app->list);
1001 kzfree(ptr_app);
1002 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1003 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001004 /* Populate the structure for sending scm call to load image */
1005 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1006 req.app_id = data->client.app_id;
1007
1008 /* SCM_CALL to unload the app */
1009 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1010 sizeof(struct qseecom_unload_app_ireq),
1011 &resp, sizeof(resp));
1012 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001013 pr_err("scm_call to unload app (id = %d) failed\n",
1014 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001015 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001016 } else {
1017 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001018 }
1019 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1020 ret = __qseecom_process_incomplete_cmd(data, &resp);
1021 if (ret) {
1022 pr_err("process_incomplete_cmd fail err: %d\n",
1023 ret);
1024 return ret;
1025 }
1026 }
1027 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001028 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001029 data->released = true;
1030 return ret;
1031}
1032
1033static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1034 uint32_t virt)
1035{
1036 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1037}
1038
Zhen Kongf4948192013-11-25 13:05:35 -08001039static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1040 uint32_t virt)
1041{
1042 return (uint32_t)data->client.sb_virt +
1043 (virt - data->client.user_virt_sb_base);
1044}
1045
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001046int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1047 struct qseecom_send_svc_cmd_req *req_ptr,
1048 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1049{
1050 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001051 void *req_buf = NULL;
1052
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001053 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1054 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1055 req_ptr, send_svc_ireq_ptr);
1056 return -EINVAL;
1057 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001058
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -08001059 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
1060 pr_err("Invalid req/resp buffer, exiting\n");
1061 return -EINVAL;
1062 }
1063
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001064 if (((uint32_t)req_ptr->cmd_req_buf <
1065 data_ptr->client.user_virt_sb_base)
1066 || ((uint32_t)req_ptr->cmd_req_buf >=
1067 (data_ptr->client.user_virt_sb_base +
1068 data_ptr->client.sb_length))) {
1069 pr_err("cmd buffer address not within shared bufffer\n");
1070 return -EINVAL;
1071 }
1072
1073
1074 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1075 || ((uint32_t)req_ptr->resp_buf >=
1076 (data_ptr->client.user_virt_sb_base +
1077 data_ptr->client.sb_length))){
1078 pr_err("response buffer address not within shared bufffer\n");
1079 return -EINVAL;
1080 }
1081
1082 req_buf = data_ptr->client.sb_virt;
1083
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001084 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1085 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001086 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001087 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1088 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1089 (uint32_t)req_ptr->resp_buf));
1090 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1091
1092 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1093 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1094 return ret;
1095}
1096
1097static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1098 void __user *argp)
1099{
1100 int ret = 0;
1101 struct qseecom_client_send_service_ireq send_svc_ireq;
1102 struct qseecom_command_scm_resp resp;
1103 struct qseecom_send_svc_cmd_req req;
1104 /*struct qseecom_command_scm_resp resp;*/
1105
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001106 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001107 (void __user *)argp,
1108 sizeof(req))) {
1109 pr_err("copy_from_user failed\n");
1110 return -EFAULT;
1111 }
1112
1113 if (req.resp_buf == NULL) {
1114 pr_err("cmd buffer or response buffer is null\n");
1115 return -EINVAL;
1116 }
1117
Zhen Kong2edf90d2013-08-27 12:05:06 -07001118 data->type = QSEECOM_SECURE_SERVICE;
1119
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001120 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001121 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1122 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001123 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1124 &send_svc_ireq))
1125 return -EINVAL;
1126 break;
1127 default:
1128 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1129 return -EINVAL;
1130 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301131
Zhen Kong2edf90d2013-08-27 12:05:06 -07001132 if (qseecom.support_bus_scaling) {
1133 qseecom_scale_bus_bandwidth_timer(HIGH,
1134 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1135 if (ret) {
1136 pr_err("Fail to set bw HIGH%d\n", ret);
1137 return ret;
1138 }
1139 } else {
1140 ret = qsee_vote_for_clock(data, CLK_DFAB);
1141 if (ret) {
1142 pr_err("Failed to vote for DFAB clock%d\n", ret);
1143 return ret;
1144 }
1145 ret = qsee_vote_for_clock(data, CLK_SFPB);
1146 if (ret) {
1147 qsee_disable_clock_vote(data, CLK_DFAB);
1148 pr_err("Failed to vote for SFPB clock%d\n", ret);
1149 goto exit;
1150 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301151 }
1152
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001153 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1154 data->client.sb_virt, data->client.sb_length,
1155 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001156 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1157 sizeof(send_svc_ireq),
1158 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001159 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1160 data->client.sb_virt, data->client.sb_length,
1161 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001162 if (ret) {
1163 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001164 if (!qseecom.support_bus_scaling) {
1165 qsee_disable_clock_vote(data, CLK_DFAB);
1166 qsee_disable_clock_vote(data, CLK_SFPB);
1167 }
1168 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001169 }
1170
1171 switch (resp.result) {
1172 case QSEOS_RESULT_SUCCESS:
1173 break;
1174 case QSEOS_RESULT_INCOMPLETE:
1175 pr_err("qseos_result_incomplete\n");
1176 ret = __qseecom_process_incomplete_cmd(data, &resp);
1177 if (ret) {
1178 pr_err("process_incomplete_cmd fail: err: %d\n",
1179 ret);
1180 }
1181 break;
1182 case QSEOS_RESULT_FAILURE:
1183 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1184 break;
1185 default:
1186 pr_err("Response result %d not supported\n",
1187 resp.result);
1188 ret = -EINVAL;
1189 break;
1190 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001191exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001192 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001193}
1194
Mona Hossain2892b6b2012-02-17 13:53:11 -08001195static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1196 struct qseecom_send_cmd_req *req)
1197{
1198 int ret = 0;
1199 u32 reqd_len_sb_in = 0;
1200 struct qseecom_client_send_data_ireq send_data_req;
1201 struct qseecom_command_scm_resp resp;
1202
1203 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1204 pr_err("cmd buffer or response buffer is null\n");
1205 return -EINVAL;
1206 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001207 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1208 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1209 data->client.sb_length))) {
1210 pr_err("cmd buffer address not within shared bufffer\n");
1211 return -EINVAL;
1212 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001213
Mona Hossaindddf4442013-10-01 14:08:20 -07001214
1215 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1216 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1217 data->client.sb_length))){
1218 pr_err("response buffer address not within shared bufffer\n");
1219 return -EINVAL;
1220 }
1221
1222 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001223 req->cmd_req_len > data->client.sb_length ||
1224 req->resp_len > data->client.sb_length) {
1225 pr_err("cmd buffer length or "
1226 "response buffer length not valid\n");
1227 return -EINVAL;
1228 }
1229
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001230 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1231 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1232 return -EINVAL;
1233 }
1234
Mona Hossain2892b6b2012-02-17 13:53:11 -08001235 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1236 if (reqd_len_sb_in > data->client.sb_length) {
1237 pr_debug("Not enough memory to fit cmd_buf and "
1238 "resp_buf. Required: %u, Available: %u\n",
1239 reqd_len_sb_in, data->client.sb_length);
1240 return -ENOMEM;
1241 }
1242
1243 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1244 send_data_req.app_id = data->client.app_id;
1245 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1246 (uint32_t)req->cmd_req_buf));
1247 send_data_req.req_len = req->cmd_req_len;
1248 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1249 (uint32_t)req->resp_buf));
1250 send_data_req.rsp_len = req->resp_len;
1251
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001252 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1253 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001254 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001255 ION_IOC_CLEAN_INV_CACHES);
1256
Mona Hossain2892b6b2012-02-17 13:53:11 -08001257 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1258 sizeof(send_data_req),
1259 &resp, sizeof(resp));
1260 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001261 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1262 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001263 return ret;
1264 }
1265
1266 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1267 ret = __qseecom_process_incomplete_cmd(data, &resp);
1268 if (ret) {
1269 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1270 return ret;
1271 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001272 } else {
1273 if (resp.result != QSEOS_RESULT_SUCCESS) {
1274 pr_err("Response result %d not supported\n",
1275 resp.result);
1276 ret = -EINVAL;
1277 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001278 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001279 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1280 data->client.sb_virt, data->client.sb_length,
1281 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001282 return ret;
1283}
1284
Mona Hossain2892b6b2012-02-17 13:53:11 -08001285static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1286{
1287 int ret = 0;
1288 struct qseecom_send_cmd_req req;
1289
1290 ret = copy_from_user(&req, argp, sizeof(req));
1291 if (ret) {
1292 pr_err("copy_from_user failed\n");
1293 return ret;
1294 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001295 ret = __qseecom_send_cmd(data, &req);
1296
Mona Hossain2892b6b2012-02-17 13:53:11 -08001297 if (ret)
1298 return ret;
1299
Mona Hossain2892b6b2012-02-17 13:53:11 -08001300 return ret;
1301}
1302
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001303static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1304 struct qseecom_dev_handle *data,
1305 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001306{
1307 struct ion_handle *ihandle;
1308 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001309 int ret = 0;
1310 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001311 uint32_t len = 0;
1312 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001313 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1314 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1315 struct qseecom_registered_listener_list *this_lstnr = NULL;
1316
1317 if (msg == NULL) {
1318 pr_err("Invalid address\n");
1319 return -EINVAL;
1320 }
1321 if (listener_svc) {
1322 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1323 this_lstnr = __qseecom_find_svc(data->listener.id);
1324 if (IS_ERR_OR_NULL(this_lstnr)) {
1325 pr_err("Invalid listener ID\n");
1326 return -ENOMEM;
1327 }
1328 } else {
1329 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1330 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001331
1332 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001333 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001334 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001335 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001336 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001337 if (IS_ERR_OR_NULL(ihandle)) {
1338 pr_err("Ion client can't retrieve the handle\n");
1339 return -ENOMEM;
1340 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001341 field = (char *) cmd_req->cmd_req_buf +
1342 cmd_req->ifd_data[i].cmd_buf_offset;
1343 } else if ((listener_svc) &&
1344 (lstnr_resp->ifd_data[i].fd > 0)) {
1345 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1346 lstnr_resp->ifd_data[i].fd);
1347 if (IS_ERR_OR_NULL(ihandle)) {
1348 pr_err("Ion client can't retrieve the handle\n");
1349 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001350 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001351 field = lstnr_resp->resp_buf_ptr +
1352 lstnr_resp->ifd_data[i].cmd_buf_offset;
1353 } else {
1354 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001355 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001356 /* Populate the cmd data structure with the phys_addr */
1357 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1358 if (sg_ptr == NULL) {
1359 pr_err("IOn client could not retrieve sg table\n");
1360 goto err;
1361 }
1362 if (sg_ptr->nents == 0) {
1363 pr_err("Num of scattered entries is 0\n");
1364 goto err;
1365 }
1366 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1367 pr_err("Num of scattered entries");
1368 pr_err(" (%d) is greater than max supported %d\n",
1369 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1370 goto err;
1371 }
1372 sg = sg_ptr->sgl;
1373 if (sg_ptr->nents == 1) {
1374 uint32_t *update;
1375 update = (uint32_t *) field;
1376 if (cleanup)
1377 *update = 0;
1378 else
1379 *update = (uint32_t)sg_dma_address(
1380 sg_ptr->sgl);
1381 len += (uint32_t)sg->length;
1382 } else {
1383 struct qseecom_sg_entry *update;
1384 int j = 0;
1385 update = (struct qseecom_sg_entry *) field;
1386 for (j = 0; j < sg_ptr->nents; j++) {
1387 if (cleanup) {
1388 update->phys_addr = 0;
1389 update->len = 0;
1390 } else {
1391 update->phys_addr = (uint32_t)
1392 sg_dma_address(sg);
1393 update->len = sg->length;
1394 }
1395 len += sg->length;
1396 update++;
1397 sg = sg_next(sg);
1398 }
1399 }
1400 if (cleanup)
1401 msm_ion_do_cache_op(qseecom.ion_clnt,
1402 ihandle, NULL, len,
1403 ION_IOC_INV_CACHES);
1404 else
1405 msm_ion_do_cache_op(qseecom.ion_clnt,
1406 ihandle, NULL, len,
1407 ION_IOC_CLEAN_INV_CACHES);
1408 /* Deallocate the handle */
1409 if (!IS_ERR_OR_NULL(ihandle))
1410 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001411 }
1412 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001413err:
1414 if (!IS_ERR_OR_NULL(ihandle))
1415 ion_free(qseecom.ion_clnt, ihandle);
1416 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001417}
1418
1419static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1420 void __user *argp)
1421{
1422 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001423 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001424 struct qseecom_send_modfd_cmd_req req;
1425 struct qseecom_send_cmd_req send_cmd_req;
1426
1427 ret = copy_from_user(&req, argp, sizeof(req));
1428 if (ret) {
1429 pr_err("copy_from_user failed\n");
1430 return ret;
1431 }
Zhen Kongf4948192013-11-25 13:05:35 -08001432
1433 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1434 pr_err("cmd buffer or response buffer is null\n");
1435 return -EINVAL;
1436 }
1437 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1438 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1439 data->client.sb_length))) {
1440 pr_err("cmd buffer address not within shared bufffer\n");
1441 return -EINVAL;
1442 }
1443
1444 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1445 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1446 data->client.sb_length))){
1447 pr_err("response buffer address not within shared bufffer\n");
1448 return -EINVAL;
1449 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001450 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1451 send_cmd_req.cmd_req_len = req.cmd_req_len;
1452 send_cmd_req.resp_buf = req.resp_buf;
1453 send_cmd_req.resp_len = req.resp_len;
1454
Mona Hossaindddf4442013-10-01 14:08:20 -07001455 /* validate offsets */
1456 for (i = 0; i < MAX_ION_FD; i++) {
1457 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1458 pr_err("Invalid offset %d = 0x%x\n",
1459 i, req.ifd_data[i].cmd_buf_offset);
1460 return -EINVAL;
1461 }
1462 }
Zhen Kongf4948192013-11-25 13:05:35 -08001463 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1464 (uint32_t)req.cmd_req_buf);
1465 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1466 (uint32_t)req.resp_buf);
1467
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001468 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001469 if (ret)
1470 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001471 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001472 if (ret)
1473 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001474 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001475 if (ret)
1476 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001477
Mona Hossain2892b6b2012-02-17 13:53:11 -08001478 return ret;
1479}
1480
1481static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1482 struct qseecom_registered_listener_list *svc)
1483{
1484 int ret;
1485 ret = (svc->rcv_req_flag != 0);
1486 return ret || data->abort;
1487}
1488
1489static int qseecom_receive_req(struct qseecom_dev_handle *data)
1490{
1491 int ret = 0;
1492 struct qseecom_registered_listener_list *this_lstnr;
1493
1494 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301495 if (!this_lstnr) {
1496 pr_err("Invalid listener ID\n");
1497 return -ENODATA;
1498 }
1499
Mona Hossain2892b6b2012-02-17 13:53:11 -08001500 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001501 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001502 __qseecom_listener_has_rcvd_req(data,
1503 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001504 pr_warning("Interrupted: exiting Listener Service = %d\n",
1505 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001506 /* woken up for different reason */
1507 return -ERESTARTSYS;
1508 }
1509
1510 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001511 pr_err("Aborting Listener Service = %d\n",
1512 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001513 return -ENODEV;
1514 }
1515 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001516 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001517 }
1518 return ret;
1519}
1520
Mona Hossaind44a3842012-10-15 09:41:35 -07001521static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1522{
1523 struct elf32_hdr *ehdr;
1524
1525 if (fw_entry->size < sizeof(*ehdr)) {
1526 pr_err("%s: Not big enough to be an elf header\n",
1527 qseecom.pdev->init_name);
1528 return false;
1529 }
1530 ehdr = (struct elf32_hdr *)fw_entry->data;
1531 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1532 pr_err("%s: Not an elf header\n",
1533 qseecom.pdev->init_name);
1534 return false;
1535 }
1536
1537 if (ehdr->e_phnum == 0) {
1538 pr_err("%s: No loadable segments\n",
1539 qseecom.pdev->init_name);
1540 return false;
1541 }
1542 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1543 sizeof(struct elf32_hdr) > fw_entry->size) {
1544 pr_err("%s: Program headers not within mdt\n",
1545 qseecom.pdev->init_name);
1546 return false;
1547 }
1548 return true;
1549}
1550
1551static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1552{
1553 int ret = -1;
1554 int i = 0, rc = 0;
1555 const struct firmware *fw_entry = NULL;
1556 struct elf32_phdr *phdr;
1557 char fw_name[MAX_APP_NAME_SIZE];
1558 struct elf32_hdr *ehdr;
1559 int num_images = 0;
1560
1561 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1562 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1563 if (rc) {
1564 pr_err("error with request_firmware\n");
1565 ret = -EIO;
1566 goto err;
1567 }
1568 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1569 ret = -EIO;
1570 goto err;
1571 }
1572 *fw_size = fw_entry->size;
1573 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1574 ehdr = (struct elf32_hdr *)fw_entry->data;
1575 num_images = ehdr->e_phnum;
1576 release_firmware(fw_entry);
1577 for (i = 0; i < num_images; i++, phdr++) {
1578 memset(fw_name, 0, sizeof(fw_name));
1579 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1580 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1581 if (ret)
1582 goto err;
1583 *fw_size += fw_entry->size;
1584 release_firmware(fw_entry);
1585 }
1586 return ret;
1587err:
1588 if (fw_entry)
1589 release_firmware(fw_entry);
1590 *fw_size = 0;
1591 return ret;
1592}
1593
1594static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1595 struct qseecom_load_app_ireq *load_req)
1596{
1597 int ret = -1;
1598 int i = 0, rc = 0;
1599 const struct firmware *fw_entry = NULL;
1600 char fw_name[MAX_APP_NAME_SIZE];
1601 u8 *img_data_ptr = img_data;
1602 struct elf32_hdr *ehdr;
1603 int num_images = 0;
1604
1605 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1606 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1607 if (rc) {
1608 ret = -EIO;
1609 goto err;
1610 }
1611 load_req->img_len = fw_entry->size;
1612 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1613 img_data_ptr = img_data_ptr + fw_entry->size;
1614 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1615 ehdr = (struct elf32_hdr *)fw_entry->data;
1616 num_images = ehdr->e_phnum;
1617 release_firmware(fw_entry);
1618 for (i = 0; i < num_images; i++) {
1619 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1620 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1621 if (ret) {
1622 pr_err("Failed to locate blob %s\n", fw_name);
1623 goto err;
1624 }
1625 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1626 img_data_ptr = img_data_ptr + fw_entry->size;
1627 load_req->img_len += fw_entry->size;
1628 release_firmware(fw_entry);
1629 }
1630 load_req->phy_addr = virt_to_phys(img_data);
1631 return ret;
1632err:
1633 release_firmware(fw_entry);
1634 return ret;
1635}
1636
1637static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1638{
1639 int ret = -1;
1640 uint32_t fw_size = 0;
1641 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1642 struct qseecom_command_scm_resp resp;
1643 u8 *img_data = NULL;
1644
1645 if (__qseecom_get_fw_size(appname, &fw_size))
1646 return -EIO;
1647
1648 img_data = kzalloc(fw_size, GFP_KERNEL);
1649 if (!img_data) {
1650 pr_err("Failied to allocate memory for copying image data\n");
1651 return -ENOMEM;
1652 }
1653 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1654 if (ret) {
1655 kzfree(img_data);
1656 return -EIO;
1657 }
1658
1659 /* Populate the remaining parameters */
1660 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1661 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001662 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001663 if (ret) {
1664 kzfree(img_data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001665 return -EIO;
1666 }
1667
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001668 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001669 /* SCM_CALL to load the image */
1670 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1671 sizeof(struct qseecom_load_app_ireq),
1672 &resp, sizeof(resp));
1673 kzfree(img_data);
1674 if (ret) {
1675 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001676 __qseecom_disable_clk_scale_down(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001677 return -EIO;
1678 }
1679
1680 switch (resp.result) {
1681 case QSEOS_RESULT_SUCCESS:
1682 ret = resp.data;
1683 break;
1684 case QSEOS_RESULT_INCOMPLETE:
1685 ret = __qseecom_process_incomplete_cmd(data, &resp);
1686 if (ret)
1687 pr_err("process_incomplete_cmd FAILED\n");
1688 else
1689 ret = resp.data;
1690 break;
1691 case QSEOS_RESULT_FAILURE:
1692 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1693 break;
1694 default:
1695 pr_err("scm call return unknown response %d\n", resp.result);
1696 ret = -EINVAL;
1697 break;
1698 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001699 __qseecom_disable_clk_scale_down(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001700
Mona Hossaind44a3842012-10-15 09:41:35 -07001701 return ret;
1702}
1703
Mona Hossain9498f5e2013-01-23 18:08:45 -08001704static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001705{
1706 int32_t ret = 0;
1707 uint32_t fw_size = 0;
1708 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1709 struct qseecom_command_scm_resp resp;
1710 u8 *img_data = NULL;
1711
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001712 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001713 return -EIO;
1714
1715 img_data = kzalloc(fw_size, GFP_KERNEL);
1716 if (!img_data) {
1717 pr_err("Mem allocation for lib image data failed\n");
1718 return -ENOMEM;
1719 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001720 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001721 if (ret) {
1722 kzfree(img_data);
1723 return -EIO;
1724 }
1725 /* Populate the remaining parameters */
1726 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001727 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001728 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001729 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08001730 kzfree(img_data);
1731 return -EIO;
1732 }
1733
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001734 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001735 /* SCM_CALL to load the image */
1736 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1737 sizeof(struct qseecom_load_lib_image_ireq),
1738 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001739 if (ret) {
1740 pr_err("scm_call to load failed : ret %d\n", ret);
1741 ret = -EIO;
1742 } else {
1743 switch (resp.result) {
1744 case QSEOS_RESULT_SUCCESS:
1745 break;
1746 case QSEOS_RESULT_FAILURE:
1747 pr_err("scm call failed w/response result%d\n",
1748 resp.result);
1749 ret = -EINVAL;
1750 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001751 case QSEOS_RESULT_INCOMPLETE:
1752 ret = __qseecom_process_incomplete_cmd(data, &resp);
1753 if (ret)
1754 pr_err("process_incomplete_cmd failed err: %d\n",
1755 ret);
1756 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001757 default:
1758 pr_err("scm call return unknown response %d\n",
1759 resp.result);
1760 ret = -EINVAL;
1761 break;
1762 }
1763 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001764 kzfree(img_data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001765 __qseecom_disable_clk_scale_down(data);
Mona Hossain05c73562012-10-29 17:49:01 -07001766 return ret;
1767}
1768
1769static int qseecom_unload_commonlib_image(void)
1770{
1771 int ret = -EINVAL;
1772 struct qseecom_unload_lib_image_ireq unload_req = {0};
1773 struct qseecom_command_scm_resp resp;
1774
1775 /* Populate the remaining parameters */
1776 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1777 /* SCM_CALL to load the image */
1778 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1779 sizeof(struct qseecom_unload_lib_image_ireq),
1780 &resp, sizeof(resp));
1781 if (ret) {
1782 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1783 ret = -EIO;
1784 } else {
1785 switch (resp.result) {
1786 case QSEOS_RESULT_SUCCESS:
1787 break;
1788 case QSEOS_RESULT_FAILURE:
1789 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1790 break;
1791 default:
1792 pr_err("scm call return unknown response %d\n",
1793 resp.result);
1794 ret = -EINVAL;
1795 break;
1796 }
1797 }
1798 return ret;
1799}
1800
Mona Hossaind44a3842012-10-15 09:41:35 -07001801int qseecom_start_app(struct qseecom_handle **handle,
1802 char *app_name, uint32_t size)
1803{
Mona Hossain05c73562012-10-29 17:49:01 -07001804 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001805 unsigned long flags = 0;
1806 struct qseecom_dev_handle *data = NULL;
1807 struct qseecom_check_app_ireq app_ireq;
1808 struct qseecom_registered_app_list *entry = NULL;
1809 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1810 bool found_app = false;
1811 uint32_t len;
1812 ion_phys_addr_t pa;
1813
Mona Hossain823f9882012-11-23 14:42:20 -08001814 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1815 if (!(*handle)) {
1816 pr_err("failed to allocate memory for kernel client handle\n");
1817 return -ENOMEM;
1818 }
1819
Mona Hossaind44a3842012-10-15 09:41:35 -07001820 data = kzalloc(sizeof(*data), GFP_KERNEL);
1821 if (!data) {
1822 pr_err("kmalloc failed\n");
1823 if (ret == 0) {
1824 kfree(*handle);
1825 *handle = NULL;
1826 }
1827 return -ENOMEM;
1828 }
1829 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001830 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001831 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001832 data->client.sb_length = size;
1833 data->client.user_virt_sb_base = 0;
1834 data->client.ihandle = NULL;
1835
1836 init_waitqueue_head(&data->abort_wq);
1837 atomic_set(&data->ioctl_count, 0);
1838
1839 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1840 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1841 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1842 pr_err("Ion client could not retrieve the handle\n");
1843 kfree(data);
1844 kfree(*handle);
1845 *handle = NULL;
1846 return -EINVAL;
1847 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001848 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001849 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001850 if (qseecom.commonlib_loaded == false) {
1851 ret = qseecom_load_commonlib_image(data);
1852 if (ret == 0)
1853 qseecom.commonlib_loaded = true;
1854 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001855 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001856 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001857 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001858 ret = -EIO;
1859 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001860 }
1861
1862 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1863 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1864 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001865 if (ret < 0)
1866 goto err;
1867
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001868 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001869 if (ret > 0) {
1870 pr_warn("App id %d for [%s] app exists\n", ret,
1871 (char *)app_ireq.app_name);
1872 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1873 list_for_each_entry(entry,
1874 &qseecom.registered_app_list_head, list){
1875 if (entry->app_id == ret) {
1876 entry->ref_cnt++;
1877 found_app = true;
1878 break;
1879 }
1880 }
1881 spin_unlock_irqrestore(
1882 &qseecom.registered_app_list_lock, flags);
1883 if (!found_app)
1884 pr_warn("App_id %d [%s] was loaded but not registered\n",
1885 ret, (char *)app_ireq.app_name);
1886 } else {
1887 /* load the app and get the app_id */
1888 pr_debug("%s: Loading app for the first time'\n",
1889 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001890 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001891 if (ret < 0)
1892 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001893 data->client.app_id = ret;
1894 }
1895 if (!found_app) {
1896 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1897 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001898 pr_err("kmalloc for app entry failed\n");
1899 ret = -ENOMEM;
1900 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001901 }
1902 entry->app_id = ret;
1903 entry->ref_cnt = 1;
1904
1905 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1906 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1907 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1908 flags);
1909 }
1910
1911 /* Get the physical address of the ION BUF */
1912 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1913 /* Populate the structure for sending scm call to load image */
1914 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1915 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001916 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001917 data->client.sb_phys = pa;
1918 (*handle)->dev = (void *)data;
1919 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1920 (*handle)->sbuf_len = data->client.sb_length;
1921
1922 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1923 if (!kclient_entry) {
1924 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001925 ret = -ENOMEM;
1926 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001927 }
1928 kclient_entry->handle = *handle;
1929
1930 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1931 list_add_tail(&kclient_entry->list,
1932 &qseecom.registered_kclient_list_head);
1933 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1934
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001935 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001936 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001937
1938err:
1939 kfree(data);
1940 kfree(*handle);
1941 *handle = NULL;
1942 mutex_unlock(&app_access_lock);
1943 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001944}
1945EXPORT_SYMBOL(qseecom_start_app);
1946
1947int qseecom_shutdown_app(struct qseecom_handle **handle)
1948{
1949 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001950 struct qseecom_dev_handle *data;
1951
Mona Hossaind44a3842012-10-15 09:41:35 -07001952 struct qseecom_registered_kclient_list *kclient = NULL;
1953 unsigned long flags = 0;
1954 bool found_handle = false;
1955
Mona Hossain33824022013-02-25 09:32:33 -08001956 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001957 pr_err("Handle is not initialized\n");
1958 return -EINVAL;
1959 }
Mona Hossain33824022013-02-25 09:32:33 -08001960 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001961 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1962 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1963 list) {
1964 if (kclient->handle == (*handle)) {
1965 list_del(&kclient->list);
1966 found_handle = true;
1967 break;
1968 }
1969 }
1970 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1971 if (!found_handle)
1972 pr_err("Unable to find the handle, exiting\n");
1973 else
1974 ret = qseecom_unload_app(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001975
1976 if (qseecom.support_bus_scaling) {
1977 mutex_lock(&qsee_bw_mutex);
1978 if (data->mode != INACTIVE) {
1979 qseecom_unregister_bus_bandwidth_needs(data);
1980 if (qseecom.cumulative_mode == INACTIVE) {
1981 ret = __qseecom_set_msm_bus_request(INACTIVE);
1982 if (ret)
1983 pr_err("Fail to scale down bus\n");
1984 }
1985 }
1986 mutex_unlock(&qsee_bw_mutex);
1987 } else {
1988 if (data->fast_load_enabled == true)
1989 qsee_disable_clock_vote(data, CLK_SFPB);
1990 if (data->perf_enabled == true)
1991 qsee_disable_clock_vote(data, CLK_DFAB);
1992 }
Mona Hossaind44a3842012-10-15 09:41:35 -07001993 if (ret == 0) {
1994 kzfree(data);
1995 kzfree(*handle);
1996 kzfree(kclient);
1997 *handle = NULL;
1998 }
1999 return ret;
2000}
2001EXPORT_SYMBOL(qseecom_shutdown_app);
2002
2003int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2004 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2005{
2006 int ret = 0;
2007 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2008 struct qseecom_dev_handle *data;
2009
Mona Hossaind44a3842012-10-15 09:41:35 -07002010 if (handle == NULL) {
2011 pr_err("Handle is not initialized\n");
2012 return -EINVAL;
2013 }
2014 data = handle->dev;
2015
2016 req.cmd_req_len = sbuf_len;
2017 req.resp_len = rbuf_len;
2018 req.cmd_req_buf = send_buf;
2019 req.resp_buf = resp_buf;
2020
2021 mutex_lock(&app_access_lock);
2022 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002023 if (qseecom.support_bus_scaling)
2024 qseecom_scale_bus_bandwidth_timer(INACTIVE,
2025 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002026 ret = __qseecom_send_cmd(data, &req);
2027
2028 atomic_dec(&data->ioctl_count);
2029 mutex_unlock(&app_access_lock);
2030
2031 if (ret)
2032 return ret;
2033
2034 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2035 req.resp_len, req.resp_buf);
2036 return ret;
2037}
2038EXPORT_SYMBOL(qseecom_send_command);
2039
Mona Hossain91a8fc92012-11-07 19:58:30 -08002040int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2041{
Mona Hossainfca6f422013-01-12 13:00:35 -08002042 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002043 if ((handle == NULL) || (handle->dev == NULL)) {
2044 pr_err("No valid kernel client\n");
2045 return -EINVAL;
2046 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002047 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002048 if (qseecom.support_bus_scaling) {
2049 mutex_lock(&qsee_bw_mutex);
2050 __qseecom_register_bus_bandwidth_needs(handle->dev,
2051 HIGH);
2052 mutex_unlock(&qsee_bw_mutex);
2053 if (ret)
2054 pr_err("Failed to scale bus (med) %d\n", ret);
2055 } else {
2056 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2057 if (ret)
2058 pr_err("Failed to vote for DFAB clock%d\n",
2059 ret);
2060 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2061 if (ret) {
2062 pr_err("Failed to vote for SFPB clock%d\n",
2063 ret);
2064 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2065 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002066 }
2067 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002068 if (!qseecom.support_bus_scaling) {
2069 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2070 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
2071 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002072 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002073 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002074}
2075EXPORT_SYMBOL(qseecom_set_bandwidth);
2076
Mona Hossain2892b6b2012-02-17 13:53:11 -08002077static int qseecom_send_resp(void)
2078{
2079 qseecom.send_resp_flag = 1;
2080 wake_up_interruptible(&qseecom.send_resp_wq);
2081 return 0;
2082}
2083
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002084
2085static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2086 void __user *argp)
2087{
2088 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002089 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002090 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002091
2092 if (copy_from_user(&resp, argp, sizeof(resp))) {
2093 pr_err("copy_from_user failed");
2094 return -EINVAL;
2095 }
Zhen Kongf4948192013-11-25 13:05:35 -08002096 this_lstnr = __qseecom_find_svc(data->listener.id);
2097 if (this_lstnr == NULL)
2098 return -EINVAL;
2099
2100 if (resp.resp_buf_ptr == NULL) {
2101 pr_err("Invalid resp_buf_ptr\n");
2102 return -EINVAL;
2103 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002104 /* validate offsets */
2105 for (i = 0; i < MAX_ION_FD; i++) {
2106 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2107 pr_err("Invalid offset %d = 0x%x\n",
2108 i, resp.ifd_data[i].cmd_buf_offset);
2109 return -EINVAL;
2110 }
2111 }
Zhen Kongf4948192013-11-25 13:05:35 -08002112
2113 if (((uint32_t)resp.resp_buf_ptr <
2114 this_lstnr->user_virt_sb_base)
2115 || ((uint32_t)resp.resp_buf_ptr >=
2116 (this_lstnr->user_virt_sb_base +
2117 this_lstnr->sb_length))) {
2118 pr_err("resp_buf_ptr address not within shared buffer\n");
2119 return -EINVAL;
2120 }
2121 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2122 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002123 __qseecom_update_cmd_buf(&resp, false, data, true);
2124 qseecom.send_resp_flag = 1;
2125 wake_up_interruptible(&qseecom.send_resp_wq);
2126 return 0;
2127}
2128
2129
Mona Hossain2892b6b2012-02-17 13:53:11 -08002130static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2131 void __user *argp)
2132{
2133 struct qseecom_qseos_version_req req;
2134
2135 if (copy_from_user(&req, argp, sizeof(req))) {
2136 pr_err("copy_from_user failed");
2137 return -EINVAL;
2138 }
2139 req.qseos_version = qseecom.qseos_version;
2140 if (copy_to_user(argp, &req, sizeof(req))) {
2141 pr_err("copy_to_user failed");
2142 return -EINVAL;
2143 }
2144 return 0;
2145}
2146
Mona Hossainc92629e2013-04-01 13:37:46 -07002147static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002148{
2149 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002150 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002151
Mona Hossainc92629e2013-04-01 13:37:46 -07002152 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002153 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002154 else
2155 qclk = &qseecom.ce_drv;
2156
2157 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002158
2159 if (qclk->clk_access_cnt == ULONG_MAX)
2160 goto err;
2161
Mona Hossainc92629e2013-04-01 13:37:46 -07002162 if (qclk->clk_access_cnt > 0) {
2163 qclk->clk_access_cnt++;
2164 mutex_unlock(&clk_access_lock);
2165 return rc;
2166 }
2167
Mona Hossain6311d572013-03-01 15:54:02 -08002168 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002169 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002170 if (rc) {
2171 pr_err("Unable to enable/prepare CE core clk\n");
2172 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002173 }
2174 /* Enable CE clk */
2175 rc = clk_prepare_enable(qclk->ce_clk);
2176 if (rc) {
2177 pr_err("Unable to enable/prepare CE iface clk\n");
2178 goto ce_clk_err;
2179 }
2180 /* Enable AXI clk */
2181 rc = clk_prepare_enable(qclk->ce_bus_clk);
2182 if (rc) {
2183 pr_err("Unable to enable/prepare CE bus clk\n");
2184 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002185 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002186 qclk->clk_access_cnt++;
2187 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002188 return 0;
2189
2190ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002191 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002192ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002193 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002194err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002195 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002196 return -EIO;
2197}
2198
Mona Hossainc92629e2013-04-01 13:37:46 -07002199static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002200{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002201 struct qseecom_clk *qclk;
2202
Mona Hossainc92629e2013-04-01 13:37:46 -07002203 if (ce == CLK_QSEE)
2204 qclk = &qseecom.qsee;
2205 else
2206 qclk = &qseecom.ce_drv;
2207
2208 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002209
2210 if (qclk->clk_access_cnt == 0) {
2211 mutex_unlock(&clk_access_lock);
2212 return;
2213 }
2214
Mona Hossainc92629e2013-04-01 13:37:46 -07002215 if (qclk->clk_access_cnt == 1) {
2216 if (qclk->ce_clk != NULL)
2217 clk_disable_unprepare(qclk->ce_clk);
2218 if (qclk->ce_core_clk != NULL)
2219 clk_disable_unprepare(qclk->ce_core_clk);
2220 if (qclk->ce_bus_clk != NULL)
2221 clk_disable_unprepare(qclk->ce_bus_clk);
2222 }
2223 qclk->clk_access_cnt--;
2224 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002225}
2226
Mona Hossain04d3fac2012-12-03 10:10:37 -08002227static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2228 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002229{
2230 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002231 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002232
Mona Hossain17a4faf2013-03-22 16:40:56 -07002233 qclk = &qseecom.qsee;
2234 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002235 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002236
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002237 switch (clk_type) {
2238 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002239 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002240 if (!qseecom.qsee_bw_count) {
2241 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002242 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002243 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002244 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002245 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002246 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002247 if (!ret) {
2248 ret =
2249 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002250 qseecom.qsee_perf_client, 1);
2251 if ((ret) &&
2252 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002253 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002254 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002255 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002256 if (ret)
2257 pr_err("DFAB Bandwidth req failed (%d)\n",
2258 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002259 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002260 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002261 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002262 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002263 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002264 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002265 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002266 }
2267 mutex_unlock(&qsee_bw_mutex);
2268 break;
2269 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002270 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002271 if (!qseecom.qsee_sfpb_bw_count) {
2272 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002273 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002274 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002275 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002276 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002277 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002278 if (!ret) {
2279 ret =
2280 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002281 qseecom.qsee_perf_client, 2);
2282 if ((ret) &&
2283 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002284 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002285 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002286 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002287
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002288 if (ret)
2289 pr_err("SFPB Bandwidth req failed (%d)\n",
2290 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002291 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002292 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002293 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002294 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002295 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002296 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002297 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002298 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002299 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002300 break;
2301 default:
2302 pr_err("Clock type not defined\n");
2303 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002304 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002305 return ret;
2306}
2307
Mona Hossain04d3fac2012-12-03 10:10:37 -08002308static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2309 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002310{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002311 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002312 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002313
Mona Hossain17a4faf2013-03-22 16:40:56 -07002314 qclk = &qseecom.qsee;
2315 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002316 return;
2317
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002318 switch (clk_type) {
2319 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002320 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002321 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002322 pr_err("Client error.Extra call to disable DFAB clk\n");
2323 mutex_unlock(&qsee_bw_mutex);
2324 return;
2325 }
2326
Mona Hossain17a4faf2013-03-22 16:40:56 -07002327 if (qseecom.qsee_bw_count == 1) {
2328 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002329 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002330 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002331 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002332 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002333 qseecom.qsee_perf_client, 0);
2334 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002335 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002336 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002337 if (ret)
2338 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002339 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002340 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002341 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002342 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002343 }
2344 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002345 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002346 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002347 }
2348 mutex_unlock(&qsee_bw_mutex);
2349 break;
2350 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002351 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002352 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002353 pr_err("Client error.Extra call to disable SFPB clk\n");
2354 mutex_unlock(&qsee_bw_mutex);
2355 return;
2356 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002357 if (qseecom.qsee_sfpb_bw_count == 1) {
2358 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002359 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002360 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002361 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002362 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002363 qseecom.qsee_perf_client, 0);
2364 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002365 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002366 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002367 if (ret)
2368 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002369 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002370 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002371 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002372 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002373 }
2374 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002375 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002376 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002377 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002378 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002379 break;
2380 default:
2381 pr_err("Clock type not defined\n");
2382 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002383 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002384
Mona Hossain2892b6b2012-02-17 13:53:11 -08002385}
2386
Mona Hossain5ab9d772012-04-11 21:00:40 -07002387static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2388 void __user *argp)
2389{
2390 struct ion_handle *ihandle; /* Ion handle */
2391 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002392 int ret;
2393 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002394 ion_phys_addr_t pa = 0;
2395 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002396 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002397 struct qseecom_load_app_ireq load_req;
2398 struct qseecom_command_scm_resp resp;
2399
2400 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002401 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002402 (void __user *)argp,
2403 sizeof(struct qseecom_load_img_req))) {
2404 pr_err("copy_from_user failed\n");
2405 return -EFAULT;
2406 }
2407
2408 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002409 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002410 load_img_req.ifd_data_fd);
2411 if (IS_ERR_OR_NULL(ihandle)) {
2412 pr_err("Ion client could not retrieve the handle\n");
2413 return -ENOMEM;
2414 }
2415
2416 /* Get the physical address of the ION BUF */
2417 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2418
2419 /* Populate the structure for sending scm call to load image */
2420 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2421 load_req.mdt_len = load_img_req.mdt_len;
2422 load_req.img_len = load_img_req.img_len;
2423 load_req.phy_addr = pa;
2424
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002425 /* SCM_CALL tied to Core0 */
2426 mask = CPU_MASK_CPU0;
2427 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2428 if (set_cpu_ret) {
2429 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2430 set_cpu_ret);
2431 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302432 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002433 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302434
Mona Hossain6311d572013-03-01 15:54:02 -08002435 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002436 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002437 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002438 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302439 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002440 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002441 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2442 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002443 /* SCM_CALL to load the external elf */
2444 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2445 sizeof(struct qseecom_load_app_ireq),
2446 &resp, sizeof(resp));
2447 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002448 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002449 ret);
2450 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302451 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002452 }
2453
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302454 switch (resp.result) {
2455 case QSEOS_RESULT_SUCCESS:
2456 break;
2457 case QSEOS_RESULT_INCOMPLETE:
2458 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002459 ret = __qseecom_process_incomplete_cmd(data, &resp);
2460 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302461 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2462 break;
2463 case QSEOS_RESULT_FAILURE:
2464 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2465 ret = -EFAULT;
2466 break;
2467 default:
2468 pr_err("scm_call response result %d not supported\n",
2469 resp.result);
2470 ret = -EFAULT;
2471 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002472 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002473
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302474exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002475 __qseecom_disable_clk_scale_down(data);
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302476exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002477 /* Restore the CPU mask */
2478 mask = CPU_MASK_ALL;
2479 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2480 if (set_cpu_ret) {
2481 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2482 set_cpu_ret);
2483 ret = -EFAULT;
2484 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302485exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002486 /* Deallocate the handle */
2487 if (!IS_ERR_OR_NULL(ihandle))
2488 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002489 return ret;
2490}
2491
2492static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2493{
2494 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002495 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002496 struct qseecom_command_scm_resp resp;
2497 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002498 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002499
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302500 /* unavailable client app */
2501 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2502
Mona Hossain5ab9d772012-04-11 21:00:40 -07002503 /* Populate the structure for sending scm call to unload image */
2504 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002505
2506 /* SCM_CALL tied to Core0 */
2507 mask = CPU_MASK_CPU0;
2508 ret = set_cpus_allowed_ptr(current, &mask);
2509 if (ret) {
2510 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2511 ret);
2512 return -EFAULT;
2513 }
2514
Mona Hossain5ab9d772012-04-11 21:00:40 -07002515 /* SCM_CALL to unload the external elf */
2516 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2517 sizeof(struct qseecom_unload_app_ireq),
2518 &resp, sizeof(resp));
2519 if (ret) {
2520 pr_err("scm_call to unload failed : ret %d\n",
2521 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002522 ret = -EFAULT;
2523 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002524 }
2525 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2526 ret = __qseecom_process_incomplete_cmd(data, &resp);
2527 if (ret)
2528 pr_err("process_incomplete_cmd fail err: %d\n",
2529 ret);
2530 } else {
2531 if (resp.result != QSEOS_RESULT_SUCCESS) {
2532 pr_err("scm_call to unload image failed resp.result =%d\n",
2533 resp.result);
2534 ret = -EFAULT;
2535 }
2536 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002537
2538qseecom_unload_external_elf_scm_err:
2539 /* Restore the CPU mask */
2540 mask = CPU_MASK_ALL;
2541 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2542 if (set_cpu_ret) {
2543 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2544 set_cpu_ret);
2545 ret = -EFAULT;
2546 }
2547
Mona Hossain5ab9d772012-04-11 21:00:40 -07002548 return ret;
2549}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002550
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002551static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2552 void __user *argp)
2553{
2554
2555 int32_t ret;
2556 struct qseecom_qseos_app_load_query query_req;
2557 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002558 struct qseecom_registered_app_list *entry = NULL;
2559 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002560
2561 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002562 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002563 (void __user *)argp,
2564 sizeof(struct qseecom_qseos_app_load_query))) {
2565 pr_err("copy_from_user failed\n");
2566 return -EFAULT;
2567 }
2568
2569 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002570 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002571 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2572
2573 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002574
2575 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002576 pr_err(" scm call to check if app is loaded failed");
2577 return ret; /* scm call failed */
2578 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002579 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002580 (char *)(req.app_name));
2581 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2582 list_for_each_entry(entry,
2583 &qseecom.registered_app_list_head, list){
2584 if (entry->app_id == ret) {
2585 entry->ref_cnt++;
2586 break;
2587 }
2588 }
2589 spin_unlock_irqrestore(
2590 &qseecom.registered_app_list_lock, flags);
2591 data->client.app_id = ret;
2592 query_req.app_id = ret;
2593
2594 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2595 pr_err("copy_to_user failed\n");
2596 return -EFAULT;
2597 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002598 return -EEXIST; /* app already loaded */
2599 } else {
2600 return 0; /* app not loaded */
2601 }
2602}
2603
Mona Hossain4cf78a92013-02-14 12:06:41 -08002604static int __qseecom_get_ce_pipe_info(
2605 enum qseecom_key_management_usage_type usage,
2606 uint32_t *pipe, uint32_t *ce_hw)
2607{
2608 int ret;
2609 switch (usage) {
2610 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2611 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2612 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2613 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2614 qseecom.ce_info.disk_encrypt_pipe,
2615 qseecom.ce_info.hlos_ce_hw_instance);
2616 ret = -EINVAL;
2617 } else {
2618 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2619 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2620 ret = 0;
2621 }
2622 break;
2623 default:
2624 ret = -EINVAL;
2625 break;
2626 }
2627 return ret;
2628}
2629
2630static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2631 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002632 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002633{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002634 struct qseecom_command_scm_resp resp;
2635 int ret;
2636
Zhen Kong9730ddf2013-12-17 16:49:43 -08002637 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2638 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002639 pr_err("Error:: unsupported usage %d\n", usage);
2640 return -EFAULT;
2641 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002642 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002643
2644 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002645 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002646 &resp, sizeof(resp));
2647 if (ret) {
2648 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002649 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002650 return ret;
2651 }
2652
2653 switch (resp.result) {
2654 case QSEOS_RESULT_SUCCESS:
2655 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002656 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002657 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002658 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002659 case QSEOS_RESULT_INCOMPLETE:
2660 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002661 if (ret) {
2662 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002663 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002664 ret = 0;
2665 } else {
2666 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2667 resp.result);
2668 }
2669 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002670 break;
2671 case QSEOS_RESULT_FAILURE:
2672 default:
2673 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2674 ret = -EINVAL;
2675 break;
2676 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002677 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002678 return ret;
2679}
2680
2681static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2682 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002683 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002684{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002685 struct qseecom_command_scm_resp resp;
2686 int ret;
2687
2688 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2689 pr_err("Error:: unsupported usage %d\n", usage);
2690 return -EFAULT;
2691 }
2692
Mona Hossainc92629e2013-04-01 13:37:46 -07002693 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002694
2695 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002696 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002697 &resp, sizeof(struct qseecom_command_scm_resp));
2698 if (ret) {
2699 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002700 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002701 return ret;
2702 }
2703
2704 switch (resp.result) {
2705 case QSEOS_RESULT_SUCCESS:
2706 break;
2707 case QSEOS_RESULT_INCOMPLETE:
2708 ret = __qseecom_process_incomplete_cmd(data, &resp);
2709 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002710 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2711 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002712 break;
2713 case QSEOS_RESULT_FAILURE:
2714 default:
2715 pr_err("Delete key scm call failed resp.result %d\n",
2716 resp.result);
2717 ret = -EINVAL;
2718 break;
2719 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002720 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002721 return ret;
2722}
2723
2724static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2725 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002726 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002727{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002728 struct qseecom_command_scm_resp resp;
2729 int ret;
2730
Zhen Kong9730ddf2013-12-17 16:49:43 -08002731 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2732 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002733 pr_err("Error:: unsupported usage %d\n", usage);
2734 return -EFAULT;
2735 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002736
Zhen Kongdb2bf742013-05-13 23:55:42 -07002737 __qseecom_enable_clk(CLK_QSEE);
2738 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002739 __qseecom_enable_clk(CLK_CE_DRV);
2740
Zhen Kong336636e2013-04-15 11:04:54 -07002741 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002742 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002743 &resp, sizeof(struct qseecom_command_scm_resp));
2744 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002745 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002746 __qseecom_disable_clk(CLK_QSEE);
2747 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2748 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kong336636e2013-04-15 11:04:54 -07002749 return ret;
2750 }
2751
Mona Hossain4cf78a92013-02-14 12:06:41 -08002752 switch (resp.result) {
2753 case QSEOS_RESULT_SUCCESS:
2754 break;
2755 case QSEOS_RESULT_INCOMPLETE:
2756 ret = __qseecom_process_incomplete_cmd(data, &resp);
2757 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002758 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2759 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002760 break;
2761 case QSEOS_RESULT_FAILURE:
2762 default:
2763 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2764 ret = -EINVAL;
2765 break;
2766 }
2767
Zhen Kongdb2bf742013-05-13 23:55:42 -07002768 __qseecom_disable_clk(CLK_QSEE);
2769 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002770 __qseecom_disable_clk(CLK_CE_DRV);
2771
Mona Hossain4cf78a92013-02-14 12:06:41 -08002772 return ret;
2773}
2774
Zhen Kong9730ddf2013-12-17 16:49:43 -08002775static int __qseecom_update_current_key_user_info(
2776 struct qseecom_dev_handle *data,
2777 enum qseecom_key_management_usage_type usage,
2778 struct qseecom_key_userinfo_update_ireq *ireq)
2779{
2780 struct qseecom_command_scm_resp resp;
2781 int ret;
2782
2783 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2784 usage >= QSEOS_KM_USAGE_MAX) {
2785 pr_err("Error:: unsupported usage %d\n", usage);
2786 return -EFAULT;
2787 }
2788
2789 __qseecom_enable_clk(CLK_QSEE);
2790
2791 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
2792 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
2793 &resp, sizeof(struct qseecom_command_scm_resp));
2794 if (ret) {
2795 pr_err("scm call to update key userinfo failed : %d\n", ret);
2796 __qseecom_disable_clk(CLK_QSEE);
2797 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2798 __qseecom_disable_clk(CLK_CE_DRV);
2799 return ret;
2800 }
2801
2802 switch (resp.result) {
2803 case QSEOS_RESULT_SUCCESS:
2804 break;
2805 case QSEOS_RESULT_INCOMPLETE:
2806 ret = __qseecom_process_incomplete_cmd(data, &resp);
2807 if (ret)
2808 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2809 resp.result);
2810 break;
2811 case QSEOS_RESULT_FAILURE:
2812 default:
2813 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2814 ret = -EINVAL;
2815 break;
2816 }
2817
2818 __qseecom_disable_clk(CLK_QSEE);
2819 return ret;
2820}
2821
Mona Hossain4cf78a92013-02-14 12:06:41 -08002822static int qseecom_create_key(struct qseecom_dev_handle *data,
2823 void __user *argp)
2824{
2825 uint32_t ce_hw = 0;
2826 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002827 int ret = 0;
2828 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002829 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002830 struct qseecom_key_generate_ireq generate_key_ireq;
2831 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002832
2833 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2834 if (ret) {
2835 pr_err("copy_from_user failed\n");
2836 return ret;
2837 }
2838
Zhen Kong9730ddf2013-12-17 16:49:43 -08002839 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2840 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002841 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2842 return -EFAULT;
2843 }
2844
2845 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2846 if (ret) {
2847 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2848 return -EINVAL;
2849 }
2850
Zhen Kong9730ddf2013-12-17 16:49:43 -08002851 generate_key_ireq.flags = flags;
2852 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
2853 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2854 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2855 memcpy((void *)generate_key_ireq.key_id,
2856 (void *)key_id_array[create_key_req.usage - 1],
2857 QSEECOM_KEY_ID_SIZE);
2858 memcpy((void *)generate_key_ireq.hash32,
2859 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
2860
Mona Hossain4cf78a92013-02-14 12:06:41 -08002861 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002862 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002863 if (ret) {
2864 pr_err("Failed to generate key on storage: %d\n", ret);
2865 return -EFAULT;
2866 }
2867
Zhen Kong9730ddf2013-12-17 16:49:43 -08002868 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2869 set_key_ireq.ce = ce_hw;
2870 set_key_ireq.pipe = pipe;
2871 set_key_ireq.flags = flags;
2872
2873 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2874 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
2875 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2876 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2877 memcpy((void *)set_key_ireq.key_id,
2878 (void *)key_id_array[create_key_req.usage - 1],
2879 QSEECOM_KEY_ID_SIZE);
2880 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002881 QSEECOM_HASH_SIZE);
2882
2883 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002884 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002885 if (ret) {
2886 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2887 pipe, ce_hw, ret);
2888 return -EFAULT;
2889 }
2890
2891 return ret;
2892}
2893
2894static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2895 void __user *argp)
2896{
2897 uint32_t ce_hw = 0;
2898 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002899 int ret = 0;
2900 uint32_t flags = 0;
2901 int i;
2902 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002903 struct qseecom_key_delete_ireq delete_key_ireq;
2904 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002905
2906 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2907 if (ret) {
2908 pr_err("copy_from_user failed\n");
2909 return ret;
2910 }
2911
Zhen Kong9730ddf2013-12-17 16:49:43 -08002912 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2913 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002914 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2915 return -EFAULT;
2916 }
2917
2918 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2919 if (ret) {
2920 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2921 return -EINVAL;
2922 }
2923
Zhen Kong9730ddf2013-12-17 16:49:43 -08002924 delete_key_ireq.flags = flags;
2925 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
2926 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2927 memcpy((void *)delete_key_ireq.key_id,
2928 (void *)key_id_array[wipe_key_req.usage - 1],
2929 QSEECOM_KEY_ID_SIZE);
2930 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2931
2932 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
2933 &delete_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002934 if (ret) {
2935 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2936 return -EFAULT;
2937 }
2938
Zhen Kong9730ddf2013-12-17 16:49:43 -08002939 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2940 clear_key_ireq.ce = ce_hw;
2941 clear_key_ireq.pipe = pipe;
2942 clear_key_ireq.flags = flags;
2943 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002944 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kong9730ddf2013-12-17 16:49:43 -08002945 clear_key_ireq.key_id[i] = 0xff;
2946 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2947
Mona Hossain4cf78a92013-02-14 12:06:41 -08002948 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002949 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002950 if (ret) {
2951 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2952 pipe, ce_hw, ret);
2953 return -EFAULT;
2954 }
2955
2956 return ret;
2957}
2958
Zhen Kong9730ddf2013-12-17 16:49:43 -08002959static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
2960 void __user *argp)
2961{
2962 int ret = 0;
2963 uint32_t flags = 0;
2964 struct qseecom_update_key_userinfo_req update_key_req;
2965 struct qseecom_key_userinfo_update_ireq ireq;
2966
2967 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
2968 if (ret) {
2969 pr_err("copy_from_user failed\n");
2970 return ret;
2971 }
2972
2973 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2974 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
2975 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
2976 return -EFAULT;
2977 }
2978
2979 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
2980 ireq.flags = flags;
2981 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2982 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
2983 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
2984 memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
2985 QSEECOM_KEY_ID_SIZE);
2986 memcpy((void *)ireq.current_hash32,
2987 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
2988 memcpy((void *)ireq.new_hash32,
2989 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
2990
2991 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
2992 &ireq);
2993 if (ret) {
2994 pr_err("Failed to update key info: %d\n", ret);
2995 return -EFAULT;
2996 }
2997 return ret;
2998
2999}
3000
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003001static int qseecom_is_es_activated(void __user *argp)
3002{
3003 struct qseecom_is_es_activated_req req;
3004 int ret;
3005 int resp_buf;
3006
3007 if (qseecom.qsee_version < QSEE_VERSION_04) {
3008 pr_err("invalid qsee version");
3009 return -ENODEV;
3010 }
3011
3012 if (argp == NULL) {
3013 pr_err("arg is null");
3014 return -EINVAL;
3015 }
3016
3017 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3018 (void *) &resp_buf, sizeof(resp_buf));
3019 if (ret) {
3020 pr_err("scm_call failed");
3021 return ret;
3022 }
3023
3024 req.is_activated = resp_buf;
3025 ret = copy_to_user(argp, &req, sizeof(req));
3026 if (ret) {
3027 pr_err("copy_to_user failed");
3028 return ret;
3029 }
3030
3031 return 0;
3032}
3033
3034static int qseecom_save_partition_hash(void __user *argp)
3035{
3036 struct qseecom_save_partition_hash_req req;
3037 int ret;
3038
3039 if (qseecom.qsee_version < QSEE_VERSION_04) {
3040 pr_err("invalid qsee version ");
3041 return -ENODEV;
3042 }
3043
3044 if (argp == NULL) {
3045 pr_err("arg is null");
3046 return -EINVAL;
3047 }
3048
3049 ret = copy_from_user(&req, argp, sizeof(req));
3050 if (ret) {
3051 pr_err("copy_from_user failed");
3052 return ret;
3053 }
3054
3055 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3056 (void *) &req, sizeof(req), NULL, 0);
3057 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003058 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003059 return ret;
3060 }
3061
3062 return 0;
3063}
3064
Mona Hossain2892b6b2012-02-17 13:53:11 -08003065static long qseecom_ioctl(struct file *file, unsigned cmd,
3066 unsigned long arg)
3067{
3068 int ret = 0;
3069 struct qseecom_dev_handle *data = file->private_data;
3070 void __user *argp = (void __user *) arg;
3071
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303072 if (!data) {
3073 pr_err("Invalid/uninitialized device handle\n");
3074 return -EINVAL;
3075 }
3076
Mona Hossain2892b6b2012-02-17 13:53:11 -08003077 if (data->abort) {
3078 pr_err("Aborting qseecom driver\n");
3079 return -ENODEV;
3080 }
3081
3082 switch (cmd) {
3083 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003084 if (data->type != QSEECOM_GENERIC) {
3085 pr_err("reg lstnr req: invalid handle (%d)\n",
3086 data->type);
3087 ret = -EINVAL;
3088 break;
3089 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003090 pr_debug("ioctl register_listener_req()\n");
3091 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003092 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003093 ret = qseecom_register_listener(data, argp);
3094 atomic_dec(&data->ioctl_count);
3095 wake_up_all(&data->abort_wq);
3096 if (ret)
3097 pr_err("failed qseecom_register_listener: %d\n", ret);
3098 break;
3099 }
3100 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003101 if ((data->listener.id == 0) ||
3102 (data->type != QSEECOM_LISTENER_SERVICE)) {
3103 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3104 data->type, data->listener.id);
3105 ret = -EINVAL;
3106 break;
3107 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003108 pr_debug("ioctl unregister_listener_req()\n");
3109 atomic_inc(&data->ioctl_count);
3110 ret = qseecom_unregister_listener(data);
3111 atomic_dec(&data->ioctl_count);
3112 wake_up_all(&data->abort_wq);
3113 if (ret)
3114 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3115 break;
3116 }
3117 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003118 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003119 if ((data->client.app_id == 0) ||
3120 (data->type != QSEECOM_CLIENT_APP)) {
3121 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3122 data->type, data->client.app_id);
3123 ret = -EINVAL;
3124 break;
3125 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003126 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003127 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003128 if (qseecom.support_bus_scaling)
3129 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3130 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003131 atomic_inc(&data->ioctl_count);
3132 ret = qseecom_send_cmd(data, argp);
3133 atomic_dec(&data->ioctl_count);
3134 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003135 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003136 if (ret)
3137 pr_err("failed qseecom_send_cmd: %d\n", ret);
3138 break;
3139 }
3140 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003141 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003142 if ((data->client.app_id == 0) ||
3143 (data->type != QSEECOM_CLIENT_APP)) {
3144 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3145 data->type, data->client.app_id);
3146 ret = -EINVAL;
3147 break;
3148 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003149 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003150 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003151 if (qseecom.support_bus_scaling)
3152 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3153 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003154 atomic_inc(&data->ioctl_count);
3155 ret = qseecom_send_modfd_cmd(data, argp);
3156 atomic_dec(&data->ioctl_count);
3157 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003158 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003159 if (ret)
3160 pr_err("failed qseecom_send_cmd: %d\n", ret);
3161 break;
3162 }
3163 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003164 if ((data->listener.id == 0) ||
3165 (data->type != QSEECOM_LISTENER_SERVICE)) {
3166 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3167 data->type, data->listener.id);
3168 ret = -EINVAL;
3169 break;
3170 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003171 atomic_inc(&data->ioctl_count);
3172 ret = qseecom_receive_req(data);
3173 atomic_dec(&data->ioctl_count);
3174 wake_up_all(&data->abort_wq);
3175 if (ret)
3176 pr_err("failed qseecom_receive_req: %d\n", ret);
3177 break;
3178 }
3179 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003180 if ((data->listener.id == 0) ||
3181 (data->type != QSEECOM_LISTENER_SERVICE)) {
3182 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3183 data->type, data->listener.id);
3184 ret = -EINVAL;
3185 break;
3186 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003187 atomic_inc(&data->ioctl_count);
3188 ret = qseecom_send_resp();
3189 atomic_dec(&data->ioctl_count);
3190 wake_up_all(&data->abort_wq);
3191 if (ret)
3192 pr_err("failed qseecom_send_resp: %d\n", ret);
3193 break;
3194 }
3195 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003196 if ((data->type != QSEECOM_CLIENT_APP) &&
3197 (data->type != QSEECOM_GENERIC) &&
3198 (data->type != QSEECOM_SECURE_SERVICE)) {
3199 pr_err("set mem param req: invalid handle (%d)\n",
3200 data->type);
3201 ret = -EINVAL;
3202 break;
3203 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003204 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003205 ret = qseecom_set_client_mem_param(data, argp);
3206 if (ret)
3207 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3208 ret);
3209 break;
3210 }
3211 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003212 if ((data->type != QSEECOM_GENERIC) &&
3213 (data->type != QSEECOM_CLIENT_APP)) {
3214 pr_err("load app req: invalid handle (%d)\n",
3215 data->type);
3216 ret = -EINVAL;
3217 break;
3218 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003219 data->type = QSEECOM_CLIENT_APP;
3220 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003221 mutex_lock(&app_access_lock);
3222 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003223 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3224 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003225 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003226 if (ret == 0)
3227 qseecom.commonlib_loaded = true;
3228 }
3229 }
3230 if (ret == 0)
3231 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003232 atomic_dec(&data->ioctl_count);
3233 mutex_unlock(&app_access_lock);
3234 if (ret)
3235 pr_err("failed load_app request: %d\n", ret);
3236 break;
3237 }
3238 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003239 if ((data->client.app_id == 0) ||
3240 (data->type != QSEECOM_CLIENT_APP)) {
3241 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3242 data->type, data->client.app_id);
3243 ret = -EINVAL;
3244 break;
3245 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003246 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003247 mutex_lock(&app_access_lock);
3248 atomic_inc(&data->ioctl_count);
3249 ret = qseecom_unload_app(data);
3250 atomic_dec(&data->ioctl_count);
3251 mutex_unlock(&app_access_lock);
3252 if (ret)
3253 pr_err("failed unload_app request: %d\n", ret);
3254 break;
3255 }
3256 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3257 atomic_inc(&data->ioctl_count);
3258 ret = qseecom_get_qseos_version(data, argp);
3259 if (ret)
3260 pr_err("qseecom_get_qseos_version: %d\n", ret);
3261 atomic_dec(&data->ioctl_count);
3262 break;
3263 }
3264 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003265 if ((data->type != QSEECOM_GENERIC) &&
3266 (data->type != QSEECOM_CLIENT_APP)) {
3267 pr_err("perf enable req: invalid handle (%d)\n",
3268 data->type);
3269 ret = -EINVAL;
3270 break;
3271 }
3272 if ((data->type == QSEECOM_CLIENT_APP) &&
3273 (data->client.app_id == 0)) {
3274 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3275 data->type, data->client.app_id);
3276 ret = -EINVAL;
3277 break;
3278 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003279 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003280 if (qseecom.support_bus_scaling) {
3281 mutex_lock(&qsee_bw_mutex);
3282 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3283 mutex_unlock(&qsee_bw_mutex);
3284 } else {
3285 ret = qsee_vote_for_clock(data, CLK_DFAB);
3286 if (ret)
3287 pr_err("Fail to vote for DFAB clock%d\n", ret);
3288 ret = qsee_vote_for_clock(data, CLK_SFPB);
3289 if (ret)
3290 pr_err("Fail to vote for SFPB clock%d\n", ret);
3291 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003292 atomic_dec(&data->ioctl_count);
3293 break;
3294 }
3295 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003296 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3297 (data->type != QSEECOM_CLIENT_APP)) {
3298 pr_err("perf disable req: invalid handle (%d)\n",
3299 data->type);
3300 ret = -EINVAL;
3301 break;
3302 }
3303 if ((data->type == QSEECOM_CLIENT_APP) &&
3304 (data->client.app_id == 0)) {
3305 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3306 data->type, data->client.app_id);
3307 ret = -EINVAL;
3308 break;
3309 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003310 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003311 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003312 qsee_disable_clock_vote(data, CLK_DFAB);
3313 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003314 }
3315 atomic_dec(&data->ioctl_count);
3316 break;
3317 }
3318
3319 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3320 if ((data->client.app_id == 0) ||
3321 (data->type != QSEECOM_CLIENT_APP)) {
3322 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3323 data->type, data->client.app_id);
3324 ret = -EINVAL;
3325 break;
3326 }
3327 atomic_inc(&data->ioctl_count);
3328 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003329 atomic_dec(&data->ioctl_count);
3330 break;
3331 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003332 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003333 if (data->type != QSEECOM_GENERIC) {
3334 pr_err("load ext elf req: invalid client handle (%d)\n",
3335 data->type);
3336 ret = -EINVAL;
3337 break;
3338 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003339 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003340 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003341 mutex_lock(&app_access_lock);
3342 atomic_inc(&data->ioctl_count);
3343 ret = qseecom_load_external_elf(data, argp);
3344 atomic_dec(&data->ioctl_count);
3345 mutex_unlock(&app_access_lock);
3346 if (ret)
3347 pr_err("failed load_external_elf request: %d\n", ret);
3348 break;
3349 }
3350 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003351 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3352 pr_err("unload ext elf req: invalid handle (%d)\n",
3353 data->type);
3354 ret = -EINVAL;
3355 break;
3356 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003357 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003358 mutex_lock(&app_access_lock);
3359 atomic_inc(&data->ioctl_count);
3360 ret = qseecom_unload_external_elf(data);
3361 atomic_dec(&data->ioctl_count);
3362 mutex_unlock(&app_access_lock);
3363 if (ret)
3364 pr_err("failed unload_app request: %d\n", ret);
3365 break;
3366 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003367 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003368 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003369 mutex_lock(&app_access_lock);
3370 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003371 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003372 ret = qseecom_query_app_loaded(data, argp);
3373 atomic_dec(&data->ioctl_count);
3374 mutex_unlock(&app_access_lock);
3375 break;
3376 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003377 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003378 if (data->type != QSEECOM_GENERIC) {
3379 pr_err("send cmd svc req: invalid handle (%d)\n",
3380 data->type);
3381 ret = -EINVAL;
3382 break;
3383 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003384 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003385 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003386 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003387 qseecom.qsee_version);
3388 return -EINVAL;
3389 }
3390 mutex_lock(&app_access_lock);
3391 atomic_inc(&data->ioctl_count);
3392 ret = qseecom_send_service_cmd(data, argp);
3393 atomic_dec(&data->ioctl_count);
3394 mutex_unlock(&app_access_lock);
3395 break;
3396 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003397 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003398 if (data->type != QSEECOM_GENERIC) {
3399 pr_err("create key req: invalid handle (%d)\n",
3400 data->type);
3401 ret = -EINVAL;
3402 break;
3403 }
Zhen Kong336636e2013-04-15 11:04:54 -07003404 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003405 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003406 qseecom.qsee_version);
3407 return -EINVAL;
3408 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003409 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003410 atomic_inc(&data->ioctl_count);
3411 ret = qseecom_create_key(data, argp);
3412 if (ret)
3413 pr_err("failed to create encryption key: %d\n", ret);
3414
3415 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003416 break;
3417 }
3418 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003419 if (data->type != QSEECOM_GENERIC) {
3420 pr_err("wipe key req: invalid handle (%d)\n",
3421 data->type);
3422 ret = -EINVAL;
3423 break;
3424 }
Zhen Kong336636e2013-04-15 11:04:54 -07003425 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003426 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003427 qseecom.qsee_version);
3428 return -EINVAL;
3429 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003430 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003431 atomic_inc(&data->ioctl_count);
3432 ret = qseecom_wipe_key(data, argp);
3433 if (ret)
3434 pr_err("failed to wipe encryption key: %d\n", ret);
3435 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003436 break;
3437 }
3438 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
3439 if (data->type != QSEECOM_GENERIC) {
3440 pr_err("update key req: invalid handle (%d)\n",
3441 data->type);
3442 ret = -EINVAL;
3443 break;
3444 }
3445 if (qseecom.qsee_version < QSEE_VERSION_05) {
3446 pr_err("Update Key feature unsupported in qsee ver %u\n",
3447 qseecom.qsee_version);
3448 return -EINVAL;
3449 }
3450 data->released = true;
3451 atomic_inc(&data->ioctl_count);
3452 ret = qseecom_update_key_user_info(data, argp);
3453 if (ret)
3454 pr_err("failed to update key user info: %d\n", ret);
3455 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003456 break;
3457 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003458 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003459 if (data->type != QSEECOM_GENERIC) {
3460 pr_err("save part hash req: invalid handle (%d)\n",
3461 data->type);
3462 ret = -EINVAL;
3463 break;
3464 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003465 data->released = true;
3466 mutex_lock(&app_access_lock);
3467 atomic_inc(&data->ioctl_count);
3468 ret = qseecom_save_partition_hash(argp);
3469 atomic_dec(&data->ioctl_count);
3470 mutex_unlock(&app_access_lock);
3471 break;
3472 }
3473 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003474 if (data->type != QSEECOM_GENERIC) {
3475 pr_err("ES activated req: invalid handle (%d)\n",
3476 data->type);
3477 ret = -EINVAL;
3478 break;
3479 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003480 data->released = true;
3481 mutex_lock(&app_access_lock);
3482 atomic_inc(&data->ioctl_count);
3483 ret = qseecom_is_es_activated(argp);
3484 atomic_dec(&data->ioctl_count);
3485 mutex_unlock(&app_access_lock);
3486 break;
3487 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003488 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003489 if ((data->listener.id == 0) ||
3490 (data->type != QSEECOM_LISTENER_SERVICE)) {
3491 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3492 data->type, data->listener.id);
3493 ret = -EINVAL;
3494 break;
3495 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003496 /* Only one client allowed here at a time */
3497 atomic_inc(&data->ioctl_count);
3498 ret = qseecom_send_modfd_resp(data, argp);
3499 atomic_dec(&data->ioctl_count);
3500 wake_up_all(&data->abort_wq);
3501 if (ret)
3502 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3503 break;
3504 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003505 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003506 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003507 return -EINVAL;
3508 }
3509 return ret;
3510}
3511
3512static int qseecom_open(struct inode *inode, struct file *file)
3513{
3514 int ret = 0;
3515 struct qseecom_dev_handle *data;
3516
3517 data = kzalloc(sizeof(*data), GFP_KERNEL);
3518 if (!data) {
3519 pr_err("kmalloc failed\n");
3520 return -ENOMEM;
3521 }
3522 file->private_data = data;
3523 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003524 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003525 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003526 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003527 init_waitqueue_head(&data->abort_wq);
3528 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003529
Mona Hossain2892b6b2012-02-17 13:53:11 -08003530 return ret;
3531}
3532
3533static int qseecom_release(struct inode *inode, struct file *file)
3534{
3535 struct qseecom_dev_handle *data = file->private_data;
3536 int ret = 0;
3537
3538 if (data->released == false) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003539 pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
3540 data->type, data->mode, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003541 switch (data->type) {
3542 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003543 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003544 break;
3545 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003546 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003547 break;
3548 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003549 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003550 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003551 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003552 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003553 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303554 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3555 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003556 default:
3557 pr_err("Unsupported clnt_handle_type %d",
3558 data->type);
3559 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003560 }
3561 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003562
Zhen Kong2edf90d2013-08-27 12:05:06 -07003563 if (qseecom.support_bus_scaling) {
3564 mutex_lock(&qsee_bw_mutex);
3565 if (data->mode != INACTIVE) {
3566 qseecom_unregister_bus_bandwidth_needs(data);
3567 if (qseecom.cumulative_mode == INACTIVE) {
3568 ret = __qseecom_set_msm_bus_request(INACTIVE);
3569 if (ret)
3570 pr_err("Fail to scale down bus\n");
3571 }
3572 }
3573 mutex_unlock(&qsee_bw_mutex);
3574 } else {
3575 if (data->fast_load_enabled == true)
3576 qsee_disable_clock_vote(data, CLK_SFPB);
3577 if (data->perf_enabled == true)
3578 qsee_disable_clock_vote(data, CLK_DFAB);
3579 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003580 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003581
Mona Hossain2892b6b2012-02-17 13:53:11 -08003582 return ret;
3583}
3584
Mona Hossain2892b6b2012-02-17 13:53:11 -08003585static const struct file_operations qseecom_fops = {
3586 .owner = THIS_MODULE,
3587 .unlocked_ioctl = qseecom_ioctl,
3588 .open = qseecom_open,
3589 .release = qseecom_release
3590};
3591
Mona Hossainc92629e2013-04-01 13:37:46 -07003592static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003593{
3594 int rc = 0;
3595 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003596 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003597 char *core_clk_src = NULL;
3598 char *core_clk = NULL;
3599 char *iface_clk = NULL;
3600 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003601
Mona Hossainc92629e2013-04-01 13:37:46 -07003602 switch (ce) {
3603 case CLK_QSEE: {
3604 core_clk_src = "core_clk_src";
3605 core_clk = "core_clk";
3606 iface_clk = "iface_clk";
3607 bus_clk = "bus_clk";
3608 qclk = &qseecom.qsee;
3609 qclk->instance = CLK_QSEE;
3610 break;
3611 };
3612 case CLK_CE_DRV: {
3613 core_clk_src = "ce_drv_core_clk_src";
3614 core_clk = "ce_drv_core_clk";
3615 iface_clk = "ce_drv_iface_clk";
3616 bus_clk = "ce_drv_bus_clk";
3617 qclk = &qseecom.ce_drv;
3618 qclk->instance = CLK_CE_DRV;
3619 break;
3620 };
3621 default:
3622 pr_err("Invalid ce hw instance: %d!\n", ce);
3623 return -EIO;
3624 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003625 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003626
Mona Hossainc92629e2013-04-01 13:37:46 -07003627 /* Get CE3 src core clk. */
3628 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003629 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003630 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003631 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003632 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003633 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003634 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003635 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003636 }
3637 } else {
3638 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003639 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003640 }
3641
3642 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003643 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003644 if (IS_ERR(qclk->ce_core_clk)) {
3645 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003646 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003647 if (qclk->ce_core_src_clk != NULL)
3648 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003649 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003650 }
3651
3652 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003653 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003654 if (IS_ERR(qclk->ce_clk)) {
3655 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003656 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003657 if (qclk->ce_core_src_clk != NULL)
3658 clk_put(qclk->ce_core_src_clk);
3659 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003660 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003661 }
3662
3663 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003664 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003665 if (IS_ERR(qclk->ce_bus_clk)) {
3666 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003667 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003668 if (qclk->ce_core_src_clk != NULL)
3669 clk_put(qclk->ce_core_src_clk);
3670 clk_put(qclk->ce_core_clk);
3671 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003672 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003673 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003674 return rc;
3675}
3676
Mona Hossainc92629e2013-04-01 13:37:46 -07003677static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003678{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003679 struct qseecom_clk *qclk;
3680
Mona Hossainc92629e2013-04-01 13:37:46 -07003681 if (ce == CLK_QSEE)
3682 qclk = &qseecom.qsee;
3683 else
3684 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003685
3686 if (qclk->ce_clk != NULL) {
3687 clk_put(qclk->ce_clk);
3688 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003689 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003690 if (qclk->ce_core_clk != NULL) {
3691 clk_put(qclk->ce_core_clk);
3692 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003693 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003694 if (qclk->ce_bus_clk != NULL) {
3695 clk_put(qclk->ce_bus_clk);
3696 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003697 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003698 if (qclk->ce_core_src_clk != NULL) {
3699 clk_put(qclk->ce_core_src_clk);
3700 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003701 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003702}
3703
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003704static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003705{
3706 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003707 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003708 struct device *class_dev;
3709 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003710 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003711 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3712
Mona Hossain17a4faf2013-03-22 16:40:56 -07003713 qseecom.qsee_bw_count = 0;
3714 qseecom.qsee_perf_client = 0;
3715 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003716
Mona Hossain17a4faf2013-03-22 16:40:56 -07003717 qseecom.qsee.ce_core_clk = NULL;
3718 qseecom.qsee.ce_clk = NULL;
3719 qseecom.qsee.ce_core_src_clk = NULL;
3720 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003721
Zhen Kong2edf90d2013-08-27 12:05:06 -07003722 qseecom.cumulative_mode = 0;
3723 qseecom.current_mode = INACTIVE;
3724 qseecom.support_bus_scaling = false;
3725
Mona Hossainc92629e2013-04-01 13:37:46 -07003726 qseecom.ce_drv.ce_core_clk = NULL;
3727 qseecom.ce_drv.ce_clk = NULL;
3728 qseecom.ce_drv.ce_core_src_clk = NULL;
3729 qseecom.ce_drv.ce_bus_clk = NULL;
3730
Mona Hossain2892b6b2012-02-17 13:53:11 -08003731 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3732 if (rc < 0) {
3733 pr_err("alloc_chrdev_region failed %d\n", rc);
3734 return rc;
3735 }
3736
3737 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3738 if (IS_ERR(driver_class)) {
3739 rc = -ENOMEM;
3740 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303741 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003742 }
3743
3744 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3745 QSEECOM_DEV);
3746 if (!class_dev) {
3747 pr_err("class_device_create failed %d\n", rc);
3748 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303749 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003750 }
3751
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303752 cdev_init(&qseecom.cdev, &qseecom_fops);
3753 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003754
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303755 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003756 if (rc < 0) {
3757 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303758 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003759 }
3760
3761 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3762 spin_lock_init(&qseecom.registered_listener_list_lock);
3763 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3764 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003765 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3766 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003767 init_waitqueue_head(&qseecom.send_resp_wq);
3768 qseecom.send_resp_flag = 0;
3769
3770 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3771 &qsee_not_legacy, sizeof(qsee_not_legacy));
3772 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003773 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303774 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003775 }
Mona Hossain05c73562012-10-29 17:49:01 -07003776 if (qsee_not_legacy) {
3777 uint32_t feature = 10;
3778
3779 qseecom.qsee_version = QSEEE_VERSION_00;
3780 rc = scm_call(6, 3, &feature, sizeof(feature),
3781 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3782 if (rc) {
3783 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303784 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003785 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003786 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003787 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003788 pr_err("QSEE legacy version is not supported:");
3789 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3790 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303791 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003792 }
Mona Hossain05c73562012-10-29 17:49:01 -07003793 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003794 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003795 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003796 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003797 if (qseecom.ion_clnt == NULL) {
3798 pr_err("Ion client cannot be created\n");
3799 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303800 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003801 }
3802
3803 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003804 if (pdev->dev.of_node) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003805 qseecom.support_bus_scaling =
3806 of_property_read_bool((&pdev->dev)->of_node,
3807 "qcom,support-bus-scaling");
3808 pr_warn("support_bus_scaling=0x%x",
3809 qseecom.support_bus_scaling);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003810 if (of_property_read_u32((&pdev->dev)->of_node,
3811 "qcom,disk-encrypt-pipe-pair",
3812 &qseecom.ce_info.disk_encrypt_pipe)) {
3813 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3814 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3815 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303816 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003817 } else {
3818 pr_warn("bam_pipe_pair=0x%x",
3819 qseecom.ce_info.disk_encrypt_pipe);
3820 }
3821
3822 if (of_property_read_u32((&pdev->dev)->of_node,
3823 "qcom,qsee-ce-hw-instance",
3824 &qseecom.ce_info.qsee_ce_hw_instance)) {
3825 pr_err("Fail to get qsee ce hw instance information.\n");
3826 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3827 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303828 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003829 } else {
3830 pr_warn("qsee-ce-hw-instance=0x%x",
3831 qseecom.ce_info.qsee_ce_hw_instance);
3832 }
3833
3834 if (of_property_read_u32((&pdev->dev)->of_node,
3835 "qcom,hlos-ce-hw-instance",
3836 &qseecom.ce_info.hlos_ce_hw_instance)) {
3837 pr_err("Fail to get hlos ce hw instance information.\n");
3838 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3839 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303840 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003841 } else {
3842 pr_warn("hlos-ce-hw-instance=0x%x",
3843 qseecom.ce_info.hlos_ce_hw_instance);
3844 }
3845
Mona Hossainc92629e2013-04-01 13:37:46 -07003846 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3847 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3848
3849 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003850 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303851 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003852
Mona Hossainc92629e2013-04-01 13:37:46 -07003853 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3854 ret = __qseecom_init_clk(CLK_CE_DRV);
3855 if (ret) {
3856 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303857 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003858 }
3859 } else {
3860 struct qseecom_clk *qclk;
3861
3862 qclk = &qseecom.qsee;
3863 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3864 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3865 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3866 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3867 }
3868
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003869 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3870 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003871 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3872 struct resource *resource = NULL;
3873 struct qsee_apps_region_info_ireq req;
3874 struct qseecom_command_scm_resp resp;
3875
3876 resource = platform_get_resource_byname(pdev,
3877 IORESOURCE_MEM, "secapp-region");
3878 if (resource) {
3879 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3880 req.addr = resource->start;
3881 req.size = resource_size(resource);
3882 pr_warn("secure app region addr=0x%x size=0x%x",
3883 req.addr, req.size);
3884 } else {
3885 pr_err("Fail to get secure app region info\n");
3886 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303887 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003888 }
3889 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3890 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003891 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3892 pr_err("send secapp reg fail %d resp.res %d\n",
3893 rc, resp.result);
3894 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303895 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003896 }
3897 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003898 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003899 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3900 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003901 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07003902 if (qseecom.support_bus_scaling) {
3903 init_timer(&(qseecom.bw_scale_down_timer));
3904 INIT_WORK(&qseecom.bw_inactive_req_ws,
3905 qseecom_bw_inactive_req_work);
3906 qseecom.bw_scale_down_timer.function =
3907 qseecom_scale_bus_bandwidth_timer_callback;
3908 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003909 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003910 qseecom_platform_support);
3911
Mona Hossain17a4faf2013-03-22 16:40:56 -07003912 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003913 pr_err("Unable to register bus client\n");
3914 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303915
3916exit_destroy_ion_client:
3917 ion_client_destroy(qseecom.ion_clnt);
3918exit_del_cdev:
3919 cdev_del(&qseecom.cdev);
3920exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003921 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303922exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003923 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303924exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003925 unregister_chrdev_region(qseecom_device_no, 1);
3926 return rc;
3927}
3928
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003929static int __devinit qseecom_remove(struct platform_device *pdev)
3930{
Mona Hossaind44a3842012-10-15 09:41:35 -07003931 struct qseecom_registered_kclient_list *kclient = NULL;
3932 unsigned long flags = 0;
3933 int ret = 0;
3934
Mona Hossaind44a3842012-10-15 09:41:35 -07003935 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303936
Mona Hossaind44a3842012-10-15 09:41:35 -07003937 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303938 list) {
3939 if (!kclient)
3940 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07003941
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303942 /* Break the loop if client handle is NULL */
3943 if (!kclient->handle)
3944 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07003945
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303946 if (list_empty(&kclient->list))
3947 goto exit_free_kc_handle;
3948
3949 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07003950 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303951 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07003952 kzfree(kclient->handle->dev);
3953 kzfree(kclient->handle);
3954 kzfree(kclient);
3955 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003956 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303957
3958exit_free_kc_handle:
3959 kzfree(kclient->handle);
3960exit_free_kclient:
3961 kzfree(kclient);
3962exit_irqrestore:
3963 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3964
3965 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07003966 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003967
Mona Hossain17a4faf2013-03-22 16:40:56 -07003968 if (qseecom.qsee_perf_client)
3969 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3970 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303971 if (pdev->dev.platform_data != NULL)
3972 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
3973
Zhen Kong2edf90d2013-08-27 12:05:06 -07003974 if (qseecom.support_bus_scaling) {
3975 cancel_work_sync(&qseecom.bw_inactive_req_ws);
3976 del_timer_sync(&qseecom.bw_scale_down_timer);
3977 }
3978
Mona Hossaind39e33b2012-11-05 13:36:40 -08003979 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003980 if (pdev->dev.of_node) {
3981 __qseecom_deinit_clk(CLK_QSEE);
3982 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3983 __qseecom_deinit_clk(CLK_CE_DRV);
3984 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303985
3986 ion_client_destroy(qseecom.ion_clnt);
3987
3988 cdev_del(&qseecom.cdev);
3989
3990 device_destroy(driver_class, qseecom_device_no);
3991
3992 class_destroy(driver_class);
3993
3994 unregister_chrdev_region(qseecom_device_no, 1);
3995
Mona Hossaind44a3842012-10-15 09:41:35 -07003996 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303997}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003998
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003999static struct of_device_id qseecom_match[] = {
4000 {
4001 .compatible = "qcom,qseecom",
4002 },
4003 {}
4004};
4005
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004006static struct platform_driver qseecom_plat_driver = {
4007 .probe = qseecom_probe,
4008 .remove = qseecom_remove,
4009 .driver = {
4010 .name = "qseecom",
4011 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004012 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004013 },
4014};
4015
4016static int __devinit qseecom_init(void)
4017{
4018 return platform_driver_register(&qseecom_plat_driver);
4019}
4020
4021static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004022{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304023 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004024}
4025
4026MODULE_LICENSE("GPL v2");
4027MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4028
4029module_init(qseecom_init);
4030module_exit(qseecom_exit);