blob: f139b211fdd9d185c4f512b41695cddf2329bb5c [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;
Mona Hossain91da2c52013-03-29 17:28:31 -0700543 sigset_t new_sigset;
544 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800545
Mona Hossain2892b6b2012-02-17 13:53:11 -0800546 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
547 lstnr = resp->data;
548 /*
549 * Wake up blocking lsitener service with the lstnr id
550 */
551 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
552 flags);
553 list_for_each_entry(ptr_svc,
554 &qseecom.registered_listener_list_head, list) {
555 if (ptr_svc->svc.listener_id == lstnr) {
556 ptr_svc->rcv_req_flag = 1;
557 wake_up_interruptible(&ptr_svc->rcv_req_wq);
558 break;
559 }
560 }
561 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
562 flags);
563 if (ptr_svc->svc.listener_id != lstnr) {
564 pr_warning("Service requested for does on exist\n");
565 return -ERESTARTSYS;
566 }
567 pr_debug("waking up rcv_req_wq and "
568 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800569
Mona Hossain91da2c52013-03-29 17:28:31 -0700570 /* initialize the new signal mask with all signals*/
571 sigfillset(&new_sigset);
572 /* block all signals */
573 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
574
575 do {
576 if (!wait_event_freezable(qseecom.send_resp_wq,
577 __qseecom_listener_has_sent_rsp(data)))
578 break;
579 } while (1);
580
581 /* restore signal mask */
582 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
583 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700584 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
585 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700586 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800587 send_data_rsp.status = QSEOS_RESULT_FAILURE;
588 } else {
589 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800590 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800591
Mona Hossain2892b6b2012-02-17 13:53:11 -0800592 qseecom.send_resp_flag = 0;
593 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
594 send_data_rsp.listener_id = lstnr ;
595
596 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
597 (const void *)&send_data_rsp,
598 sizeof(send_data_rsp), resp,
599 sizeof(*resp));
600 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700601 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800602 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800603 return ret;
604 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800605 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
606 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
607 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
608 resp->result, data->client.app_id, lstnr);
609 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700610 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800611 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800612 if (rc)
613 return rc;
614
Mona Hossain2892b6b2012-02-17 13:53:11 -0800615 return ret;
616}
617
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700618static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
619{
620 int32_t ret;
621 struct qseecom_command_scm_resp resp;
622
623 /* SCM_CALL to check if app_id for the mentioned app exists */
624 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
625 sizeof(struct qseecom_check_app_ireq),
626 &resp, sizeof(resp));
627 if (ret) {
628 pr_err("scm_call to check if app is already loaded failed\n");
629 return -EINVAL;
630 }
631
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700632 if (resp.result == QSEOS_RESULT_FAILURE) {
633 return 0;
634 } else {
635 switch (resp.resp_type) {
636 /*qsee returned listener type response */
637 case QSEOS_LISTENER_ID:
638 pr_err("resp type is of listener type instead of app");
639 return -EINVAL;
640 break;
641 case QSEOS_APP_ID:
642 return resp.data;
643 default:
644 pr_err("invalid resp type (%d) from qsee",
645 resp.resp_type);
646 return -ENODEV;
647 break;
648 }
649 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700650}
651
Mona Hossain2892b6b2012-02-17 13:53:11 -0800652static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
653{
654 struct qseecom_registered_app_list *entry = NULL;
655 unsigned long flags = 0;
656 u32 app_id = 0;
657 struct ion_handle *ihandle; /* Ion handle */
658 struct qseecom_load_img_req load_img_req;
659 int32_t ret;
660 ion_phys_addr_t pa = 0;
661 uint32_t len;
662 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800663 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700664 struct qseecom_load_app_ireq load_req;
665
Mona Hossain2892b6b2012-02-17 13:53:11 -0800666 /* Copy the relevant information needed for loading the image */
667 if (__copy_from_user(&load_img_req,
668 (void __user *)argp,
669 sizeof(struct qseecom_load_img_req))) {
670 pr_err("copy_from_user failed\n");
671 return -EFAULT;
672 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700673 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800674 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700675 if (ret)
676 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800677 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
678 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800679
Mona Hossain436b75f2012-11-20 17:10:40 -0800680 ret = __qseecom_check_app_exists(req);
681 if (ret < 0)
682 return ret;
683 else
684 app_id = ret;
685
686 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700687 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800688 (char *)(req.app_name));
689 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
690 list_for_each_entry(entry,
691 &qseecom.registered_app_list_head, list){
692 if (entry->app_id == app_id) {
693 entry->ref_cnt++;
694 break;
695 }
696 }
697 spin_unlock_irqrestore(
698 &qseecom.registered_app_list_lock, flags);
699 } else {
700 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700701 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800702 /* Get the handle of the shared fd */
703 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800704 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800705 if (IS_ERR_OR_NULL(ihandle)) {
706 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800707 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800708 return -ENOMEM;
709 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800710
Mona Hossain436b75f2012-11-20 17:10:40 -0800711 /* Get the physical address of the ION BUF */
712 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800713
Mona Hossain436b75f2012-11-20 17:10:40 -0800714 /* Populate the structure for sending scm call to load image */
715 memcpy(load_req.app_name, load_img_req.img_name,
716 MAX_APP_NAME_SIZE);
717 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
718 load_req.mdt_len = load_img_req.mdt_len;
719 load_req.img_len = load_img_req.img_len;
720 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800721
Mona Hossain436b75f2012-11-20 17:10:40 -0800722 /* SCM_CALL to load the app and get the app_id back */
723 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700724 sizeof(struct qseecom_load_app_ireq),
725 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700726 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800727 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800728 if (!IS_ERR_OR_NULL(ihandle))
729 ion_free(qseecom.ion_clnt, ihandle);
730 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800731 return -EINVAL;
732 }
733
734 if (resp.result == QSEOS_RESULT_FAILURE) {
735 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700736 if (!IS_ERR_OR_NULL(ihandle))
737 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800738 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800739 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700740 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700741
Mona Hossain436b75f2012-11-20 17:10:40 -0800742 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
743 ret = __qseecom_process_incomplete_cmd(data, &resp);
744 if (ret) {
745 pr_err("process_incomplete_cmd failed err: %d\n",
746 ret);
747 if (!IS_ERR_OR_NULL(ihandle))
748 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800749 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800750 return ret;
751 }
752 }
753
754 if (resp.result != QSEOS_RESULT_SUCCESS) {
755 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700756 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800757 if (!IS_ERR_OR_NULL(ihandle))
758 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800759 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800760 return -EFAULT;
761 }
762
763 app_id = resp.data;
764
765 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
766 if (!entry) {
767 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800768 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800769 return -ENOMEM;
770 }
771 entry->app_id = app_id;
772 entry->ref_cnt = 1;
773
774 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700775 if (!IS_ERR_OR_NULL(ihandle))
776 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700777
Mona Hossain436b75f2012-11-20 17:10:40 -0800778 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
779 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
780 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
781 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700782
Mona Hossain436b75f2012-11-20 17:10:40 -0800783 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700784 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800785 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800786 data->client.app_id = app_id;
787 load_img_req.app_id = app_id;
788 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
789 pr_err("copy_to_user failed\n");
790 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800791 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800792 return -EFAULT;
793 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800794 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800795 return 0;
796}
797
798static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
799{
800 wake_up_all(&qseecom.send_resp_wq);
801 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700802 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800803 atomic_read(&data->ioctl_count) <= 1)) {
804 pr_err("Interrupted from abort\n");
805 return -ERESTARTSYS;
806 break;
807 }
808 }
809 /* Set unload app */
810 return 1;
811}
812
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800813static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
814{
815 int ret = 0;
816 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
817 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
818 ion_free(qseecom.ion_clnt, data->client.ihandle);
819 data->client.ihandle = NULL;
820 }
821 return ret;
822}
823
Mona Hossain2892b6b2012-02-17 13:53:11 -0800824static int qseecom_unload_app(struct qseecom_dev_handle *data)
825{
826 unsigned long flags;
827 int ret = 0;
828 struct qseecom_command_scm_resp resp;
829 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700830 bool unload = false;
831 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800832
Mona Hossain1fb538f2012-08-30 16:19:38 -0700833 if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
834 (data->client.app_id > 0)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800835 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
836 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
837 list) {
838 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700839 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800840 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700841 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800842 break;
843 } else {
844 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700845 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700846 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800847 break;
848 }
849 }
850 }
851 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
852 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700853 if (found_app == false) {
854 pr_err("Cannot find app with id = %d\n",
855 data->client.app_id);
856 return -EINVAL;
857 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800858 }
859
860 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
861 struct qseecom_unload_app_ireq req;
862
Mona Hossain340dba82012-08-07 19:54:46 -0700863 __qseecom_cleanup_app(data);
864 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
865 list_del(&ptr_app->list);
866 kzfree(ptr_app);
867 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
868 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800869 /* Populate the structure for sending scm call to load image */
870 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
871 req.app_id = data->client.app_id;
872
873 /* SCM_CALL to unload the app */
874 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
875 sizeof(struct qseecom_unload_app_ireq),
876 &resp, sizeof(resp));
877 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700878 pr_err("scm_call to unload app (id = %d) failed\n",
879 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800880 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700881 } else {
882 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800883 }
884 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
885 ret = __qseecom_process_incomplete_cmd(data, &resp);
886 if (ret) {
887 pr_err("process_incomplete_cmd fail err: %d\n",
888 ret);
889 return ret;
890 }
891 }
892 }
893
894 if (qseecom.qseos_version == QSEOS_VERSION_13) {
895 data->abort = 1;
896 wake_up_all(&qseecom.send_resp_wq);
897 while (atomic_read(&data->ioctl_count) > 0) {
Mona Hossainacea1022012-04-09 13:37:27 -0700898 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800899 atomic_read(&data->ioctl_count) <= 0)) {
900 pr_err("Interrupted from abort\n");
901 ret = -ERESTARTSYS;
902 break;
903 }
904 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800905 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800906 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800907 data->released = true;
908 return ret;
909}
910
911static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
912 uint32_t virt)
913{
914 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
915}
916
917static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
918 struct qseecom_send_cmd_req *req)
919{
920 int ret = 0;
921 unsigned long flags;
922 u32 reqd_len_sb_in = 0;
923 struct qseecom_command cmd;
924 struct qseecom_response resp;
925
926
927 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
928 pr_err("cmd buffer or response buffer is null\n");
929 return -EINVAL;
930 }
931
932 if (req->cmd_req_len <= 0 ||
933 req->resp_len <= 0 ||
934 req->cmd_req_len > data->client.sb_length ||
935 req->resp_len > data->client.sb_length) {
936 pr_err("cmd buffer length or "
937 "response buffer length not valid\n");
938 return -EINVAL;
939 }
940
941 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
942 if (reqd_len_sb_in > data->client.sb_length) {
943 pr_debug("Not enough memory to fit cmd_buf and "
944 "resp_buf. Required: %u, Available: %u\n",
945 reqd_len_sb_in, data->client.sb_length);
946 return -ENOMEM;
947 }
948 cmd.cmd_type = TZ_SCHED_CMD_NEW;
949 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
950 cmd.sb_in_cmd_len = req->cmd_req_len;
951
952 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
953 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
954 resp.sb_in_rsp_len = req->resp_len;
955
956 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
957 sizeof(cmd), &resp, sizeof(resp));
958
959 if (ret) {
960 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
961 return ret;
962 }
963
964 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
965 /*
966 * If cmd is incomplete, get the callback cmd out from SB out
967 * and put it on the list
968 */
969 struct qseecom_registered_listener_list *ptr_svc = NULL;
970 /*
971 * We don't know which service can handle the command. so we
972 * wake up all blocking services and let them figure out if
973 * they can handle the given command.
974 */
975 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
976 flags);
977 list_for_each_entry(ptr_svc,
978 &qseecom.registered_listener_list_head, list) {
979 ptr_svc->rcv_req_flag = 1;
980 wake_up_interruptible(&ptr_svc->rcv_req_wq);
981 }
982 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
983 flags);
984
985 pr_debug("waking up rcv_req_wq and "
986 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700987 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800988 __qseecom_listener_has_sent_rsp(data))) {
989 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
990 return -ERESTARTSYS;
991 }
992
993 if (data->abort) {
994 pr_err("Aborting driver\n");
995 return -ENODEV;
996 }
997 qseecom.send_resp_flag = 0;
998 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
999 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
1000 sizeof(cmd), &resp, sizeof(resp));
1001 if (ret) {
1002 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1003 return ret;
1004 }
1005 }
1006 return ret;
1007}
1008
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001009int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1010 struct qseecom_send_svc_cmd_req *req_ptr,
1011 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1012{
1013 int ret = 0;
1014 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1015 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1016 req_ptr, send_svc_ireq_ptr);
1017 return -EINVAL;
1018 }
1019 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1020 send_svc_ireq_ptr->key_type =
1021 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
1022 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1023 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1024 (uint32_t)req_ptr->resp_buf));
1025 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1026
1027 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1028 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1029 return ret;
1030}
1031
1032static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1033 void __user *argp)
1034{
1035 int ret = 0;
1036 struct qseecom_client_send_service_ireq send_svc_ireq;
1037 struct qseecom_command_scm_resp resp;
1038 struct qseecom_send_svc_cmd_req req;
1039 /*struct qseecom_command_scm_resp resp;*/
1040
1041 if (__copy_from_user(&req,
1042 (void __user *)argp,
1043 sizeof(req))) {
1044 pr_err("copy_from_user failed\n");
1045 return -EFAULT;
1046 }
1047
1048 if (req.resp_buf == NULL) {
1049 pr_err("cmd buffer or response buffer is null\n");
1050 return -EINVAL;
1051 }
1052
1053 data->type = QSEECOM_SECURE_SERVICE;
1054
1055 switch (req.cmd_id) {
1056 case QSEE_RPMB_PROVISION_KEY_COMMAND:
1057 case QSEE_RPMB_ERASE_COMMAND:
1058 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1059 &send_svc_ireq))
1060 return -EINVAL;
1061 break;
1062 default:
1063 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1064 return -EINVAL;
1065 }
1066
1067 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1068 sizeof(send_svc_ireq),
1069 &resp, sizeof(resp));
1070 if (ret) {
1071 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1072 return ret;
1073 }
1074
1075 switch (resp.result) {
1076 case QSEOS_RESULT_SUCCESS:
1077 break;
1078 case QSEOS_RESULT_INCOMPLETE:
1079 pr_err("qseos_result_incomplete\n");
1080 ret = __qseecom_process_incomplete_cmd(data, &resp);
1081 if (ret) {
1082 pr_err("process_incomplete_cmd fail: err: %d\n",
1083 ret);
1084 }
1085 break;
1086 case QSEOS_RESULT_FAILURE:
1087 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1088 break;
1089 default:
1090 pr_err("Response result %d not supported\n",
1091 resp.result);
1092 ret = -EINVAL;
1093 break;
1094 }
1095 return ret;
1096
1097}
1098
Mona Hossain2892b6b2012-02-17 13:53:11 -08001099static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1100 struct qseecom_send_cmd_req *req)
1101{
1102 int ret = 0;
1103 u32 reqd_len_sb_in = 0;
1104 struct qseecom_client_send_data_ireq send_data_req;
1105 struct qseecom_command_scm_resp resp;
1106
1107 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1108 pr_err("cmd buffer or response buffer is null\n");
1109 return -EINVAL;
1110 }
1111
1112 if (req->cmd_req_len <= 0 ||
1113 req->resp_len <= 0 ||
1114 req->cmd_req_len > data->client.sb_length ||
1115 req->resp_len > data->client.sb_length) {
1116 pr_err("cmd buffer length or "
1117 "response buffer length not valid\n");
1118 return -EINVAL;
1119 }
1120
1121 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1122 if (reqd_len_sb_in > data->client.sb_length) {
1123 pr_debug("Not enough memory to fit cmd_buf and "
1124 "resp_buf. Required: %u, Available: %u\n",
1125 reqd_len_sb_in, data->client.sb_length);
1126 return -ENOMEM;
1127 }
1128
1129 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1130 send_data_req.app_id = data->client.app_id;
1131 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1132 (uint32_t)req->cmd_req_buf));
1133 send_data_req.req_len = req->cmd_req_len;
1134 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1135 (uint32_t)req->resp_buf));
1136 send_data_req.rsp_len = req->resp_len;
1137
1138 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1139 sizeof(send_data_req),
1140 &resp, sizeof(resp));
1141 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001142 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1143 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001144 return ret;
1145 }
1146
1147 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1148 ret = __qseecom_process_incomplete_cmd(data, &resp);
1149 if (ret) {
1150 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1151 return ret;
1152 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001153 } else {
1154 if (resp.result != QSEOS_RESULT_SUCCESS) {
1155 pr_err("Response result %d not supported\n",
1156 resp.result);
1157 ret = -EINVAL;
1158 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001159 }
1160 return ret;
1161}
1162
1163
1164static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1165{
1166 int ret = 0;
1167 struct qseecom_send_cmd_req req;
1168
1169 ret = copy_from_user(&req, argp, sizeof(req));
1170 if (ret) {
1171 pr_err("copy_from_user failed\n");
1172 return ret;
1173 }
1174 if (qseecom.qseos_version == QSEOS_VERSION_14)
1175 ret = __qseecom_send_cmd(data, &req);
1176 else
1177 ret = __qseecom_send_cmd_legacy(data, &req);
1178 if (ret)
1179 return ret;
1180
1181 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1182 req.resp_len, req.resp_buf);
1183 return ret;
1184}
1185
1186static int __qseecom_send_cmd_req_clean_up(
1187 struct qseecom_send_modfd_cmd_req *req)
1188{
1189 char *field;
1190 uint32_t *update;
1191 int ret = 0;
1192 int i = 0;
1193
1194 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001195 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001196 field = (char *)req->cmd_req_buf +
1197 req->ifd_data[i].cmd_buf_offset;
1198 update = (uint32_t *) field;
1199 *update = 0;
1200 }
1201 }
1202 return ret;
1203}
1204
1205static int __qseecom_update_with_phy_addr(
1206 struct qseecom_send_modfd_cmd_req *req)
1207{
1208 struct ion_handle *ihandle;
1209 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001210 int ret = 0;
1211 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001212
1213 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001214 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001215 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001216 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001217 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001218 req->ifd_data[i].fd);
1219 if (IS_ERR_OR_NULL(ihandle)) {
1220 pr_err("Ion client can't retrieve the handle\n");
1221 return -ENOMEM;
1222 }
1223 field = (char *) req->cmd_req_buf +
1224 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001225
1226 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001227 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1228 if (sg_ptr == NULL) {
1229 pr_err("IOn client could not retrieve sg table\n");
1230 goto err;
1231 }
1232 if (sg_ptr->nents == 0) {
1233 pr_err("Num of scattered entries is 0\n");
1234 goto err;
1235 }
1236 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1237 pr_err("Num of scattered entries");
1238 pr_err(" (%d) is greater than max supported %d\n",
1239 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1240 goto err;
1241 }
1242 if (sg_ptr->nents == 1) {
1243 uint32_t *update;
1244 update = (uint32_t *) field;
1245 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
1246 } else {
1247 struct qseecom_sg_entry *update;
1248 struct scatterlist *sg;
1249 int j = 0;
1250 update = (struct qseecom_sg_entry *) field;
1251 sg = sg_ptr->sgl;
1252 for (j = 0; j < sg_ptr->nents; j++) {
1253 update->phys_addr = (uint32_t)
1254 sg_dma_address(sg);
1255 update->len = (uint32_t)sg->length;
1256 update++;
1257 sg = sg_next(sg);
1258 }
1259 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001260 /* Deallocate the handle */
1261 if (!IS_ERR_OR_NULL(ihandle))
1262 ion_free(qseecom.ion_clnt, ihandle);
1263 }
1264 }
1265 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001266err:
1267 if (!IS_ERR_OR_NULL(ihandle))
1268 ion_free(qseecom.ion_clnt, ihandle);
1269 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001270}
1271
1272static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1273 void __user *argp)
1274{
1275 int ret = 0;
1276 struct qseecom_send_modfd_cmd_req req;
1277 struct qseecom_send_cmd_req send_cmd_req;
1278
1279 ret = copy_from_user(&req, argp, sizeof(req));
1280 if (ret) {
1281 pr_err("copy_from_user failed\n");
1282 return ret;
1283 }
1284 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1285 send_cmd_req.cmd_req_len = req.cmd_req_len;
1286 send_cmd_req.resp_buf = req.resp_buf;
1287 send_cmd_req.resp_len = req.resp_len;
1288
1289 ret = __qseecom_update_with_phy_addr(&req);
1290 if (ret)
1291 return ret;
1292 if (qseecom.qseos_version == QSEOS_VERSION_14)
1293 ret = __qseecom_send_cmd(data, &send_cmd_req);
1294 else
1295 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1296 __qseecom_send_cmd_req_clean_up(&req);
1297
1298 if (ret)
1299 return ret;
1300
1301 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1302 req.resp_len, req.resp_buf);
1303 return ret;
1304}
1305
1306static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1307 struct qseecom_registered_listener_list *svc)
1308{
1309 int ret;
1310 ret = (svc->rcv_req_flag != 0);
1311 return ret || data->abort;
1312}
1313
1314static int qseecom_receive_req(struct qseecom_dev_handle *data)
1315{
1316 int ret = 0;
1317 struct qseecom_registered_listener_list *this_lstnr;
1318
1319 this_lstnr = __qseecom_find_svc(data->listener.id);
1320 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001321 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001322 __qseecom_listener_has_rcvd_req(data,
1323 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001324 pr_warning("Interrupted: exiting Listener Service = %d\n",
1325 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001326 /* woken up for different reason */
1327 return -ERESTARTSYS;
1328 }
1329
1330 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001331 pr_err("Aborting Listener Service = %d\n",
1332 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001333 return -ENODEV;
1334 }
1335 this_lstnr->rcv_req_flag = 0;
1336 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1337 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1338 break;
1339 } else {
1340 break;
1341 }
1342 }
1343 return ret;
1344}
1345
Mona Hossaind44a3842012-10-15 09:41:35 -07001346static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1347{
1348 struct elf32_hdr *ehdr;
1349
1350 if (fw_entry->size < sizeof(*ehdr)) {
1351 pr_err("%s: Not big enough to be an elf header\n",
1352 qseecom.pdev->init_name);
1353 return false;
1354 }
1355 ehdr = (struct elf32_hdr *)fw_entry->data;
1356 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1357 pr_err("%s: Not an elf header\n",
1358 qseecom.pdev->init_name);
1359 return false;
1360 }
1361
1362 if (ehdr->e_phnum == 0) {
1363 pr_err("%s: No loadable segments\n",
1364 qseecom.pdev->init_name);
1365 return false;
1366 }
1367 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1368 sizeof(struct elf32_hdr) > fw_entry->size) {
1369 pr_err("%s: Program headers not within mdt\n",
1370 qseecom.pdev->init_name);
1371 return false;
1372 }
1373 return true;
1374}
1375
1376static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1377{
1378 int ret = -1;
1379 int i = 0, rc = 0;
1380 const struct firmware *fw_entry = NULL;
1381 struct elf32_phdr *phdr;
1382 char fw_name[MAX_APP_NAME_SIZE];
1383 struct elf32_hdr *ehdr;
1384 int num_images = 0;
1385
1386 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1387 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1388 if (rc) {
1389 pr_err("error with request_firmware\n");
1390 ret = -EIO;
1391 goto err;
1392 }
1393 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1394 ret = -EIO;
1395 goto err;
1396 }
1397 *fw_size = fw_entry->size;
1398 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1399 ehdr = (struct elf32_hdr *)fw_entry->data;
1400 num_images = ehdr->e_phnum;
1401 release_firmware(fw_entry);
1402 for (i = 0; i < num_images; i++, phdr++) {
1403 memset(fw_name, 0, sizeof(fw_name));
1404 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1405 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1406 if (ret)
1407 goto err;
1408 *fw_size += fw_entry->size;
1409 release_firmware(fw_entry);
1410 }
1411 return ret;
1412err:
1413 if (fw_entry)
1414 release_firmware(fw_entry);
1415 *fw_size = 0;
1416 return ret;
1417}
1418
1419static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1420 struct qseecom_load_app_ireq *load_req)
1421{
1422 int ret = -1;
1423 int i = 0, rc = 0;
1424 const struct firmware *fw_entry = NULL;
1425 char fw_name[MAX_APP_NAME_SIZE];
1426 u8 *img_data_ptr = img_data;
1427 struct elf32_hdr *ehdr;
1428 int num_images = 0;
1429
1430 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1431 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1432 if (rc) {
1433 ret = -EIO;
1434 goto err;
1435 }
1436 load_req->img_len = fw_entry->size;
1437 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1438 img_data_ptr = img_data_ptr + fw_entry->size;
1439 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1440 ehdr = (struct elf32_hdr *)fw_entry->data;
1441 num_images = ehdr->e_phnum;
1442 release_firmware(fw_entry);
1443 for (i = 0; i < num_images; i++) {
1444 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1445 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1446 if (ret) {
1447 pr_err("Failed to locate blob %s\n", fw_name);
1448 goto err;
1449 }
1450 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1451 img_data_ptr = img_data_ptr + fw_entry->size;
1452 load_req->img_len += fw_entry->size;
1453 release_firmware(fw_entry);
1454 }
1455 load_req->phy_addr = virt_to_phys(img_data);
1456 return ret;
1457err:
1458 release_firmware(fw_entry);
1459 return ret;
1460}
1461
1462static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1463{
1464 int ret = -1;
1465 uint32_t fw_size = 0;
1466 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1467 struct qseecom_command_scm_resp resp;
1468 u8 *img_data = NULL;
1469
1470 if (__qseecom_get_fw_size(appname, &fw_size))
1471 return -EIO;
1472
1473 img_data = kzalloc(fw_size, GFP_KERNEL);
1474 if (!img_data) {
1475 pr_err("Failied to allocate memory for copying image data\n");
1476 return -ENOMEM;
1477 }
1478 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1479 if (ret) {
1480 kzfree(img_data);
1481 return -EIO;
1482 }
1483
1484 /* Populate the remaining parameters */
1485 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1486 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001487 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001488 if (ret) {
1489 kzfree(img_data);
1490 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001491 return -EIO;
1492 }
1493
Mona Hossaind44a3842012-10-15 09:41:35 -07001494 /* SCM_CALL to load the image */
1495 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1496 sizeof(struct qseecom_load_app_ireq),
1497 &resp, sizeof(resp));
1498 kzfree(img_data);
1499 if (ret) {
1500 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001501 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001502 return -EIO;
1503 }
1504
1505 switch (resp.result) {
1506 case QSEOS_RESULT_SUCCESS:
1507 ret = resp.data;
1508 break;
1509 case QSEOS_RESULT_INCOMPLETE:
1510 ret = __qseecom_process_incomplete_cmd(data, &resp);
1511 if (ret)
1512 pr_err("process_incomplete_cmd FAILED\n");
1513 else
1514 ret = resp.data;
1515 break;
1516 case QSEOS_RESULT_FAILURE:
1517 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1518 break;
1519 default:
1520 pr_err("scm call return unknown response %d\n", resp.result);
1521 ret = -EINVAL;
1522 break;
1523 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001524 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001525
Mona Hossaind44a3842012-10-15 09:41:35 -07001526 return ret;
1527}
1528
Mona Hossain9498f5e2013-01-23 18:08:45 -08001529static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001530{
1531 int32_t ret = 0;
1532 uint32_t fw_size = 0;
1533 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1534 struct qseecom_command_scm_resp resp;
1535 u8 *img_data = NULL;
1536
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001537 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001538 return -EIO;
1539
1540 img_data = kzalloc(fw_size, GFP_KERNEL);
1541 if (!img_data) {
1542 pr_err("Mem allocation for lib image data failed\n");
1543 return -ENOMEM;
1544 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001545 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001546 if (ret) {
1547 kzfree(img_data);
1548 return -EIO;
1549 }
1550 /* Populate the remaining parameters */
1551 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001552 /* Vote for the SFPB clock */
1553 ret = qsee_vote_for_clock(data, CLK_SFPB);
1554 if (ret) {
1555 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1556 kzfree(img_data);
1557 return -EIO;
1558 }
1559
Mona Hossain05c73562012-10-29 17:49:01 -07001560 /* SCM_CALL to load the image */
1561 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1562 sizeof(struct qseecom_load_lib_image_ireq),
1563 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001564 if (ret) {
1565 pr_err("scm_call to load failed : ret %d\n", ret);
1566 ret = -EIO;
1567 } else {
1568 switch (resp.result) {
1569 case QSEOS_RESULT_SUCCESS:
1570 break;
1571 case QSEOS_RESULT_FAILURE:
1572 pr_err("scm call failed w/response result%d\n",
1573 resp.result);
1574 ret = -EINVAL;
1575 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001576 case QSEOS_RESULT_INCOMPLETE:
1577 ret = __qseecom_process_incomplete_cmd(data, &resp);
1578 if (ret)
1579 pr_err("process_incomplete_cmd failed err: %d\n",
1580 ret);
1581 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001582 default:
1583 pr_err("scm call return unknown response %d\n",
1584 resp.result);
1585 ret = -EINVAL;
1586 break;
1587 }
1588 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001589 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001590 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001591 return ret;
1592}
1593
1594static int qseecom_unload_commonlib_image(void)
1595{
1596 int ret = -EINVAL;
1597 struct qseecom_unload_lib_image_ireq unload_req = {0};
1598 struct qseecom_command_scm_resp resp;
1599
1600 /* Populate the remaining parameters */
1601 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1602 /* SCM_CALL to load the image */
1603 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1604 sizeof(struct qseecom_unload_lib_image_ireq),
1605 &resp, sizeof(resp));
1606 if (ret) {
1607 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1608 ret = -EIO;
1609 } else {
1610 switch (resp.result) {
1611 case QSEOS_RESULT_SUCCESS:
1612 break;
1613 case QSEOS_RESULT_FAILURE:
1614 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1615 break;
1616 default:
1617 pr_err("scm call return unknown response %d\n",
1618 resp.result);
1619 ret = -EINVAL;
1620 break;
1621 }
1622 }
1623 return ret;
1624}
1625
Mona Hossaind44a3842012-10-15 09:41:35 -07001626int qseecom_start_app(struct qseecom_handle **handle,
1627 char *app_name, uint32_t size)
1628{
Mona Hossain05c73562012-10-29 17:49:01 -07001629 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001630 unsigned long flags = 0;
1631 struct qseecom_dev_handle *data = NULL;
1632 struct qseecom_check_app_ireq app_ireq;
1633 struct qseecom_registered_app_list *entry = NULL;
1634 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1635 bool found_app = false;
1636 uint32_t len;
1637 ion_phys_addr_t pa;
1638
1639 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1640 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1641 return -EINVAL;
1642 }
1643
Mona Hossain823f9882012-11-23 14:42:20 -08001644 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1645 if (!(*handle)) {
1646 pr_err("failed to allocate memory for kernel client handle\n");
1647 return -ENOMEM;
1648 }
1649
Mona Hossaind44a3842012-10-15 09:41:35 -07001650 data = kzalloc(sizeof(*data), GFP_KERNEL);
1651 if (!data) {
1652 pr_err("kmalloc failed\n");
1653 if (ret == 0) {
1654 kfree(*handle);
1655 *handle = NULL;
1656 }
1657 return -ENOMEM;
1658 }
1659 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001660 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001661 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001662 data->client.sb_length = size;
1663 data->client.user_virt_sb_base = 0;
1664 data->client.ihandle = NULL;
1665
1666 init_waitqueue_head(&data->abort_wq);
1667 atomic_set(&data->ioctl_count, 0);
1668
1669 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1670 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1671 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1672 pr_err("Ion client could not retrieve the handle\n");
1673 kfree(data);
1674 kfree(*handle);
1675 *handle = NULL;
1676 return -EINVAL;
1677 }
1678
Mona Hossain9498f5e2013-01-23 18:08:45 -08001679 if (qseecom.qsee_version > QSEEE_VERSION_00) {
1680 mutex_lock(&app_access_lock);
1681 if (qseecom.commonlib_loaded == false) {
1682 ret = qseecom_load_commonlib_image(data);
1683 if (ret == 0)
1684 qseecom.commonlib_loaded = true;
1685 }
1686 mutex_unlock(&app_access_lock);
1687 }
1688
1689 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001690 pr_err("Failed to load commonlib image\n");
Mona Hossain9498f5e2013-01-23 18:08:45 -08001691 kfree(data);
1692 kfree(*handle);
1693 *handle = NULL;
1694 return -EIO;
1695 }
1696
1697 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1698 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1699 ret = __qseecom_check_app_exists(app_ireq);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001700 if (ret < 0) {
1701 kzfree(data);
1702 kfree(*handle);
1703 *handle = NULL;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001704 return -EINVAL;
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001705 }
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001706 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001707 if (ret > 0) {
1708 pr_warn("App id %d for [%s] app exists\n", ret,
1709 (char *)app_ireq.app_name);
1710 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1711 list_for_each_entry(entry,
1712 &qseecom.registered_app_list_head, list){
1713 if (entry->app_id == ret) {
1714 entry->ref_cnt++;
1715 found_app = true;
1716 break;
1717 }
1718 }
1719 spin_unlock_irqrestore(
1720 &qseecom.registered_app_list_lock, flags);
1721 if (!found_app)
1722 pr_warn("App_id %d [%s] was loaded but not registered\n",
1723 ret, (char *)app_ireq.app_name);
1724 } else {
1725 /* load the app and get the app_id */
1726 pr_debug("%s: Loading app for the first time'\n",
1727 qseecom.pdev->init_name);
1728 mutex_lock(&app_access_lock);
1729 ret = __qseecom_load_fw(data, app_name);
1730 mutex_unlock(&app_access_lock);
1731
1732 if (ret < 0) {
1733 kfree(*handle);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001734 kfree(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001735 *handle = NULL;
1736 return ret;
1737 }
1738 data->client.app_id = ret;
1739 }
1740 if (!found_app) {
1741 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1742 if (!entry) {
1743 pr_err("kmalloc failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001744 kfree(data);
1745 kfree(*handle);
1746 *handle = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001747 return -ENOMEM;
1748 }
1749 entry->app_id = ret;
1750 entry->ref_cnt = 1;
1751
1752 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1753 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1754 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1755 flags);
1756 }
1757
1758 /* Get the physical address of the ION BUF */
1759 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1760 /* Populate the structure for sending scm call to load image */
1761 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1762 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001763 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001764 data->client.sb_phys = pa;
1765 (*handle)->dev = (void *)data;
1766 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1767 (*handle)->sbuf_len = data->client.sb_length;
1768
1769 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1770 if (!kclient_entry) {
1771 pr_err("kmalloc failed\n");
1772 return -ENOMEM;
1773 }
1774 kclient_entry->handle = *handle;
1775
1776 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1777 list_add_tail(&kclient_entry->list,
1778 &qseecom.registered_kclient_list_head);
1779 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1780
1781 return 0;
1782}
1783EXPORT_SYMBOL(qseecom_start_app);
1784
1785int qseecom_shutdown_app(struct qseecom_handle **handle)
1786{
1787 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001788 struct qseecom_dev_handle *data;
1789
Mona Hossaind44a3842012-10-15 09:41:35 -07001790 struct qseecom_registered_kclient_list *kclient = NULL;
1791 unsigned long flags = 0;
1792 bool found_handle = false;
1793
1794 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1795 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1796 return -EINVAL;
1797 }
Mona Hossain33824022013-02-25 09:32:33 -08001798 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001799 pr_err("Handle is not initialized\n");
1800 return -EINVAL;
1801 }
Mona Hossain33824022013-02-25 09:32:33 -08001802 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001803 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1804 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1805 list) {
1806 if (kclient->handle == (*handle)) {
1807 list_del(&kclient->list);
1808 found_handle = true;
1809 break;
1810 }
1811 }
1812 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1813 if (!found_handle)
1814 pr_err("Unable to find the handle, exiting\n");
1815 else
1816 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001817 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001818 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001819 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001820 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001821 if (ret == 0) {
1822 kzfree(data);
1823 kzfree(*handle);
1824 kzfree(kclient);
1825 *handle = NULL;
1826 }
1827 return ret;
1828}
1829EXPORT_SYMBOL(qseecom_shutdown_app);
1830
1831int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1832 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1833{
1834 int ret = 0;
1835 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1836 struct qseecom_dev_handle *data;
1837
1838 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1839 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1840 return -EINVAL;
1841 }
1842
1843 if (handle == NULL) {
1844 pr_err("Handle is not initialized\n");
1845 return -EINVAL;
1846 }
1847 data = handle->dev;
1848
1849 req.cmd_req_len = sbuf_len;
1850 req.resp_len = rbuf_len;
1851 req.cmd_req_buf = send_buf;
1852 req.resp_buf = resp_buf;
1853
1854 mutex_lock(&app_access_lock);
1855 atomic_inc(&data->ioctl_count);
1856
1857 ret = __qseecom_send_cmd(data, &req);
1858
1859 atomic_dec(&data->ioctl_count);
1860 mutex_unlock(&app_access_lock);
1861
1862 if (ret)
1863 return ret;
1864
1865 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1866 req.resp_len, req.resp_buf);
1867 return ret;
1868}
1869EXPORT_SYMBOL(qseecom_send_command);
1870
Mona Hossain91a8fc92012-11-07 19:58:30 -08001871int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1872{
Mona Hossainfca6f422013-01-12 13:00:35 -08001873 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001874 if ((handle == NULL) || (handle->dev == NULL)) {
1875 pr_err("No valid kernel client\n");
1876 return -EINVAL;
1877 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001878 if (high) {
1879 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1880 if (ret)
1881 pr_err("Failed to vote for DFAB clock%d\n", ret);
1882 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1883 if (ret) {
1884 pr_err("Failed to vote for SFPB clock%d\n", ret);
1885 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1886 }
1887 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001888 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001889 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001890 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001891 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001892}
1893EXPORT_SYMBOL(qseecom_set_bandwidth);
1894
Mona Hossain2892b6b2012-02-17 13:53:11 -08001895static int qseecom_send_resp(void)
1896{
1897 qseecom.send_resp_flag = 1;
1898 wake_up_interruptible(&qseecom.send_resp_wq);
1899 return 0;
1900}
1901
1902static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1903 void __user *argp)
1904{
1905 struct qseecom_qseos_version_req req;
1906
1907 if (copy_from_user(&req, argp, sizeof(req))) {
1908 pr_err("copy_from_user failed");
1909 return -EINVAL;
1910 }
1911 req.qseos_version = qseecom.qseos_version;
1912 if (copy_to_user(argp, &req, sizeof(req))) {
1913 pr_err("copy_to_user failed");
1914 return -EINVAL;
1915 }
1916 return 0;
1917}
1918
Mona Hossainc92629e2013-04-01 13:37:46 -07001919static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001920{
1921 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001922 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001923
Mona Hossainc92629e2013-04-01 13:37:46 -07001924 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001925 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001926 else
1927 qclk = &qseecom.ce_drv;
1928
1929 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001930
1931 if (qclk->clk_access_cnt == ULONG_MAX)
1932 goto err;
1933
Mona Hossainc92629e2013-04-01 13:37:46 -07001934 if (qclk->clk_access_cnt > 0) {
1935 qclk->clk_access_cnt++;
1936 mutex_unlock(&clk_access_lock);
1937 return rc;
1938 }
1939
Mona Hossain6311d572013-03-01 15:54:02 -08001940 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001941 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001942 if (rc) {
1943 pr_err("Unable to enable/prepare CE core clk\n");
1944 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001945 }
1946 /* Enable CE clk */
1947 rc = clk_prepare_enable(qclk->ce_clk);
1948 if (rc) {
1949 pr_err("Unable to enable/prepare CE iface clk\n");
1950 goto ce_clk_err;
1951 }
1952 /* Enable AXI clk */
1953 rc = clk_prepare_enable(qclk->ce_bus_clk);
1954 if (rc) {
1955 pr_err("Unable to enable/prepare CE bus clk\n");
1956 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001957 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001958 qclk->clk_access_cnt++;
1959 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001960 return 0;
1961
1962ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001963 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001964ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001965 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001966err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001967 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001968 return -EIO;
1969}
1970
Mona Hossainc92629e2013-04-01 13:37:46 -07001971static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001972{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001973 struct qseecom_clk *qclk;
1974
Mona Hossainc92629e2013-04-01 13:37:46 -07001975 if (ce == CLK_QSEE)
1976 qclk = &qseecom.qsee;
1977 else
1978 qclk = &qseecom.ce_drv;
1979
1980 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001981
1982 if (qclk->clk_access_cnt == 0) {
1983 mutex_unlock(&clk_access_lock);
1984 return;
1985 }
1986
Mona Hossainc92629e2013-04-01 13:37:46 -07001987 if (qclk->clk_access_cnt == 1) {
1988 if (qclk->ce_clk != NULL)
1989 clk_disable_unprepare(qclk->ce_clk);
1990 if (qclk->ce_core_clk != NULL)
1991 clk_disable_unprepare(qclk->ce_core_clk);
1992 if (qclk->ce_bus_clk != NULL)
1993 clk_disable_unprepare(qclk->ce_bus_clk);
1994 }
1995 qclk->clk_access_cnt--;
1996 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001997}
1998
Mona Hossain04d3fac2012-12-03 10:10:37 -08001999static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2000 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002001{
2002 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002003 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002004
Mona Hossain17a4faf2013-03-22 16:40:56 -07002005 qclk = &qseecom.qsee;
2006 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002007 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002008
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002009 switch (clk_type) {
2010 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002011 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002012 if (!qseecom.qsee_bw_count) {
2013 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002014 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002015 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002016 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002017 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002018 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002019 if (!ret) {
2020 ret =
2021 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002022 qseecom.qsee_perf_client, 1);
2023 if ((ret) &&
2024 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002025 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002026 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002027 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002028 if (ret)
2029 pr_err("DFAB Bandwidth req failed (%d)\n",
2030 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002031 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002032 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002033 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002034 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002035 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002036 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002037 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002038 }
2039 mutex_unlock(&qsee_bw_mutex);
2040 break;
2041 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002042 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002043 if (!qseecom.qsee_sfpb_bw_count) {
2044 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002045 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002046 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002047 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002048 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002049 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002050 if (!ret) {
2051 ret =
2052 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002053 qseecom.qsee_perf_client, 2);
2054 if ((ret) &&
2055 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002056 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002057 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002058 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002059
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002060 if (ret)
2061 pr_err("SFPB Bandwidth req failed (%d)\n",
2062 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002063 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002064 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002065 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002066 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002067 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002068 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002069 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002070 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002071 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002072 break;
2073 default:
2074 pr_err("Clock type not defined\n");
2075 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002076 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002077 return ret;
2078}
2079
Mona Hossain04d3fac2012-12-03 10:10:37 -08002080static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2081 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002082{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002083 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002084 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002085
Mona Hossain17a4faf2013-03-22 16:40:56 -07002086 qclk = &qseecom.qsee;
2087 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002088 return;
2089
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002090 switch (clk_type) {
2091 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002092 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002093 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002094 pr_err("Client error.Extra call to disable DFAB clk\n");
2095 mutex_unlock(&qsee_bw_mutex);
2096 return;
2097 }
2098
Mona Hossain17a4faf2013-03-22 16:40:56 -07002099 if (qseecom.qsee_bw_count == 1) {
2100 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002101 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002102 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002103 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002104 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002105 qseecom.qsee_perf_client, 0);
2106 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002107 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002108 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002109 if (ret)
2110 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002111 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002112 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002113 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002114 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002115 }
2116 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002117 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002118 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002119 }
2120 mutex_unlock(&qsee_bw_mutex);
2121 break;
2122 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002123 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002124 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002125 pr_err("Client error.Extra call to disable SFPB clk\n");
2126 mutex_unlock(&qsee_bw_mutex);
2127 return;
2128 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002129 if (qseecom.qsee_sfpb_bw_count == 1) {
2130 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002131 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002132 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002133 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002134 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002135 qseecom.qsee_perf_client, 0);
2136 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002137 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002138 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002139 if (ret)
2140 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002141 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002142 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002143 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002144 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002145 }
2146 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002147 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002148 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002149 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002150 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002151 break;
2152 default:
2153 pr_err("Clock type not defined\n");
2154 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002155 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002156
Mona Hossain2892b6b2012-02-17 13:53:11 -08002157}
2158
Mona Hossain5ab9d772012-04-11 21:00:40 -07002159static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2160 void __user *argp)
2161{
2162 struct ion_handle *ihandle; /* Ion handle */
2163 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002164 int ret;
2165 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002166 ion_phys_addr_t pa = 0;
2167 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002168 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002169 struct qseecom_load_app_ireq load_req;
2170 struct qseecom_command_scm_resp resp;
2171
2172 /* Copy the relevant information needed for loading the image */
2173 if (__copy_from_user(&load_img_req,
2174 (void __user *)argp,
2175 sizeof(struct qseecom_load_img_req))) {
2176 pr_err("copy_from_user failed\n");
2177 return -EFAULT;
2178 }
2179
2180 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002181 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002182 load_img_req.ifd_data_fd);
2183 if (IS_ERR_OR_NULL(ihandle)) {
2184 pr_err("Ion client could not retrieve the handle\n");
2185 return -ENOMEM;
2186 }
2187
2188 /* Get the physical address of the ION BUF */
2189 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2190
2191 /* Populate the structure for sending scm call to load image */
2192 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2193 load_req.mdt_len = load_img_req.mdt_len;
2194 load_req.img_len = load_img_req.img_len;
2195 load_req.phy_addr = pa;
2196
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002197 /* SCM_CALL tied to Core0 */
2198 mask = CPU_MASK_CPU0;
2199 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2200 if (set_cpu_ret) {
2201 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2202 set_cpu_ret);
2203 ret = -EFAULT;
2204 goto qseecom_load_external_elf_set_cpu_err;
2205 }
Mona Hossain6311d572013-03-01 15:54:02 -08002206 /* Vote for the SFPB clock */
2207 ret = qsee_vote_for_clock(data, CLK_SFPB);
2208 if (ret) {
2209 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2210 ret = -EIO;
2211 goto qseecom_load_external_elf_set_cpu_err;
2212 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002213
Mona Hossain5ab9d772012-04-11 21:00:40 -07002214 /* SCM_CALL to load the external elf */
2215 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2216 sizeof(struct qseecom_load_app_ireq),
2217 &resp, sizeof(resp));
2218 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002219 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002220 ret);
2221 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002222 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002223 }
2224
2225 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2226 ret = __qseecom_process_incomplete_cmd(data, &resp);
2227 if (ret)
2228 pr_err("process_incomplete_cmd failed err: %d\n",
2229 ret);
2230 } else {
2231 if (resp.result != QSEOS_RESULT_SUCCESS) {
2232 pr_err("scm_call to load image failed resp.result =%d\n",
2233 resp.result);
2234 ret = -EFAULT;
2235 }
2236 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002237
2238qseecom_load_external_elf_scm_err:
2239 /* Restore the CPU mask */
2240 mask = CPU_MASK_ALL;
2241 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2242 if (set_cpu_ret) {
2243 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2244 set_cpu_ret);
2245 ret = -EFAULT;
2246 }
2247
2248qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002249 /* Deallocate the handle */
2250 if (!IS_ERR_OR_NULL(ihandle))
2251 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002252 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002253 return ret;
2254}
2255
2256static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2257{
2258 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002259 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002260 struct qseecom_command_scm_resp resp;
2261 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002262 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002263
2264 /* Populate the structure for sending scm call to unload image */
2265 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002266
2267 /* SCM_CALL tied to Core0 */
2268 mask = CPU_MASK_CPU0;
2269 ret = set_cpus_allowed_ptr(current, &mask);
2270 if (ret) {
2271 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2272 ret);
2273 return -EFAULT;
2274 }
2275
Mona Hossain5ab9d772012-04-11 21:00:40 -07002276 /* SCM_CALL to unload the external elf */
2277 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2278 sizeof(struct qseecom_unload_app_ireq),
2279 &resp, sizeof(resp));
2280 if (ret) {
2281 pr_err("scm_call to unload failed : ret %d\n",
2282 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002283 ret = -EFAULT;
2284 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002285 }
2286 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2287 ret = __qseecom_process_incomplete_cmd(data, &resp);
2288 if (ret)
2289 pr_err("process_incomplete_cmd fail err: %d\n",
2290 ret);
2291 } else {
2292 if (resp.result != QSEOS_RESULT_SUCCESS) {
2293 pr_err("scm_call to unload image failed resp.result =%d\n",
2294 resp.result);
2295 ret = -EFAULT;
2296 }
2297 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002298
2299qseecom_unload_external_elf_scm_err:
2300 /* Restore the CPU mask */
2301 mask = CPU_MASK_ALL;
2302 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2303 if (set_cpu_ret) {
2304 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2305 set_cpu_ret);
2306 ret = -EFAULT;
2307 }
2308
Mona Hossain5ab9d772012-04-11 21:00:40 -07002309 return ret;
2310}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002311
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002312static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2313 void __user *argp)
2314{
2315
2316 int32_t ret;
2317 struct qseecom_qseos_app_load_query query_req;
2318 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002319 struct qseecom_registered_app_list *entry = NULL;
2320 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002321
2322 /* Copy the relevant information needed for loading the image */
2323 if (__copy_from_user(&query_req,
2324 (void __user *)argp,
2325 sizeof(struct qseecom_qseos_app_load_query))) {
2326 pr_err("copy_from_user failed\n");
2327 return -EFAULT;
2328 }
2329
2330 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2331 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2332
2333 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002334
2335 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002336 pr_err(" scm call to check if app is loaded failed");
2337 return ret; /* scm call failed */
2338 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002339 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002340 (char *)(req.app_name));
2341 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2342 list_for_each_entry(entry,
2343 &qseecom.registered_app_list_head, list){
2344 if (entry->app_id == ret) {
2345 entry->ref_cnt++;
2346 break;
2347 }
2348 }
2349 spin_unlock_irqrestore(
2350 &qseecom.registered_app_list_lock, flags);
2351 data->client.app_id = ret;
2352 query_req.app_id = ret;
2353
2354 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2355 pr_err("copy_to_user failed\n");
2356 return -EFAULT;
2357 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002358 return -EEXIST; /* app already loaded */
2359 } else {
2360 return 0; /* app not loaded */
2361 }
2362}
2363
Mona Hossain4cf78a92013-02-14 12:06:41 -08002364static int __qseecom_get_ce_pipe_info(
2365 enum qseecom_key_management_usage_type usage,
2366 uint32_t *pipe, uint32_t *ce_hw)
2367{
2368 int ret;
2369 switch (usage) {
2370 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2371 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2372 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2373 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2374 qseecom.ce_info.disk_encrypt_pipe,
2375 qseecom.ce_info.hlos_ce_hw_instance);
2376 ret = -EINVAL;
2377 } else {
2378 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2379 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2380 ret = 0;
2381 }
2382 break;
2383 default:
2384 ret = -EINVAL;
2385 break;
2386 }
2387 return ret;
2388}
2389
2390static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2391 enum qseecom_key_management_usage_type usage,
2392 uint8_t *key_id, uint32_t flags)
2393{
2394 struct qseecom_key_generate_ireq ireq;
2395 struct qseecom_command_scm_resp resp;
2396 int ret;
2397
2398 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2399 pr_err("Error:: unsupported usage %d\n", usage);
2400 return -EFAULT;
2401 }
2402
2403 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2404 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002405 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002406
Mona Hossainc92629e2013-04-01 13:37:46 -07002407 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002408
2409 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002410 &ireq, sizeof(struct qseecom_key_generate_ireq),
2411 &resp, sizeof(resp));
2412 if (ret) {
2413 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002414 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002415 return ret;
2416 }
2417
2418 switch (resp.result) {
2419 case QSEOS_RESULT_SUCCESS:
2420 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002421 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
2422 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002423 case QSEOS_RESULT_INCOMPLETE:
2424 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002425 if (ret) {
2426 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
2427 pr_warn("process_incomplete_cmd return Key ID exits.\n");
2428 ret = 0;
2429 } else {
2430 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2431 resp.result);
2432 }
2433 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002434 break;
2435 case QSEOS_RESULT_FAILURE:
2436 default:
2437 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2438 ret = -EINVAL;
2439 break;
2440 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002441 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002442 return ret;
2443}
2444
2445static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2446 enum qseecom_key_management_usage_type usage,
2447 uint8_t *key_id, uint32_t flags)
2448{
2449 struct qseecom_key_delete_ireq ireq;
2450 struct qseecom_command_scm_resp resp;
2451 int ret;
2452
2453 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2454 pr_err("Error:: unsupported usage %d\n", usage);
2455 return -EFAULT;
2456 }
2457
2458 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2459 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002460 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002461
Mona Hossainc92629e2013-04-01 13:37:46 -07002462 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002463
2464 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002465 &ireq, sizeof(struct qseecom_key_delete_ireq),
2466 &resp, sizeof(struct qseecom_command_scm_resp));
2467 if (ret) {
2468 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002469 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002470 return ret;
2471 }
2472
2473 switch (resp.result) {
2474 case QSEOS_RESULT_SUCCESS:
2475 break;
2476 case QSEOS_RESULT_INCOMPLETE:
2477 ret = __qseecom_process_incomplete_cmd(data, &resp);
2478 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002479 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2480 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002481 break;
2482 case QSEOS_RESULT_FAILURE:
2483 default:
2484 pr_err("Delete key scm call failed resp.result %d\n",
2485 resp.result);
2486 ret = -EINVAL;
2487 break;
2488 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002489 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002490 return ret;
2491}
2492
2493static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2494 enum qseecom_key_management_usage_type usage,
2495 struct qseecom_set_key_parameter *set_key_para)
2496{
2497 struct qseecom_key_select_ireq ireq;
2498 struct qseecom_command_scm_resp resp;
2499 int ret;
2500
2501 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2502 pr_err("Error:: unsupported usage %d\n", usage);
2503 return -EFAULT;
2504 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002505
2506 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2507 __qseecom_enable_clk(CLK_QSEE);
2508 else
2509 __qseecom_enable_clk(CLK_CE_DRV);
2510
Mona Hossain4cf78a92013-02-14 12:06:41 -08002511 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002512 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002513 ireq.ce = set_key_para->ce_hw;
2514 ireq.pipe = set_key_para->pipe;
2515 ireq.flags = set_key_para->flags;
2516
Zhen Kong1f09c7692013-05-03 17:50:32 -07002517 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2518 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002519
Mona Hossain4cf78a92013-02-14 12:06:41 -08002520 if (set_key_para->set_clear_key_flag ==
2521 QSEECOM_SET_CE_KEY_CMD)
2522 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2523 QSEECOM_HASH_SIZE);
2524 else
2525 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2526
Zhen Kong336636e2013-04-15 11:04:54 -07002527 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002528 &ireq, sizeof(struct qseecom_key_select_ireq),
2529 &resp, sizeof(struct qseecom_command_scm_resp));
2530 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002531 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
2532 return ret;
2533 }
2534
Mona Hossain4cf78a92013-02-14 12:06:41 -08002535 switch (resp.result) {
2536 case QSEOS_RESULT_SUCCESS:
2537 break;
2538 case QSEOS_RESULT_INCOMPLETE:
2539 ret = __qseecom_process_incomplete_cmd(data, &resp);
2540 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002541 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2542 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002543 break;
2544 case QSEOS_RESULT_FAILURE:
2545 default:
2546 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2547 ret = -EINVAL;
2548 break;
2549 }
2550
Mona Hossainc92629e2013-04-01 13:37:46 -07002551 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2552 __qseecom_disable_clk(CLK_QSEE);
2553 else
2554 __qseecom_disable_clk(CLK_CE_DRV);
2555
Mona Hossain4cf78a92013-02-14 12:06:41 -08002556 return ret;
2557}
2558
2559static int qseecom_create_key(struct qseecom_dev_handle *data,
2560 void __user *argp)
2561{
2562 uint32_t ce_hw = 0;
2563 uint32_t pipe = 0;
2564 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2565 int ret = 0;
2566 uint32_t flags = 0;
2567 struct qseecom_set_key_parameter set_key_para;
2568 struct qseecom_create_key_req create_key_req;
2569
2570 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2571 if (ret) {
2572 pr_err("copy_from_user failed\n");
2573 return ret;
2574 }
2575
2576 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2577 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2578 return -EFAULT;
2579 }
2580
2581 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2582 if (ret) {
2583 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2584 return -EINVAL;
2585 }
2586
2587 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2588 key_id, flags);
2589 if (ret) {
2590 pr_err("Failed to generate key on storage: %d\n", ret);
2591 return -EFAULT;
2592 }
2593
2594 set_key_para.ce_hw = ce_hw;
2595 set_key_para.pipe = pipe;
2596 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2597 set_key_para.flags = flags;
2598 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2599 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2600 QSEECOM_HASH_SIZE);
2601
2602 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2603 &set_key_para);
2604 if (ret) {
2605 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2606 pipe, ce_hw, ret);
2607 return -EFAULT;
2608 }
2609
2610 return ret;
2611}
2612
2613static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2614 void __user *argp)
2615{
2616 uint32_t ce_hw = 0;
2617 uint32_t pipe = 0;
2618 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2619 int ret = 0;
2620 uint32_t flags = 0;
2621 int i;
2622 struct qseecom_wipe_key_req wipe_key_req;
2623 struct qseecom_set_key_parameter clear_key_para;
2624
2625 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2626 if (ret) {
2627 pr_err("copy_from_user failed\n");
2628 return ret;
2629 }
2630
2631 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2632 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2633 return -EFAULT;
2634 }
2635
2636 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2637 if (ret) {
2638 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2639 return -EINVAL;
2640 }
2641
2642 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2643 flags);
2644 if (ret) {
2645 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2646 return -EFAULT;
2647 }
2648
2649 /* an invalid key_id 0xff is used to indicate clear key*/
2650 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2651 clear_key_para.key_id[i] = 0xff;
2652 clear_key_para.ce_hw = ce_hw;
2653 clear_key_para.pipe = pipe;
2654 clear_key_para.flags = flags;
2655 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2656 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2657 &clear_key_para);
2658 if (ret) {
2659 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2660 pipe, ce_hw, ret);
2661 return -EFAULT;
2662 }
2663
2664 return ret;
2665}
2666
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002667static int qseecom_is_es_activated(void __user *argp)
2668{
2669 struct qseecom_is_es_activated_req req;
2670 int ret;
2671 int resp_buf;
2672
2673 if (qseecom.qsee_version < QSEE_VERSION_04) {
2674 pr_err("invalid qsee version");
2675 return -ENODEV;
2676 }
2677
2678 if (argp == NULL) {
2679 pr_err("arg is null");
2680 return -EINVAL;
2681 }
2682
2683 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2684 (void *) &resp_buf, sizeof(resp_buf));
2685 if (ret) {
2686 pr_err("scm_call failed");
2687 return ret;
2688 }
2689
2690 req.is_activated = resp_buf;
2691 ret = copy_to_user(argp, &req, sizeof(req));
2692 if (ret) {
2693 pr_err("copy_to_user failed");
2694 return ret;
2695 }
2696
2697 return 0;
2698}
2699
2700static int qseecom_save_partition_hash(void __user *argp)
2701{
2702 struct qseecom_save_partition_hash_req req;
2703 int ret;
2704
2705 if (qseecom.qsee_version < QSEE_VERSION_04) {
2706 pr_err("invalid qsee version ");
2707 return -ENODEV;
2708 }
2709
2710 if (argp == NULL) {
2711 pr_err("arg is null");
2712 return -EINVAL;
2713 }
2714
2715 ret = copy_from_user(&req, argp, sizeof(req));
2716 if (ret) {
2717 pr_err("copy_from_user failed");
2718 return ret;
2719 }
2720
2721 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2722 (void *) &req, sizeof(req), NULL, 0);
2723 if (ret) {
2724 pr_err("scm_call failed");
2725 return ret;
2726 }
2727
2728 return 0;
2729}
2730
Mona Hossain2892b6b2012-02-17 13:53:11 -08002731static long qseecom_ioctl(struct file *file, unsigned cmd,
2732 unsigned long arg)
2733{
2734 int ret = 0;
2735 struct qseecom_dev_handle *data = file->private_data;
2736 void __user *argp = (void __user *) arg;
2737
2738 if (data->abort) {
2739 pr_err("Aborting qseecom driver\n");
2740 return -ENODEV;
2741 }
2742
2743 switch (cmd) {
2744 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2745 pr_debug("ioctl register_listener_req()\n");
2746 atomic_inc(&data->ioctl_count);
2747 ret = qseecom_register_listener(data, argp);
2748 atomic_dec(&data->ioctl_count);
2749 wake_up_all(&data->abort_wq);
2750 if (ret)
2751 pr_err("failed qseecom_register_listener: %d\n", ret);
2752 break;
2753 }
2754 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2755 pr_debug("ioctl unregister_listener_req()\n");
2756 atomic_inc(&data->ioctl_count);
2757 ret = qseecom_unregister_listener(data);
2758 atomic_dec(&data->ioctl_count);
2759 wake_up_all(&data->abort_wq);
2760 if (ret)
2761 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2762 break;
2763 }
2764 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2765 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002766 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002767 atomic_inc(&data->ioctl_count);
2768 ret = qseecom_send_cmd(data, argp);
2769 atomic_dec(&data->ioctl_count);
2770 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002771 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002772 if (ret)
2773 pr_err("failed qseecom_send_cmd: %d\n", ret);
2774 break;
2775 }
2776 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2777 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002778 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002779 atomic_inc(&data->ioctl_count);
2780 ret = qseecom_send_modfd_cmd(data, argp);
2781 atomic_dec(&data->ioctl_count);
2782 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002783 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002784 if (ret)
2785 pr_err("failed qseecom_send_cmd: %d\n", ret);
2786 break;
2787 }
2788 case QSEECOM_IOCTL_RECEIVE_REQ: {
2789 atomic_inc(&data->ioctl_count);
2790 ret = qseecom_receive_req(data);
2791 atomic_dec(&data->ioctl_count);
2792 wake_up_all(&data->abort_wq);
2793 if (ret)
2794 pr_err("failed qseecom_receive_req: %d\n", ret);
2795 break;
2796 }
2797 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2798 atomic_inc(&data->ioctl_count);
2799 ret = qseecom_send_resp();
2800 atomic_dec(&data->ioctl_count);
2801 wake_up_all(&data->abort_wq);
2802 if (ret)
2803 pr_err("failed qseecom_send_resp: %d\n", ret);
2804 break;
2805 }
2806 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2807 ret = qseecom_set_client_mem_param(data, argp);
2808 if (ret)
2809 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2810 ret);
2811 break;
2812 }
2813 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2814 mutex_lock(&app_access_lock);
2815 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002816 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2817 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002818 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002819 if (ret == 0)
2820 qseecom.commonlib_loaded = true;
2821 }
2822 }
2823 if (ret == 0)
2824 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002825 atomic_dec(&data->ioctl_count);
2826 mutex_unlock(&app_access_lock);
2827 if (ret)
2828 pr_err("failed load_app request: %d\n", ret);
2829 break;
2830 }
2831 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2832 mutex_lock(&app_access_lock);
2833 atomic_inc(&data->ioctl_count);
2834 ret = qseecom_unload_app(data);
2835 atomic_dec(&data->ioctl_count);
2836 mutex_unlock(&app_access_lock);
2837 if (ret)
2838 pr_err("failed unload_app request: %d\n", ret);
2839 break;
2840 }
2841 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2842 atomic_inc(&data->ioctl_count);
2843 ret = qseecom_get_qseos_version(data, argp);
2844 if (ret)
2845 pr_err("qseecom_get_qseos_version: %d\n", ret);
2846 atomic_dec(&data->ioctl_count);
2847 break;
2848 }
2849 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2850 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002851 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002852 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002853 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002854 ret = qsee_vote_for_clock(data, CLK_SFPB);
2855 if (ret)
2856 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002857 atomic_dec(&data->ioctl_count);
2858 break;
2859 }
2860 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2861 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002862 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002863 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002864 atomic_dec(&data->ioctl_count);
2865 break;
2866 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002867 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2868 data->released = true;
2869 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2870 pr_err("Loading External elf image unsupported in rev 0x13\n");
2871 ret = -EINVAL;
2872 break;
2873 }
2874 mutex_lock(&app_access_lock);
2875 atomic_inc(&data->ioctl_count);
2876 ret = qseecom_load_external_elf(data, argp);
2877 atomic_dec(&data->ioctl_count);
2878 mutex_unlock(&app_access_lock);
2879 if (ret)
2880 pr_err("failed load_external_elf request: %d\n", ret);
2881 break;
2882 }
2883 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2884 data->released = true;
2885 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2886 pr_err("Unloading External elf image unsupported in rev 0x13\n");
2887 ret = -EINVAL;
2888 break;
2889 }
2890 mutex_lock(&app_access_lock);
2891 atomic_inc(&data->ioctl_count);
2892 ret = qseecom_unload_external_elf(data);
2893 atomic_dec(&data->ioctl_count);
2894 mutex_unlock(&app_access_lock);
2895 if (ret)
2896 pr_err("failed unload_app request: %d\n", ret);
2897 break;
2898 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002899 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2900 mutex_lock(&app_access_lock);
2901 atomic_inc(&data->ioctl_count);
2902 ret = qseecom_query_app_loaded(data, argp);
2903 atomic_dec(&data->ioctl_count);
2904 mutex_unlock(&app_access_lock);
2905 break;
2906 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002907 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2908 if (qseecom.qsee_version < QSEE_VERSION_03) {
2909 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2910 qseecom.qsee_version);
2911 return -EINVAL;
2912 }
2913 mutex_lock(&app_access_lock);
2914 atomic_inc(&data->ioctl_count);
2915 ret = qseecom_send_service_cmd(data, argp);
2916 atomic_dec(&data->ioctl_count);
2917 mutex_unlock(&app_access_lock);
2918 break;
2919 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002920 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002921 if (qseecom.qsee_version < QSEE_VERSION_05) {
2922 pr_err("Create Key feature not supported in qsee version %u\n",
2923 qseecom.qsee_version);
2924 return -EINVAL;
2925 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002926 data->released = true;
2927 mutex_lock(&app_access_lock);
2928 atomic_inc(&data->ioctl_count);
2929 ret = qseecom_create_key(data, argp);
2930 if (ret)
2931 pr_err("failed to create encryption key: %d\n", ret);
2932
2933 atomic_dec(&data->ioctl_count);
2934 mutex_unlock(&app_access_lock);
2935 break;
2936 }
2937 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Kong336636e2013-04-15 11:04:54 -07002938 if (qseecom.qsee_version < QSEE_VERSION_05) {
2939 pr_err("Wipe Key feature not supported in qsee version %u\n",
2940 qseecom.qsee_version);
2941 return -EINVAL;
2942 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002943 data->released = true;
2944 mutex_lock(&app_access_lock);
2945 atomic_inc(&data->ioctl_count);
2946 ret = qseecom_wipe_key(data, argp);
2947 if (ret)
2948 pr_err("failed to wipe encryption key: %d\n", ret);
2949 atomic_dec(&data->ioctl_count);
2950 mutex_unlock(&app_access_lock);
2951 break;
2952 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002953 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
2954 data->released = true;
2955 mutex_lock(&app_access_lock);
2956 atomic_inc(&data->ioctl_count);
2957 ret = qseecom_save_partition_hash(argp);
2958 atomic_dec(&data->ioctl_count);
2959 mutex_unlock(&app_access_lock);
2960 break;
2961 }
2962 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
2963 data->released = true;
2964 mutex_lock(&app_access_lock);
2965 atomic_inc(&data->ioctl_count);
2966 ret = qseecom_is_es_activated(argp);
2967 atomic_dec(&data->ioctl_count);
2968 mutex_unlock(&app_access_lock);
2969 break;
2970 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002971 default:
2972 return -EINVAL;
2973 }
2974 return ret;
2975}
2976
2977static int qseecom_open(struct inode *inode, struct file *file)
2978{
2979 int ret = 0;
2980 struct qseecom_dev_handle *data;
2981
2982 data = kzalloc(sizeof(*data), GFP_KERNEL);
2983 if (!data) {
2984 pr_err("kmalloc failed\n");
2985 return -ENOMEM;
2986 }
2987 file->private_data = data;
2988 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002989 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002990 data->released = false;
2991 init_waitqueue_head(&data->abort_wq);
2992 atomic_set(&data->ioctl_count, 0);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002993 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2994 int pil_error;
2995 mutex_lock(&pil_access_lock);
2996 if (pil_ref_cnt == 0) {
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002997 pil = subsystem_get("tzapps");
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002998 if (IS_ERR(pil)) {
2999 pr_err("Playready PIL image load failed\n");
3000 pil_error = PTR_ERR(pil);
3001 pil = NULL;
3002 pr_debug("tzapps image load FAILED\n");
3003 mutex_unlock(&pil_access_lock);
3004 return pil_error;
3005 }
3006 }
3007 pil_ref_cnt++;
3008 mutex_unlock(&pil_access_lock);
3009 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003010 return ret;
3011}
3012
3013static int qseecom_release(struct inode *inode, struct file *file)
3014{
3015 struct qseecom_dev_handle *data = file->private_data;
3016 int ret = 0;
3017
3018 if (data->released == false) {
3019 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003020 switch (data->type) {
3021 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003022 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003023 break;
3024 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003025 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003026 break;
3027 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003028 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003029 ret = qseecom_unmap_ion_allocated_memory(data);
3030 if (ret) {
3031 pr_err("Close failed\n");
3032 return ret;
3033 }
3034 break;
3035 default:
3036 pr_err("Unsupported clnt_handle_type %d",
3037 data->type);
3038 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003039 }
3040 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003041
Mona Hossainc9c83c72013-04-11 12:43:48 -07003042 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003043 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07003044 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003045 qsee_disable_clock_vote(data, CLK_DFAB);
3046
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003047 if (qseecom.qseos_version == QSEOS_VERSION_13) {
3048 mutex_lock(&pil_access_lock);
3049 if (pil_ref_cnt == 1)
Stephen Boyd77db8bb2012-06-27 15:15:16 -07003050 subsystem_put(pil);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003051 pil_ref_cnt--;
3052 mutex_unlock(&pil_access_lock);
3053 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003054 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003055
Mona Hossain2892b6b2012-02-17 13:53:11 -08003056 return ret;
3057}
3058
Mona Hossain2892b6b2012-02-17 13:53:11 -08003059static const struct file_operations qseecom_fops = {
3060 .owner = THIS_MODULE,
3061 .unlocked_ioctl = qseecom_ioctl,
3062 .open = qseecom_open,
3063 .release = qseecom_release
3064};
3065
Mona Hossainc92629e2013-04-01 13:37:46 -07003066static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003067{
3068 int rc = 0;
3069 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003070 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003071 char *core_clk_src = NULL;
3072 char *core_clk = NULL;
3073 char *iface_clk = NULL;
3074 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003075
Mona Hossainc92629e2013-04-01 13:37:46 -07003076 switch (ce) {
3077 case CLK_QSEE: {
3078 core_clk_src = "core_clk_src";
3079 core_clk = "core_clk";
3080 iface_clk = "iface_clk";
3081 bus_clk = "bus_clk";
3082 qclk = &qseecom.qsee;
3083 qclk->instance = CLK_QSEE;
3084 break;
3085 };
3086 case CLK_CE_DRV: {
3087 core_clk_src = "ce_drv_core_clk_src";
3088 core_clk = "ce_drv_core_clk";
3089 iface_clk = "ce_drv_iface_clk";
3090 bus_clk = "ce_drv_bus_clk";
3091 qclk = &qseecom.ce_drv;
3092 qclk->instance = CLK_CE_DRV;
3093 break;
3094 };
3095 default:
3096 pr_err("Invalid ce hw instance: %d!\n", ce);
3097 return -EIO;
3098 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003099 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003100
Mona Hossainc92629e2013-04-01 13:37:46 -07003101 /* Get CE3 src core clk. */
3102 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003103 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003104 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003105 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003106 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003107 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003108 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003109 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003110 }
3111 } else {
3112 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003113 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003114 }
3115
3116 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003117 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003118 if (IS_ERR(qclk->ce_core_clk)) {
3119 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003120 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003121 if (qclk->ce_core_src_clk != NULL)
3122 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003123 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003124 }
3125
3126 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003127 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003128 if (IS_ERR(qclk->ce_clk)) {
3129 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003130 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003131 if (qclk->ce_core_src_clk != NULL)
3132 clk_put(qclk->ce_core_src_clk);
3133 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003134 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003135 }
3136
3137 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003138 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003139 if (IS_ERR(qclk->ce_bus_clk)) {
3140 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003141 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003142 if (qclk->ce_core_src_clk != NULL)
3143 clk_put(qclk->ce_core_src_clk);
3144 clk_put(qclk->ce_core_clk);
3145 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003146 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003147 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003148 return rc;
3149}
3150
Mona Hossainc92629e2013-04-01 13:37:46 -07003151static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003152{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003153 struct qseecom_clk *qclk;
3154
Mona Hossainc92629e2013-04-01 13:37:46 -07003155 if (ce == CLK_QSEE)
3156 qclk = &qseecom.qsee;
3157 else
3158 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003159
3160 if (qclk->ce_clk != NULL) {
3161 clk_put(qclk->ce_clk);
3162 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003163 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003164 if (qclk->ce_core_clk != NULL) {
3165 clk_put(qclk->ce_core_clk);
3166 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003167 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003168 if (qclk->ce_bus_clk != NULL) {
3169 clk_put(qclk->ce_bus_clk);
3170 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003171 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003172 if (qclk->ce_core_src_clk != NULL) {
3173 clk_put(qclk->ce_core_src_clk);
3174 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003175 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003176}
3177
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003178static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003179{
3180 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003181 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003182 struct device *class_dev;
3183 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003184 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003185 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3186
Mona Hossain17a4faf2013-03-22 16:40:56 -07003187 qseecom.qsee_bw_count = 0;
3188 qseecom.qsee_perf_client = 0;
3189 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003190
Mona Hossain17a4faf2013-03-22 16:40:56 -07003191 qseecom.qsee.ce_core_clk = NULL;
3192 qseecom.qsee.ce_clk = NULL;
3193 qseecom.qsee.ce_core_src_clk = NULL;
3194 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003195
Mona Hossainc92629e2013-04-01 13:37:46 -07003196 qseecom.ce_drv.ce_core_clk = NULL;
3197 qseecom.ce_drv.ce_clk = NULL;
3198 qseecom.ce_drv.ce_core_src_clk = NULL;
3199 qseecom.ce_drv.ce_bus_clk = NULL;
3200
Mona Hossain2892b6b2012-02-17 13:53:11 -08003201 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3202 if (rc < 0) {
3203 pr_err("alloc_chrdev_region failed %d\n", rc);
3204 return rc;
3205 }
3206
3207 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3208 if (IS_ERR(driver_class)) {
3209 rc = -ENOMEM;
3210 pr_err("class_create failed %d\n", rc);
3211 goto unregister_chrdev_region;
3212 }
3213
3214 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3215 QSEECOM_DEV);
3216 if (!class_dev) {
3217 pr_err("class_device_create failed %d\n", rc);
3218 rc = -ENOMEM;
3219 goto class_destroy;
3220 }
3221
3222 cdev_init(&qseecom_cdev, &qseecom_fops);
3223 qseecom_cdev.owner = THIS_MODULE;
3224
3225 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
3226 if (rc < 0) {
3227 pr_err("cdev_add failed %d\n", rc);
3228 goto err;
3229 }
3230
3231 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3232 spin_lock_init(&qseecom.registered_listener_list_lock);
3233 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3234 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003235 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3236 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003237 init_waitqueue_head(&qseecom.send_resp_wq);
3238 qseecom.send_resp_flag = 0;
3239
3240 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3241 &qsee_not_legacy, sizeof(qsee_not_legacy));
3242 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003243 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003244 goto err;
3245 }
Mona Hossain05c73562012-10-29 17:49:01 -07003246 if (qsee_not_legacy) {
3247 uint32_t feature = 10;
3248
3249 qseecom.qsee_version = QSEEE_VERSION_00;
3250 rc = scm_call(6, 3, &feature, sizeof(feature),
3251 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3252 if (rc) {
3253 pr_err("Failed to get QSEE version info %d\n", rc);
3254 goto err;
3255 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003256 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003257 } else {
Mona Hossain2892b6b2012-02-17 13:53:11 -08003258 qseecom.qseos_version = QSEOS_VERSION_13;
Mona Hossain05c73562012-10-29 17:49:01 -07003259 qseecom.qsee_version = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003260 pil = NULL;
3261 pil_ref_cnt = 0;
3262 }
Mona Hossain05c73562012-10-29 17:49:01 -07003263 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003264 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003265 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003266 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003267 if (qseecom.ion_clnt == NULL) {
3268 pr_err("Ion client cannot be created\n");
3269 rc = -ENOMEM;
3270 goto err;
3271 }
3272
3273 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003274 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003275
Mona Hossain4cf78a92013-02-14 12:06:41 -08003276 if (of_property_read_u32((&pdev->dev)->of_node,
3277 "qcom,disk-encrypt-pipe-pair",
3278 &qseecom.ce_info.disk_encrypt_pipe)) {
3279 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3280 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3281 rc = -EINVAL;
3282 goto err;
3283 } else {
3284 pr_warn("bam_pipe_pair=0x%x",
3285 qseecom.ce_info.disk_encrypt_pipe);
3286 }
3287
3288 if (of_property_read_u32((&pdev->dev)->of_node,
3289 "qcom,qsee-ce-hw-instance",
3290 &qseecom.ce_info.qsee_ce_hw_instance)) {
3291 pr_err("Fail to get qsee ce hw instance information.\n");
3292 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3293 rc = -EINVAL;
3294 goto err;
3295 } else {
3296 pr_warn("qsee-ce-hw-instance=0x%x",
3297 qseecom.ce_info.qsee_ce_hw_instance);
3298 }
3299
3300 if (of_property_read_u32((&pdev->dev)->of_node,
3301 "qcom,hlos-ce-hw-instance",
3302 &qseecom.ce_info.hlos_ce_hw_instance)) {
3303 pr_err("Fail to get hlos ce hw instance information.\n");
3304 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3305 rc = -EINVAL;
3306 goto err;
3307 } else {
3308 pr_warn("hlos-ce-hw-instance=0x%x",
3309 qseecom.ce_info.hlos_ce_hw_instance);
3310 }
3311
Mona Hossainc92629e2013-04-01 13:37:46 -07003312 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3313 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3314
3315 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003316 if (ret)
3317 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003318
Mona Hossainc92629e2013-04-01 13:37:46 -07003319 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3320 ret = __qseecom_init_clk(CLK_CE_DRV);
3321 if (ret) {
3322 __qseecom_deinit_clk(CLK_QSEE);
3323 goto err;
3324 }
3325 } else {
3326 struct qseecom_clk *qclk;
3327
3328 qclk = &qseecom.qsee;
3329 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3330 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3331 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3332 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3333 }
3334
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003335 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3336 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003337 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3338 struct resource *resource = NULL;
3339 struct qsee_apps_region_info_ireq req;
3340 struct qseecom_command_scm_resp resp;
3341
3342 resource = platform_get_resource_byname(pdev,
3343 IORESOURCE_MEM, "secapp-region");
3344 if (resource) {
3345 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3346 req.addr = resource->start;
3347 req.size = resource_size(resource);
3348 pr_warn("secure app region addr=0x%x size=0x%x",
3349 req.addr, req.size);
3350 } else {
3351 pr_err("Fail to get secure app region info\n");
3352 rc = -EINVAL;
3353 goto err;
3354 }
3355 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3356 &resp, sizeof(resp));
3357 if (rc) {
3358 pr_err("Failed to send secapp region info %d\n",
3359 rc);
3360 goto err;
3361 }
3362 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003363 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003364 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3365 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003366 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003367
Mona Hossain17a4faf2013-03-22 16:40:56 -07003368 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003369 qseecom_platform_support);
3370
Mona Hossain17a4faf2013-03-22 16:40:56 -07003371 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003372 pr_err("Unable to register bus client\n");
3373 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003374err:
3375 device_destroy(driver_class, qseecom_device_no);
3376class_destroy:
3377 class_destroy(driver_class);
3378unregister_chrdev_region:
3379 unregister_chrdev_region(qseecom_device_no, 1);
3380 return rc;
3381}
3382
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003383static int __devinit qseecom_remove(struct platform_device *pdev)
3384{
Mona Hossaind44a3842012-10-15 09:41:35 -07003385 struct qseecom_registered_kclient_list *kclient = NULL;
3386 unsigned long flags = 0;
3387 int ret = 0;
3388
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003389 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003390 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003391
3392 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3393 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3394 struct qseecom_registered_kclient_list, list);
3395 if (list_empty(&kclient->list)) {
3396 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3397 flags);
3398 return 0;
3399 }
3400 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3401 list) {
3402 if (kclient)
3403 list_del(&kclient->list);
3404 break;
3405 }
3406 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3407
3408
3409 while (kclient->handle != NULL) {
3410 ret = qseecom_unload_app(kclient->handle->dev);
3411 if (ret == 0) {
3412 kzfree(kclient->handle->dev);
3413 kzfree(kclient->handle);
3414 kzfree(kclient);
3415 }
3416 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3417 kclient = list_entry(
3418 (&qseecom.registered_kclient_list_head)->next,
3419 struct qseecom_registered_kclient_list, list);
3420 if (list_empty(&kclient->list)) {
3421 spin_unlock_irqrestore(
3422 &qseecom.registered_kclient_list_lock, flags);
3423 return 0;
3424 }
3425 list_for_each_entry(kclient,
3426 &qseecom.registered_kclient_list_head, list) {
3427 if (kclient)
3428 list_del(&kclient->list);
3429 break;
3430 }
3431 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3432 flags);
3433 if (!kclient) {
3434 ret = 0;
3435 break;
3436 }
3437 }
Mona Hossain05c73562012-10-29 17:49:01 -07003438 if (qseecom.qseos_version > QSEEE_VERSION_00)
3439 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003440
Mona Hossain17a4faf2013-03-22 16:40:56 -07003441 if (qseecom.qsee_perf_client)
3442 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3443 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003444 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003445 if (pdev->dev.of_node) {
3446 __qseecom_deinit_clk(CLK_QSEE);
3447 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3448 __qseecom_deinit_clk(CLK_CE_DRV);
3449 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003450 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003451};
3452
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003453static struct of_device_id qseecom_match[] = {
3454 {
3455 .compatible = "qcom,qseecom",
3456 },
3457 {}
3458};
3459
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003460static struct platform_driver qseecom_plat_driver = {
3461 .probe = qseecom_probe,
3462 .remove = qseecom_remove,
3463 .driver = {
3464 .name = "qseecom",
3465 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003466 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003467 },
3468};
3469
3470static int __devinit qseecom_init(void)
3471{
3472 return platform_driver_register(&qseecom_plat_driver);
3473}
3474
3475static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003476{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003477 device_destroy(driver_class, qseecom_device_no);
3478 class_destroy(driver_class);
3479 unregister_chrdev_region(qseecom_device_no, 1);
3480 ion_client_destroy(qseecom.ion_clnt);
3481}
3482
3483MODULE_LICENSE("GPL v2");
3484MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3485
3486module_init(qseecom_init);
3487module_exit(qseecom_exit);