blob: 55e3e4e25ac0c2d1d71fbcd5bda52ce186c6fc98 [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
Mona Hossain5b76a622012-11-15 20:09:08 -080055
Mona Hossain05c73562012-10-29 17:49:01 -070056
57#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080058
Mona Hossaind39e33b2012-11-05 13:36:40 -080059#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080060
Mona Hossain13dd8922013-01-03 06:11:09 -080061#define QSEECOM_MAX_SG_ENTRY 512
Mona Hossain4cf78a92013-02-14 12:06:41 -080062#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
Mona Hossainf1f2ed62012-11-15 19:51:33 -080063
Amir Samuelovd1fc7412013-03-10 16:56:13 +020064/* Save partition image hash for authentication check */
65#define SCM_SAVE_PARTITION_HASH_ID 0x01
66
67/* Check if enterprise security is activate */
68#define SCM_IS_ACTIVATED_ID 0x02
69
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070070enum qseecom_clk_definitions {
71 CLK_DFAB = 0,
72 CLK_SFPB,
73};
74
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080075enum qseecom_client_handle_type {
76 QSEECOM_CLIENT_APP = 0,
77 QSEECOM_LISTENER_SERVICE,
78 QSEECOM_SECURE_SERVICE,
79 QSEECOM_GENERIC,
80};
81
Mona Hossainc92629e2013-04-01 13:37:46 -070082enum qseecom_ce_hw_instance {
83 CLK_QSEE = 0,
84 CLK_CE_DRV,
85};
86
Mona Hossain2892b6b2012-02-17 13:53:11 -080087static struct class *driver_class;
88static dev_t qseecom_device_no;
89static struct cdev qseecom_cdev;
90
91/* Data structures used in legacy support */
92static void *pil;
93static uint32_t pil_ref_cnt;
94static DEFINE_MUTEX(pil_access_lock);
95
Mona Hossain2892b6b2012-02-17 13:53:11 -080096static DEFINE_MUTEX(qsee_bw_mutex);
97static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -070098static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -080099
Mona Hossain2892b6b2012-02-17 13:53:11 -0800100struct qseecom_registered_listener_list {
101 struct list_head list;
102 struct qseecom_register_listener_req svc;
103 u8 *sb_reg_req;
104 u8 *sb_virt;
105 s32 sb_phys;
106 size_t sb_length;
107 struct ion_handle *ihandle; /* Retrieve phy addr */
108
109 wait_queue_head_t rcv_req_wq;
110 int rcv_req_flag;
111};
112
113struct qseecom_registered_app_list {
114 struct list_head list;
115 u32 app_id;
116 u32 ref_cnt;
117};
118
Mona Hossaind44a3842012-10-15 09:41:35 -0700119struct qseecom_registered_kclient_list {
120 struct list_head list;
121 struct qseecom_handle *handle;
122};
123
Mona Hossain4cf78a92013-02-14 12:06:41 -0800124struct ce_hw_usage_info {
125 uint32_t qsee_ce_hw_instance;
126 uint32_t hlos_ce_hw_instance;
127 uint32_t disk_encrypt_pipe;
128};
129
Mona Hossain17a4faf2013-03-22 16:40:56 -0700130struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700131 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700132 struct clk *ce_core_clk;
133 struct clk *ce_clk;
134 struct clk *ce_core_src_clk;
135 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700136 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700137};
138
Mona Hossain2892b6b2012-02-17 13:53:11 -0800139struct qseecom_control {
140 struct ion_client *ion_clnt; /* Ion client */
141 struct list_head registered_listener_list_head;
142 spinlock_t registered_listener_list_lock;
143
144 struct list_head registered_app_list_head;
145 spinlock_t registered_app_list_lock;
146
Mona Hossaind44a3842012-10-15 09:41:35 -0700147 struct list_head registered_kclient_list_head;
148 spinlock_t registered_kclient_list_lock;
149
Mona Hossain2892b6b2012-02-17 13:53:11 -0800150 wait_queue_head_t send_resp_wq;
151 int send_resp_flag;
152
153 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700154 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700155 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700156 bool commonlib_loaded;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800157 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700158
159 int qsee_bw_count;
160 int qsee_sfpb_bw_count;
161
162 uint32_t qsee_perf_client;
163 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700164 struct qseecom_clk ce_drv;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800165};
166
167struct qseecom_client_handle {
168 u32 app_id;
169 u8 *sb_virt;
170 s32 sb_phys;
171 uint32_t user_virt_sb_base;
172 size_t sb_length;
173 struct ion_handle *ihandle; /* Retrieve phy addr */
174};
175
176struct qseecom_listener_handle {
177 u32 id;
178};
179
180static struct qseecom_control qseecom;
181
182struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800183 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800184 union {
185 struct qseecom_client_handle client;
186 struct qseecom_listener_handle listener;
187 };
188 bool released;
189 int abort;
190 wait_queue_head_t abort_wq;
191 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700192 bool perf_enabled;
193 bool fast_load_enabled;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800194};
195
Mona Hossain4cf78a92013-02-14 12:06:41 -0800196enum qseecom_set_clear_key_flag {
197 QSEECOM_CLEAR_CE_KEY_CMD = 0,
198 QSEECOM_SET_CE_KEY_CMD,
199};
200
201struct qseecom_set_key_parameter {
202 uint32_t ce_hw;
203 uint32_t pipe;
204 uint32_t flags;
205 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
206 unsigned char hash32[QSEECOM_HASH_SIZE];
207 enum qseecom_set_clear_key_flag set_clear_key_flag;
208};
209
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800210struct qseecom_sg_entry {
211 uint32_t phys_addr;
212 uint32_t len;
213};
214
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700215/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800216static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
217static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700218
Mona Hossain2892b6b2012-02-17 13:53:11 -0800219static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800220 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800221{
222 struct qseecom_registered_listener_list *ptr;
223 int unique = 1;
224 unsigned long flags;
225
226 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
227 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800228 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800229 pr_err("Service id: %u is already registered\n",
230 ptr->svc.listener_id);
231 unique = 0;
232 break;
233 }
234 }
235 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
236 return unique;
237}
238
239static struct qseecom_registered_listener_list *__qseecom_find_svc(
240 int32_t listener_id)
241{
242 struct qseecom_registered_listener_list *entry = NULL;
243 unsigned long flags;
244
245 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
246 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
247 {
248 if (entry->svc.listener_id == listener_id)
249 break;
250 }
251 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
252 return entry;
253}
254
255static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
256 struct qseecom_dev_handle *handle,
257 struct qseecom_register_listener_req *listener)
258{
259 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800260 struct qseecom_register_listener_ireq req;
261 struct qseecom_command_scm_resp resp;
262 ion_phys_addr_t pa;
263
264 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800265 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
266 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800267 if (svc->ihandle == NULL) {
268 pr_err("Ion client could not retrieve the handle\n");
269 return -ENOMEM;
270 }
271
272 /* Get the physical address of the ION BUF */
273 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
274
275 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700276 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800277 svc->sb_phys = pa;
278
279 if (qseecom.qseos_version == QSEOS_VERSION_14) {
280 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
281 req.listener_id = svc->svc.listener_id;
282 req.sb_len = svc->sb_length;
283 req.sb_ptr = (void *)svc->sb_phys;
284
285 resp.result = QSEOS_RESULT_INCOMPLETE;
286
287 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
288 sizeof(req), &resp, sizeof(resp));
289 if (ret) {
290 pr_err("qseecom_scm_call failed with err: %d\n", ret);
291 return -EINVAL;
292 }
293
294 if (resp.result != QSEOS_RESULT_SUCCESS) {
295 pr_err("Error SB registration req: resp.result = %d\n",
296 resp.result);
297 return -EPERM;
298 }
299 } else {
300 struct qseecom_command cmd;
301 struct qseecom_response resp;
302 struct qse_pr_init_sb_req_s sb_init_req;
303 struct qse_pr_init_sb_rsp_s sb_init_rsp;
304
305 svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
306 sizeof(sb_init_rsp)), GFP_KERNEL);
307
308 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
309 sb_init_req.listener_id = svc->svc.listener_id;
310 sb_init_req.sb_len = svc->sb_length;
311 sb_init_req.sb_ptr = svc->sb_phys;
312
313 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
314
315 /* It will always be a new cmd from this method */
316 cmd.cmd_type = TZ_SCHED_CMD_NEW;
317 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
318 cmd.sb_in_cmd_len = sizeof(sb_init_req);
319
320 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
321
322 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
323 , &resp, sizeof(resp));
324
325 if (ret) {
326 pr_err("qseecom_scm_call failed with err: %d\n", ret);
327 return -EINVAL;
328 }
329
330 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
331 pr_err("SB registration fail resp.cmd_status %d\n",
332 resp.cmd_status);
333 return -EINVAL;
334 }
335 memset(svc->sb_virt, 0, svc->sb_length);
336 }
337 return 0;
338}
339
340static int qseecom_register_listener(struct qseecom_dev_handle *data,
341 void __user *argp)
342{
343 int ret = 0;
344 unsigned long flags;
345 struct qseecom_register_listener_req rcvd_lstnr;
346 struct qseecom_registered_listener_list *new_entry;
347
348 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
349 if (ret) {
350 pr_err("copy_from_user failed\n");
351 return ret;
352 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800353 data->listener.id = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800354 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800355 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800356 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800357 data->released = true;
358 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800359 }
360
361 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
362 if (!new_entry) {
363 pr_err("kmalloc failed\n");
364 return -ENOMEM;
365 }
366 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
367 new_entry->rcv_req_flag = 0;
368
369 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
370 new_entry->sb_length = rcvd_lstnr.sb_size;
371 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
372 pr_err("qseecom_set_sb_memoryfailed\n");
373 kzfree(new_entry);
374 return -ENOMEM;
375 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800376
Mona Hossain2892b6b2012-02-17 13:53:11 -0800377 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800378 init_waitqueue_head(&new_entry->rcv_req_wq);
379
380 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
381 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
382 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800383
Mona Hossain2892b6b2012-02-17 13:53:11 -0800384 return ret;
385}
386
387static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
388{
389 int ret = 0;
390 unsigned long flags;
391 uint32_t unmap_mem = 0;
392 struct qseecom_register_listener_ireq req;
393 struct qseecom_registered_listener_list *ptr_svc = NULL;
394 struct qseecom_command_scm_resp resp;
395 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
396
397 if (qseecom.qseos_version == QSEOS_VERSION_14) {
398 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
399 req.listener_id = data->listener.id;
400 resp.result = QSEOS_RESULT_INCOMPLETE;
401
402 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
403 sizeof(req), &resp, sizeof(resp));
404 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700405 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
406 ret, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800407 return ret;
408 }
409
410 if (resp.result != QSEOS_RESULT_SUCCESS) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700411 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
412 resp.result, data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800413 return -EPERM;
414 }
415 } else {
416 struct qse_pr_init_sb_req_s sb_init_req;
417 struct qseecom_command cmd;
418 struct qseecom_response resp;
419 struct qseecom_registered_listener_list *svc;
420
421 svc = __qseecom_find_svc(data->listener.id);
422 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
423 sb_init_req.listener_id = data->listener.id;
424 sb_init_req.sb_len = 0;
425 sb_init_req.sb_ptr = 0;
426
427 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
428
429 /* It will always be a new cmd from this method */
430 cmd.cmd_type = TZ_SCHED_CMD_NEW;
431 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
432 cmd.sb_in_cmd_len = sizeof(sb_init_req);
433 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
434
435 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
436 &resp, sizeof(resp));
437 if (ret) {
438 pr_err("qseecom_scm_call failed with err: %d\n", ret);
439 return ret;
440 }
441 kzfree(svc->sb_reg_req);
442 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
443 pr_err("Error with SB initialization\n");
444 return -EPERM;
445 }
446 }
447 data->abort = 1;
448 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
449 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
450 list) {
451 if (ptr_svc->svc.listener_id == data->listener.id) {
452 wake_up_all(&ptr_svc->rcv_req_wq);
453 break;
454 }
455 }
456 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
457
458 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700459 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800460 atomic_read(&data->ioctl_count) <= 1)) {
461 pr_err("Interrupted from abort\n");
462 ret = -ERESTARTSYS;
463 break;
464 }
465 }
466
467 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
468 list_for_each_entry(ptr_svc,
469 &qseecom.registered_listener_list_head,
470 list)
471 {
472 if (ptr_svc->svc.listener_id == data->listener.id) {
473 if (ptr_svc->sb_virt) {
474 unmap_mem = 1;
475 ihandle = ptr_svc->ihandle;
476 }
477 list_del(&ptr_svc->list);
478 kzfree(ptr_svc);
479 break;
480 }
481 }
482 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
483
484 /* Unmap the memory */
485 if (unmap_mem) {
486 if (!IS_ERR_OR_NULL(ihandle)) {
487 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
488 ion_free(qseecom.ion_clnt, ihandle);
489 }
490 }
491 data->released = true;
492 return ret;
493}
494
495static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
496 void __user *argp)
497{
498 ion_phys_addr_t pa;
499 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800500 struct qseecom_set_sb_mem_param_req req;
501 uint32_t len;
502
503 /* Copy the relevant information needed for loading the image */
504 if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
505 return -EFAULT;
506
Mona Hossain2892b6b2012-02-17 13:53:11 -0800507 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800508 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
509 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800510 if (IS_ERR_OR_NULL(data->client.ihandle)) {
511 pr_err("Ion client could not retrieve the handle\n");
512 return -ENOMEM;
513 }
514 /* Get the physical address of the ION BUF */
515 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
516 /* Populate the structure for sending scm call to load image */
517 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700518 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800519 data->client.sb_phys = pa;
520 data->client.sb_length = req.sb_len;
521 data->client.user_virt_sb_base = req.virt_sb_base;
522 return 0;
523}
524
Mona Hossain2892b6b2012-02-17 13:53:11 -0800525static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
526{
527 int ret;
528 ret = (qseecom.send_resp_flag != 0);
529 return ret || data->abort;
530}
531
532static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
533 struct qseecom_command_scm_resp *resp)
534{
535 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800536 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800537 uint32_t lstnr;
538 unsigned long flags;
539 struct qseecom_client_listener_data_irsp send_data_rsp;
540 struct qseecom_registered_listener_list *ptr_svc = NULL;
541
Mona Hossain2892b6b2012-02-17 13:53:11 -0800542 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
543 lstnr = resp->data;
544 /*
545 * Wake up blocking lsitener service with the lstnr id
546 */
547 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
548 flags);
549 list_for_each_entry(ptr_svc,
550 &qseecom.registered_listener_list_head, list) {
551 if (ptr_svc->svc.listener_id == lstnr) {
552 ptr_svc->rcv_req_flag = 1;
553 wake_up_interruptible(&ptr_svc->rcv_req_wq);
554 break;
555 }
556 }
557 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
558 flags);
559 if (ptr_svc->svc.listener_id != lstnr) {
560 pr_warning("Service requested for does on exist\n");
561 return -ERESTARTSYS;
562 }
563 pr_debug("waking up rcv_req_wq and "
564 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700565 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800566 __qseecom_listener_has_sent_rsp(data))) {
567 pr_warning("Interrupted: exiting send_cmd loop\n");
Mona Hossaineaa69b72013-04-15 17:20:15 -0700568 ret = -ERESTARTSYS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800569 }
570
Mona Hossaineaa69b72013-04-15 17:20:15 -0700571 if ((data->abort) || (ret == -ERESTARTSYS)) {
572 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
573 data->client.app_id, lstnr, ret);
574 if (data->abort)
575 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800576 send_data_rsp.status = QSEOS_RESULT_FAILURE;
577 } else {
578 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800579 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800580
Mona Hossain2892b6b2012-02-17 13:53:11 -0800581 qseecom.send_resp_flag = 0;
582 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
583 send_data_rsp.listener_id = lstnr ;
584
585 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
586 (const void *)&send_data_rsp,
587 sizeof(send_data_rsp), resp,
588 sizeof(*resp));
589 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700590 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800591 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800592 return ret;
593 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800594 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
595 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
596 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
597 resp->result, data->client.app_id, lstnr);
598 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700599 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800600 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800601 if (rc)
602 return rc;
603
Mona Hossain2892b6b2012-02-17 13:53:11 -0800604 return ret;
605}
606
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700607static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
608{
609 int32_t ret;
610 struct qseecom_command_scm_resp resp;
611
612 /* SCM_CALL to check if app_id for the mentioned app exists */
613 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
614 sizeof(struct qseecom_check_app_ireq),
615 &resp, sizeof(resp));
616 if (ret) {
617 pr_err("scm_call to check if app is already loaded failed\n");
618 return -EINVAL;
619 }
620
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700621 if (resp.result == QSEOS_RESULT_FAILURE) {
622 return 0;
623 } else {
624 switch (resp.resp_type) {
625 /*qsee returned listener type response */
626 case QSEOS_LISTENER_ID:
627 pr_err("resp type is of listener type instead of app");
628 return -EINVAL;
629 break;
630 case QSEOS_APP_ID:
631 return resp.data;
632 default:
633 pr_err("invalid resp type (%d) from qsee",
634 resp.resp_type);
635 return -ENODEV;
636 break;
637 }
638 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700639}
640
Mona Hossain2892b6b2012-02-17 13:53:11 -0800641static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
642{
643 struct qseecom_registered_app_list *entry = NULL;
644 unsigned long flags = 0;
645 u32 app_id = 0;
646 struct ion_handle *ihandle; /* Ion handle */
647 struct qseecom_load_img_req load_img_req;
648 int32_t ret;
649 ion_phys_addr_t pa = 0;
650 uint32_t len;
651 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800652 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700653 struct qseecom_load_app_ireq load_req;
654
Mona Hossain2892b6b2012-02-17 13:53:11 -0800655 /* Copy the relevant information needed for loading the image */
656 if (__copy_from_user(&load_img_req,
657 (void __user *)argp,
658 sizeof(struct qseecom_load_img_req))) {
659 pr_err("copy_from_user failed\n");
660 return -EFAULT;
661 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700662 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800663 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700664 if (ret)
665 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800666 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
667 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800668
Mona Hossain436b75f2012-11-20 17:10:40 -0800669 ret = __qseecom_check_app_exists(req);
670 if (ret < 0)
671 return ret;
672 else
673 app_id = ret;
674
675 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700676 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800677 (char *)(req.app_name));
678 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
679 list_for_each_entry(entry,
680 &qseecom.registered_app_list_head, list){
681 if (entry->app_id == app_id) {
682 entry->ref_cnt++;
683 break;
684 }
685 }
686 spin_unlock_irqrestore(
687 &qseecom.registered_app_list_lock, flags);
688 } else {
689 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700690 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800691 /* Get the handle of the shared fd */
692 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800693 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800694 if (IS_ERR_OR_NULL(ihandle)) {
695 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800696 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800697 return -ENOMEM;
698 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800699
Mona Hossain436b75f2012-11-20 17:10:40 -0800700 /* Get the physical address of the ION BUF */
701 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800702
Mona Hossain436b75f2012-11-20 17:10:40 -0800703 /* Populate the structure for sending scm call to load image */
704 memcpy(load_req.app_name, load_img_req.img_name,
705 MAX_APP_NAME_SIZE);
706 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
707 load_req.mdt_len = load_img_req.mdt_len;
708 load_req.img_len = load_img_req.img_len;
709 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800710
Mona Hossain436b75f2012-11-20 17:10:40 -0800711 /* SCM_CALL to load the app and get the app_id back */
712 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700713 sizeof(struct qseecom_load_app_ireq),
714 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700715 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800716 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800717 if (!IS_ERR_OR_NULL(ihandle))
718 ion_free(qseecom.ion_clnt, ihandle);
719 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800720 return -EINVAL;
721 }
722
723 if (resp.result == QSEOS_RESULT_FAILURE) {
724 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700725 if (!IS_ERR_OR_NULL(ihandle))
726 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800727 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800728 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700729 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700730
Mona Hossain436b75f2012-11-20 17:10:40 -0800731 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
732 ret = __qseecom_process_incomplete_cmd(data, &resp);
733 if (ret) {
734 pr_err("process_incomplete_cmd failed err: %d\n",
735 ret);
736 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 ret;
740 }
741 }
742
743 if (resp.result != QSEOS_RESULT_SUCCESS) {
744 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700745 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800746 if (!IS_ERR_OR_NULL(ihandle))
747 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800748 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800749 return -EFAULT;
750 }
751
752 app_id = resp.data;
753
754 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
755 if (!entry) {
756 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800757 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800758 return -ENOMEM;
759 }
760 entry->app_id = app_id;
761 entry->ref_cnt = 1;
762
763 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700764 if (!IS_ERR_OR_NULL(ihandle))
765 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700766
Mona Hossain436b75f2012-11-20 17:10:40 -0800767 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
768 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
769 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
770 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700771
Mona Hossain436b75f2012-11-20 17:10:40 -0800772 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700773 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800774 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800775 data->client.app_id = app_id;
776 load_img_req.app_id = app_id;
777 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
778 pr_err("copy_to_user failed\n");
779 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800780 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800781 return -EFAULT;
782 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800783 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800784 return 0;
785}
786
787static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
788{
789 wake_up_all(&qseecom.send_resp_wq);
790 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700791 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800792 atomic_read(&data->ioctl_count) <= 1)) {
793 pr_err("Interrupted from abort\n");
794 return -ERESTARTSYS;
795 break;
796 }
797 }
798 /* Set unload app */
799 return 1;
800}
801
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800802static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
803{
804 int ret = 0;
805 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
806 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
807 ion_free(qseecom.ion_clnt, data->client.ihandle);
808 data->client.ihandle = NULL;
809 }
810 return ret;
811}
812
Mona Hossain2892b6b2012-02-17 13:53:11 -0800813static int qseecom_unload_app(struct qseecom_dev_handle *data)
814{
815 unsigned long flags;
816 int ret = 0;
817 struct qseecom_command_scm_resp resp;
818 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700819 bool unload = false;
820 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800821
Mona Hossain1fb538f2012-08-30 16:19:38 -0700822 if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
823 (data->client.app_id > 0)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800824 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
825 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
826 list) {
827 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700828 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800829 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700830 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800831 break;
832 } else {
833 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700834 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700835 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800836 break;
837 }
838 }
839 }
840 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
841 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700842 if (found_app == false) {
843 pr_err("Cannot find app with id = %d\n",
844 data->client.app_id);
845 return -EINVAL;
846 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800847 }
848
849 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
850 struct qseecom_unload_app_ireq req;
851
Mona Hossain340dba82012-08-07 19:54:46 -0700852 __qseecom_cleanup_app(data);
853 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
854 list_del(&ptr_app->list);
855 kzfree(ptr_app);
856 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
857 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800858 /* Populate the structure for sending scm call to load image */
859 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
860 req.app_id = data->client.app_id;
861
862 /* SCM_CALL to unload the app */
863 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
864 sizeof(struct qseecom_unload_app_ireq),
865 &resp, sizeof(resp));
866 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700867 pr_err("scm_call to unload app (id = %d) failed\n",
868 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800869 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700870 } else {
871 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800872 }
873 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
874 ret = __qseecom_process_incomplete_cmd(data, &resp);
875 if (ret) {
876 pr_err("process_incomplete_cmd fail err: %d\n",
877 ret);
878 return ret;
879 }
880 }
881 }
882
883 if (qseecom.qseos_version == QSEOS_VERSION_13) {
884 data->abort = 1;
885 wake_up_all(&qseecom.send_resp_wq);
886 while (atomic_read(&data->ioctl_count) > 0) {
Mona Hossainacea1022012-04-09 13:37:27 -0700887 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800888 atomic_read(&data->ioctl_count) <= 0)) {
889 pr_err("Interrupted from abort\n");
890 ret = -ERESTARTSYS;
891 break;
892 }
893 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800894 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800895 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800896 data->released = true;
897 return ret;
898}
899
900static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
901 uint32_t virt)
902{
903 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
904}
905
906static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
907 struct qseecom_send_cmd_req *req)
908{
909 int ret = 0;
910 unsigned long flags;
911 u32 reqd_len_sb_in = 0;
912 struct qseecom_command cmd;
913 struct qseecom_response resp;
914
915
916 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
917 pr_err("cmd buffer or response buffer is null\n");
918 return -EINVAL;
919 }
920
921 if (req->cmd_req_len <= 0 ||
922 req->resp_len <= 0 ||
923 req->cmd_req_len > data->client.sb_length ||
924 req->resp_len > data->client.sb_length) {
925 pr_err("cmd buffer length or "
926 "response buffer length not valid\n");
927 return -EINVAL;
928 }
929
930 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
931 if (reqd_len_sb_in > data->client.sb_length) {
932 pr_debug("Not enough memory to fit cmd_buf and "
933 "resp_buf. Required: %u, Available: %u\n",
934 reqd_len_sb_in, data->client.sb_length);
935 return -ENOMEM;
936 }
937 cmd.cmd_type = TZ_SCHED_CMD_NEW;
938 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
939 cmd.sb_in_cmd_len = req->cmd_req_len;
940
941 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
942 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
943 resp.sb_in_rsp_len = req->resp_len;
944
945 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
946 sizeof(cmd), &resp, sizeof(resp));
947
948 if (ret) {
949 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
950 return ret;
951 }
952
953 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
954 /*
955 * If cmd is incomplete, get the callback cmd out from SB out
956 * and put it on the list
957 */
958 struct qseecom_registered_listener_list *ptr_svc = NULL;
959 /*
960 * We don't know which service can handle the command. so we
961 * wake up all blocking services and let them figure out if
962 * they can handle the given command.
963 */
964 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
965 flags);
966 list_for_each_entry(ptr_svc,
967 &qseecom.registered_listener_list_head, list) {
968 ptr_svc->rcv_req_flag = 1;
969 wake_up_interruptible(&ptr_svc->rcv_req_wq);
970 }
971 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
972 flags);
973
974 pr_debug("waking up rcv_req_wq and "
975 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700976 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800977 __qseecom_listener_has_sent_rsp(data))) {
978 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
979 return -ERESTARTSYS;
980 }
981
982 if (data->abort) {
983 pr_err("Aborting driver\n");
984 return -ENODEV;
985 }
986 qseecom.send_resp_flag = 0;
987 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
988 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
989 sizeof(cmd), &resp, sizeof(resp));
990 if (ret) {
991 pr_err("qseecom_scm_call failed with err: %d\n", ret);
992 return ret;
993 }
994 }
995 return ret;
996}
997
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800998int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
999 struct qseecom_send_svc_cmd_req *req_ptr,
1000 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1001{
1002 int ret = 0;
1003 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1004 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1005 req_ptr, send_svc_ireq_ptr);
1006 return -EINVAL;
1007 }
1008 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1009 send_svc_ireq_ptr->key_type =
1010 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
1011 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1012 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1013 (uint32_t)req_ptr->resp_buf));
1014 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1015
1016 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1017 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1018 return ret;
1019}
1020
1021static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1022 void __user *argp)
1023{
1024 int ret = 0;
1025 struct qseecom_client_send_service_ireq send_svc_ireq;
1026 struct qseecom_command_scm_resp resp;
1027 struct qseecom_send_svc_cmd_req req;
1028 /*struct qseecom_command_scm_resp resp;*/
1029
1030 if (__copy_from_user(&req,
1031 (void __user *)argp,
1032 sizeof(req))) {
1033 pr_err("copy_from_user failed\n");
1034 return -EFAULT;
1035 }
1036
1037 if (req.resp_buf == NULL) {
1038 pr_err("cmd buffer or response buffer is null\n");
1039 return -EINVAL;
1040 }
1041
1042 data->type = QSEECOM_SECURE_SERVICE;
1043
1044 switch (req.cmd_id) {
1045 case QSEE_RPMB_PROVISION_KEY_COMMAND:
1046 case QSEE_RPMB_ERASE_COMMAND:
1047 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1048 &send_svc_ireq))
1049 return -EINVAL;
1050 break;
1051 default:
1052 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1053 return -EINVAL;
1054 }
1055
1056 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1057 sizeof(send_svc_ireq),
1058 &resp, sizeof(resp));
1059 if (ret) {
1060 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1061 return ret;
1062 }
1063
1064 switch (resp.result) {
1065 case QSEOS_RESULT_SUCCESS:
1066 break;
1067 case QSEOS_RESULT_INCOMPLETE:
1068 pr_err("qseos_result_incomplete\n");
1069 ret = __qseecom_process_incomplete_cmd(data, &resp);
1070 if (ret) {
1071 pr_err("process_incomplete_cmd fail: err: %d\n",
1072 ret);
1073 }
1074 break;
1075 case QSEOS_RESULT_FAILURE:
1076 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1077 break;
1078 default:
1079 pr_err("Response result %d not supported\n",
1080 resp.result);
1081 ret = -EINVAL;
1082 break;
1083 }
1084 return ret;
1085
1086}
1087
Mona Hossain2892b6b2012-02-17 13:53:11 -08001088static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1089 struct qseecom_send_cmd_req *req)
1090{
1091 int ret = 0;
1092 u32 reqd_len_sb_in = 0;
1093 struct qseecom_client_send_data_ireq send_data_req;
1094 struct qseecom_command_scm_resp resp;
1095
1096 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1097 pr_err("cmd buffer or response buffer is null\n");
1098 return -EINVAL;
1099 }
1100
1101 if (req->cmd_req_len <= 0 ||
1102 req->resp_len <= 0 ||
1103 req->cmd_req_len > data->client.sb_length ||
1104 req->resp_len > data->client.sb_length) {
1105 pr_err("cmd buffer length or "
1106 "response buffer length not valid\n");
1107 return -EINVAL;
1108 }
1109
1110 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1111 if (reqd_len_sb_in > data->client.sb_length) {
1112 pr_debug("Not enough memory to fit cmd_buf and "
1113 "resp_buf. Required: %u, Available: %u\n",
1114 reqd_len_sb_in, data->client.sb_length);
1115 return -ENOMEM;
1116 }
1117
1118 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1119 send_data_req.app_id = data->client.app_id;
1120 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1121 (uint32_t)req->cmd_req_buf));
1122 send_data_req.req_len = req->cmd_req_len;
1123 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1124 (uint32_t)req->resp_buf));
1125 send_data_req.rsp_len = req->resp_len;
1126
1127 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1128 sizeof(send_data_req),
1129 &resp, sizeof(resp));
1130 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001131 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1132 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001133 return ret;
1134 }
1135
1136 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1137 ret = __qseecom_process_incomplete_cmd(data, &resp);
1138 if (ret) {
1139 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1140 return ret;
1141 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001142 } else {
1143 if (resp.result != QSEOS_RESULT_SUCCESS) {
1144 pr_err("Response result %d not supported\n",
1145 resp.result);
1146 ret = -EINVAL;
1147 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001148 }
1149 return ret;
1150}
1151
1152
1153static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1154{
1155 int ret = 0;
1156 struct qseecom_send_cmd_req req;
1157
1158 ret = copy_from_user(&req, argp, sizeof(req));
1159 if (ret) {
1160 pr_err("copy_from_user failed\n");
1161 return ret;
1162 }
1163 if (qseecom.qseos_version == QSEOS_VERSION_14)
1164 ret = __qseecom_send_cmd(data, &req);
1165 else
1166 ret = __qseecom_send_cmd_legacy(data, &req);
1167 if (ret)
1168 return ret;
1169
1170 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1171 req.resp_len, req.resp_buf);
1172 return ret;
1173}
1174
1175static int __qseecom_send_cmd_req_clean_up(
1176 struct qseecom_send_modfd_cmd_req *req)
1177{
1178 char *field;
1179 uint32_t *update;
1180 int ret = 0;
1181 int i = 0;
1182
1183 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001184 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001185 field = (char *)req->cmd_req_buf +
1186 req->ifd_data[i].cmd_buf_offset;
1187 update = (uint32_t *) field;
1188 *update = 0;
1189 }
1190 }
1191 return ret;
1192}
1193
1194static int __qseecom_update_with_phy_addr(
1195 struct qseecom_send_modfd_cmd_req *req)
1196{
1197 struct ion_handle *ihandle;
1198 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001199 int ret = 0;
1200 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001201
1202 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001203 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001204 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001205 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001206 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001207 req->ifd_data[i].fd);
1208 if (IS_ERR_OR_NULL(ihandle)) {
1209 pr_err("Ion client can't retrieve the handle\n");
1210 return -ENOMEM;
1211 }
1212 field = (char *) req->cmd_req_buf +
1213 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001214
1215 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001216 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1217 if (sg_ptr == NULL) {
1218 pr_err("IOn client could not retrieve sg table\n");
1219 goto err;
1220 }
1221 if (sg_ptr->nents == 0) {
1222 pr_err("Num of scattered entries is 0\n");
1223 goto err;
1224 }
1225 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1226 pr_err("Num of scattered entries");
1227 pr_err(" (%d) is greater than max supported %d\n",
1228 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1229 goto err;
1230 }
1231 if (sg_ptr->nents == 1) {
1232 uint32_t *update;
1233 update = (uint32_t *) field;
1234 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
1235 } else {
1236 struct qseecom_sg_entry *update;
1237 struct scatterlist *sg;
1238 int j = 0;
1239 update = (struct qseecom_sg_entry *) field;
1240 sg = sg_ptr->sgl;
1241 for (j = 0; j < sg_ptr->nents; j++) {
1242 update->phys_addr = (uint32_t)
1243 sg_dma_address(sg);
1244 update->len = (uint32_t)sg->length;
1245 update++;
1246 sg = sg_next(sg);
1247 }
1248 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001249 /* Deallocate the handle */
1250 if (!IS_ERR_OR_NULL(ihandle))
1251 ion_free(qseecom.ion_clnt, ihandle);
1252 }
1253 }
1254 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001255err:
1256 if (!IS_ERR_OR_NULL(ihandle))
1257 ion_free(qseecom.ion_clnt, ihandle);
1258 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001259}
1260
1261static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1262 void __user *argp)
1263{
1264 int ret = 0;
1265 struct qseecom_send_modfd_cmd_req req;
1266 struct qseecom_send_cmd_req send_cmd_req;
1267
1268 ret = copy_from_user(&req, argp, sizeof(req));
1269 if (ret) {
1270 pr_err("copy_from_user failed\n");
1271 return ret;
1272 }
1273 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1274 send_cmd_req.cmd_req_len = req.cmd_req_len;
1275 send_cmd_req.resp_buf = req.resp_buf;
1276 send_cmd_req.resp_len = req.resp_len;
1277
1278 ret = __qseecom_update_with_phy_addr(&req);
1279 if (ret)
1280 return ret;
1281 if (qseecom.qseos_version == QSEOS_VERSION_14)
1282 ret = __qseecom_send_cmd(data, &send_cmd_req);
1283 else
1284 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1285 __qseecom_send_cmd_req_clean_up(&req);
1286
1287 if (ret)
1288 return ret;
1289
1290 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1291 req.resp_len, req.resp_buf);
1292 return ret;
1293}
1294
1295static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1296 struct qseecom_registered_listener_list *svc)
1297{
1298 int ret;
1299 ret = (svc->rcv_req_flag != 0);
1300 return ret || data->abort;
1301}
1302
1303static int qseecom_receive_req(struct qseecom_dev_handle *data)
1304{
1305 int ret = 0;
1306 struct qseecom_registered_listener_list *this_lstnr;
1307
1308 this_lstnr = __qseecom_find_svc(data->listener.id);
1309 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001310 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001311 __qseecom_listener_has_rcvd_req(data,
1312 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001313 pr_warning("Interrupted: exiting Listener Service = %d\n",
1314 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001315 /* woken up for different reason */
1316 return -ERESTARTSYS;
1317 }
1318
1319 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001320 pr_err("Aborting Listener Service = %d\n",
1321 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001322 return -ENODEV;
1323 }
1324 this_lstnr->rcv_req_flag = 0;
1325 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1326 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1327 break;
1328 } else {
1329 break;
1330 }
1331 }
1332 return ret;
1333}
1334
Mona Hossaind44a3842012-10-15 09:41:35 -07001335static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1336{
1337 struct elf32_hdr *ehdr;
1338
1339 if (fw_entry->size < sizeof(*ehdr)) {
1340 pr_err("%s: Not big enough to be an elf header\n",
1341 qseecom.pdev->init_name);
1342 return false;
1343 }
1344 ehdr = (struct elf32_hdr *)fw_entry->data;
1345 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1346 pr_err("%s: Not an elf header\n",
1347 qseecom.pdev->init_name);
1348 return false;
1349 }
1350
1351 if (ehdr->e_phnum == 0) {
1352 pr_err("%s: No loadable segments\n",
1353 qseecom.pdev->init_name);
1354 return false;
1355 }
1356 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1357 sizeof(struct elf32_hdr) > fw_entry->size) {
1358 pr_err("%s: Program headers not within mdt\n",
1359 qseecom.pdev->init_name);
1360 return false;
1361 }
1362 return true;
1363}
1364
1365static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1366{
1367 int ret = -1;
1368 int i = 0, rc = 0;
1369 const struct firmware *fw_entry = NULL;
1370 struct elf32_phdr *phdr;
1371 char fw_name[MAX_APP_NAME_SIZE];
1372 struct elf32_hdr *ehdr;
1373 int num_images = 0;
1374
1375 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1376 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1377 if (rc) {
1378 pr_err("error with request_firmware\n");
1379 ret = -EIO;
1380 goto err;
1381 }
1382 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1383 ret = -EIO;
1384 goto err;
1385 }
1386 *fw_size = fw_entry->size;
1387 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1388 ehdr = (struct elf32_hdr *)fw_entry->data;
1389 num_images = ehdr->e_phnum;
1390 release_firmware(fw_entry);
1391 for (i = 0; i < num_images; i++, phdr++) {
1392 memset(fw_name, 0, sizeof(fw_name));
1393 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1394 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1395 if (ret)
1396 goto err;
1397 *fw_size += fw_entry->size;
1398 release_firmware(fw_entry);
1399 }
1400 return ret;
1401err:
1402 if (fw_entry)
1403 release_firmware(fw_entry);
1404 *fw_size = 0;
1405 return ret;
1406}
1407
1408static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1409 struct qseecom_load_app_ireq *load_req)
1410{
1411 int ret = -1;
1412 int i = 0, rc = 0;
1413 const struct firmware *fw_entry = NULL;
1414 char fw_name[MAX_APP_NAME_SIZE];
1415 u8 *img_data_ptr = img_data;
1416 struct elf32_hdr *ehdr;
1417 int num_images = 0;
1418
1419 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1420 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1421 if (rc) {
1422 ret = -EIO;
1423 goto err;
1424 }
1425 load_req->img_len = fw_entry->size;
1426 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1427 img_data_ptr = img_data_ptr + fw_entry->size;
1428 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1429 ehdr = (struct elf32_hdr *)fw_entry->data;
1430 num_images = ehdr->e_phnum;
1431 release_firmware(fw_entry);
1432 for (i = 0; i < num_images; i++) {
1433 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1434 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1435 if (ret) {
1436 pr_err("Failed to locate blob %s\n", fw_name);
1437 goto err;
1438 }
1439 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1440 img_data_ptr = img_data_ptr + fw_entry->size;
1441 load_req->img_len += fw_entry->size;
1442 release_firmware(fw_entry);
1443 }
1444 load_req->phy_addr = virt_to_phys(img_data);
1445 return ret;
1446err:
1447 release_firmware(fw_entry);
1448 return ret;
1449}
1450
1451static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1452{
1453 int ret = -1;
1454 uint32_t fw_size = 0;
1455 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1456 struct qseecom_command_scm_resp resp;
1457 u8 *img_data = NULL;
1458
1459 if (__qseecom_get_fw_size(appname, &fw_size))
1460 return -EIO;
1461
1462 img_data = kzalloc(fw_size, GFP_KERNEL);
1463 if (!img_data) {
1464 pr_err("Failied to allocate memory for copying image data\n");
1465 return -ENOMEM;
1466 }
1467 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1468 if (ret) {
1469 kzfree(img_data);
1470 return -EIO;
1471 }
1472
1473 /* Populate the remaining parameters */
1474 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1475 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001476 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001477 if (ret) {
1478 kzfree(img_data);
1479 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001480 return -EIO;
1481 }
1482
Mona Hossaind44a3842012-10-15 09:41:35 -07001483 /* SCM_CALL to load the image */
1484 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1485 sizeof(struct qseecom_load_app_ireq),
1486 &resp, sizeof(resp));
1487 kzfree(img_data);
1488 if (ret) {
1489 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001490 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001491 return -EIO;
1492 }
1493
1494 switch (resp.result) {
1495 case QSEOS_RESULT_SUCCESS:
1496 ret = resp.data;
1497 break;
1498 case QSEOS_RESULT_INCOMPLETE:
1499 ret = __qseecom_process_incomplete_cmd(data, &resp);
1500 if (ret)
1501 pr_err("process_incomplete_cmd FAILED\n");
1502 else
1503 ret = resp.data;
1504 break;
1505 case QSEOS_RESULT_FAILURE:
1506 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1507 break;
1508 default:
1509 pr_err("scm call return unknown response %d\n", resp.result);
1510 ret = -EINVAL;
1511 break;
1512 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001513 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001514
Mona Hossaind44a3842012-10-15 09:41:35 -07001515 return ret;
1516}
1517
Mona Hossain9498f5e2013-01-23 18:08:45 -08001518static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001519{
1520 int32_t ret = 0;
1521 uint32_t fw_size = 0;
1522 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1523 struct qseecom_command_scm_resp resp;
1524 u8 *img_data = NULL;
1525
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001526 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001527 return -EIO;
1528
1529 img_data = kzalloc(fw_size, GFP_KERNEL);
1530 if (!img_data) {
1531 pr_err("Mem allocation for lib image data failed\n");
1532 return -ENOMEM;
1533 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001534 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001535 if (ret) {
1536 kzfree(img_data);
1537 return -EIO;
1538 }
1539 /* Populate the remaining parameters */
1540 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001541 /* Vote for the SFPB clock */
1542 ret = qsee_vote_for_clock(data, CLK_SFPB);
1543 if (ret) {
1544 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1545 kzfree(img_data);
1546 return -EIO;
1547 }
1548
Mona Hossain05c73562012-10-29 17:49:01 -07001549 /* SCM_CALL to load the image */
1550 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1551 sizeof(struct qseecom_load_lib_image_ireq),
1552 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001553 if (ret) {
1554 pr_err("scm_call to load failed : ret %d\n", ret);
1555 ret = -EIO;
1556 } else {
1557 switch (resp.result) {
1558 case QSEOS_RESULT_SUCCESS:
1559 break;
1560 case QSEOS_RESULT_FAILURE:
1561 pr_err("scm call failed w/response result%d\n",
1562 resp.result);
1563 ret = -EINVAL;
1564 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001565 case QSEOS_RESULT_INCOMPLETE:
1566 ret = __qseecom_process_incomplete_cmd(data, &resp);
1567 if (ret)
1568 pr_err("process_incomplete_cmd failed err: %d\n",
1569 ret);
1570 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001571 default:
1572 pr_err("scm call return unknown response %d\n",
1573 resp.result);
1574 ret = -EINVAL;
1575 break;
1576 }
1577 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001578 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001579 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001580 return ret;
1581}
1582
1583static int qseecom_unload_commonlib_image(void)
1584{
1585 int ret = -EINVAL;
1586 struct qseecom_unload_lib_image_ireq unload_req = {0};
1587 struct qseecom_command_scm_resp resp;
1588
1589 /* Populate the remaining parameters */
1590 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1591 /* SCM_CALL to load the image */
1592 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1593 sizeof(struct qseecom_unload_lib_image_ireq),
1594 &resp, sizeof(resp));
1595 if (ret) {
1596 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1597 ret = -EIO;
1598 } else {
1599 switch (resp.result) {
1600 case QSEOS_RESULT_SUCCESS:
1601 break;
1602 case QSEOS_RESULT_FAILURE:
1603 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1604 break;
1605 default:
1606 pr_err("scm call return unknown response %d\n",
1607 resp.result);
1608 ret = -EINVAL;
1609 break;
1610 }
1611 }
1612 return ret;
1613}
1614
Mona Hossaind44a3842012-10-15 09:41:35 -07001615int qseecom_start_app(struct qseecom_handle **handle,
1616 char *app_name, uint32_t size)
1617{
Mona Hossain05c73562012-10-29 17:49:01 -07001618 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001619 unsigned long flags = 0;
1620 struct qseecom_dev_handle *data = NULL;
1621 struct qseecom_check_app_ireq app_ireq;
1622 struct qseecom_registered_app_list *entry = NULL;
1623 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1624 bool found_app = false;
1625 uint32_t len;
1626 ion_phys_addr_t pa;
1627
1628 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1629 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1630 return -EINVAL;
1631 }
1632
Mona Hossain823f9882012-11-23 14:42:20 -08001633 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1634 if (!(*handle)) {
1635 pr_err("failed to allocate memory for kernel client handle\n");
1636 return -ENOMEM;
1637 }
1638
Mona Hossaind44a3842012-10-15 09:41:35 -07001639 data = kzalloc(sizeof(*data), GFP_KERNEL);
1640 if (!data) {
1641 pr_err("kmalloc failed\n");
1642 if (ret == 0) {
1643 kfree(*handle);
1644 *handle = NULL;
1645 }
1646 return -ENOMEM;
1647 }
1648 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001649 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001650 data->released = false;
1651 data->client.app_id = ret;
1652 data->client.sb_length = size;
1653 data->client.user_virt_sb_base = 0;
1654 data->client.ihandle = NULL;
1655
1656 init_waitqueue_head(&data->abort_wq);
1657 atomic_set(&data->ioctl_count, 0);
1658
1659 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1660 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1661 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1662 pr_err("Ion client could not retrieve the handle\n");
1663 kfree(data);
1664 kfree(*handle);
1665 *handle = NULL;
1666 return -EINVAL;
1667 }
1668
Mona Hossain9498f5e2013-01-23 18:08:45 -08001669 if (qseecom.qsee_version > QSEEE_VERSION_00) {
1670 mutex_lock(&app_access_lock);
1671 if (qseecom.commonlib_loaded == false) {
1672 ret = qseecom_load_commonlib_image(data);
1673 if (ret == 0)
1674 qseecom.commonlib_loaded = true;
1675 }
1676 mutex_unlock(&app_access_lock);
1677 }
1678
1679 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001680 pr_err("Failed to load commonlib image\n");
Mona Hossain9498f5e2013-01-23 18:08:45 -08001681 kfree(data);
1682 kfree(*handle);
1683 *handle = NULL;
1684 return -EIO;
1685 }
1686
1687 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1688 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1689 ret = __qseecom_check_app_exists(app_ireq);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001690 if (ret < 0) {
1691 kzfree(data);
1692 kfree(*handle);
1693 *handle = NULL;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001694 return -EINVAL;
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001695 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001696
Mona Hossaind44a3842012-10-15 09:41:35 -07001697 if (ret > 0) {
1698 pr_warn("App id %d for [%s] app exists\n", ret,
1699 (char *)app_ireq.app_name);
1700 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1701 list_for_each_entry(entry,
1702 &qseecom.registered_app_list_head, list){
1703 if (entry->app_id == ret) {
1704 entry->ref_cnt++;
1705 found_app = true;
1706 break;
1707 }
1708 }
1709 spin_unlock_irqrestore(
1710 &qseecom.registered_app_list_lock, flags);
1711 if (!found_app)
1712 pr_warn("App_id %d [%s] was loaded but not registered\n",
1713 ret, (char *)app_ireq.app_name);
1714 } else {
1715 /* load the app and get the app_id */
1716 pr_debug("%s: Loading app for the first time'\n",
1717 qseecom.pdev->init_name);
1718 mutex_lock(&app_access_lock);
1719 ret = __qseecom_load_fw(data, app_name);
1720 mutex_unlock(&app_access_lock);
1721
1722 if (ret < 0) {
1723 kfree(*handle);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001724 kfree(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001725 *handle = NULL;
1726 return ret;
1727 }
1728 data->client.app_id = ret;
1729 }
1730 if (!found_app) {
1731 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1732 if (!entry) {
1733 pr_err("kmalloc failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001734 kfree(data);
1735 kfree(*handle);
1736 *handle = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001737 return -ENOMEM;
1738 }
1739 entry->app_id = ret;
1740 entry->ref_cnt = 1;
1741
1742 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1743 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1744 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1745 flags);
1746 }
1747
1748 /* Get the physical address of the ION BUF */
1749 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1750 /* Populate the structure for sending scm call to load image */
1751 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1752 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001753 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001754 data->client.sb_phys = pa;
1755 (*handle)->dev = (void *)data;
1756 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1757 (*handle)->sbuf_len = data->client.sb_length;
1758
1759 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1760 if (!kclient_entry) {
1761 pr_err("kmalloc failed\n");
1762 return -ENOMEM;
1763 }
1764 kclient_entry->handle = *handle;
1765
1766 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1767 list_add_tail(&kclient_entry->list,
1768 &qseecom.registered_kclient_list_head);
1769 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1770
1771 return 0;
1772}
1773EXPORT_SYMBOL(qseecom_start_app);
1774
1775int qseecom_shutdown_app(struct qseecom_handle **handle)
1776{
1777 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001778 struct qseecom_dev_handle *data;
1779
Mona Hossaind44a3842012-10-15 09:41:35 -07001780 struct qseecom_registered_kclient_list *kclient = NULL;
1781 unsigned long flags = 0;
1782 bool found_handle = false;
1783
1784 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1785 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1786 return -EINVAL;
1787 }
Mona Hossain33824022013-02-25 09:32:33 -08001788 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001789 pr_err("Handle is not initialized\n");
1790 return -EINVAL;
1791 }
Mona Hossain33824022013-02-25 09:32:33 -08001792 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001793 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1794 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1795 list) {
1796 if (kclient->handle == (*handle)) {
1797 list_del(&kclient->list);
1798 found_handle = true;
1799 break;
1800 }
1801 }
1802 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1803 if (!found_handle)
1804 pr_err("Unable to find the handle, exiting\n");
1805 else
1806 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001807 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001808 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001809 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001810 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001811 if (ret == 0) {
1812 kzfree(data);
1813 kzfree(*handle);
1814 kzfree(kclient);
1815 *handle = NULL;
1816 }
1817 return ret;
1818}
1819EXPORT_SYMBOL(qseecom_shutdown_app);
1820
1821int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1822 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1823{
1824 int ret = 0;
1825 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1826 struct qseecom_dev_handle *data;
1827
1828 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1829 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1830 return -EINVAL;
1831 }
1832
1833 if (handle == NULL) {
1834 pr_err("Handle is not initialized\n");
1835 return -EINVAL;
1836 }
1837 data = handle->dev;
1838
1839 req.cmd_req_len = sbuf_len;
1840 req.resp_len = rbuf_len;
1841 req.cmd_req_buf = send_buf;
1842 req.resp_buf = resp_buf;
1843
1844 mutex_lock(&app_access_lock);
1845 atomic_inc(&data->ioctl_count);
1846
1847 ret = __qseecom_send_cmd(data, &req);
1848
1849 atomic_dec(&data->ioctl_count);
1850 mutex_unlock(&app_access_lock);
1851
1852 if (ret)
1853 return ret;
1854
1855 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1856 req.resp_len, req.resp_buf);
1857 return ret;
1858}
1859EXPORT_SYMBOL(qseecom_send_command);
1860
Mona Hossain91a8fc92012-11-07 19:58:30 -08001861int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1862{
Mona Hossainfca6f422013-01-12 13:00:35 -08001863 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001864 if ((handle == NULL) || (handle->dev == NULL)) {
1865 pr_err("No valid kernel client\n");
1866 return -EINVAL;
1867 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001868 if (high) {
1869 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1870 if (ret)
1871 pr_err("Failed to vote for DFAB clock%d\n", ret);
1872 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1873 if (ret) {
1874 pr_err("Failed to vote for SFPB clock%d\n", ret);
1875 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1876 }
1877 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001878 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001879 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001880 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001881 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001882}
1883EXPORT_SYMBOL(qseecom_set_bandwidth);
1884
Mona Hossain2892b6b2012-02-17 13:53:11 -08001885static int qseecom_send_resp(void)
1886{
1887 qseecom.send_resp_flag = 1;
1888 wake_up_interruptible(&qseecom.send_resp_wq);
1889 return 0;
1890}
1891
1892static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1893 void __user *argp)
1894{
1895 struct qseecom_qseos_version_req req;
1896
1897 if (copy_from_user(&req, argp, sizeof(req))) {
1898 pr_err("copy_from_user failed");
1899 return -EINVAL;
1900 }
1901 req.qseos_version = qseecom.qseos_version;
1902 if (copy_to_user(argp, &req, sizeof(req))) {
1903 pr_err("copy_to_user failed");
1904 return -EINVAL;
1905 }
1906 return 0;
1907}
1908
Mona Hossainc92629e2013-04-01 13:37:46 -07001909static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001910{
1911 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001912 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001913
Mona Hossainc92629e2013-04-01 13:37:46 -07001914 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001915 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001916 else
1917 qclk = &qseecom.ce_drv;
1918
1919 mutex_lock(&clk_access_lock);
1920 if (qclk->clk_access_cnt > 0) {
1921 qclk->clk_access_cnt++;
1922 mutex_unlock(&clk_access_lock);
1923 return rc;
1924 }
1925
Mona Hossain6311d572013-03-01 15:54:02 -08001926 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001927 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001928 if (rc) {
1929 pr_err("Unable to enable/prepare CE core clk\n");
1930 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001931 }
1932 /* Enable CE clk */
1933 rc = clk_prepare_enable(qclk->ce_clk);
1934 if (rc) {
1935 pr_err("Unable to enable/prepare CE iface clk\n");
1936 goto ce_clk_err;
1937 }
1938 /* Enable AXI clk */
1939 rc = clk_prepare_enable(qclk->ce_bus_clk);
1940 if (rc) {
1941 pr_err("Unable to enable/prepare CE bus clk\n");
1942 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001943 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001944 qclk->clk_access_cnt++;
1945 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001946 return 0;
1947
1948ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001949 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001950ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001951 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001952err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001953 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001954 return -EIO;
1955}
1956
Mona Hossainc92629e2013-04-01 13:37:46 -07001957static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001958{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001959 struct qseecom_clk *qclk;
1960
Mona Hossainc92629e2013-04-01 13:37:46 -07001961 if (ce == CLK_QSEE)
1962 qclk = &qseecom.qsee;
1963 else
1964 qclk = &qseecom.ce_drv;
1965
1966 mutex_lock(&clk_access_lock);
1967 if (qclk->clk_access_cnt == 1) {
1968 if (qclk->ce_clk != NULL)
1969 clk_disable_unprepare(qclk->ce_clk);
1970 if (qclk->ce_core_clk != NULL)
1971 clk_disable_unprepare(qclk->ce_core_clk);
1972 if (qclk->ce_bus_clk != NULL)
1973 clk_disable_unprepare(qclk->ce_bus_clk);
1974 }
1975 qclk->clk_access_cnt--;
1976 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001977}
1978
Mona Hossain04d3fac2012-12-03 10:10:37 -08001979static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1980 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001981{
1982 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001983 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001984
Mona Hossain17a4faf2013-03-22 16:40:56 -07001985 qclk = &qseecom.qsee;
1986 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001987 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001988
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001989 switch (clk_type) {
1990 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001991 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001992 if (!qseecom.qsee_bw_count) {
1993 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001994 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001995 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001996 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001997 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07001998 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001999 if (!ret) {
2000 ret =
2001 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002002 qseecom.qsee_perf_client, 1);
2003 if ((ret) &&
2004 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002005 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002006 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002007 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002008 if (ret)
2009 pr_err("DFAB Bandwidth req failed (%d)\n",
2010 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002011 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002012 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002013 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002014 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002015 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002016 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002017 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002018 }
2019 mutex_unlock(&qsee_bw_mutex);
2020 break;
2021 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002022 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002023 if (!qseecom.qsee_sfpb_bw_count) {
2024 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002025 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002026 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002027 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002028 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002029 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002030 if (!ret) {
2031 ret =
2032 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002033 qseecom.qsee_perf_client, 2);
2034 if ((ret) &&
2035 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002036 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002037 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002038 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002039
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002040 if (ret)
2041 pr_err("SFPB Bandwidth req failed (%d)\n",
2042 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002043 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002044 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002045 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002046 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002047 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002048 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002049 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002050 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002051 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002052 break;
2053 default:
2054 pr_err("Clock type not defined\n");
2055 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002056 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002057 return ret;
2058}
2059
Mona Hossain04d3fac2012-12-03 10:10:37 -08002060static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2061 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002062{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002063 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002064 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002065
Mona Hossain17a4faf2013-03-22 16:40:56 -07002066 qclk = &qseecom.qsee;
2067 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002068 return;
2069
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002070 switch (clk_type) {
2071 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002072 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002073 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002074 pr_err("Client error.Extra call to disable DFAB clk\n");
2075 mutex_unlock(&qsee_bw_mutex);
2076 return;
2077 }
2078
Mona Hossain17a4faf2013-03-22 16:40:56 -07002079 if (qseecom.qsee_bw_count == 1) {
2080 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002081 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002082 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002083 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002084 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002085 qseecom.qsee_perf_client, 0);
2086 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002087 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002088 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002089 if (ret)
2090 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002091 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002092 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002093 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002094 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002095 }
2096 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002097 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002098 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002099 }
2100 mutex_unlock(&qsee_bw_mutex);
2101 break;
2102 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002103 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002104 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002105 pr_err("Client error.Extra call to disable SFPB clk\n");
2106 mutex_unlock(&qsee_bw_mutex);
2107 return;
2108 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002109 if (qseecom.qsee_sfpb_bw_count == 1) {
2110 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002111 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002112 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002113 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002114 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002115 qseecom.qsee_perf_client, 0);
2116 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002117 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002118 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002119 if (ret)
2120 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002121 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002122 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002123 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002124 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002125 }
2126 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002127 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002128 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002129 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002130 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002131 break;
2132 default:
2133 pr_err("Clock type not defined\n");
2134 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002135 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002136
Mona Hossain2892b6b2012-02-17 13:53:11 -08002137}
2138
Mona Hossain5ab9d772012-04-11 21:00:40 -07002139static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2140 void __user *argp)
2141{
2142 struct ion_handle *ihandle; /* Ion handle */
2143 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002144 int ret;
2145 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002146 ion_phys_addr_t pa = 0;
2147 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002148 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002149 struct qseecom_load_app_ireq load_req;
2150 struct qseecom_command_scm_resp resp;
2151
2152 /* Copy the relevant information needed for loading the image */
2153 if (__copy_from_user(&load_img_req,
2154 (void __user *)argp,
2155 sizeof(struct qseecom_load_img_req))) {
2156 pr_err("copy_from_user failed\n");
2157 return -EFAULT;
2158 }
2159
2160 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002161 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002162 load_img_req.ifd_data_fd);
2163 if (IS_ERR_OR_NULL(ihandle)) {
2164 pr_err("Ion client could not retrieve the handle\n");
2165 return -ENOMEM;
2166 }
2167
2168 /* Get the physical address of the ION BUF */
2169 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2170
2171 /* Populate the structure for sending scm call to load image */
2172 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2173 load_req.mdt_len = load_img_req.mdt_len;
2174 load_req.img_len = load_img_req.img_len;
2175 load_req.phy_addr = pa;
2176
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002177 /* SCM_CALL tied to Core0 */
2178 mask = CPU_MASK_CPU0;
2179 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2180 if (set_cpu_ret) {
2181 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2182 set_cpu_ret);
2183 ret = -EFAULT;
2184 goto qseecom_load_external_elf_set_cpu_err;
2185 }
Mona Hossain6311d572013-03-01 15:54:02 -08002186 /* Vote for the SFPB clock */
2187 ret = qsee_vote_for_clock(data, CLK_SFPB);
2188 if (ret) {
2189 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2190 ret = -EIO;
2191 goto qseecom_load_external_elf_set_cpu_err;
2192 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002193
Mona Hossain5ab9d772012-04-11 21:00:40 -07002194 /* SCM_CALL to load the external elf */
2195 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2196 sizeof(struct qseecom_load_app_ireq),
2197 &resp, sizeof(resp));
2198 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002199 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002200 ret);
2201 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002202 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002203 }
2204
2205 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2206 ret = __qseecom_process_incomplete_cmd(data, &resp);
2207 if (ret)
2208 pr_err("process_incomplete_cmd failed err: %d\n",
2209 ret);
2210 } else {
2211 if (resp.result != QSEOS_RESULT_SUCCESS) {
2212 pr_err("scm_call to load image failed resp.result =%d\n",
2213 resp.result);
2214 ret = -EFAULT;
2215 }
2216 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002217
2218qseecom_load_external_elf_scm_err:
2219 /* Restore the CPU mask */
2220 mask = CPU_MASK_ALL;
2221 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2222 if (set_cpu_ret) {
2223 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2224 set_cpu_ret);
2225 ret = -EFAULT;
2226 }
2227
2228qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002229 /* Deallocate the handle */
2230 if (!IS_ERR_OR_NULL(ihandle))
2231 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002232 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002233 return ret;
2234}
2235
2236static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2237{
2238 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002239 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002240 struct qseecom_command_scm_resp resp;
2241 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002242 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002243
2244 /* Populate the structure for sending scm call to unload image */
2245 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002246
2247 /* SCM_CALL tied to Core0 */
2248 mask = CPU_MASK_CPU0;
2249 ret = set_cpus_allowed_ptr(current, &mask);
2250 if (ret) {
2251 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2252 ret);
2253 return -EFAULT;
2254 }
2255
Mona Hossain5ab9d772012-04-11 21:00:40 -07002256 /* SCM_CALL to unload the external elf */
2257 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2258 sizeof(struct qseecom_unload_app_ireq),
2259 &resp, sizeof(resp));
2260 if (ret) {
2261 pr_err("scm_call to unload failed : ret %d\n",
2262 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002263 ret = -EFAULT;
2264 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002265 }
2266 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2267 ret = __qseecom_process_incomplete_cmd(data, &resp);
2268 if (ret)
2269 pr_err("process_incomplete_cmd fail err: %d\n",
2270 ret);
2271 } else {
2272 if (resp.result != QSEOS_RESULT_SUCCESS) {
2273 pr_err("scm_call to unload image failed resp.result =%d\n",
2274 resp.result);
2275 ret = -EFAULT;
2276 }
2277 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002278
2279qseecom_unload_external_elf_scm_err:
2280 /* Restore the CPU mask */
2281 mask = CPU_MASK_ALL;
2282 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2283 if (set_cpu_ret) {
2284 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2285 set_cpu_ret);
2286 ret = -EFAULT;
2287 }
2288
Mona Hossain5ab9d772012-04-11 21:00:40 -07002289 return ret;
2290}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002291
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002292static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2293 void __user *argp)
2294{
2295
2296 int32_t ret;
2297 struct qseecom_qseos_app_load_query query_req;
2298 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002299 struct qseecom_registered_app_list *entry = NULL;
2300 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002301
2302 /* Copy the relevant information needed for loading the image */
2303 if (__copy_from_user(&query_req,
2304 (void __user *)argp,
2305 sizeof(struct qseecom_qseos_app_load_query))) {
2306 pr_err("copy_from_user failed\n");
2307 return -EFAULT;
2308 }
2309
2310 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2311 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2312
2313 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002314
2315 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002316 pr_err(" scm call to check if app is loaded failed");
2317 return ret; /* scm call failed */
2318 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002319 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002320 (char *)(req.app_name));
2321 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2322 list_for_each_entry(entry,
2323 &qseecom.registered_app_list_head, list){
2324 if (entry->app_id == ret) {
2325 entry->ref_cnt++;
2326 break;
2327 }
2328 }
2329 spin_unlock_irqrestore(
2330 &qseecom.registered_app_list_lock, flags);
2331 data->client.app_id = ret;
2332 query_req.app_id = ret;
2333
2334 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2335 pr_err("copy_to_user failed\n");
2336 return -EFAULT;
2337 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002338 return -EEXIST; /* app already loaded */
2339 } else {
2340 return 0; /* app not loaded */
2341 }
2342}
2343
Mona Hossain4cf78a92013-02-14 12:06:41 -08002344static int __qseecom_get_ce_pipe_info(
2345 enum qseecom_key_management_usage_type usage,
2346 uint32_t *pipe, uint32_t *ce_hw)
2347{
2348 int ret;
2349 switch (usage) {
2350 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2351 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2352 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2353 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2354 qseecom.ce_info.disk_encrypt_pipe,
2355 qseecom.ce_info.hlos_ce_hw_instance);
2356 ret = -EINVAL;
2357 } else {
2358 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2359 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2360 ret = 0;
2361 }
2362 break;
2363 default:
2364 ret = -EINVAL;
2365 break;
2366 }
2367 return ret;
2368}
2369
2370static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2371 enum qseecom_key_management_usage_type usage,
2372 uint8_t *key_id, uint32_t flags)
2373{
2374 struct qseecom_key_generate_ireq ireq;
2375 struct qseecom_command_scm_resp resp;
2376 int ret;
2377
2378 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2379 pr_err("Error:: unsupported usage %d\n", usage);
2380 return -EFAULT;
2381 }
2382
2383 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2384 ireq.flags = flags;
2385
Mona Hossainc92629e2013-04-01 13:37:46 -07002386 __qseecom_enable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002387 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_GENERATE_KEY,
2388 &ireq, sizeof(struct qseecom_key_generate_ireq),
2389 &resp, sizeof(resp));
2390 if (ret) {
2391 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002392 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002393 return ret;
2394 }
2395
2396 switch (resp.result) {
2397 case QSEOS_RESULT_SUCCESS:
2398 break;
2399 case QSEOS_RESULT_INCOMPLETE:
2400 ret = __qseecom_process_incomplete_cmd(data, &resp);
2401 if (ret)
2402 pr_err("process_incomplete_cmd FAILED\n");
2403 break;
2404 case QSEOS_RESULT_FAILURE:
2405 default:
2406 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2407 ret = -EINVAL;
2408 break;
2409 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002410 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002411 return ret;
2412}
2413
2414static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2415 enum qseecom_key_management_usage_type usage,
2416 uint8_t *key_id, uint32_t flags)
2417{
2418 struct qseecom_key_delete_ireq ireq;
2419 struct qseecom_command_scm_resp resp;
2420 int ret;
2421
2422 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2423 pr_err("Error:: unsupported usage %d\n", usage);
2424 return -EFAULT;
2425 }
2426
2427 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2428 ireq.flags = flags;
2429
Mona Hossainc92629e2013-04-01 13:37:46 -07002430 __qseecom_enable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002431 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_DELETE_KEY,
2432 &ireq, sizeof(struct qseecom_key_delete_ireq),
2433 &resp, sizeof(struct qseecom_command_scm_resp));
2434 if (ret) {
2435 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002436 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002437 return ret;
2438 }
2439
2440 switch (resp.result) {
2441 case QSEOS_RESULT_SUCCESS:
2442 break;
2443 case QSEOS_RESULT_INCOMPLETE:
2444 ret = __qseecom_process_incomplete_cmd(data, &resp);
2445 if (ret)
2446 pr_err("process_incomplete_cmd FAILED\n");
2447 break;
2448 case QSEOS_RESULT_FAILURE:
2449 default:
2450 pr_err("Delete key scm call failed resp.result %d\n",
2451 resp.result);
2452 ret = -EINVAL;
2453 break;
2454 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002455 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002456 return ret;
2457}
2458
2459static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2460 enum qseecom_key_management_usage_type usage,
2461 struct qseecom_set_key_parameter *set_key_para)
2462{
2463 struct qseecom_key_select_ireq ireq;
2464 struct qseecom_command_scm_resp resp;
2465 int ret;
2466
2467 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2468 pr_err("Error:: unsupported usage %d\n", usage);
2469 return -EFAULT;
2470 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002471
2472 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2473 __qseecom_enable_clk(CLK_QSEE);
2474 else
2475 __qseecom_enable_clk(CLK_CE_DRV);
2476
Mona Hossain4cf78a92013-02-14 12:06:41 -08002477 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
2478 ireq.ce = set_key_para->ce_hw;
2479 ireq.pipe = set_key_para->pipe;
2480 ireq.flags = set_key_para->flags;
2481
2482 if (set_key_para->set_clear_key_flag ==
2483 QSEECOM_SET_CE_KEY_CMD)
2484 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2485 QSEECOM_HASH_SIZE);
2486 else
2487 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2488
2489 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_SET_KEY,
2490 &ireq, sizeof(struct qseecom_key_select_ireq),
2491 &resp, sizeof(struct qseecom_command_scm_resp));
2492 if (ret) {
2493 pr_err("scm call to set key failed : %d\n", ret);
2494 return ret;
2495 }
2496
2497 switch (resp.result) {
2498 case QSEOS_RESULT_SUCCESS:
2499 break;
2500 case QSEOS_RESULT_INCOMPLETE:
2501 ret = __qseecom_process_incomplete_cmd(data, &resp);
2502 if (ret)
2503 pr_err("process_incomplete_cmd FAILED\n");
2504 break;
2505 case QSEOS_RESULT_FAILURE:
2506 default:
2507 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2508 ret = -EINVAL;
2509 break;
2510 }
2511
Mona Hossainc92629e2013-04-01 13:37:46 -07002512 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2513 __qseecom_disable_clk(CLK_QSEE);
2514 else
2515 __qseecom_disable_clk(CLK_CE_DRV);
2516
Mona Hossain4cf78a92013-02-14 12:06:41 -08002517 return ret;
2518}
2519
2520static int qseecom_create_key(struct qseecom_dev_handle *data,
2521 void __user *argp)
2522{
2523 uint32_t ce_hw = 0;
2524 uint32_t pipe = 0;
2525 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2526 int ret = 0;
2527 uint32_t flags = 0;
2528 struct qseecom_set_key_parameter set_key_para;
2529 struct qseecom_create_key_req create_key_req;
2530
2531 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2532 if (ret) {
2533 pr_err("copy_from_user failed\n");
2534 return ret;
2535 }
2536
2537 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2538 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2539 return -EFAULT;
2540 }
2541
2542 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2543 if (ret) {
2544 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2545 return -EINVAL;
2546 }
2547
2548 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2549 key_id, flags);
2550 if (ret) {
2551 pr_err("Failed to generate key on storage: %d\n", ret);
2552 return -EFAULT;
2553 }
2554
2555 set_key_para.ce_hw = ce_hw;
2556 set_key_para.pipe = pipe;
2557 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2558 set_key_para.flags = flags;
2559 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2560 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2561 QSEECOM_HASH_SIZE);
2562
2563 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2564 &set_key_para);
2565 if (ret) {
2566 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2567 pipe, ce_hw, ret);
2568 return -EFAULT;
2569 }
2570
2571 return ret;
2572}
2573
2574static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2575 void __user *argp)
2576{
2577 uint32_t ce_hw = 0;
2578 uint32_t pipe = 0;
2579 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2580 int ret = 0;
2581 uint32_t flags = 0;
2582 int i;
2583 struct qseecom_wipe_key_req wipe_key_req;
2584 struct qseecom_set_key_parameter clear_key_para;
2585
2586 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2587 if (ret) {
2588 pr_err("copy_from_user failed\n");
2589 return ret;
2590 }
2591
2592 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2593 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2594 return -EFAULT;
2595 }
2596
2597 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2598 if (ret) {
2599 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2600 return -EINVAL;
2601 }
2602
2603 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2604 flags);
2605 if (ret) {
2606 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2607 return -EFAULT;
2608 }
2609
2610 /* an invalid key_id 0xff is used to indicate clear key*/
2611 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2612 clear_key_para.key_id[i] = 0xff;
2613 clear_key_para.ce_hw = ce_hw;
2614 clear_key_para.pipe = pipe;
2615 clear_key_para.flags = flags;
2616 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2617 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2618 &clear_key_para);
2619 if (ret) {
2620 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2621 pipe, ce_hw, ret);
2622 return -EFAULT;
2623 }
2624
2625 return ret;
2626}
2627
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002628static int qseecom_is_es_activated(void __user *argp)
2629{
2630 struct qseecom_is_es_activated_req req;
2631 int ret;
2632 int resp_buf;
2633
2634 if (qseecom.qsee_version < QSEE_VERSION_04) {
2635 pr_err("invalid qsee version");
2636 return -ENODEV;
2637 }
2638
2639 if (argp == NULL) {
2640 pr_err("arg is null");
2641 return -EINVAL;
2642 }
2643
2644 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2645 (void *) &resp_buf, sizeof(resp_buf));
2646 if (ret) {
2647 pr_err("scm_call failed");
2648 return ret;
2649 }
2650
2651 req.is_activated = resp_buf;
2652 ret = copy_to_user(argp, &req, sizeof(req));
2653 if (ret) {
2654 pr_err("copy_to_user failed");
2655 return ret;
2656 }
2657
2658 return 0;
2659}
2660
2661static int qseecom_save_partition_hash(void __user *argp)
2662{
2663 struct qseecom_save_partition_hash_req req;
2664 int ret;
2665
2666 if (qseecom.qsee_version < QSEE_VERSION_04) {
2667 pr_err("invalid qsee version ");
2668 return -ENODEV;
2669 }
2670
2671 if (argp == NULL) {
2672 pr_err("arg is null");
2673 return -EINVAL;
2674 }
2675
2676 ret = copy_from_user(&req, argp, sizeof(req));
2677 if (ret) {
2678 pr_err("copy_from_user failed");
2679 return ret;
2680 }
2681
2682 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2683 (void *) &req, sizeof(req), NULL, 0);
2684 if (ret) {
2685 pr_err("scm_call failed");
2686 return ret;
2687 }
2688
2689 return 0;
2690}
2691
Mona Hossain2892b6b2012-02-17 13:53:11 -08002692static long qseecom_ioctl(struct file *file, unsigned cmd,
2693 unsigned long arg)
2694{
2695 int ret = 0;
2696 struct qseecom_dev_handle *data = file->private_data;
2697 void __user *argp = (void __user *) arg;
2698
2699 if (data->abort) {
2700 pr_err("Aborting qseecom driver\n");
2701 return -ENODEV;
2702 }
2703
2704 switch (cmd) {
2705 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2706 pr_debug("ioctl register_listener_req()\n");
2707 atomic_inc(&data->ioctl_count);
2708 ret = qseecom_register_listener(data, argp);
2709 atomic_dec(&data->ioctl_count);
2710 wake_up_all(&data->abort_wq);
2711 if (ret)
2712 pr_err("failed qseecom_register_listener: %d\n", ret);
2713 break;
2714 }
2715 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2716 pr_debug("ioctl unregister_listener_req()\n");
2717 atomic_inc(&data->ioctl_count);
2718 ret = qseecom_unregister_listener(data);
2719 atomic_dec(&data->ioctl_count);
2720 wake_up_all(&data->abort_wq);
2721 if (ret)
2722 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2723 break;
2724 }
2725 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2726 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002727 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002728 atomic_inc(&data->ioctl_count);
2729 ret = qseecom_send_cmd(data, argp);
2730 atomic_dec(&data->ioctl_count);
2731 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002732 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002733 if (ret)
2734 pr_err("failed qseecom_send_cmd: %d\n", ret);
2735 break;
2736 }
2737 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2738 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002739 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002740 atomic_inc(&data->ioctl_count);
2741 ret = qseecom_send_modfd_cmd(data, argp);
2742 atomic_dec(&data->ioctl_count);
2743 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002744 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002745 if (ret)
2746 pr_err("failed qseecom_send_cmd: %d\n", ret);
2747 break;
2748 }
2749 case QSEECOM_IOCTL_RECEIVE_REQ: {
2750 atomic_inc(&data->ioctl_count);
2751 ret = qseecom_receive_req(data);
2752 atomic_dec(&data->ioctl_count);
2753 wake_up_all(&data->abort_wq);
2754 if (ret)
2755 pr_err("failed qseecom_receive_req: %d\n", ret);
2756 break;
2757 }
2758 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2759 atomic_inc(&data->ioctl_count);
2760 ret = qseecom_send_resp();
2761 atomic_dec(&data->ioctl_count);
2762 wake_up_all(&data->abort_wq);
2763 if (ret)
2764 pr_err("failed qseecom_send_resp: %d\n", ret);
2765 break;
2766 }
2767 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2768 ret = qseecom_set_client_mem_param(data, argp);
2769 if (ret)
2770 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2771 ret);
2772 break;
2773 }
2774 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2775 mutex_lock(&app_access_lock);
2776 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002777 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2778 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002779 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002780 if (ret == 0)
2781 qseecom.commonlib_loaded = true;
2782 }
2783 }
2784 if (ret == 0)
2785 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002786 atomic_dec(&data->ioctl_count);
2787 mutex_unlock(&app_access_lock);
2788 if (ret)
2789 pr_err("failed load_app request: %d\n", ret);
2790 break;
2791 }
2792 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2793 mutex_lock(&app_access_lock);
2794 atomic_inc(&data->ioctl_count);
2795 ret = qseecom_unload_app(data);
2796 atomic_dec(&data->ioctl_count);
2797 mutex_unlock(&app_access_lock);
2798 if (ret)
2799 pr_err("failed unload_app request: %d\n", ret);
2800 break;
2801 }
2802 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2803 atomic_inc(&data->ioctl_count);
2804 ret = qseecom_get_qseos_version(data, argp);
2805 if (ret)
2806 pr_err("qseecom_get_qseos_version: %d\n", ret);
2807 atomic_dec(&data->ioctl_count);
2808 break;
2809 }
2810 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2811 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002812 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002813 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002814 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002815 ret = qsee_vote_for_clock(data, CLK_SFPB);
2816 if (ret)
2817 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002818 atomic_dec(&data->ioctl_count);
2819 break;
2820 }
2821 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2822 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002823 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002824 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002825 atomic_dec(&data->ioctl_count);
2826 break;
2827 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002828 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2829 data->released = true;
2830 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2831 pr_err("Loading External elf image unsupported in rev 0x13\n");
2832 ret = -EINVAL;
2833 break;
2834 }
2835 mutex_lock(&app_access_lock);
2836 atomic_inc(&data->ioctl_count);
2837 ret = qseecom_load_external_elf(data, argp);
2838 atomic_dec(&data->ioctl_count);
2839 mutex_unlock(&app_access_lock);
2840 if (ret)
2841 pr_err("failed load_external_elf request: %d\n", ret);
2842 break;
2843 }
2844 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2845 data->released = true;
2846 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2847 pr_err("Unloading External elf image unsupported in rev 0x13\n");
2848 ret = -EINVAL;
2849 break;
2850 }
2851 mutex_lock(&app_access_lock);
2852 atomic_inc(&data->ioctl_count);
2853 ret = qseecom_unload_external_elf(data);
2854 atomic_dec(&data->ioctl_count);
2855 mutex_unlock(&app_access_lock);
2856 if (ret)
2857 pr_err("failed unload_app request: %d\n", ret);
2858 break;
2859 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002860 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2861 mutex_lock(&app_access_lock);
2862 atomic_inc(&data->ioctl_count);
2863 ret = qseecom_query_app_loaded(data, argp);
2864 atomic_dec(&data->ioctl_count);
2865 mutex_unlock(&app_access_lock);
2866 break;
2867 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002868 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2869 if (qseecom.qsee_version < QSEE_VERSION_03) {
2870 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2871 qseecom.qsee_version);
2872 return -EINVAL;
2873 }
2874 mutex_lock(&app_access_lock);
2875 atomic_inc(&data->ioctl_count);
2876 ret = qseecom_send_service_cmd(data, argp);
2877 atomic_dec(&data->ioctl_count);
2878 mutex_unlock(&app_access_lock);
2879 break;
2880 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002881 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
2882 data->released = true;
2883 mutex_lock(&app_access_lock);
2884 atomic_inc(&data->ioctl_count);
2885 ret = qseecom_create_key(data, argp);
2886 if (ret)
2887 pr_err("failed to create encryption key: %d\n", ret);
2888
2889 atomic_dec(&data->ioctl_count);
2890 mutex_unlock(&app_access_lock);
2891 break;
2892 }
2893 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
2894 data->released = true;
2895 mutex_lock(&app_access_lock);
2896 atomic_inc(&data->ioctl_count);
2897 ret = qseecom_wipe_key(data, argp);
2898 if (ret)
2899 pr_err("failed to wipe encryption key: %d\n", ret);
2900 atomic_dec(&data->ioctl_count);
2901 mutex_unlock(&app_access_lock);
2902 break;
2903 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002904 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
2905 data->released = true;
2906 mutex_lock(&app_access_lock);
2907 atomic_inc(&data->ioctl_count);
2908 ret = qseecom_save_partition_hash(argp);
2909 atomic_dec(&data->ioctl_count);
2910 mutex_unlock(&app_access_lock);
2911 break;
2912 }
2913 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
2914 data->released = true;
2915 mutex_lock(&app_access_lock);
2916 atomic_inc(&data->ioctl_count);
2917 ret = qseecom_is_es_activated(argp);
2918 atomic_dec(&data->ioctl_count);
2919 mutex_unlock(&app_access_lock);
2920 break;
2921 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002922 default:
2923 return -EINVAL;
2924 }
2925 return ret;
2926}
2927
2928static int qseecom_open(struct inode *inode, struct file *file)
2929{
2930 int ret = 0;
2931 struct qseecom_dev_handle *data;
2932
2933 data = kzalloc(sizeof(*data), GFP_KERNEL);
2934 if (!data) {
2935 pr_err("kmalloc failed\n");
2936 return -ENOMEM;
2937 }
2938 file->private_data = data;
2939 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002940 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002941 data->released = false;
2942 init_waitqueue_head(&data->abort_wq);
2943 atomic_set(&data->ioctl_count, 0);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002944 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2945 int pil_error;
2946 mutex_lock(&pil_access_lock);
2947 if (pil_ref_cnt == 0) {
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002948 pil = subsystem_get("tzapps");
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002949 if (IS_ERR(pil)) {
2950 pr_err("Playready PIL image load failed\n");
2951 pil_error = PTR_ERR(pil);
2952 pil = NULL;
2953 pr_debug("tzapps image load FAILED\n");
2954 mutex_unlock(&pil_access_lock);
2955 return pil_error;
2956 }
2957 }
2958 pil_ref_cnt++;
2959 mutex_unlock(&pil_access_lock);
2960 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002961 return ret;
2962}
2963
2964static int qseecom_release(struct inode *inode, struct file *file)
2965{
2966 struct qseecom_dev_handle *data = file->private_data;
2967 int ret = 0;
2968
2969 if (data->released == false) {
2970 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002971 switch (data->type) {
2972 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002973 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002974 break;
2975 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002976 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002977 break;
2978 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07002979 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002980 ret = qseecom_unmap_ion_allocated_memory(data);
2981 if (ret) {
2982 pr_err("Close failed\n");
2983 return ret;
2984 }
2985 break;
2986 default:
2987 pr_err("Unsupported clnt_handle_type %d",
2988 data->type);
2989 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002990 }
2991 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002992
Mona Hossainc9c83c72013-04-11 12:43:48 -07002993 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002994 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07002995 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002996 qsee_disable_clock_vote(data, CLK_DFAB);
2997
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002998 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2999 mutex_lock(&pil_access_lock);
3000 if (pil_ref_cnt == 1)
Stephen Boyd77db8bb2012-06-27 15:15:16 -07003001 subsystem_put(pil);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003002 pil_ref_cnt--;
3003 mutex_unlock(&pil_access_lock);
3004 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003005 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003006
Mona Hossain2892b6b2012-02-17 13:53:11 -08003007 return ret;
3008}
3009
Mona Hossain2892b6b2012-02-17 13:53:11 -08003010static const struct file_operations qseecom_fops = {
3011 .owner = THIS_MODULE,
3012 .unlocked_ioctl = qseecom_ioctl,
3013 .open = qseecom_open,
3014 .release = qseecom_release
3015};
3016
Mona Hossainc92629e2013-04-01 13:37:46 -07003017static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003018{
3019 int rc = 0;
3020 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003021 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003022 char *core_clk_src = NULL;
3023 char *core_clk = NULL;
3024 char *iface_clk = NULL;
3025 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003026
Mona Hossainc92629e2013-04-01 13:37:46 -07003027 switch (ce) {
3028 case CLK_QSEE: {
3029 core_clk_src = "core_clk_src";
3030 core_clk = "core_clk";
3031 iface_clk = "iface_clk";
3032 bus_clk = "bus_clk";
3033 qclk = &qseecom.qsee;
3034 qclk->instance = CLK_QSEE;
3035 break;
3036 };
3037 case CLK_CE_DRV: {
3038 core_clk_src = "ce_drv_core_clk_src";
3039 core_clk = "ce_drv_core_clk";
3040 iface_clk = "ce_drv_iface_clk";
3041 bus_clk = "ce_drv_bus_clk";
3042 qclk = &qseecom.ce_drv;
3043 qclk->instance = CLK_CE_DRV;
3044 break;
3045 };
3046 default:
3047 pr_err("Invalid ce hw instance: %d!\n", ce);
3048 return -EIO;
3049 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003050 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003051
Mona Hossainc92629e2013-04-01 13:37:46 -07003052 /* Get CE3 src core clk. */
3053 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003054 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003055 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003056 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003057 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003058 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003059 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003060 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003061 }
3062 } else {
3063 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003064 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003065 }
3066
3067 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003068 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003069 if (IS_ERR(qclk->ce_core_clk)) {
3070 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003071 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003072 if (qclk->ce_core_src_clk != NULL)
3073 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003074 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003075 }
3076
3077 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003078 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003079 if (IS_ERR(qclk->ce_clk)) {
3080 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003081 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003082 if (qclk->ce_core_src_clk != NULL)
3083 clk_put(qclk->ce_core_src_clk);
3084 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003085 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003086 }
3087
3088 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003089 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003090 if (IS_ERR(qclk->ce_bus_clk)) {
3091 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003092 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003093 if (qclk->ce_core_src_clk != NULL)
3094 clk_put(qclk->ce_core_src_clk);
3095 clk_put(qclk->ce_core_clk);
3096 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003097 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003098 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003099 return rc;
3100}
3101
Mona Hossainc92629e2013-04-01 13:37:46 -07003102static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003103{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003104 struct qseecom_clk *qclk;
3105
Mona Hossainc92629e2013-04-01 13:37:46 -07003106 if (ce == CLK_QSEE)
3107 qclk = &qseecom.qsee;
3108 else
3109 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003110
3111 if (qclk->ce_clk != NULL) {
3112 clk_put(qclk->ce_clk);
3113 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003114 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003115 if (qclk->ce_core_clk != NULL) {
3116 clk_put(qclk->ce_core_clk);
3117 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003118 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003119 if (qclk->ce_bus_clk != NULL) {
3120 clk_put(qclk->ce_bus_clk);
3121 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003122 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003123 if (qclk->ce_core_src_clk != NULL) {
3124 clk_put(qclk->ce_core_src_clk);
3125 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003126 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003127}
3128
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003129static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003130{
3131 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003132 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003133 struct device *class_dev;
3134 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003135 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003136 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3137
Mona Hossain17a4faf2013-03-22 16:40:56 -07003138 qseecom.qsee_bw_count = 0;
3139 qseecom.qsee_perf_client = 0;
3140 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003141
Mona Hossain17a4faf2013-03-22 16:40:56 -07003142 qseecom.qsee.ce_core_clk = NULL;
3143 qseecom.qsee.ce_clk = NULL;
3144 qseecom.qsee.ce_core_src_clk = NULL;
3145 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003146
Mona Hossainc92629e2013-04-01 13:37:46 -07003147 qseecom.ce_drv.ce_core_clk = NULL;
3148 qseecom.ce_drv.ce_clk = NULL;
3149 qseecom.ce_drv.ce_core_src_clk = NULL;
3150 qseecom.ce_drv.ce_bus_clk = NULL;
3151
Mona Hossain2892b6b2012-02-17 13:53:11 -08003152 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3153 if (rc < 0) {
3154 pr_err("alloc_chrdev_region failed %d\n", rc);
3155 return rc;
3156 }
3157
3158 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3159 if (IS_ERR(driver_class)) {
3160 rc = -ENOMEM;
3161 pr_err("class_create failed %d\n", rc);
3162 goto unregister_chrdev_region;
3163 }
3164
3165 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3166 QSEECOM_DEV);
3167 if (!class_dev) {
3168 pr_err("class_device_create failed %d\n", rc);
3169 rc = -ENOMEM;
3170 goto class_destroy;
3171 }
3172
3173 cdev_init(&qseecom_cdev, &qseecom_fops);
3174 qseecom_cdev.owner = THIS_MODULE;
3175
3176 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
3177 if (rc < 0) {
3178 pr_err("cdev_add failed %d\n", rc);
3179 goto err;
3180 }
3181
3182 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3183 spin_lock_init(&qseecom.registered_listener_list_lock);
3184 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3185 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003186 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3187 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003188 init_waitqueue_head(&qseecom.send_resp_wq);
3189 qseecom.send_resp_flag = 0;
3190
3191 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3192 &qsee_not_legacy, sizeof(qsee_not_legacy));
3193 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003194 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003195 goto err;
3196 }
Mona Hossain05c73562012-10-29 17:49:01 -07003197 if (qsee_not_legacy) {
3198 uint32_t feature = 10;
3199
3200 qseecom.qsee_version = QSEEE_VERSION_00;
3201 rc = scm_call(6, 3, &feature, sizeof(feature),
3202 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3203 if (rc) {
3204 pr_err("Failed to get QSEE version info %d\n", rc);
3205 goto err;
3206 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003207 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003208 } else {
Mona Hossain2892b6b2012-02-17 13:53:11 -08003209 qseecom.qseos_version = QSEOS_VERSION_13;
Mona Hossain05c73562012-10-29 17:49:01 -07003210 qseecom.qsee_version = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003211 pil = NULL;
3212 pil_ref_cnt = 0;
3213 }
Mona Hossain05c73562012-10-29 17:49:01 -07003214 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003215 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003216 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003217 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003218 if (qseecom.ion_clnt == NULL) {
3219 pr_err("Ion client cannot be created\n");
3220 rc = -ENOMEM;
3221 goto err;
3222 }
3223
3224 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003225 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003226
Mona Hossain4cf78a92013-02-14 12:06:41 -08003227 if (of_property_read_u32((&pdev->dev)->of_node,
3228 "qcom,disk-encrypt-pipe-pair",
3229 &qseecom.ce_info.disk_encrypt_pipe)) {
3230 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3231 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3232 rc = -EINVAL;
3233 goto err;
3234 } else {
3235 pr_warn("bam_pipe_pair=0x%x",
3236 qseecom.ce_info.disk_encrypt_pipe);
3237 }
3238
3239 if (of_property_read_u32((&pdev->dev)->of_node,
3240 "qcom,qsee-ce-hw-instance",
3241 &qseecom.ce_info.qsee_ce_hw_instance)) {
3242 pr_err("Fail to get qsee ce hw instance information.\n");
3243 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3244 rc = -EINVAL;
3245 goto err;
3246 } else {
3247 pr_warn("qsee-ce-hw-instance=0x%x",
3248 qseecom.ce_info.qsee_ce_hw_instance);
3249 }
3250
3251 if (of_property_read_u32((&pdev->dev)->of_node,
3252 "qcom,hlos-ce-hw-instance",
3253 &qseecom.ce_info.hlos_ce_hw_instance)) {
3254 pr_err("Fail to get hlos ce hw instance information.\n");
3255 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3256 rc = -EINVAL;
3257 goto err;
3258 } else {
3259 pr_warn("hlos-ce-hw-instance=0x%x",
3260 qseecom.ce_info.hlos_ce_hw_instance);
3261 }
3262
Mona Hossainc92629e2013-04-01 13:37:46 -07003263 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3264 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3265
3266 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003267 if (ret)
3268 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003269
Mona Hossainc92629e2013-04-01 13:37:46 -07003270 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3271 ret = __qseecom_init_clk(CLK_CE_DRV);
3272 if (ret) {
3273 __qseecom_deinit_clk(CLK_QSEE);
3274 goto err;
3275 }
3276 } else {
3277 struct qseecom_clk *qclk;
3278
3279 qclk = &qseecom.qsee;
3280 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3281 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3282 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3283 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3284 }
3285
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003286 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3287 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003288 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3289 struct resource *resource = NULL;
3290 struct qsee_apps_region_info_ireq req;
3291 struct qseecom_command_scm_resp resp;
3292
3293 resource = platform_get_resource_byname(pdev,
3294 IORESOURCE_MEM, "secapp-region");
3295 if (resource) {
3296 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3297 req.addr = resource->start;
3298 req.size = resource_size(resource);
3299 pr_warn("secure app region addr=0x%x size=0x%x",
3300 req.addr, req.size);
3301 } else {
3302 pr_err("Fail to get secure app region info\n");
3303 rc = -EINVAL;
3304 goto err;
3305 }
3306 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3307 &resp, sizeof(resp));
3308 if (rc) {
3309 pr_err("Failed to send secapp region info %d\n",
3310 rc);
3311 goto err;
3312 }
3313 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003314 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003315 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3316 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003317 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003318
Mona Hossain17a4faf2013-03-22 16:40:56 -07003319 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003320 qseecom_platform_support);
3321
Mona Hossain17a4faf2013-03-22 16:40:56 -07003322 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003323 pr_err("Unable to register bus client\n");
3324 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003325err:
3326 device_destroy(driver_class, qseecom_device_no);
3327class_destroy:
3328 class_destroy(driver_class);
3329unregister_chrdev_region:
3330 unregister_chrdev_region(qseecom_device_no, 1);
3331 return rc;
3332}
3333
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003334static int __devinit qseecom_remove(struct platform_device *pdev)
3335{
Mona Hossaind44a3842012-10-15 09:41:35 -07003336 struct qseecom_registered_kclient_list *kclient = NULL;
3337 unsigned long flags = 0;
3338 int ret = 0;
3339
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003340 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003341 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003342
3343 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3344 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3345 struct qseecom_registered_kclient_list, list);
3346 if (list_empty(&kclient->list)) {
3347 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3348 flags);
3349 return 0;
3350 }
3351 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3352 list) {
3353 if (kclient)
3354 list_del(&kclient->list);
3355 break;
3356 }
3357 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3358
3359
3360 while (kclient->handle != NULL) {
3361 ret = qseecom_unload_app(kclient->handle->dev);
3362 if (ret == 0) {
3363 kzfree(kclient->handle->dev);
3364 kzfree(kclient->handle);
3365 kzfree(kclient);
3366 }
3367 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3368 kclient = list_entry(
3369 (&qseecom.registered_kclient_list_head)->next,
3370 struct qseecom_registered_kclient_list, list);
3371 if (list_empty(&kclient->list)) {
3372 spin_unlock_irqrestore(
3373 &qseecom.registered_kclient_list_lock, flags);
3374 return 0;
3375 }
3376 list_for_each_entry(kclient,
3377 &qseecom.registered_kclient_list_head, list) {
3378 if (kclient)
3379 list_del(&kclient->list);
3380 break;
3381 }
3382 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3383 flags);
3384 if (!kclient) {
3385 ret = 0;
3386 break;
3387 }
3388 }
Mona Hossain05c73562012-10-29 17:49:01 -07003389 if (qseecom.qseos_version > QSEEE_VERSION_00)
3390 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003391
Mona Hossain17a4faf2013-03-22 16:40:56 -07003392 if (qseecom.qsee_perf_client)
3393 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3394 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003395 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003396 if (pdev->dev.of_node) {
3397 __qseecom_deinit_clk(CLK_QSEE);
3398 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3399 __qseecom_deinit_clk(CLK_CE_DRV);
3400 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003401 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003402};
3403
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003404static struct of_device_id qseecom_match[] = {
3405 {
3406 .compatible = "qcom,qseecom",
3407 },
3408 {}
3409};
3410
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003411static struct platform_driver qseecom_plat_driver = {
3412 .probe = qseecom_probe,
3413 .remove = qseecom_remove,
3414 .driver = {
3415 .name = "qseecom",
3416 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003417 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003418 },
3419};
3420
3421static int __devinit qseecom_init(void)
3422{
3423 return platform_driver_register(&qseecom_plat_driver);
3424}
3425
3426static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003427{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003428 device_destroy(driver_class, qseecom_device_no);
3429 class_destroy(driver_class);
3430 unregister_chrdev_region(qseecom_device_no, 1);
3431 ion_client_destroy(qseecom.ion_clnt);
3432}
3433
3434MODULE_LICENSE("GPL v2");
3435MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3436
3437module_init(qseecom_init);
3438module_exit(qseecom_exit);