blob: fa28d6a2c7915c2241316573c1f91f2e7d9e033d [file] [log] [blame]
Mona Hossaind44a3842012-10-15 09:41:35 -07001/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
Mona Hossain2892b6b2012-02-17 13:53:11 -08002 *
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08003 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Mona Hossain2892b6b2012-02-17 13:53:11 -08004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/platform_device.h>
22#include <linux/debugfs.h>
23#include <linux/cdev.h>
24#include <linux/uaccess.h>
25#include <linux/sched.h>
26#include <linux/list.h>
27#include <linux/mutex.h>
28#include <linux/io.h>
Mitchel Humpherys4f8be2e2012-09-06 10:41:41 -070029#include <linux/msm_ion.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080030#include <linux/types.h>
31#include <linux/clk.h>
32#include <linux/qseecom.h>
Mona Hossaind44a3842012-10-15 09:41:35 -070033#include <linux/elf.h>
34#include <linux/firmware.h>
Mona Hossainacea1022012-04-09 13:37:27 -070035#include <linux/freezer.h>
Mona Hossainf1f2ed62012-11-15 19:51:33 -080036#include <linux/scatterlist.h>
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070037#include <mach/board.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080038#include <mach/msm_bus.h>
39#include <mach/msm_bus_board.h>
40#include <mach/scm.h>
Stephen Boyd77db8bb2012-06-27 15:15:16 -070041#include <mach/subsystem_restart.h>
Ramesh Masavarapuff377032012-09-14 12:11:32 -070042#include <mach/socinfo.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080043#include <mach/qseecomi.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080044#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070045#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080046
47#define QSEECOM_DEV "qseecom"
48#define QSEOS_VERSION_13 0x13
49#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
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070072enum qseecom_clk_definitions {
73 CLK_DFAB = 0,
74 CLK_SFPB,
75};
76
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080077enum qseecom_client_handle_type {
78 QSEECOM_CLIENT_APP = 0,
79 QSEECOM_LISTENER_SERVICE,
80 QSEECOM_SECURE_SERVICE,
81 QSEECOM_GENERIC,
82};
83
Mona Hossainc92629e2013-04-01 13:37:46 -070084enum qseecom_ce_hw_instance {
85 CLK_QSEE = 0,
86 CLK_CE_DRV,
87};
88
Mona Hossain2892b6b2012-02-17 13:53:11 -080089static struct class *driver_class;
90static dev_t qseecom_device_no;
91static struct cdev qseecom_cdev;
92
93/* Data structures used in legacy support */
94static void *pil;
95static uint32_t pil_ref_cnt;
96static DEFINE_MUTEX(pil_access_lock);
97
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;
105 u8 *sb_reg_req;
106 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;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800167};
168
169struct qseecom_client_handle {
170 u32 app_id;
171 u8 *sb_virt;
172 s32 sb_phys;
173 uint32_t user_virt_sb_base;
174 size_t sb_length;
175 struct ion_handle *ihandle; /* Retrieve phy addr */
176};
177
178struct qseecom_listener_handle {
179 u32 id;
180};
181
182static struct qseecom_control qseecom;
183
184struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800185 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800186 union {
187 struct qseecom_client_handle client;
188 struct qseecom_listener_handle listener;
189 };
190 bool released;
191 int abort;
192 wait_queue_head_t abort_wq;
193 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700194 bool perf_enabled;
195 bool fast_load_enabled;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800196};
197
Mona Hossain4cf78a92013-02-14 12:06:41 -0800198enum qseecom_set_clear_key_flag {
199 QSEECOM_CLEAR_CE_KEY_CMD = 0,
200 QSEECOM_SET_CE_KEY_CMD,
201};
202
203struct qseecom_set_key_parameter {
204 uint32_t ce_hw;
205 uint32_t pipe;
206 uint32_t flags;
207 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
208 unsigned char hash32[QSEECOM_HASH_SIZE];
209 enum qseecom_set_clear_key_flag set_clear_key_flag;
210};
211
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800212struct qseecom_sg_entry {
213 uint32_t phys_addr;
214 uint32_t len;
215};
216
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700217/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800218static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
219static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700220
Mona Hossain2892b6b2012-02-17 13:53:11 -0800221static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800222 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800223{
224 struct qseecom_registered_listener_list *ptr;
225 int unique = 1;
226 unsigned long flags;
227
228 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
229 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800230 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800231 pr_err("Service id: %u is already registered\n",
232 ptr->svc.listener_id);
233 unique = 0;
234 break;
235 }
236 }
237 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
238 return unique;
239}
240
241static struct qseecom_registered_listener_list *__qseecom_find_svc(
242 int32_t listener_id)
243{
244 struct qseecom_registered_listener_list *entry = NULL;
245 unsigned long flags;
246
247 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
248 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
249 {
250 if (entry->svc.listener_id == listener_id)
251 break;
252 }
253 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
254 return entry;
255}
256
257static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
258 struct qseecom_dev_handle *handle,
259 struct qseecom_register_listener_req *listener)
260{
261 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800262 struct qseecom_register_listener_ireq req;
263 struct qseecom_command_scm_resp resp;
264 ion_phys_addr_t pa;
265
266 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800267 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
268 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800269 if (svc->ihandle == NULL) {
270 pr_err("Ion client could not retrieve the handle\n");
271 return -ENOMEM;
272 }
273
274 /* Get the physical address of the ION BUF */
275 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
276
277 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700278 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800279 svc->sb_phys = pa;
280
281 if (qseecom.qseos_version == QSEOS_VERSION_14) {
282 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
283 req.listener_id = svc->svc.listener_id;
284 req.sb_len = svc->sb_length;
285 req.sb_ptr = (void *)svc->sb_phys;
286
287 resp.result = QSEOS_RESULT_INCOMPLETE;
288
289 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
290 sizeof(req), &resp, sizeof(resp));
291 if (ret) {
292 pr_err("qseecom_scm_call failed with err: %d\n", ret);
293 return -EINVAL;
294 }
295
296 if (resp.result != QSEOS_RESULT_SUCCESS) {
297 pr_err("Error SB registration req: resp.result = %d\n",
298 resp.result);
299 return -EPERM;
300 }
301 } else {
302 struct qseecom_command cmd;
303 struct qseecom_response resp;
304 struct qse_pr_init_sb_req_s sb_init_req;
305 struct qse_pr_init_sb_rsp_s sb_init_rsp;
306
307 svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
308 sizeof(sb_init_rsp)), GFP_KERNEL);
309
310 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
311 sb_init_req.listener_id = svc->svc.listener_id;
312 sb_init_req.sb_len = svc->sb_length;
313 sb_init_req.sb_ptr = svc->sb_phys;
314
315 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
316
317 /* It will always be a new cmd from this method */
318 cmd.cmd_type = TZ_SCHED_CMD_NEW;
319 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
320 cmd.sb_in_cmd_len = sizeof(sb_init_req);
321
322 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
323
324 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
325 , &resp, sizeof(resp));
326
327 if (ret) {
328 pr_err("qseecom_scm_call failed with err: %d\n", ret);
329 return -EINVAL;
330 }
331
332 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
333 pr_err("SB registration fail resp.cmd_status %d\n",
334 resp.cmd_status);
335 return -EINVAL;
336 }
337 memset(svc->sb_virt, 0, svc->sb_length);
338 }
339 return 0;
340}
341
342static int qseecom_register_listener(struct qseecom_dev_handle *data,
343 void __user *argp)
344{
345 int ret = 0;
346 unsigned long flags;
347 struct qseecom_register_listener_req rcvd_lstnr;
348 struct qseecom_registered_listener_list *new_entry;
349
350 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
351 if (ret) {
352 pr_err("copy_from_user failed\n");
353 return ret;
354 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800355 data->listener.id = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800356 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800357 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800358 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800359 data->released = true;
360 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800361 }
362
363 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
364 if (!new_entry) {
365 pr_err("kmalloc failed\n");
366 return -ENOMEM;
367 }
368 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
369 new_entry->rcv_req_flag = 0;
370
371 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
372 new_entry->sb_length = rcvd_lstnr.sb_size;
373 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
374 pr_err("qseecom_set_sb_memoryfailed\n");
375 kzfree(new_entry);
376 return -ENOMEM;
377 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800378
Mona Hossain2892b6b2012-02-17 13:53:11 -0800379 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800380 init_waitqueue_head(&new_entry->rcv_req_wq);
381
382 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
383 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
384 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800385
Mona Hossain2892b6b2012-02-17 13:53:11 -0800386 return ret;
387}
388
389static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
390{
391 int ret = 0;
392 unsigned long flags;
393 uint32_t unmap_mem = 0;
394 struct qseecom_register_listener_ireq req;
395 struct qseecom_registered_listener_list *ptr_svc = NULL;
396 struct qseecom_command_scm_resp resp;
397 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
398
399 if (qseecom.qseos_version == QSEOS_VERSION_14) {
400 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
401 req.listener_id = data->listener.id;
402 resp.result = QSEOS_RESULT_INCOMPLETE;
403
404 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
405 sizeof(req), &resp, sizeof(resp));
406 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700407 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
408 ret, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800409 return ret;
410 }
411
412 if (resp.result != QSEOS_RESULT_SUCCESS) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700413 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
414 resp.result, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800415 return -EPERM;
416 }
417 } else {
418 struct qse_pr_init_sb_req_s sb_init_req;
419 struct qseecom_command cmd;
420 struct qseecom_response resp;
421 struct qseecom_registered_listener_list *svc;
422
423 svc = __qseecom_find_svc(data->listener.id);
424 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
425 sb_init_req.listener_id = data->listener.id;
426 sb_init_req.sb_len = 0;
427 sb_init_req.sb_ptr = 0;
428
429 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
430
431 /* It will always be a new cmd from this method */
432 cmd.cmd_type = TZ_SCHED_CMD_NEW;
433 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
434 cmd.sb_in_cmd_len = sizeof(sb_init_req);
435 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
436
437 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
438 &resp, sizeof(resp));
439 if (ret) {
440 pr_err("qseecom_scm_call failed with err: %d\n", ret);
441 return ret;
442 }
443 kzfree(svc->sb_reg_req);
444 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
445 pr_err("Error with SB initialization\n");
446 return -EPERM;
447 }
448 }
449 data->abort = 1;
450 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
451 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
452 list) {
453 if (ptr_svc->svc.listener_id == data->listener.id) {
454 wake_up_all(&ptr_svc->rcv_req_wq);
455 break;
456 }
457 }
458 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
459
460 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700461 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800462 atomic_read(&data->ioctl_count) <= 1)) {
463 pr_err("Interrupted from abort\n");
464 ret = -ERESTARTSYS;
465 break;
466 }
467 }
468
469 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
470 list_for_each_entry(ptr_svc,
471 &qseecom.registered_listener_list_head,
472 list)
473 {
474 if (ptr_svc->svc.listener_id == data->listener.id) {
475 if (ptr_svc->sb_virt) {
476 unmap_mem = 1;
477 ihandle = ptr_svc->ihandle;
478 }
479 list_del(&ptr_svc->list);
480 kzfree(ptr_svc);
481 break;
482 }
483 }
484 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
485
486 /* Unmap the memory */
487 if (unmap_mem) {
488 if (!IS_ERR_OR_NULL(ihandle)) {
489 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
490 ion_free(qseecom.ion_clnt, ihandle);
491 }
492 }
493 data->released = true;
494 return ret;
495}
496
497static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
498 void __user *argp)
499{
500 ion_phys_addr_t pa;
501 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800502 struct qseecom_set_sb_mem_param_req req;
503 uint32_t len;
504
505 /* Copy the relevant information needed for loading the image */
506 if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
507 return -EFAULT;
508
Mona Hossain2892b6b2012-02-17 13:53:11 -0800509 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800510 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
511 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800512 if (IS_ERR_OR_NULL(data->client.ihandle)) {
513 pr_err("Ion client could not retrieve the handle\n");
514 return -ENOMEM;
515 }
516 /* Get the physical address of the ION BUF */
517 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
518 /* Populate the structure for sending scm call to load image */
519 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700520 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800521 data->client.sb_phys = pa;
522 data->client.sb_length = req.sb_len;
523 data->client.user_virt_sb_base = req.virt_sb_base;
524 return 0;
525}
526
Mona Hossain2892b6b2012-02-17 13:53:11 -0800527static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
528{
529 int ret;
530 ret = (qseecom.send_resp_flag != 0);
531 return ret || data->abort;
532}
533
534static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
535 struct qseecom_command_scm_resp *resp)
536{
537 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800538 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800539 uint32_t lstnr;
540 unsigned long flags;
541 struct qseecom_client_listener_data_irsp send_data_rsp;
542 struct qseecom_registered_listener_list *ptr_svc = NULL;
543
Mona Hossain2892b6b2012-02-17 13:53:11 -0800544 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
545 lstnr = resp->data;
546 /*
547 * Wake up blocking lsitener service with the lstnr id
548 */
549 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
550 flags);
551 list_for_each_entry(ptr_svc,
552 &qseecom.registered_listener_list_head, list) {
553 if (ptr_svc->svc.listener_id == lstnr) {
554 ptr_svc->rcv_req_flag = 1;
555 wake_up_interruptible(&ptr_svc->rcv_req_wq);
556 break;
557 }
558 }
559 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
560 flags);
561 if (ptr_svc->svc.listener_id != lstnr) {
562 pr_warning("Service requested for does on exist\n");
563 return -ERESTARTSYS;
564 }
565 pr_debug("waking up rcv_req_wq and "
566 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700567 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800568 __qseecom_listener_has_sent_rsp(data))) {
569 pr_warning("Interrupted: exiting send_cmd loop\n");
Mona Hossaineaa69b72013-04-15 17:20:15 -0700570 ret = -ERESTARTSYS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800571 }
572
Mona Hossaineaa69b72013-04-15 17:20:15 -0700573 if ((data->abort) || (ret == -ERESTARTSYS)) {
574 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
575 data->client.app_id, lstnr, ret);
576 if (data->abort)
577 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800578 send_data_rsp.status = QSEOS_RESULT_FAILURE;
579 } else {
580 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800581 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800582
Mona Hossain2892b6b2012-02-17 13:53:11 -0800583 qseecom.send_resp_flag = 0;
584 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
585 send_data_rsp.listener_id = lstnr ;
586
587 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
588 (const void *)&send_data_rsp,
589 sizeof(send_data_rsp), resp,
590 sizeof(*resp));
591 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700592 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800593 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800594 return ret;
595 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800596 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
597 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
598 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
599 resp->result, data->client.app_id, lstnr);
600 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700601 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800602 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800603 if (rc)
604 return rc;
605
Mona Hossain2892b6b2012-02-17 13:53:11 -0800606 return ret;
607}
608
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700609static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
610{
611 int32_t ret;
612 struct qseecom_command_scm_resp resp;
613
614 /* SCM_CALL to check if app_id for the mentioned app exists */
615 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
616 sizeof(struct qseecom_check_app_ireq),
617 &resp, sizeof(resp));
618 if (ret) {
619 pr_err("scm_call to check if app is already loaded failed\n");
620 return -EINVAL;
621 }
622
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700623 if (resp.result == QSEOS_RESULT_FAILURE) {
624 return 0;
625 } else {
626 switch (resp.resp_type) {
627 /*qsee returned listener type response */
628 case QSEOS_LISTENER_ID:
629 pr_err("resp type is of listener type instead of app");
630 return -EINVAL;
631 break;
632 case QSEOS_APP_ID:
633 return resp.data;
634 default:
635 pr_err("invalid resp type (%d) from qsee",
636 resp.resp_type);
637 return -ENODEV;
638 break;
639 }
640 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700641}
642
Mona Hossain2892b6b2012-02-17 13:53:11 -0800643static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
644{
645 struct qseecom_registered_app_list *entry = NULL;
646 unsigned long flags = 0;
647 u32 app_id = 0;
648 struct ion_handle *ihandle; /* Ion handle */
649 struct qseecom_load_img_req load_img_req;
650 int32_t ret;
651 ion_phys_addr_t pa = 0;
652 uint32_t len;
653 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800654 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700655 struct qseecom_load_app_ireq load_req;
656
Mona Hossain2892b6b2012-02-17 13:53:11 -0800657 /* Copy the relevant information needed for loading the image */
658 if (__copy_from_user(&load_img_req,
659 (void __user *)argp,
660 sizeof(struct qseecom_load_img_req))) {
661 pr_err("copy_from_user failed\n");
662 return -EFAULT;
663 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700664 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800665 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700666 if (ret)
667 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800668 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
669 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800670
Mona Hossain436b75f2012-11-20 17:10:40 -0800671 ret = __qseecom_check_app_exists(req);
672 if (ret < 0)
673 return ret;
674 else
675 app_id = ret;
676
677 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700678 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800679 (char *)(req.app_name));
680 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
681 list_for_each_entry(entry,
682 &qseecom.registered_app_list_head, list){
683 if (entry->app_id == app_id) {
684 entry->ref_cnt++;
685 break;
686 }
687 }
688 spin_unlock_irqrestore(
689 &qseecom.registered_app_list_lock, flags);
690 } else {
691 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700692 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800693 /* Get the handle of the shared fd */
694 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800695 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800696 if (IS_ERR_OR_NULL(ihandle)) {
697 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800698 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800699 return -ENOMEM;
700 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800701
Mona Hossain436b75f2012-11-20 17:10:40 -0800702 /* Get the physical address of the ION BUF */
703 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800704
Mona Hossain436b75f2012-11-20 17:10:40 -0800705 /* Populate the structure for sending scm call to load image */
706 memcpy(load_req.app_name, load_img_req.img_name,
707 MAX_APP_NAME_SIZE);
708 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
709 load_req.mdt_len = load_img_req.mdt_len;
710 load_req.img_len = load_img_req.img_len;
711 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800712
Mona Hossain436b75f2012-11-20 17:10:40 -0800713 /* SCM_CALL to load the app and get the app_id back */
714 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700715 sizeof(struct qseecom_load_app_ireq),
716 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700717 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800718 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800719 if (!IS_ERR_OR_NULL(ihandle))
720 ion_free(qseecom.ion_clnt, ihandle);
721 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800722 return -EINVAL;
723 }
724
725 if (resp.result == QSEOS_RESULT_FAILURE) {
726 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700727 if (!IS_ERR_OR_NULL(ihandle))
728 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800729 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800730 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700731 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700732
Mona Hossain436b75f2012-11-20 17:10:40 -0800733 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
734 ret = __qseecom_process_incomplete_cmd(data, &resp);
735 if (ret) {
736 pr_err("process_incomplete_cmd failed err: %d\n",
737 ret);
738 if (!IS_ERR_OR_NULL(ihandle))
739 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800740 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800741 return ret;
742 }
743 }
744
745 if (resp.result != QSEOS_RESULT_SUCCESS) {
746 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700747 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800748 if (!IS_ERR_OR_NULL(ihandle))
749 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800750 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800751 return -EFAULT;
752 }
753
754 app_id = resp.data;
755
756 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
757 if (!entry) {
758 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800759 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800760 return -ENOMEM;
761 }
762 entry->app_id = app_id;
763 entry->ref_cnt = 1;
764
765 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700766 if (!IS_ERR_OR_NULL(ihandle))
767 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700768
Mona Hossain436b75f2012-11-20 17:10:40 -0800769 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
770 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
771 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
772 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700773
Mona Hossain436b75f2012-11-20 17:10:40 -0800774 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700775 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800776 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800777 data->client.app_id = app_id;
778 load_img_req.app_id = app_id;
779 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
780 pr_err("copy_to_user failed\n");
781 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800782 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800783 return -EFAULT;
784 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800785 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800786 return 0;
787}
788
789static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
790{
791 wake_up_all(&qseecom.send_resp_wq);
792 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700793 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800794 atomic_read(&data->ioctl_count) <= 1)) {
795 pr_err("Interrupted from abort\n");
796 return -ERESTARTSYS;
797 break;
798 }
799 }
800 /* Set unload app */
801 return 1;
802}
803
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800804static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
805{
806 int ret = 0;
807 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
808 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
809 ion_free(qseecom.ion_clnt, data->client.ihandle);
810 data->client.ihandle = NULL;
811 }
812 return ret;
813}
814
Mona Hossain2892b6b2012-02-17 13:53:11 -0800815static int qseecom_unload_app(struct qseecom_dev_handle *data)
816{
817 unsigned long flags;
818 int ret = 0;
819 struct qseecom_command_scm_resp resp;
820 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700821 bool unload = false;
822 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800823
Mona Hossain1fb538f2012-08-30 16:19:38 -0700824 if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
825 (data->client.app_id > 0)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800826 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
827 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
828 list) {
829 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700830 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800831 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700832 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800833 break;
834 } else {
835 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700836 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700837 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800838 break;
839 }
840 }
841 }
842 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
843 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700844 if (found_app == false) {
845 pr_err("Cannot find app with id = %d\n",
846 data->client.app_id);
847 return -EINVAL;
848 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800849 }
850
851 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
852 struct qseecom_unload_app_ireq req;
853
Mona Hossain340dba82012-08-07 19:54:46 -0700854 __qseecom_cleanup_app(data);
855 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
856 list_del(&ptr_app->list);
857 kzfree(ptr_app);
858 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
859 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800860 /* Populate the structure for sending scm call to load image */
861 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
862 req.app_id = data->client.app_id;
863
864 /* SCM_CALL to unload the app */
865 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
866 sizeof(struct qseecom_unload_app_ireq),
867 &resp, sizeof(resp));
868 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700869 pr_err("scm_call to unload app (id = %d) failed\n",
870 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800871 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700872 } else {
873 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800874 }
875 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
876 ret = __qseecom_process_incomplete_cmd(data, &resp);
877 if (ret) {
878 pr_err("process_incomplete_cmd fail err: %d\n",
879 ret);
880 return ret;
881 }
882 }
883 }
884
885 if (qseecom.qseos_version == QSEOS_VERSION_13) {
886 data->abort = 1;
887 wake_up_all(&qseecom.send_resp_wq);
888 while (atomic_read(&data->ioctl_count) > 0) {
Mona Hossainacea1022012-04-09 13:37:27 -0700889 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800890 atomic_read(&data->ioctl_count) <= 0)) {
891 pr_err("Interrupted from abort\n");
892 ret = -ERESTARTSYS;
893 break;
894 }
895 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800896 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800897 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800898 data->released = true;
899 return ret;
900}
901
902static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
903 uint32_t virt)
904{
905 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
906}
907
908static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
909 struct qseecom_send_cmd_req *req)
910{
911 int ret = 0;
912 unsigned long flags;
913 u32 reqd_len_sb_in = 0;
914 struct qseecom_command cmd;
915 struct qseecom_response resp;
916
917
918 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
919 pr_err("cmd buffer or response buffer is null\n");
920 return -EINVAL;
921 }
922
923 if (req->cmd_req_len <= 0 ||
924 req->resp_len <= 0 ||
925 req->cmd_req_len > data->client.sb_length ||
926 req->resp_len > data->client.sb_length) {
927 pr_err("cmd buffer length or "
928 "response buffer length not valid\n");
929 return -EINVAL;
930 }
931
932 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
933 if (reqd_len_sb_in > data->client.sb_length) {
934 pr_debug("Not enough memory to fit cmd_buf and "
935 "resp_buf. Required: %u, Available: %u\n",
936 reqd_len_sb_in, data->client.sb_length);
937 return -ENOMEM;
938 }
939 cmd.cmd_type = TZ_SCHED_CMD_NEW;
940 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
941 cmd.sb_in_cmd_len = req->cmd_req_len;
942
943 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
944 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
945 resp.sb_in_rsp_len = req->resp_len;
946
947 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
948 sizeof(cmd), &resp, sizeof(resp));
949
950 if (ret) {
951 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
952 return ret;
953 }
954
955 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
956 /*
957 * If cmd is incomplete, get the callback cmd out from SB out
958 * and put it on the list
959 */
960 struct qseecom_registered_listener_list *ptr_svc = NULL;
961 /*
962 * We don't know which service can handle the command. so we
963 * wake up all blocking services and let them figure out if
964 * they can handle the given command.
965 */
966 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
967 flags);
968 list_for_each_entry(ptr_svc,
969 &qseecom.registered_listener_list_head, list) {
970 ptr_svc->rcv_req_flag = 1;
971 wake_up_interruptible(&ptr_svc->rcv_req_wq);
972 }
973 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
974 flags);
975
976 pr_debug("waking up rcv_req_wq and "
977 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700978 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800979 __qseecom_listener_has_sent_rsp(data))) {
980 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
981 return -ERESTARTSYS;
982 }
983
984 if (data->abort) {
985 pr_err("Aborting driver\n");
986 return -ENODEV;
987 }
988 qseecom.send_resp_flag = 0;
989 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
990 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
991 sizeof(cmd), &resp, sizeof(resp));
992 if (ret) {
993 pr_err("qseecom_scm_call failed with err: %d\n", ret);
994 return ret;
995 }
996 }
997 return ret;
998}
999
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001000int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1001 struct qseecom_send_svc_cmd_req *req_ptr,
1002 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1003{
1004 int ret = 0;
1005 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1006 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1007 req_ptr, send_svc_ireq_ptr);
1008 return -EINVAL;
1009 }
1010 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1011 send_svc_ireq_ptr->key_type =
1012 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
1013 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1014 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1015 (uint32_t)req_ptr->resp_buf));
1016 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1017
1018 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1019 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1020 return ret;
1021}
1022
1023static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1024 void __user *argp)
1025{
1026 int ret = 0;
1027 struct qseecom_client_send_service_ireq send_svc_ireq;
1028 struct qseecom_command_scm_resp resp;
1029 struct qseecom_send_svc_cmd_req req;
1030 /*struct qseecom_command_scm_resp resp;*/
1031
1032 if (__copy_from_user(&req,
1033 (void __user *)argp,
1034 sizeof(req))) {
1035 pr_err("copy_from_user failed\n");
1036 return -EFAULT;
1037 }
1038
1039 if (req.resp_buf == NULL) {
1040 pr_err("cmd buffer or response buffer is null\n");
1041 return -EINVAL;
1042 }
1043
1044 data->type = QSEECOM_SECURE_SERVICE;
1045
1046 switch (req.cmd_id) {
1047 case QSEE_RPMB_PROVISION_KEY_COMMAND:
1048 case QSEE_RPMB_ERASE_COMMAND:
1049 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1050 &send_svc_ireq))
1051 return -EINVAL;
1052 break;
1053 default:
1054 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1055 return -EINVAL;
1056 }
1057
1058 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1059 sizeof(send_svc_ireq),
1060 &resp, sizeof(resp));
1061 if (ret) {
1062 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1063 return ret;
1064 }
1065
1066 switch (resp.result) {
1067 case QSEOS_RESULT_SUCCESS:
1068 break;
1069 case QSEOS_RESULT_INCOMPLETE:
1070 pr_err("qseos_result_incomplete\n");
1071 ret = __qseecom_process_incomplete_cmd(data, &resp);
1072 if (ret) {
1073 pr_err("process_incomplete_cmd fail: err: %d\n",
1074 ret);
1075 }
1076 break;
1077 case QSEOS_RESULT_FAILURE:
1078 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1079 break;
1080 default:
1081 pr_err("Response result %d not supported\n",
1082 resp.result);
1083 ret = -EINVAL;
1084 break;
1085 }
1086 return ret;
1087
1088}
1089
Mona Hossain2892b6b2012-02-17 13:53:11 -08001090static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1091 struct qseecom_send_cmd_req *req)
1092{
1093 int ret = 0;
1094 u32 reqd_len_sb_in = 0;
1095 struct qseecom_client_send_data_ireq send_data_req;
1096 struct qseecom_command_scm_resp resp;
1097
1098 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1099 pr_err("cmd buffer or response buffer is null\n");
1100 return -EINVAL;
1101 }
1102
1103 if (req->cmd_req_len <= 0 ||
1104 req->resp_len <= 0 ||
1105 req->cmd_req_len > data->client.sb_length ||
1106 req->resp_len > data->client.sb_length) {
1107 pr_err("cmd buffer length or "
1108 "response buffer length not valid\n");
1109 return -EINVAL;
1110 }
1111
1112 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1113 if (reqd_len_sb_in > data->client.sb_length) {
1114 pr_debug("Not enough memory to fit cmd_buf and "
1115 "resp_buf. Required: %u, Available: %u\n",
1116 reqd_len_sb_in, data->client.sb_length);
1117 return -ENOMEM;
1118 }
1119
1120 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1121 send_data_req.app_id = data->client.app_id;
1122 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1123 (uint32_t)req->cmd_req_buf));
1124 send_data_req.req_len = req->cmd_req_len;
1125 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1126 (uint32_t)req->resp_buf));
1127 send_data_req.rsp_len = req->resp_len;
1128
1129 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1130 sizeof(send_data_req),
1131 &resp, sizeof(resp));
1132 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001133 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1134 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001135 return ret;
1136 }
1137
1138 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1139 ret = __qseecom_process_incomplete_cmd(data, &resp);
1140 if (ret) {
1141 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1142 return ret;
1143 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001144 } else {
1145 if (resp.result != QSEOS_RESULT_SUCCESS) {
1146 pr_err("Response result %d not supported\n",
1147 resp.result);
1148 ret = -EINVAL;
1149 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001150 }
1151 return ret;
1152}
1153
1154
1155static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1156{
1157 int ret = 0;
1158 struct qseecom_send_cmd_req req;
1159
1160 ret = copy_from_user(&req, argp, sizeof(req));
1161 if (ret) {
1162 pr_err("copy_from_user failed\n");
1163 return ret;
1164 }
1165 if (qseecom.qseos_version == QSEOS_VERSION_14)
1166 ret = __qseecom_send_cmd(data, &req);
1167 else
1168 ret = __qseecom_send_cmd_legacy(data, &req);
1169 if (ret)
1170 return ret;
1171
1172 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1173 req.resp_len, req.resp_buf);
1174 return ret;
1175}
1176
1177static int __qseecom_send_cmd_req_clean_up(
1178 struct qseecom_send_modfd_cmd_req *req)
1179{
1180 char *field;
1181 uint32_t *update;
1182 int ret = 0;
1183 int i = 0;
1184
1185 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001186 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001187 field = (char *)req->cmd_req_buf +
1188 req->ifd_data[i].cmd_buf_offset;
1189 update = (uint32_t *) field;
1190 *update = 0;
1191 }
1192 }
1193 return ret;
1194}
1195
1196static int __qseecom_update_with_phy_addr(
1197 struct qseecom_send_modfd_cmd_req *req)
1198{
1199 struct ion_handle *ihandle;
1200 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001201 int ret = 0;
1202 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001203
1204 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001205 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001206 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001207 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001208 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001209 req->ifd_data[i].fd);
1210 if (IS_ERR_OR_NULL(ihandle)) {
1211 pr_err("Ion client can't retrieve the handle\n");
1212 return -ENOMEM;
1213 }
1214 field = (char *) req->cmd_req_buf +
1215 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001216
1217 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001218 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1219 if (sg_ptr == NULL) {
1220 pr_err("IOn client could not retrieve sg table\n");
1221 goto err;
1222 }
1223 if (sg_ptr->nents == 0) {
1224 pr_err("Num of scattered entries is 0\n");
1225 goto err;
1226 }
1227 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1228 pr_err("Num of scattered entries");
1229 pr_err(" (%d) is greater than max supported %d\n",
1230 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1231 goto err;
1232 }
1233 if (sg_ptr->nents == 1) {
1234 uint32_t *update;
1235 update = (uint32_t *) field;
1236 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
1237 } else {
1238 struct qseecom_sg_entry *update;
1239 struct scatterlist *sg;
1240 int j = 0;
1241 update = (struct qseecom_sg_entry *) field;
1242 sg = sg_ptr->sgl;
1243 for (j = 0; j < sg_ptr->nents; j++) {
1244 update->phys_addr = (uint32_t)
1245 sg_dma_address(sg);
1246 update->len = (uint32_t)sg->length;
1247 update++;
1248 sg = sg_next(sg);
1249 }
1250 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001251 /* Deallocate the handle */
1252 if (!IS_ERR_OR_NULL(ihandle))
1253 ion_free(qseecom.ion_clnt, ihandle);
1254 }
1255 }
1256 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001257err:
1258 if (!IS_ERR_OR_NULL(ihandle))
1259 ion_free(qseecom.ion_clnt, ihandle);
1260 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001261}
1262
1263static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1264 void __user *argp)
1265{
1266 int ret = 0;
1267 struct qseecom_send_modfd_cmd_req req;
1268 struct qseecom_send_cmd_req send_cmd_req;
1269
1270 ret = copy_from_user(&req, argp, sizeof(req));
1271 if (ret) {
1272 pr_err("copy_from_user failed\n");
1273 return ret;
1274 }
1275 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1276 send_cmd_req.cmd_req_len = req.cmd_req_len;
1277 send_cmd_req.resp_buf = req.resp_buf;
1278 send_cmd_req.resp_len = req.resp_len;
1279
1280 ret = __qseecom_update_with_phy_addr(&req);
1281 if (ret)
1282 return ret;
1283 if (qseecom.qseos_version == QSEOS_VERSION_14)
1284 ret = __qseecom_send_cmd(data, &send_cmd_req);
1285 else
1286 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1287 __qseecom_send_cmd_req_clean_up(&req);
1288
1289 if (ret)
1290 return ret;
1291
1292 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1293 req.resp_len, req.resp_buf);
1294 return ret;
1295}
1296
1297static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1298 struct qseecom_registered_listener_list *svc)
1299{
1300 int ret;
1301 ret = (svc->rcv_req_flag != 0);
1302 return ret || data->abort;
1303}
1304
1305static int qseecom_receive_req(struct qseecom_dev_handle *data)
1306{
1307 int ret = 0;
1308 struct qseecom_registered_listener_list *this_lstnr;
1309
1310 this_lstnr = __qseecom_find_svc(data->listener.id);
1311 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001312 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001313 __qseecom_listener_has_rcvd_req(data,
1314 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001315 pr_warning("Interrupted: exiting Listener Service = %d\n",
1316 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001317 /* woken up for different reason */
1318 return -ERESTARTSYS;
1319 }
1320
1321 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001322 pr_err("Aborting Listener Service = %d\n",
1323 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001324 return -ENODEV;
1325 }
1326 this_lstnr->rcv_req_flag = 0;
1327 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1328 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1329 break;
1330 } else {
1331 break;
1332 }
1333 }
1334 return ret;
1335}
1336
Mona Hossaind44a3842012-10-15 09:41:35 -07001337static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1338{
1339 struct elf32_hdr *ehdr;
1340
1341 if (fw_entry->size < sizeof(*ehdr)) {
1342 pr_err("%s: Not big enough to be an elf header\n",
1343 qseecom.pdev->init_name);
1344 return false;
1345 }
1346 ehdr = (struct elf32_hdr *)fw_entry->data;
1347 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1348 pr_err("%s: Not an elf header\n",
1349 qseecom.pdev->init_name);
1350 return false;
1351 }
1352
1353 if (ehdr->e_phnum == 0) {
1354 pr_err("%s: No loadable segments\n",
1355 qseecom.pdev->init_name);
1356 return false;
1357 }
1358 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1359 sizeof(struct elf32_hdr) > fw_entry->size) {
1360 pr_err("%s: Program headers not within mdt\n",
1361 qseecom.pdev->init_name);
1362 return false;
1363 }
1364 return true;
1365}
1366
1367static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1368{
1369 int ret = -1;
1370 int i = 0, rc = 0;
1371 const struct firmware *fw_entry = NULL;
1372 struct elf32_phdr *phdr;
1373 char fw_name[MAX_APP_NAME_SIZE];
1374 struct elf32_hdr *ehdr;
1375 int num_images = 0;
1376
1377 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1378 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1379 if (rc) {
1380 pr_err("error with request_firmware\n");
1381 ret = -EIO;
1382 goto err;
1383 }
1384 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1385 ret = -EIO;
1386 goto err;
1387 }
1388 *fw_size = fw_entry->size;
1389 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1390 ehdr = (struct elf32_hdr *)fw_entry->data;
1391 num_images = ehdr->e_phnum;
1392 release_firmware(fw_entry);
1393 for (i = 0; i < num_images; i++, phdr++) {
1394 memset(fw_name, 0, sizeof(fw_name));
1395 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1396 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1397 if (ret)
1398 goto err;
1399 *fw_size += fw_entry->size;
1400 release_firmware(fw_entry);
1401 }
1402 return ret;
1403err:
1404 if (fw_entry)
1405 release_firmware(fw_entry);
1406 *fw_size = 0;
1407 return ret;
1408}
1409
1410static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1411 struct qseecom_load_app_ireq *load_req)
1412{
1413 int ret = -1;
1414 int i = 0, rc = 0;
1415 const struct firmware *fw_entry = NULL;
1416 char fw_name[MAX_APP_NAME_SIZE];
1417 u8 *img_data_ptr = img_data;
1418 struct elf32_hdr *ehdr;
1419 int num_images = 0;
1420
1421 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1422 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1423 if (rc) {
1424 ret = -EIO;
1425 goto err;
1426 }
1427 load_req->img_len = fw_entry->size;
1428 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1429 img_data_ptr = img_data_ptr + fw_entry->size;
1430 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1431 ehdr = (struct elf32_hdr *)fw_entry->data;
1432 num_images = ehdr->e_phnum;
1433 release_firmware(fw_entry);
1434 for (i = 0; i < num_images; i++) {
1435 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1436 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1437 if (ret) {
1438 pr_err("Failed to locate blob %s\n", fw_name);
1439 goto err;
1440 }
1441 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1442 img_data_ptr = img_data_ptr + fw_entry->size;
1443 load_req->img_len += fw_entry->size;
1444 release_firmware(fw_entry);
1445 }
1446 load_req->phy_addr = virt_to_phys(img_data);
1447 return ret;
1448err:
1449 release_firmware(fw_entry);
1450 return ret;
1451}
1452
1453static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1454{
1455 int ret = -1;
1456 uint32_t fw_size = 0;
1457 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1458 struct qseecom_command_scm_resp resp;
1459 u8 *img_data = NULL;
1460
1461 if (__qseecom_get_fw_size(appname, &fw_size))
1462 return -EIO;
1463
1464 img_data = kzalloc(fw_size, GFP_KERNEL);
1465 if (!img_data) {
1466 pr_err("Failied to allocate memory for copying image data\n");
1467 return -ENOMEM;
1468 }
1469 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1470 if (ret) {
1471 kzfree(img_data);
1472 return -EIO;
1473 }
1474
1475 /* Populate the remaining parameters */
1476 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1477 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001478 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001479 if (ret) {
1480 kzfree(img_data);
1481 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001482 return -EIO;
1483 }
1484
Mona Hossaind44a3842012-10-15 09:41:35 -07001485 /* SCM_CALL to load the image */
1486 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1487 sizeof(struct qseecom_load_app_ireq),
1488 &resp, sizeof(resp));
1489 kzfree(img_data);
1490 if (ret) {
1491 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001492 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001493 return -EIO;
1494 }
1495
1496 switch (resp.result) {
1497 case QSEOS_RESULT_SUCCESS:
1498 ret = resp.data;
1499 break;
1500 case QSEOS_RESULT_INCOMPLETE:
1501 ret = __qseecom_process_incomplete_cmd(data, &resp);
1502 if (ret)
1503 pr_err("process_incomplete_cmd FAILED\n");
1504 else
1505 ret = resp.data;
1506 break;
1507 case QSEOS_RESULT_FAILURE:
1508 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1509 break;
1510 default:
1511 pr_err("scm call return unknown response %d\n", resp.result);
1512 ret = -EINVAL;
1513 break;
1514 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001515 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001516
Mona Hossaind44a3842012-10-15 09:41:35 -07001517 return ret;
1518}
1519
Mona Hossain9498f5e2013-01-23 18:08:45 -08001520static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001521{
1522 int32_t ret = 0;
1523 uint32_t fw_size = 0;
1524 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1525 struct qseecom_command_scm_resp resp;
1526 u8 *img_data = NULL;
1527
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001528 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001529 return -EIO;
1530
1531 img_data = kzalloc(fw_size, GFP_KERNEL);
1532 if (!img_data) {
1533 pr_err("Mem allocation for lib image data failed\n");
1534 return -ENOMEM;
1535 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001536 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001537 if (ret) {
1538 kzfree(img_data);
1539 return -EIO;
1540 }
1541 /* Populate the remaining parameters */
1542 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001543 /* Vote for the SFPB clock */
1544 ret = qsee_vote_for_clock(data, CLK_SFPB);
1545 if (ret) {
1546 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1547 kzfree(img_data);
1548 return -EIO;
1549 }
1550
Mona Hossain05c73562012-10-29 17:49:01 -07001551 /* SCM_CALL to load the image */
1552 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1553 sizeof(struct qseecom_load_lib_image_ireq),
1554 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001555 if (ret) {
1556 pr_err("scm_call to load failed : ret %d\n", ret);
1557 ret = -EIO;
1558 } else {
1559 switch (resp.result) {
1560 case QSEOS_RESULT_SUCCESS:
1561 break;
1562 case QSEOS_RESULT_FAILURE:
1563 pr_err("scm call failed w/response result%d\n",
1564 resp.result);
1565 ret = -EINVAL;
1566 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001567 case QSEOS_RESULT_INCOMPLETE:
1568 ret = __qseecom_process_incomplete_cmd(data, &resp);
1569 if (ret)
1570 pr_err("process_incomplete_cmd failed err: %d\n",
1571 ret);
1572 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001573 default:
1574 pr_err("scm call return unknown response %d\n",
1575 resp.result);
1576 ret = -EINVAL;
1577 break;
1578 }
1579 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001580 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001581 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001582 return ret;
1583}
1584
1585static int qseecom_unload_commonlib_image(void)
1586{
1587 int ret = -EINVAL;
1588 struct qseecom_unload_lib_image_ireq unload_req = {0};
1589 struct qseecom_command_scm_resp resp;
1590
1591 /* Populate the remaining parameters */
1592 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1593 /* SCM_CALL to load the image */
1594 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1595 sizeof(struct qseecom_unload_lib_image_ireq),
1596 &resp, sizeof(resp));
1597 if (ret) {
1598 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1599 ret = -EIO;
1600 } else {
1601 switch (resp.result) {
1602 case QSEOS_RESULT_SUCCESS:
1603 break;
1604 case QSEOS_RESULT_FAILURE:
1605 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1606 break;
1607 default:
1608 pr_err("scm call return unknown response %d\n",
1609 resp.result);
1610 ret = -EINVAL;
1611 break;
1612 }
1613 }
1614 return ret;
1615}
1616
Mona Hossaind44a3842012-10-15 09:41:35 -07001617int qseecom_start_app(struct qseecom_handle **handle,
1618 char *app_name, uint32_t size)
1619{
Mona Hossain05c73562012-10-29 17:49:01 -07001620 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001621 unsigned long flags = 0;
1622 struct qseecom_dev_handle *data = NULL;
1623 struct qseecom_check_app_ireq app_ireq;
1624 struct qseecom_registered_app_list *entry = NULL;
1625 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1626 bool found_app = false;
1627 uint32_t len;
1628 ion_phys_addr_t pa;
1629
1630 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1631 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1632 return -EINVAL;
1633 }
1634
Mona Hossain823f9882012-11-23 14:42:20 -08001635 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1636 if (!(*handle)) {
1637 pr_err("failed to allocate memory for kernel client handle\n");
1638 return -ENOMEM;
1639 }
1640
Mona Hossaind44a3842012-10-15 09:41:35 -07001641 data = kzalloc(sizeof(*data), GFP_KERNEL);
1642 if (!data) {
1643 pr_err("kmalloc failed\n");
1644 if (ret == 0) {
1645 kfree(*handle);
1646 *handle = NULL;
1647 }
1648 return -ENOMEM;
1649 }
1650 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001651 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001652 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001653 data->client.sb_length = size;
1654 data->client.user_virt_sb_base = 0;
1655 data->client.ihandle = NULL;
1656
1657 init_waitqueue_head(&data->abort_wq);
1658 atomic_set(&data->ioctl_count, 0);
1659
1660 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1661 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1662 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1663 pr_err("Ion client could not retrieve the handle\n");
1664 kfree(data);
1665 kfree(*handle);
1666 *handle = NULL;
1667 return -EINVAL;
1668 }
1669
Mona Hossain9498f5e2013-01-23 18:08:45 -08001670 if (qseecom.qsee_version > QSEEE_VERSION_00) {
1671 mutex_lock(&app_access_lock);
1672 if (qseecom.commonlib_loaded == false) {
1673 ret = qseecom_load_commonlib_image(data);
1674 if (ret == 0)
1675 qseecom.commonlib_loaded = true;
1676 }
1677 mutex_unlock(&app_access_lock);
1678 }
1679
1680 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001681 pr_err("Failed to load commonlib image\n");
Mona Hossain9498f5e2013-01-23 18:08:45 -08001682 kfree(data);
1683 kfree(*handle);
1684 *handle = NULL;
1685 return -EIO;
1686 }
1687
1688 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1689 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1690 ret = __qseecom_check_app_exists(app_ireq);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001691 if (ret < 0) {
1692 kzfree(data);
1693 kfree(*handle);
1694 *handle = NULL;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001695 return -EINVAL;
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001696 }
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001697 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001698 if (ret > 0) {
1699 pr_warn("App id %d for [%s] app exists\n", ret,
1700 (char *)app_ireq.app_name);
1701 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1702 list_for_each_entry(entry,
1703 &qseecom.registered_app_list_head, list){
1704 if (entry->app_id == ret) {
1705 entry->ref_cnt++;
1706 found_app = true;
1707 break;
1708 }
1709 }
1710 spin_unlock_irqrestore(
1711 &qseecom.registered_app_list_lock, flags);
1712 if (!found_app)
1713 pr_warn("App_id %d [%s] was loaded but not registered\n",
1714 ret, (char *)app_ireq.app_name);
1715 } else {
1716 /* load the app and get the app_id */
1717 pr_debug("%s: Loading app for the first time'\n",
1718 qseecom.pdev->init_name);
1719 mutex_lock(&app_access_lock);
1720 ret = __qseecom_load_fw(data, app_name);
1721 mutex_unlock(&app_access_lock);
1722
1723 if (ret < 0) {
1724 kfree(*handle);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001725 kfree(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001726 *handle = NULL;
1727 return ret;
1728 }
1729 data->client.app_id = ret;
1730 }
1731 if (!found_app) {
1732 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1733 if (!entry) {
1734 pr_err("kmalloc failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001735 kfree(data);
1736 kfree(*handle);
1737 *handle = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001738 return -ENOMEM;
1739 }
1740 entry->app_id = ret;
1741 entry->ref_cnt = 1;
1742
1743 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1744 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1745 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1746 flags);
1747 }
1748
1749 /* Get the physical address of the ION BUF */
1750 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1751 /* Populate the structure for sending scm call to load image */
1752 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1753 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001754 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001755 data->client.sb_phys = pa;
1756 (*handle)->dev = (void *)data;
1757 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1758 (*handle)->sbuf_len = data->client.sb_length;
1759
1760 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1761 if (!kclient_entry) {
1762 pr_err("kmalloc failed\n");
1763 return -ENOMEM;
1764 }
1765 kclient_entry->handle = *handle;
1766
1767 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1768 list_add_tail(&kclient_entry->list,
1769 &qseecom.registered_kclient_list_head);
1770 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1771
1772 return 0;
1773}
1774EXPORT_SYMBOL(qseecom_start_app);
1775
1776int qseecom_shutdown_app(struct qseecom_handle **handle)
1777{
1778 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001779 struct qseecom_dev_handle *data;
1780
Mona Hossaind44a3842012-10-15 09:41:35 -07001781 struct qseecom_registered_kclient_list *kclient = NULL;
1782 unsigned long flags = 0;
1783 bool found_handle = false;
1784
1785 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1786 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1787 return -EINVAL;
1788 }
Mona Hossain33824022013-02-25 09:32:33 -08001789 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001790 pr_err("Handle is not initialized\n");
1791 return -EINVAL;
1792 }
Mona Hossain33824022013-02-25 09:32:33 -08001793 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001794 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1795 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1796 list) {
1797 if (kclient->handle == (*handle)) {
1798 list_del(&kclient->list);
1799 found_handle = true;
1800 break;
1801 }
1802 }
1803 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1804 if (!found_handle)
1805 pr_err("Unable to find the handle, exiting\n");
1806 else
1807 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001808 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001809 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001810 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001811 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001812 if (ret == 0) {
1813 kzfree(data);
1814 kzfree(*handle);
1815 kzfree(kclient);
1816 *handle = NULL;
1817 }
1818 return ret;
1819}
1820EXPORT_SYMBOL(qseecom_shutdown_app);
1821
1822int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1823 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1824{
1825 int ret = 0;
1826 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1827 struct qseecom_dev_handle *data;
1828
1829 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1830 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1831 return -EINVAL;
1832 }
1833
1834 if (handle == NULL) {
1835 pr_err("Handle is not initialized\n");
1836 return -EINVAL;
1837 }
1838 data = handle->dev;
1839
1840 req.cmd_req_len = sbuf_len;
1841 req.resp_len = rbuf_len;
1842 req.cmd_req_buf = send_buf;
1843 req.resp_buf = resp_buf;
1844
1845 mutex_lock(&app_access_lock);
1846 atomic_inc(&data->ioctl_count);
1847
1848 ret = __qseecom_send_cmd(data, &req);
1849
1850 atomic_dec(&data->ioctl_count);
1851 mutex_unlock(&app_access_lock);
1852
1853 if (ret)
1854 return ret;
1855
1856 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1857 req.resp_len, req.resp_buf);
1858 return ret;
1859}
1860EXPORT_SYMBOL(qseecom_send_command);
1861
Mona Hossain91a8fc92012-11-07 19:58:30 -08001862int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1863{
Mona Hossainfca6f422013-01-12 13:00:35 -08001864 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001865 if ((handle == NULL) || (handle->dev == NULL)) {
1866 pr_err("No valid kernel client\n");
1867 return -EINVAL;
1868 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001869 if (high) {
1870 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1871 if (ret)
1872 pr_err("Failed to vote for DFAB clock%d\n", ret);
1873 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1874 if (ret) {
1875 pr_err("Failed to vote for SFPB clock%d\n", ret);
1876 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1877 }
1878 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001879 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001880 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001881 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001882 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001883}
1884EXPORT_SYMBOL(qseecom_set_bandwidth);
1885
Mona Hossain2892b6b2012-02-17 13:53:11 -08001886static int qseecom_send_resp(void)
1887{
1888 qseecom.send_resp_flag = 1;
1889 wake_up_interruptible(&qseecom.send_resp_wq);
1890 return 0;
1891}
1892
1893static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1894 void __user *argp)
1895{
1896 struct qseecom_qseos_version_req req;
1897
1898 if (copy_from_user(&req, argp, sizeof(req))) {
1899 pr_err("copy_from_user failed");
1900 return -EINVAL;
1901 }
1902 req.qseos_version = qseecom.qseos_version;
1903 if (copy_to_user(argp, &req, sizeof(req))) {
1904 pr_err("copy_to_user failed");
1905 return -EINVAL;
1906 }
1907 return 0;
1908}
1909
Mona Hossainc92629e2013-04-01 13:37:46 -07001910static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001911{
1912 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001913 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001914
Mona Hossainc92629e2013-04-01 13:37:46 -07001915 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001916 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001917 else
1918 qclk = &qseecom.ce_drv;
1919
1920 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001921
1922 if (qclk->clk_access_cnt == ULONG_MAX)
1923 goto err;
1924
Mona Hossainc92629e2013-04-01 13:37:46 -07001925 if (qclk->clk_access_cnt > 0) {
1926 qclk->clk_access_cnt++;
1927 mutex_unlock(&clk_access_lock);
1928 return rc;
1929 }
1930
Mona Hossain6311d572013-03-01 15:54:02 -08001931 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001932 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001933 if (rc) {
1934 pr_err("Unable to enable/prepare CE core clk\n");
1935 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001936 }
1937 /* Enable CE clk */
1938 rc = clk_prepare_enable(qclk->ce_clk);
1939 if (rc) {
1940 pr_err("Unable to enable/prepare CE iface clk\n");
1941 goto ce_clk_err;
1942 }
1943 /* Enable AXI clk */
1944 rc = clk_prepare_enable(qclk->ce_bus_clk);
1945 if (rc) {
1946 pr_err("Unable to enable/prepare CE bus clk\n");
1947 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001948 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001949 qclk->clk_access_cnt++;
1950 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001951 return 0;
1952
1953ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001954 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001955ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001956 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001957err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001958 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001959 return -EIO;
1960}
1961
Mona Hossainc92629e2013-04-01 13:37:46 -07001962static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001963{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001964 struct qseecom_clk *qclk;
1965
Mona Hossainc92629e2013-04-01 13:37:46 -07001966 if (ce == CLK_QSEE)
1967 qclk = &qseecom.qsee;
1968 else
1969 qclk = &qseecom.ce_drv;
1970
1971 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001972
1973 if (qclk->clk_access_cnt == 0) {
1974 mutex_unlock(&clk_access_lock);
1975 return;
1976 }
1977
Mona Hossainc92629e2013-04-01 13:37:46 -07001978 if (qclk->clk_access_cnt == 1) {
1979 if (qclk->ce_clk != NULL)
1980 clk_disable_unprepare(qclk->ce_clk);
1981 if (qclk->ce_core_clk != NULL)
1982 clk_disable_unprepare(qclk->ce_core_clk);
1983 if (qclk->ce_bus_clk != NULL)
1984 clk_disable_unprepare(qclk->ce_bus_clk);
1985 }
1986 qclk->clk_access_cnt--;
1987 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001988}
1989
Mona Hossain04d3fac2012-12-03 10:10:37 -08001990static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1991 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001992{
1993 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001994 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001995
Mona Hossain17a4faf2013-03-22 16:40:56 -07001996 qclk = &qseecom.qsee;
1997 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001998 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001999
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002000 switch (clk_type) {
2001 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002002 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002003 if (!qseecom.qsee_bw_count) {
2004 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002005 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002006 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002007 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002008 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002009 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002010 if (!ret) {
2011 ret =
2012 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002013 qseecom.qsee_perf_client, 1);
2014 if ((ret) &&
2015 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002016 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002017 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002018 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002019 if (ret)
2020 pr_err("DFAB Bandwidth req failed (%d)\n",
2021 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002022 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002023 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002024 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002025 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002026 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002027 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002028 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002029 }
2030 mutex_unlock(&qsee_bw_mutex);
2031 break;
2032 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002033 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002034 if (!qseecom.qsee_sfpb_bw_count) {
2035 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002036 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002037 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002038 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002039 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002040 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002041 if (!ret) {
2042 ret =
2043 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002044 qseecom.qsee_perf_client, 2);
2045 if ((ret) &&
2046 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002047 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002048 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002049 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002050
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002051 if (ret)
2052 pr_err("SFPB Bandwidth req failed (%d)\n",
2053 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002054 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002055 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002056 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002057 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002058 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002059 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002060 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002061 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002062 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002063 break;
2064 default:
2065 pr_err("Clock type not defined\n");
2066 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002067 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002068 return ret;
2069}
2070
Mona Hossain04d3fac2012-12-03 10:10:37 -08002071static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2072 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002073{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002074 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002075 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002076
Mona Hossain17a4faf2013-03-22 16:40:56 -07002077 qclk = &qseecom.qsee;
2078 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002079 return;
2080
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002081 switch (clk_type) {
2082 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002083 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002084 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002085 pr_err("Client error.Extra call to disable DFAB clk\n");
2086 mutex_unlock(&qsee_bw_mutex);
2087 return;
2088 }
2089
Mona Hossain17a4faf2013-03-22 16:40:56 -07002090 if (qseecom.qsee_bw_count == 1) {
2091 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002092 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002093 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002094 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002095 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002096 qseecom.qsee_perf_client, 0);
2097 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002098 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002099 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002100 if (ret)
2101 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002102 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002103 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002104 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002105 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002106 }
2107 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002108 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002109 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002110 }
2111 mutex_unlock(&qsee_bw_mutex);
2112 break;
2113 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002114 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002115 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002116 pr_err("Client error.Extra call to disable SFPB clk\n");
2117 mutex_unlock(&qsee_bw_mutex);
2118 return;
2119 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002120 if (qseecom.qsee_sfpb_bw_count == 1) {
2121 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002122 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002123 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002124 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002125 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002126 qseecom.qsee_perf_client, 0);
2127 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002128 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002129 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002130 if (ret)
2131 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002132 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002133 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002134 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002135 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002136 }
2137 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002138 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002139 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002140 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002141 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002142 break;
2143 default:
2144 pr_err("Clock type not defined\n");
2145 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002146 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002147
Mona Hossain2892b6b2012-02-17 13:53:11 -08002148}
2149
Mona Hossain5ab9d772012-04-11 21:00:40 -07002150static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2151 void __user *argp)
2152{
2153 struct ion_handle *ihandle; /* Ion handle */
2154 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002155 int ret;
2156 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002157 ion_phys_addr_t pa = 0;
2158 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002159 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002160 struct qseecom_load_app_ireq load_req;
2161 struct qseecom_command_scm_resp resp;
2162
2163 /* Copy the relevant information needed for loading the image */
2164 if (__copy_from_user(&load_img_req,
2165 (void __user *)argp,
2166 sizeof(struct qseecom_load_img_req))) {
2167 pr_err("copy_from_user failed\n");
2168 return -EFAULT;
2169 }
2170
2171 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002172 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002173 load_img_req.ifd_data_fd);
2174 if (IS_ERR_OR_NULL(ihandle)) {
2175 pr_err("Ion client could not retrieve the handle\n");
2176 return -ENOMEM;
2177 }
2178
2179 /* Get the physical address of the ION BUF */
2180 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2181
2182 /* Populate the structure for sending scm call to load image */
2183 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2184 load_req.mdt_len = load_img_req.mdt_len;
2185 load_req.img_len = load_img_req.img_len;
2186 load_req.phy_addr = pa;
2187
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002188 /* SCM_CALL tied to Core0 */
2189 mask = CPU_MASK_CPU0;
2190 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2191 if (set_cpu_ret) {
2192 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2193 set_cpu_ret);
2194 ret = -EFAULT;
2195 goto qseecom_load_external_elf_set_cpu_err;
2196 }
Mona Hossain6311d572013-03-01 15:54:02 -08002197 /* Vote for the SFPB clock */
2198 ret = qsee_vote_for_clock(data, CLK_SFPB);
2199 if (ret) {
2200 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2201 ret = -EIO;
2202 goto qseecom_load_external_elf_set_cpu_err;
2203 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002204
Mona Hossain5ab9d772012-04-11 21:00:40 -07002205 /* SCM_CALL to load the external elf */
2206 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2207 sizeof(struct qseecom_load_app_ireq),
2208 &resp, sizeof(resp));
2209 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002210 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002211 ret);
2212 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002213 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002214 }
2215
2216 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2217 ret = __qseecom_process_incomplete_cmd(data, &resp);
2218 if (ret)
2219 pr_err("process_incomplete_cmd failed err: %d\n",
2220 ret);
2221 } else {
2222 if (resp.result != QSEOS_RESULT_SUCCESS) {
2223 pr_err("scm_call to load image failed resp.result =%d\n",
2224 resp.result);
2225 ret = -EFAULT;
2226 }
2227 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002228
2229qseecom_load_external_elf_scm_err:
2230 /* Restore the CPU mask */
2231 mask = CPU_MASK_ALL;
2232 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2233 if (set_cpu_ret) {
2234 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2235 set_cpu_ret);
2236 ret = -EFAULT;
2237 }
2238
2239qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002240 /* Deallocate the handle */
2241 if (!IS_ERR_OR_NULL(ihandle))
2242 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002243 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002244 return ret;
2245}
2246
2247static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2248{
2249 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002250 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002251 struct qseecom_command_scm_resp resp;
2252 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002253 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002254
2255 /* Populate the structure for sending scm call to unload image */
2256 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002257
2258 /* SCM_CALL tied to Core0 */
2259 mask = CPU_MASK_CPU0;
2260 ret = set_cpus_allowed_ptr(current, &mask);
2261 if (ret) {
2262 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2263 ret);
2264 return -EFAULT;
2265 }
2266
Mona Hossain5ab9d772012-04-11 21:00:40 -07002267 /* SCM_CALL to unload the external elf */
2268 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2269 sizeof(struct qseecom_unload_app_ireq),
2270 &resp, sizeof(resp));
2271 if (ret) {
2272 pr_err("scm_call to unload failed : ret %d\n",
2273 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002274 ret = -EFAULT;
2275 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002276 }
2277 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2278 ret = __qseecom_process_incomplete_cmd(data, &resp);
2279 if (ret)
2280 pr_err("process_incomplete_cmd fail err: %d\n",
2281 ret);
2282 } else {
2283 if (resp.result != QSEOS_RESULT_SUCCESS) {
2284 pr_err("scm_call to unload image failed resp.result =%d\n",
2285 resp.result);
2286 ret = -EFAULT;
2287 }
2288 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002289
2290qseecom_unload_external_elf_scm_err:
2291 /* Restore the CPU mask */
2292 mask = CPU_MASK_ALL;
2293 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2294 if (set_cpu_ret) {
2295 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2296 set_cpu_ret);
2297 ret = -EFAULT;
2298 }
2299
Mona Hossain5ab9d772012-04-11 21:00:40 -07002300 return ret;
2301}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002302
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002303static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2304 void __user *argp)
2305{
2306
2307 int32_t ret;
2308 struct qseecom_qseos_app_load_query query_req;
2309 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002310 struct qseecom_registered_app_list *entry = NULL;
2311 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002312
2313 /* Copy the relevant information needed for loading the image */
2314 if (__copy_from_user(&query_req,
2315 (void __user *)argp,
2316 sizeof(struct qseecom_qseos_app_load_query))) {
2317 pr_err("copy_from_user failed\n");
2318 return -EFAULT;
2319 }
2320
2321 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2322 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2323
2324 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002325
2326 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002327 pr_err(" scm call to check if app is loaded failed");
2328 return ret; /* scm call failed */
2329 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002330 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002331 (char *)(req.app_name));
2332 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2333 list_for_each_entry(entry,
2334 &qseecom.registered_app_list_head, list){
2335 if (entry->app_id == ret) {
2336 entry->ref_cnt++;
2337 break;
2338 }
2339 }
2340 spin_unlock_irqrestore(
2341 &qseecom.registered_app_list_lock, flags);
2342 data->client.app_id = ret;
2343 query_req.app_id = ret;
2344
2345 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2346 pr_err("copy_to_user failed\n");
2347 return -EFAULT;
2348 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002349 return -EEXIST; /* app already loaded */
2350 } else {
2351 return 0; /* app not loaded */
2352 }
2353}
2354
Mona Hossain4cf78a92013-02-14 12:06:41 -08002355static int __qseecom_get_ce_pipe_info(
2356 enum qseecom_key_management_usage_type usage,
2357 uint32_t *pipe, uint32_t *ce_hw)
2358{
2359 int ret;
2360 switch (usage) {
2361 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2362 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2363 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2364 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2365 qseecom.ce_info.disk_encrypt_pipe,
2366 qseecom.ce_info.hlos_ce_hw_instance);
2367 ret = -EINVAL;
2368 } else {
2369 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2370 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2371 ret = 0;
2372 }
2373 break;
2374 default:
2375 ret = -EINVAL;
2376 break;
2377 }
2378 return ret;
2379}
2380
2381static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2382 enum qseecom_key_management_usage_type usage,
2383 uint8_t *key_id, uint32_t flags)
2384{
2385 struct qseecom_key_generate_ireq ireq;
2386 struct qseecom_command_scm_resp resp;
2387 int ret;
2388
2389 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2390 pr_err("Error:: unsupported usage %d\n", usage);
2391 return -EFAULT;
2392 }
2393
2394 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2395 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002396 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002397
Mona Hossainc92629e2013-04-01 13:37:46 -07002398 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002399
2400 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002401 &ireq, sizeof(struct qseecom_key_generate_ireq),
2402 &resp, sizeof(resp));
2403 if (ret) {
2404 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002405 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002406 return ret;
2407 }
2408
2409 switch (resp.result) {
2410 case QSEOS_RESULT_SUCCESS:
2411 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002412 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
2413 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002414 case QSEOS_RESULT_INCOMPLETE:
2415 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002416 if (ret) {
2417 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
2418 pr_warn("process_incomplete_cmd return Key ID exits.\n");
2419 ret = 0;
2420 } else {
2421 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2422 resp.result);
2423 }
2424 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002425 break;
2426 case QSEOS_RESULT_FAILURE:
2427 default:
2428 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2429 ret = -EINVAL;
2430 break;
2431 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002432 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002433 return ret;
2434}
2435
2436static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2437 enum qseecom_key_management_usage_type usage,
2438 uint8_t *key_id, uint32_t flags)
2439{
2440 struct qseecom_key_delete_ireq ireq;
2441 struct qseecom_command_scm_resp resp;
2442 int ret;
2443
2444 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2445 pr_err("Error:: unsupported usage %d\n", usage);
2446 return -EFAULT;
2447 }
2448
2449 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2450 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002451 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002452
Mona Hossainc92629e2013-04-01 13:37:46 -07002453 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002454
2455 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002456 &ireq, sizeof(struct qseecom_key_delete_ireq),
2457 &resp, sizeof(struct qseecom_command_scm_resp));
2458 if (ret) {
2459 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002460 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002461 return ret;
2462 }
2463
2464 switch (resp.result) {
2465 case QSEOS_RESULT_SUCCESS:
2466 break;
2467 case QSEOS_RESULT_INCOMPLETE:
2468 ret = __qseecom_process_incomplete_cmd(data, &resp);
2469 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002470 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2471 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002472 break;
2473 case QSEOS_RESULT_FAILURE:
2474 default:
2475 pr_err("Delete key scm call failed resp.result %d\n",
2476 resp.result);
2477 ret = -EINVAL;
2478 break;
2479 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002480 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002481 return ret;
2482}
2483
2484static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2485 enum qseecom_key_management_usage_type usage,
2486 struct qseecom_set_key_parameter *set_key_para)
2487{
2488 struct qseecom_key_select_ireq ireq;
2489 struct qseecom_command_scm_resp resp;
2490 int ret;
2491
2492 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2493 pr_err("Error:: unsupported usage %d\n", usage);
2494 return -EFAULT;
2495 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002496
2497 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2498 __qseecom_enable_clk(CLK_QSEE);
2499 else
2500 __qseecom_enable_clk(CLK_CE_DRV);
2501
Mona Hossain4cf78a92013-02-14 12:06:41 -08002502 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002503 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002504 ireq.ce = set_key_para->ce_hw;
2505 ireq.pipe = set_key_para->pipe;
2506 ireq.flags = set_key_para->flags;
2507
Zhen Kong1f09c7692013-05-03 17:50:32 -07002508 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2509 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002510
Mona Hossain4cf78a92013-02-14 12:06:41 -08002511 if (set_key_para->set_clear_key_flag ==
2512 QSEECOM_SET_CE_KEY_CMD)
2513 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2514 QSEECOM_HASH_SIZE);
2515 else
2516 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2517
Zhen Kong336636e2013-04-15 11:04:54 -07002518 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002519 &ireq, sizeof(struct qseecom_key_select_ireq),
2520 &resp, sizeof(struct qseecom_command_scm_resp));
2521 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002522 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
2523 return ret;
2524 }
2525
Mona Hossain4cf78a92013-02-14 12:06:41 -08002526 switch (resp.result) {
2527 case QSEOS_RESULT_SUCCESS:
2528 break;
2529 case QSEOS_RESULT_INCOMPLETE:
2530 ret = __qseecom_process_incomplete_cmd(data, &resp);
2531 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002532 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2533 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002534 break;
2535 case QSEOS_RESULT_FAILURE:
2536 default:
2537 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2538 ret = -EINVAL;
2539 break;
2540 }
2541
Mona Hossainc92629e2013-04-01 13:37:46 -07002542 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2543 __qseecom_disable_clk(CLK_QSEE);
2544 else
2545 __qseecom_disable_clk(CLK_CE_DRV);
2546
Mona Hossain4cf78a92013-02-14 12:06:41 -08002547 return ret;
2548}
2549
2550static int qseecom_create_key(struct qseecom_dev_handle *data,
2551 void __user *argp)
2552{
2553 uint32_t ce_hw = 0;
2554 uint32_t pipe = 0;
2555 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2556 int ret = 0;
2557 uint32_t flags = 0;
2558 struct qseecom_set_key_parameter set_key_para;
2559 struct qseecom_create_key_req create_key_req;
2560
2561 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2562 if (ret) {
2563 pr_err("copy_from_user failed\n");
2564 return ret;
2565 }
2566
2567 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2568 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2569 return -EFAULT;
2570 }
2571
2572 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2573 if (ret) {
2574 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2575 return -EINVAL;
2576 }
2577
2578 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2579 key_id, flags);
2580 if (ret) {
2581 pr_err("Failed to generate key on storage: %d\n", ret);
2582 return -EFAULT;
2583 }
2584
2585 set_key_para.ce_hw = ce_hw;
2586 set_key_para.pipe = pipe;
2587 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2588 set_key_para.flags = flags;
2589 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2590 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2591 QSEECOM_HASH_SIZE);
2592
2593 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2594 &set_key_para);
2595 if (ret) {
2596 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2597 pipe, ce_hw, ret);
2598 return -EFAULT;
2599 }
2600
2601 return ret;
2602}
2603
2604static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2605 void __user *argp)
2606{
2607 uint32_t ce_hw = 0;
2608 uint32_t pipe = 0;
2609 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2610 int ret = 0;
2611 uint32_t flags = 0;
2612 int i;
2613 struct qseecom_wipe_key_req wipe_key_req;
2614 struct qseecom_set_key_parameter clear_key_para;
2615
2616 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2617 if (ret) {
2618 pr_err("copy_from_user failed\n");
2619 return ret;
2620 }
2621
2622 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2623 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2624 return -EFAULT;
2625 }
2626
2627 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2628 if (ret) {
2629 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2630 return -EINVAL;
2631 }
2632
2633 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2634 flags);
2635 if (ret) {
2636 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2637 return -EFAULT;
2638 }
2639
2640 /* an invalid key_id 0xff is used to indicate clear key*/
2641 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2642 clear_key_para.key_id[i] = 0xff;
2643 clear_key_para.ce_hw = ce_hw;
2644 clear_key_para.pipe = pipe;
2645 clear_key_para.flags = flags;
2646 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2647 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2648 &clear_key_para);
2649 if (ret) {
2650 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2651 pipe, ce_hw, ret);
2652 return -EFAULT;
2653 }
2654
2655 return ret;
2656}
2657
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002658static int qseecom_is_es_activated(void __user *argp)
2659{
2660 struct qseecom_is_es_activated_req req;
2661 int ret;
2662 int resp_buf;
2663
2664 if (qseecom.qsee_version < QSEE_VERSION_04) {
2665 pr_err("invalid qsee version");
2666 return -ENODEV;
2667 }
2668
2669 if (argp == NULL) {
2670 pr_err("arg is null");
2671 return -EINVAL;
2672 }
2673
2674 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2675 (void *) &resp_buf, sizeof(resp_buf));
2676 if (ret) {
2677 pr_err("scm_call failed");
2678 return ret;
2679 }
2680
2681 req.is_activated = resp_buf;
2682 ret = copy_to_user(argp, &req, sizeof(req));
2683 if (ret) {
2684 pr_err("copy_to_user failed");
2685 return ret;
2686 }
2687
2688 return 0;
2689}
2690
2691static int qseecom_save_partition_hash(void __user *argp)
2692{
2693 struct qseecom_save_partition_hash_req req;
2694 int ret;
2695
2696 if (qseecom.qsee_version < QSEE_VERSION_04) {
2697 pr_err("invalid qsee version ");
2698 return -ENODEV;
2699 }
2700
2701 if (argp == NULL) {
2702 pr_err("arg is null");
2703 return -EINVAL;
2704 }
2705
2706 ret = copy_from_user(&req, argp, sizeof(req));
2707 if (ret) {
2708 pr_err("copy_from_user failed");
2709 return ret;
2710 }
2711
2712 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2713 (void *) &req, sizeof(req), NULL, 0);
2714 if (ret) {
2715 pr_err("scm_call failed");
2716 return ret;
2717 }
2718
2719 return 0;
2720}
2721
Mona Hossain2892b6b2012-02-17 13:53:11 -08002722static long qseecom_ioctl(struct file *file, unsigned cmd,
2723 unsigned long arg)
2724{
2725 int ret = 0;
2726 struct qseecom_dev_handle *data = file->private_data;
2727 void __user *argp = (void __user *) arg;
2728
2729 if (data->abort) {
2730 pr_err("Aborting qseecom driver\n");
2731 return -ENODEV;
2732 }
2733
2734 switch (cmd) {
2735 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2736 pr_debug("ioctl register_listener_req()\n");
2737 atomic_inc(&data->ioctl_count);
2738 ret = qseecom_register_listener(data, argp);
2739 atomic_dec(&data->ioctl_count);
2740 wake_up_all(&data->abort_wq);
2741 if (ret)
2742 pr_err("failed qseecom_register_listener: %d\n", ret);
2743 break;
2744 }
2745 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2746 pr_debug("ioctl unregister_listener_req()\n");
2747 atomic_inc(&data->ioctl_count);
2748 ret = qseecom_unregister_listener(data);
2749 atomic_dec(&data->ioctl_count);
2750 wake_up_all(&data->abort_wq);
2751 if (ret)
2752 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2753 break;
2754 }
2755 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2756 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002757 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002758 atomic_inc(&data->ioctl_count);
2759 ret = qseecom_send_cmd(data, argp);
2760 atomic_dec(&data->ioctl_count);
2761 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002762 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002763 if (ret)
2764 pr_err("failed qseecom_send_cmd: %d\n", ret);
2765 break;
2766 }
2767 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2768 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002769 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002770 atomic_inc(&data->ioctl_count);
2771 ret = qseecom_send_modfd_cmd(data, argp);
2772 atomic_dec(&data->ioctl_count);
2773 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002774 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002775 if (ret)
2776 pr_err("failed qseecom_send_cmd: %d\n", ret);
2777 break;
2778 }
2779 case QSEECOM_IOCTL_RECEIVE_REQ: {
2780 atomic_inc(&data->ioctl_count);
2781 ret = qseecom_receive_req(data);
2782 atomic_dec(&data->ioctl_count);
2783 wake_up_all(&data->abort_wq);
2784 if (ret)
2785 pr_err("failed qseecom_receive_req: %d\n", ret);
2786 break;
2787 }
2788 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2789 atomic_inc(&data->ioctl_count);
2790 ret = qseecom_send_resp();
2791 atomic_dec(&data->ioctl_count);
2792 wake_up_all(&data->abort_wq);
2793 if (ret)
2794 pr_err("failed qseecom_send_resp: %d\n", ret);
2795 break;
2796 }
2797 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2798 ret = qseecom_set_client_mem_param(data, argp);
2799 if (ret)
2800 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2801 ret);
2802 break;
2803 }
2804 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2805 mutex_lock(&app_access_lock);
2806 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002807 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2808 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002809 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002810 if (ret == 0)
2811 qseecom.commonlib_loaded = true;
2812 }
2813 }
2814 if (ret == 0)
2815 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002816 atomic_dec(&data->ioctl_count);
2817 mutex_unlock(&app_access_lock);
2818 if (ret)
2819 pr_err("failed load_app request: %d\n", ret);
2820 break;
2821 }
2822 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2823 mutex_lock(&app_access_lock);
2824 atomic_inc(&data->ioctl_count);
2825 ret = qseecom_unload_app(data);
2826 atomic_dec(&data->ioctl_count);
2827 mutex_unlock(&app_access_lock);
2828 if (ret)
2829 pr_err("failed unload_app request: %d\n", ret);
2830 break;
2831 }
2832 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2833 atomic_inc(&data->ioctl_count);
2834 ret = qseecom_get_qseos_version(data, argp);
2835 if (ret)
2836 pr_err("qseecom_get_qseos_version: %d\n", ret);
2837 atomic_dec(&data->ioctl_count);
2838 break;
2839 }
2840 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2841 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002842 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002843 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002844 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002845 ret = qsee_vote_for_clock(data, CLK_SFPB);
2846 if (ret)
2847 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002848 atomic_dec(&data->ioctl_count);
2849 break;
2850 }
2851 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2852 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002853 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002854 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002855 atomic_dec(&data->ioctl_count);
2856 break;
2857 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002858 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2859 data->released = true;
2860 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2861 pr_err("Loading External elf image unsupported in rev 0x13\n");
2862 ret = -EINVAL;
2863 break;
2864 }
2865 mutex_lock(&app_access_lock);
2866 atomic_inc(&data->ioctl_count);
2867 ret = qseecom_load_external_elf(data, argp);
2868 atomic_dec(&data->ioctl_count);
2869 mutex_unlock(&app_access_lock);
2870 if (ret)
2871 pr_err("failed load_external_elf request: %d\n", ret);
2872 break;
2873 }
2874 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2875 data->released = true;
2876 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2877 pr_err("Unloading External elf image unsupported in rev 0x13\n");
2878 ret = -EINVAL;
2879 break;
2880 }
2881 mutex_lock(&app_access_lock);
2882 atomic_inc(&data->ioctl_count);
2883 ret = qseecom_unload_external_elf(data);
2884 atomic_dec(&data->ioctl_count);
2885 mutex_unlock(&app_access_lock);
2886 if (ret)
2887 pr_err("failed unload_app request: %d\n", ret);
2888 break;
2889 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002890 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2891 mutex_lock(&app_access_lock);
2892 atomic_inc(&data->ioctl_count);
2893 ret = qseecom_query_app_loaded(data, argp);
2894 atomic_dec(&data->ioctl_count);
2895 mutex_unlock(&app_access_lock);
2896 break;
2897 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002898 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2899 if (qseecom.qsee_version < QSEE_VERSION_03) {
2900 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2901 qseecom.qsee_version);
2902 return -EINVAL;
2903 }
2904 mutex_lock(&app_access_lock);
2905 atomic_inc(&data->ioctl_count);
2906 ret = qseecom_send_service_cmd(data, argp);
2907 atomic_dec(&data->ioctl_count);
2908 mutex_unlock(&app_access_lock);
2909 break;
2910 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002911 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002912 if (qseecom.qsee_version < QSEE_VERSION_05) {
2913 pr_err("Create Key feature not supported in qsee version %u\n",
2914 qseecom.qsee_version);
2915 return -EINVAL;
2916 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002917 data->released = true;
2918 mutex_lock(&app_access_lock);
2919 atomic_inc(&data->ioctl_count);
2920 ret = qseecom_create_key(data, argp);
2921 if (ret)
2922 pr_err("failed to create encryption key: %d\n", ret);
2923
2924 atomic_dec(&data->ioctl_count);
2925 mutex_unlock(&app_access_lock);
2926 break;
2927 }
2928 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002929 if (qseecom.qsee_version < QSEE_VERSION_05) {
2930 pr_err("Wipe Key feature not supported in qsee version %u\n",
2931 qseecom.qsee_version);
2932 return -EINVAL;
2933 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002934 data->released = true;
2935 mutex_lock(&app_access_lock);
2936 atomic_inc(&data->ioctl_count);
2937 ret = qseecom_wipe_key(data, argp);
2938 if (ret)
2939 pr_err("failed to wipe encryption key: %d\n", ret);
2940 atomic_dec(&data->ioctl_count);
2941 mutex_unlock(&app_access_lock);
2942 break;
2943 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002944 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
2945 data->released = true;
2946 mutex_lock(&app_access_lock);
2947 atomic_inc(&data->ioctl_count);
2948 ret = qseecom_save_partition_hash(argp);
2949 atomic_dec(&data->ioctl_count);
2950 mutex_unlock(&app_access_lock);
2951 break;
2952 }
2953 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
2954 data->released = true;
2955 mutex_lock(&app_access_lock);
2956 atomic_inc(&data->ioctl_count);
2957 ret = qseecom_is_es_activated(argp);
2958 atomic_dec(&data->ioctl_count);
2959 mutex_unlock(&app_access_lock);
2960 break;
2961 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002962 default:
2963 return -EINVAL;
2964 }
2965 return ret;
2966}
2967
2968static int qseecom_open(struct inode *inode, struct file *file)
2969{
2970 int ret = 0;
2971 struct qseecom_dev_handle *data;
2972
2973 data = kzalloc(sizeof(*data), GFP_KERNEL);
2974 if (!data) {
2975 pr_err("kmalloc failed\n");
2976 return -ENOMEM;
2977 }
2978 file->private_data = data;
2979 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002980 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002981 data->released = false;
2982 init_waitqueue_head(&data->abort_wq);
2983 atomic_set(&data->ioctl_count, 0);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002984 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2985 int pil_error;
2986 mutex_lock(&pil_access_lock);
2987 if (pil_ref_cnt == 0) {
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002988 pil = subsystem_get("tzapps");
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002989 if (IS_ERR(pil)) {
2990 pr_err("Playready PIL image load failed\n");
2991 pil_error = PTR_ERR(pil);
2992 pil = NULL;
2993 pr_debug("tzapps image load FAILED\n");
2994 mutex_unlock(&pil_access_lock);
2995 return pil_error;
2996 }
2997 }
2998 pil_ref_cnt++;
2999 mutex_unlock(&pil_access_lock);
3000 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003001 return ret;
3002}
3003
3004static int qseecom_release(struct inode *inode, struct file *file)
3005{
3006 struct qseecom_dev_handle *data = file->private_data;
3007 int ret = 0;
3008
3009 if (data->released == false) {
3010 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003011 switch (data->type) {
3012 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003013 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003014 break;
3015 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003016 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003017 break;
3018 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003019 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003020 ret = qseecom_unmap_ion_allocated_memory(data);
3021 if (ret) {
3022 pr_err("Close failed\n");
3023 return ret;
3024 }
3025 break;
3026 default:
3027 pr_err("Unsupported clnt_handle_type %d",
3028 data->type);
3029 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003030 }
3031 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003032
Mona Hossainc9c83c72013-04-11 12:43:48 -07003033 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003034 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07003035 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003036 qsee_disable_clock_vote(data, CLK_DFAB);
3037
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003038 if (qseecom.qseos_version == QSEOS_VERSION_13) {
3039 mutex_lock(&pil_access_lock);
3040 if (pil_ref_cnt == 1)
Stephen Boyd77db8bb2012-06-27 15:15:16 -07003041 subsystem_put(pil);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003042 pil_ref_cnt--;
3043 mutex_unlock(&pil_access_lock);
3044 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003045 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003046
Mona Hossain2892b6b2012-02-17 13:53:11 -08003047 return ret;
3048}
3049
Mona Hossain2892b6b2012-02-17 13:53:11 -08003050static const struct file_operations qseecom_fops = {
3051 .owner = THIS_MODULE,
3052 .unlocked_ioctl = qseecom_ioctl,
3053 .open = qseecom_open,
3054 .release = qseecom_release
3055};
3056
Mona Hossainc92629e2013-04-01 13:37:46 -07003057static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003058{
3059 int rc = 0;
3060 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003061 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003062 char *core_clk_src = NULL;
3063 char *core_clk = NULL;
3064 char *iface_clk = NULL;
3065 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003066
Mona Hossainc92629e2013-04-01 13:37:46 -07003067 switch (ce) {
3068 case CLK_QSEE: {
3069 core_clk_src = "core_clk_src";
3070 core_clk = "core_clk";
3071 iface_clk = "iface_clk";
3072 bus_clk = "bus_clk";
3073 qclk = &qseecom.qsee;
3074 qclk->instance = CLK_QSEE;
3075 break;
3076 };
3077 case CLK_CE_DRV: {
3078 core_clk_src = "ce_drv_core_clk_src";
3079 core_clk = "ce_drv_core_clk";
3080 iface_clk = "ce_drv_iface_clk";
3081 bus_clk = "ce_drv_bus_clk";
3082 qclk = &qseecom.ce_drv;
3083 qclk->instance = CLK_CE_DRV;
3084 break;
3085 };
3086 default:
3087 pr_err("Invalid ce hw instance: %d!\n", ce);
3088 return -EIO;
3089 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003090 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003091
Mona Hossainc92629e2013-04-01 13:37:46 -07003092 /* Get CE3 src core clk. */
3093 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003094 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003095 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003096 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003097 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003098 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003099 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003100 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003101 }
3102 } else {
3103 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003104 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003105 }
3106
3107 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003108 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003109 if (IS_ERR(qclk->ce_core_clk)) {
3110 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003111 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003112 if (qclk->ce_core_src_clk != NULL)
3113 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003114 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003115 }
3116
3117 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003118 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003119 if (IS_ERR(qclk->ce_clk)) {
3120 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003121 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003122 if (qclk->ce_core_src_clk != NULL)
3123 clk_put(qclk->ce_core_src_clk);
3124 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003125 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003126 }
3127
3128 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003129 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003130 if (IS_ERR(qclk->ce_bus_clk)) {
3131 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003132 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003133 if (qclk->ce_core_src_clk != NULL)
3134 clk_put(qclk->ce_core_src_clk);
3135 clk_put(qclk->ce_core_clk);
3136 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003137 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003138 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003139 return rc;
3140}
3141
Mona Hossainc92629e2013-04-01 13:37:46 -07003142static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003143{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003144 struct qseecom_clk *qclk;
3145
Mona Hossainc92629e2013-04-01 13:37:46 -07003146 if (ce == CLK_QSEE)
3147 qclk = &qseecom.qsee;
3148 else
3149 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003150
3151 if (qclk->ce_clk != NULL) {
3152 clk_put(qclk->ce_clk);
3153 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003154 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003155 if (qclk->ce_core_clk != NULL) {
3156 clk_put(qclk->ce_core_clk);
3157 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003158 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003159 if (qclk->ce_bus_clk != NULL) {
3160 clk_put(qclk->ce_bus_clk);
3161 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003162 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003163 if (qclk->ce_core_src_clk != NULL) {
3164 clk_put(qclk->ce_core_src_clk);
3165 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003166 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003167}
3168
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003169static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003170{
3171 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003172 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003173 struct device *class_dev;
3174 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003175 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003176 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3177
Mona Hossain17a4faf2013-03-22 16:40:56 -07003178 qseecom.qsee_bw_count = 0;
3179 qseecom.qsee_perf_client = 0;
3180 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003181
Mona Hossain17a4faf2013-03-22 16:40:56 -07003182 qseecom.qsee.ce_core_clk = NULL;
3183 qseecom.qsee.ce_clk = NULL;
3184 qseecom.qsee.ce_core_src_clk = NULL;
3185 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003186
Mona Hossainc92629e2013-04-01 13:37:46 -07003187 qseecom.ce_drv.ce_core_clk = NULL;
3188 qseecom.ce_drv.ce_clk = NULL;
3189 qseecom.ce_drv.ce_core_src_clk = NULL;
3190 qseecom.ce_drv.ce_bus_clk = NULL;
3191
Mona Hossain2892b6b2012-02-17 13:53:11 -08003192 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3193 if (rc < 0) {
3194 pr_err("alloc_chrdev_region failed %d\n", rc);
3195 return rc;
3196 }
3197
3198 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3199 if (IS_ERR(driver_class)) {
3200 rc = -ENOMEM;
3201 pr_err("class_create failed %d\n", rc);
3202 goto unregister_chrdev_region;
3203 }
3204
3205 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3206 QSEECOM_DEV);
3207 if (!class_dev) {
3208 pr_err("class_device_create failed %d\n", rc);
3209 rc = -ENOMEM;
3210 goto class_destroy;
3211 }
3212
3213 cdev_init(&qseecom_cdev, &qseecom_fops);
3214 qseecom_cdev.owner = THIS_MODULE;
3215
3216 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
3217 if (rc < 0) {
3218 pr_err("cdev_add failed %d\n", rc);
3219 goto err;
3220 }
3221
3222 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3223 spin_lock_init(&qseecom.registered_listener_list_lock);
3224 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3225 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003226 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3227 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003228 init_waitqueue_head(&qseecom.send_resp_wq);
3229 qseecom.send_resp_flag = 0;
3230
3231 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3232 &qsee_not_legacy, sizeof(qsee_not_legacy));
3233 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003234 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003235 goto err;
3236 }
Mona Hossain05c73562012-10-29 17:49:01 -07003237 if (qsee_not_legacy) {
3238 uint32_t feature = 10;
3239
3240 qseecom.qsee_version = QSEEE_VERSION_00;
3241 rc = scm_call(6, 3, &feature, sizeof(feature),
3242 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3243 if (rc) {
3244 pr_err("Failed to get QSEE version info %d\n", rc);
3245 goto err;
3246 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003247 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003248 } else {
Mona Hossain2892b6b2012-02-17 13:53:11 -08003249 qseecom.qseos_version = QSEOS_VERSION_13;
Mona Hossain05c73562012-10-29 17:49:01 -07003250 qseecom.qsee_version = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003251 pil = NULL;
3252 pil_ref_cnt = 0;
3253 }
Mona Hossain05c73562012-10-29 17:49:01 -07003254 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003255 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003256 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003257 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003258 if (qseecom.ion_clnt == NULL) {
3259 pr_err("Ion client cannot be created\n");
3260 rc = -ENOMEM;
3261 goto err;
3262 }
3263
3264 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003265 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003266
Mona Hossain4cf78a92013-02-14 12:06:41 -08003267 if (of_property_read_u32((&pdev->dev)->of_node,
3268 "qcom,disk-encrypt-pipe-pair",
3269 &qseecom.ce_info.disk_encrypt_pipe)) {
3270 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3271 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3272 rc = -EINVAL;
3273 goto err;
3274 } else {
3275 pr_warn("bam_pipe_pair=0x%x",
3276 qseecom.ce_info.disk_encrypt_pipe);
3277 }
3278
3279 if (of_property_read_u32((&pdev->dev)->of_node,
3280 "qcom,qsee-ce-hw-instance",
3281 &qseecom.ce_info.qsee_ce_hw_instance)) {
3282 pr_err("Fail to get qsee ce hw instance information.\n");
3283 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3284 rc = -EINVAL;
3285 goto err;
3286 } else {
3287 pr_warn("qsee-ce-hw-instance=0x%x",
3288 qseecom.ce_info.qsee_ce_hw_instance);
3289 }
3290
3291 if (of_property_read_u32((&pdev->dev)->of_node,
3292 "qcom,hlos-ce-hw-instance",
3293 &qseecom.ce_info.hlos_ce_hw_instance)) {
3294 pr_err("Fail to get hlos ce hw instance information.\n");
3295 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3296 rc = -EINVAL;
3297 goto err;
3298 } else {
3299 pr_warn("hlos-ce-hw-instance=0x%x",
3300 qseecom.ce_info.hlos_ce_hw_instance);
3301 }
3302
Mona Hossainc92629e2013-04-01 13:37:46 -07003303 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3304 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3305
3306 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003307 if (ret)
3308 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003309
Mona Hossainc92629e2013-04-01 13:37:46 -07003310 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3311 ret = __qseecom_init_clk(CLK_CE_DRV);
3312 if (ret) {
3313 __qseecom_deinit_clk(CLK_QSEE);
3314 goto err;
3315 }
3316 } else {
3317 struct qseecom_clk *qclk;
3318
3319 qclk = &qseecom.qsee;
3320 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3321 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3322 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3323 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3324 }
3325
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003326 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3327 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003328 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3329 struct resource *resource = NULL;
3330 struct qsee_apps_region_info_ireq req;
3331 struct qseecom_command_scm_resp resp;
3332
3333 resource = platform_get_resource_byname(pdev,
3334 IORESOURCE_MEM, "secapp-region");
3335 if (resource) {
3336 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3337 req.addr = resource->start;
3338 req.size = resource_size(resource);
3339 pr_warn("secure app region addr=0x%x size=0x%x",
3340 req.addr, req.size);
3341 } else {
3342 pr_err("Fail to get secure app region info\n");
3343 rc = -EINVAL;
3344 goto err;
3345 }
3346 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3347 &resp, sizeof(resp));
3348 if (rc) {
3349 pr_err("Failed to send secapp region info %d\n",
3350 rc);
3351 goto err;
3352 }
3353 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003354 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003355 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3356 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003357 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003358
Mona Hossain17a4faf2013-03-22 16:40:56 -07003359 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003360 qseecom_platform_support);
3361
Mona Hossain17a4faf2013-03-22 16:40:56 -07003362 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003363 pr_err("Unable to register bus client\n");
3364 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003365err:
3366 device_destroy(driver_class, qseecom_device_no);
3367class_destroy:
3368 class_destroy(driver_class);
3369unregister_chrdev_region:
3370 unregister_chrdev_region(qseecom_device_no, 1);
3371 return rc;
3372}
3373
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003374static int __devinit qseecom_remove(struct platform_device *pdev)
3375{
Mona Hossaind44a3842012-10-15 09:41:35 -07003376 struct qseecom_registered_kclient_list *kclient = NULL;
3377 unsigned long flags = 0;
3378 int ret = 0;
3379
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003380 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003381 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003382
3383 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3384 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3385 struct qseecom_registered_kclient_list, list);
3386 if (list_empty(&kclient->list)) {
3387 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3388 flags);
3389 return 0;
3390 }
3391 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3392 list) {
3393 if (kclient)
3394 list_del(&kclient->list);
3395 break;
3396 }
3397 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3398
3399
3400 while (kclient->handle != NULL) {
3401 ret = qseecom_unload_app(kclient->handle->dev);
3402 if (ret == 0) {
3403 kzfree(kclient->handle->dev);
3404 kzfree(kclient->handle);
3405 kzfree(kclient);
3406 }
3407 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3408 kclient = list_entry(
3409 (&qseecom.registered_kclient_list_head)->next,
3410 struct qseecom_registered_kclient_list, list);
3411 if (list_empty(&kclient->list)) {
3412 spin_unlock_irqrestore(
3413 &qseecom.registered_kclient_list_lock, flags);
3414 return 0;
3415 }
3416 list_for_each_entry(kclient,
3417 &qseecom.registered_kclient_list_head, list) {
3418 if (kclient)
3419 list_del(&kclient->list);
3420 break;
3421 }
3422 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3423 flags);
3424 if (!kclient) {
3425 ret = 0;
3426 break;
3427 }
3428 }
Mona Hossain05c73562012-10-29 17:49:01 -07003429 if (qseecom.qseos_version > QSEEE_VERSION_00)
3430 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003431
Mona Hossain17a4faf2013-03-22 16:40:56 -07003432 if (qseecom.qsee_perf_client)
3433 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3434 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003435 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003436 if (pdev->dev.of_node) {
3437 __qseecom_deinit_clk(CLK_QSEE);
3438 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3439 __qseecom_deinit_clk(CLK_CE_DRV);
3440 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003441 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003442};
3443
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003444static struct of_device_id qseecom_match[] = {
3445 {
3446 .compatible = "qcom,qseecom",
3447 },
3448 {}
3449};
3450
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003451static struct platform_driver qseecom_plat_driver = {
3452 .probe = qseecom_probe,
3453 .remove = qseecom_remove,
3454 .driver = {
3455 .name = "qseecom",
3456 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003457 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003458 },
3459};
3460
3461static int __devinit qseecom_init(void)
3462{
3463 return platform_driver_register(&qseecom_plat_driver);
3464}
3465
3466static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003467{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003468 device_destroy(driver_class, qseecom_device_no);
3469 class_destroy(driver_class);
3470 unregister_chrdev_region(qseecom_device_no, 1);
3471 ion_client_destroy(qseecom.ion_clnt);
3472}
3473
3474MODULE_LICENSE("GPL v2");
3475MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3476
3477module_init(qseecom_init);
3478module_exit(qseecom_exit);