blob: ac77bfb6d20855b2fa8dcb3d50635a69b46a9eaa [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;
Mona Hossaind44a3842012-10-15 09:41:35 -07001651 data->client.sb_length = size;
1652 data->client.user_virt_sb_base = 0;
1653 data->client.ihandle = NULL;
1654
1655 init_waitqueue_head(&data->abort_wq);
1656 atomic_set(&data->ioctl_count, 0);
1657
1658 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1659 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1660 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1661 pr_err("Ion client could not retrieve the handle\n");
1662 kfree(data);
1663 kfree(*handle);
1664 *handle = NULL;
1665 return -EINVAL;
1666 }
1667
Mona Hossain9498f5e2013-01-23 18:08:45 -08001668 if (qseecom.qsee_version > QSEEE_VERSION_00) {
1669 mutex_lock(&app_access_lock);
1670 if (qseecom.commonlib_loaded == false) {
1671 ret = qseecom_load_commonlib_image(data);
1672 if (ret == 0)
1673 qseecom.commonlib_loaded = true;
1674 }
1675 mutex_unlock(&app_access_lock);
1676 }
1677
1678 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001679 pr_err("Failed to load commonlib image\n");
Mona Hossain9498f5e2013-01-23 18:08:45 -08001680 kfree(data);
1681 kfree(*handle);
1682 *handle = NULL;
1683 return -EIO;
1684 }
1685
1686 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1687 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1688 ret = __qseecom_check_app_exists(app_ireq);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001689 if (ret < 0) {
1690 kzfree(data);
1691 kfree(*handle);
1692 *handle = NULL;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001693 return -EINVAL;
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001694 }
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001695 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001696 if (ret > 0) {
1697 pr_warn("App id %d for [%s] app exists\n", ret,
1698 (char *)app_ireq.app_name);
1699 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1700 list_for_each_entry(entry,
1701 &qseecom.registered_app_list_head, list){
1702 if (entry->app_id == ret) {
1703 entry->ref_cnt++;
1704 found_app = true;
1705 break;
1706 }
1707 }
1708 spin_unlock_irqrestore(
1709 &qseecom.registered_app_list_lock, flags);
1710 if (!found_app)
1711 pr_warn("App_id %d [%s] was loaded but not registered\n",
1712 ret, (char *)app_ireq.app_name);
1713 } else {
1714 /* load the app and get the app_id */
1715 pr_debug("%s: Loading app for the first time'\n",
1716 qseecom.pdev->init_name);
1717 mutex_lock(&app_access_lock);
1718 ret = __qseecom_load_fw(data, app_name);
1719 mutex_unlock(&app_access_lock);
1720
1721 if (ret < 0) {
1722 kfree(*handle);
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001723 kfree(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001724 *handle = NULL;
1725 return ret;
1726 }
1727 data->client.app_id = ret;
1728 }
1729 if (!found_app) {
1730 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1731 if (!entry) {
1732 pr_err("kmalloc failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001733 kfree(data);
1734 kfree(*handle);
1735 *handle = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001736 return -ENOMEM;
1737 }
1738 entry->app_id = ret;
1739 entry->ref_cnt = 1;
1740
1741 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1742 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1743 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1744 flags);
1745 }
1746
1747 /* Get the physical address of the ION BUF */
1748 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1749 /* Populate the structure for sending scm call to load image */
1750 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1751 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001752 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001753 data->client.sb_phys = pa;
1754 (*handle)->dev = (void *)data;
1755 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1756 (*handle)->sbuf_len = data->client.sb_length;
1757
1758 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1759 if (!kclient_entry) {
1760 pr_err("kmalloc failed\n");
1761 return -ENOMEM;
1762 }
1763 kclient_entry->handle = *handle;
1764
1765 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1766 list_add_tail(&kclient_entry->list,
1767 &qseecom.registered_kclient_list_head);
1768 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1769
1770 return 0;
1771}
1772EXPORT_SYMBOL(qseecom_start_app);
1773
1774int qseecom_shutdown_app(struct qseecom_handle **handle)
1775{
1776 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001777 struct qseecom_dev_handle *data;
1778
Mona Hossaind44a3842012-10-15 09:41:35 -07001779 struct qseecom_registered_kclient_list *kclient = NULL;
1780 unsigned long flags = 0;
1781 bool found_handle = false;
1782
1783 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1784 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1785 return -EINVAL;
1786 }
Mona Hossain33824022013-02-25 09:32:33 -08001787 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001788 pr_err("Handle is not initialized\n");
1789 return -EINVAL;
1790 }
Mona Hossain33824022013-02-25 09:32:33 -08001791 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001792 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1793 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1794 list) {
1795 if (kclient->handle == (*handle)) {
1796 list_del(&kclient->list);
1797 found_handle = true;
1798 break;
1799 }
1800 }
1801 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1802 if (!found_handle)
1803 pr_err("Unable to find the handle, exiting\n");
1804 else
1805 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001806 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001807 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001808 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001809 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001810 if (ret == 0) {
1811 kzfree(data);
1812 kzfree(*handle);
1813 kzfree(kclient);
1814 *handle = NULL;
1815 }
1816 return ret;
1817}
1818EXPORT_SYMBOL(qseecom_shutdown_app);
1819
1820int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1821 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1822{
1823 int ret = 0;
1824 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1825 struct qseecom_dev_handle *data;
1826
1827 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1828 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1829 return -EINVAL;
1830 }
1831
1832 if (handle == NULL) {
1833 pr_err("Handle is not initialized\n");
1834 return -EINVAL;
1835 }
1836 data = handle->dev;
1837
1838 req.cmd_req_len = sbuf_len;
1839 req.resp_len = rbuf_len;
1840 req.cmd_req_buf = send_buf;
1841 req.resp_buf = resp_buf;
1842
1843 mutex_lock(&app_access_lock);
1844 atomic_inc(&data->ioctl_count);
1845
1846 ret = __qseecom_send_cmd(data, &req);
1847
1848 atomic_dec(&data->ioctl_count);
1849 mutex_unlock(&app_access_lock);
1850
1851 if (ret)
1852 return ret;
1853
1854 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1855 req.resp_len, req.resp_buf);
1856 return ret;
1857}
1858EXPORT_SYMBOL(qseecom_send_command);
1859
Mona Hossain91a8fc92012-11-07 19:58:30 -08001860int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1861{
Mona Hossainfca6f422013-01-12 13:00:35 -08001862 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001863 if ((handle == NULL) || (handle->dev == NULL)) {
1864 pr_err("No valid kernel client\n");
1865 return -EINVAL;
1866 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001867 if (high) {
1868 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1869 if (ret)
1870 pr_err("Failed to vote for DFAB clock%d\n", ret);
1871 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1872 if (ret) {
1873 pr_err("Failed to vote for SFPB clock%d\n", ret);
1874 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1875 }
1876 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001877 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001878 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001879 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001880 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001881}
1882EXPORT_SYMBOL(qseecom_set_bandwidth);
1883
Mona Hossain2892b6b2012-02-17 13:53:11 -08001884static int qseecom_send_resp(void)
1885{
1886 qseecom.send_resp_flag = 1;
1887 wake_up_interruptible(&qseecom.send_resp_wq);
1888 return 0;
1889}
1890
1891static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1892 void __user *argp)
1893{
1894 struct qseecom_qseos_version_req req;
1895
1896 if (copy_from_user(&req, argp, sizeof(req))) {
1897 pr_err("copy_from_user failed");
1898 return -EINVAL;
1899 }
1900 req.qseos_version = qseecom.qseos_version;
1901 if (copy_to_user(argp, &req, sizeof(req))) {
1902 pr_err("copy_to_user failed");
1903 return -EINVAL;
1904 }
1905 return 0;
1906}
1907
Mona Hossainc92629e2013-04-01 13:37:46 -07001908static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001909{
1910 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001911 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001912
Mona Hossainc92629e2013-04-01 13:37:46 -07001913 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001914 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001915 else
1916 qclk = &qseecom.ce_drv;
1917
1918 mutex_lock(&clk_access_lock);
1919 if (qclk->clk_access_cnt > 0) {
1920 qclk->clk_access_cnt++;
1921 mutex_unlock(&clk_access_lock);
1922 return rc;
1923 }
1924
Mona Hossain6311d572013-03-01 15:54:02 -08001925 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001926 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001927 if (rc) {
1928 pr_err("Unable to enable/prepare CE core clk\n");
1929 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001930 }
1931 /* Enable CE clk */
1932 rc = clk_prepare_enable(qclk->ce_clk);
1933 if (rc) {
1934 pr_err("Unable to enable/prepare CE iface clk\n");
1935 goto ce_clk_err;
1936 }
1937 /* Enable AXI clk */
1938 rc = clk_prepare_enable(qclk->ce_bus_clk);
1939 if (rc) {
1940 pr_err("Unable to enable/prepare CE bus clk\n");
1941 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001942 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001943 qclk->clk_access_cnt++;
1944 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001945 return 0;
1946
1947ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001948 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001949ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001950 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001951err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001952 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001953 return -EIO;
1954}
1955
Mona Hossainc92629e2013-04-01 13:37:46 -07001956static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001957{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001958 struct qseecom_clk *qclk;
1959
Mona Hossainc92629e2013-04-01 13:37:46 -07001960 if (ce == CLK_QSEE)
1961 qclk = &qseecom.qsee;
1962 else
1963 qclk = &qseecom.ce_drv;
1964
1965 mutex_lock(&clk_access_lock);
1966 if (qclk->clk_access_cnt == 1) {
1967 if (qclk->ce_clk != NULL)
1968 clk_disable_unprepare(qclk->ce_clk);
1969 if (qclk->ce_core_clk != NULL)
1970 clk_disable_unprepare(qclk->ce_core_clk);
1971 if (qclk->ce_bus_clk != NULL)
1972 clk_disable_unprepare(qclk->ce_bus_clk);
1973 }
1974 qclk->clk_access_cnt--;
1975 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001976}
1977
Mona Hossain04d3fac2012-12-03 10:10:37 -08001978static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1979 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001980{
1981 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001982 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001983
Mona Hossain17a4faf2013-03-22 16:40:56 -07001984 qclk = &qseecom.qsee;
1985 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001986 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001987
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001988 switch (clk_type) {
1989 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001990 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001991 if (!qseecom.qsee_bw_count) {
1992 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001993 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001994 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001995 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001996 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07001997 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001998 if (!ret) {
1999 ret =
2000 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002001 qseecom.qsee_perf_client, 1);
2002 if ((ret) &&
2003 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002004 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002005 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002006 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002007 if (ret)
2008 pr_err("DFAB Bandwidth req failed (%d)\n",
2009 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002010 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002011 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002012 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002013 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002014 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002015 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002016 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002017 }
2018 mutex_unlock(&qsee_bw_mutex);
2019 break;
2020 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002021 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002022 if (!qseecom.qsee_sfpb_bw_count) {
2023 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002024 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002025 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002026 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002027 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002028 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002029 if (!ret) {
2030 ret =
2031 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002032 qseecom.qsee_perf_client, 2);
2033 if ((ret) &&
2034 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002035 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002036 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002037 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002038
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002039 if (ret)
2040 pr_err("SFPB Bandwidth req failed (%d)\n",
2041 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002042 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002043 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002044 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002045 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002046 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002047 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002048 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002049 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002050 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002051 break;
2052 default:
2053 pr_err("Clock type not defined\n");
2054 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002055 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002056 return ret;
2057}
2058
Mona Hossain04d3fac2012-12-03 10:10:37 -08002059static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2060 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002061{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002062 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002063 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002064
Mona Hossain17a4faf2013-03-22 16:40:56 -07002065 qclk = &qseecom.qsee;
2066 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002067 return;
2068
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002069 switch (clk_type) {
2070 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002071 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002072 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002073 pr_err("Client error.Extra call to disable DFAB clk\n");
2074 mutex_unlock(&qsee_bw_mutex);
2075 return;
2076 }
2077
Mona Hossain17a4faf2013-03-22 16:40:56 -07002078 if (qseecom.qsee_bw_count == 1) {
2079 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002080 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002081 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002082 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002083 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002084 qseecom.qsee_perf_client, 0);
2085 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002086 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002087 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002088 if (ret)
2089 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002090 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002091 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002092 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002093 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002094 }
2095 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002096 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002097 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002098 }
2099 mutex_unlock(&qsee_bw_mutex);
2100 break;
2101 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002102 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002103 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002104 pr_err("Client error.Extra call to disable SFPB clk\n");
2105 mutex_unlock(&qsee_bw_mutex);
2106 return;
2107 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002108 if (qseecom.qsee_sfpb_bw_count == 1) {
2109 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002110 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002111 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002112 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002113 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002114 qseecom.qsee_perf_client, 0);
2115 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002116 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002117 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002118 if (ret)
2119 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002120 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002121 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002122 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002123 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002124 }
2125 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002126 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002127 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002128 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002129 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002130 break;
2131 default:
2132 pr_err("Clock type not defined\n");
2133 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002134 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002135
Mona Hossain2892b6b2012-02-17 13:53:11 -08002136}
2137
Mona Hossain5ab9d772012-04-11 21:00:40 -07002138static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2139 void __user *argp)
2140{
2141 struct ion_handle *ihandle; /* Ion handle */
2142 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002143 int ret;
2144 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002145 ion_phys_addr_t pa = 0;
2146 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002147 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002148 struct qseecom_load_app_ireq load_req;
2149 struct qseecom_command_scm_resp resp;
2150
2151 /* Copy the relevant information needed for loading the image */
2152 if (__copy_from_user(&load_img_req,
2153 (void __user *)argp,
2154 sizeof(struct qseecom_load_img_req))) {
2155 pr_err("copy_from_user failed\n");
2156 return -EFAULT;
2157 }
2158
2159 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002160 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002161 load_img_req.ifd_data_fd);
2162 if (IS_ERR_OR_NULL(ihandle)) {
2163 pr_err("Ion client could not retrieve the handle\n");
2164 return -ENOMEM;
2165 }
2166
2167 /* Get the physical address of the ION BUF */
2168 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2169
2170 /* Populate the structure for sending scm call to load image */
2171 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2172 load_req.mdt_len = load_img_req.mdt_len;
2173 load_req.img_len = load_img_req.img_len;
2174 load_req.phy_addr = pa;
2175
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002176 /* SCM_CALL tied to Core0 */
2177 mask = CPU_MASK_CPU0;
2178 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2179 if (set_cpu_ret) {
2180 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2181 set_cpu_ret);
2182 ret = -EFAULT;
2183 goto qseecom_load_external_elf_set_cpu_err;
2184 }
Mona Hossain6311d572013-03-01 15:54:02 -08002185 /* Vote for the SFPB clock */
2186 ret = qsee_vote_for_clock(data, CLK_SFPB);
2187 if (ret) {
2188 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2189 ret = -EIO;
2190 goto qseecom_load_external_elf_set_cpu_err;
2191 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002192
Mona Hossain5ab9d772012-04-11 21:00:40 -07002193 /* SCM_CALL to load the external elf */
2194 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2195 sizeof(struct qseecom_load_app_ireq),
2196 &resp, sizeof(resp));
2197 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002198 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002199 ret);
2200 ret = -EFAULT;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002201 goto qseecom_load_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002202 }
2203
2204 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2205 ret = __qseecom_process_incomplete_cmd(data, &resp);
2206 if (ret)
2207 pr_err("process_incomplete_cmd failed err: %d\n",
2208 ret);
2209 } else {
2210 if (resp.result != QSEOS_RESULT_SUCCESS) {
2211 pr_err("scm_call to load image failed resp.result =%d\n",
2212 resp.result);
2213 ret = -EFAULT;
2214 }
2215 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002216
2217qseecom_load_external_elf_scm_err:
2218 /* Restore the CPU mask */
2219 mask = CPU_MASK_ALL;
2220 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2221 if (set_cpu_ret) {
2222 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2223 set_cpu_ret);
2224 ret = -EFAULT;
2225 }
2226
2227qseecom_load_external_elf_set_cpu_err:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002228 /* Deallocate the handle */
2229 if (!IS_ERR_OR_NULL(ihandle))
2230 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain6311d572013-03-01 15:54:02 -08002231 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002232 return ret;
2233}
2234
2235static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2236{
2237 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002238 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002239 struct qseecom_command_scm_resp resp;
2240 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002241 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002242
2243 /* Populate the structure for sending scm call to unload image */
2244 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002245
2246 /* SCM_CALL tied to Core0 */
2247 mask = CPU_MASK_CPU0;
2248 ret = set_cpus_allowed_ptr(current, &mask);
2249 if (ret) {
2250 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2251 ret);
2252 return -EFAULT;
2253 }
2254
Mona Hossain5ab9d772012-04-11 21:00:40 -07002255 /* SCM_CALL to unload the external elf */
2256 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2257 sizeof(struct qseecom_unload_app_ireq),
2258 &resp, sizeof(resp));
2259 if (ret) {
2260 pr_err("scm_call to unload failed : ret %d\n",
2261 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002262 ret = -EFAULT;
2263 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002264 }
2265 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2266 ret = __qseecom_process_incomplete_cmd(data, &resp);
2267 if (ret)
2268 pr_err("process_incomplete_cmd fail err: %d\n",
2269 ret);
2270 } else {
2271 if (resp.result != QSEOS_RESULT_SUCCESS) {
2272 pr_err("scm_call to unload image failed resp.result =%d\n",
2273 resp.result);
2274 ret = -EFAULT;
2275 }
2276 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002277
2278qseecom_unload_external_elf_scm_err:
2279 /* Restore the CPU mask */
2280 mask = CPU_MASK_ALL;
2281 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2282 if (set_cpu_ret) {
2283 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2284 set_cpu_ret);
2285 ret = -EFAULT;
2286 }
2287
Mona Hossain5ab9d772012-04-11 21:00:40 -07002288 return ret;
2289}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002290
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002291static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2292 void __user *argp)
2293{
2294
2295 int32_t ret;
2296 struct qseecom_qseos_app_load_query query_req;
2297 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002298 struct qseecom_registered_app_list *entry = NULL;
2299 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002300
2301 /* Copy the relevant information needed for loading the image */
2302 if (__copy_from_user(&query_req,
2303 (void __user *)argp,
2304 sizeof(struct qseecom_qseos_app_load_query))) {
2305 pr_err("copy_from_user failed\n");
2306 return -EFAULT;
2307 }
2308
2309 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2310 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2311
2312 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002313
2314 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002315 pr_err(" scm call to check if app is loaded failed");
2316 return ret; /* scm call failed */
2317 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002318 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002319 (char *)(req.app_name));
2320 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2321 list_for_each_entry(entry,
2322 &qseecom.registered_app_list_head, list){
2323 if (entry->app_id == ret) {
2324 entry->ref_cnt++;
2325 break;
2326 }
2327 }
2328 spin_unlock_irqrestore(
2329 &qseecom.registered_app_list_lock, flags);
2330 data->client.app_id = ret;
2331 query_req.app_id = ret;
2332
2333 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2334 pr_err("copy_to_user failed\n");
2335 return -EFAULT;
2336 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002337 return -EEXIST; /* app already loaded */
2338 } else {
2339 return 0; /* app not loaded */
2340 }
2341}
2342
Mona Hossain4cf78a92013-02-14 12:06:41 -08002343static int __qseecom_get_ce_pipe_info(
2344 enum qseecom_key_management_usage_type usage,
2345 uint32_t *pipe, uint32_t *ce_hw)
2346{
2347 int ret;
2348 switch (usage) {
2349 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2350 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2351 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2352 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2353 qseecom.ce_info.disk_encrypt_pipe,
2354 qseecom.ce_info.hlos_ce_hw_instance);
2355 ret = -EINVAL;
2356 } else {
2357 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2358 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2359 ret = 0;
2360 }
2361 break;
2362 default:
2363 ret = -EINVAL;
2364 break;
2365 }
2366 return ret;
2367}
2368
2369static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2370 enum qseecom_key_management_usage_type usage,
2371 uint8_t *key_id, uint32_t flags)
2372{
2373 struct qseecom_key_generate_ireq ireq;
2374 struct qseecom_command_scm_resp resp;
2375 int ret;
2376
2377 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2378 pr_err("Error:: unsupported usage %d\n", usage);
2379 return -EFAULT;
2380 }
2381
2382 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2383 ireq.flags = flags;
2384
Mona Hossainc92629e2013-04-01 13:37:46 -07002385 __qseecom_enable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002386 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_GENERATE_KEY,
2387 &ireq, sizeof(struct qseecom_key_generate_ireq),
2388 &resp, sizeof(resp));
2389 if (ret) {
2390 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002391 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002392 return ret;
2393 }
2394
2395 switch (resp.result) {
2396 case QSEOS_RESULT_SUCCESS:
2397 break;
2398 case QSEOS_RESULT_INCOMPLETE:
2399 ret = __qseecom_process_incomplete_cmd(data, &resp);
2400 if (ret)
2401 pr_err("process_incomplete_cmd FAILED\n");
2402 break;
2403 case QSEOS_RESULT_FAILURE:
2404 default:
2405 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2406 ret = -EINVAL;
2407 break;
2408 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002409 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002410 return ret;
2411}
2412
2413static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2414 enum qseecom_key_management_usage_type usage,
2415 uint8_t *key_id, uint32_t flags)
2416{
2417 struct qseecom_key_delete_ireq ireq;
2418 struct qseecom_command_scm_resp resp;
2419 int ret;
2420
2421 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2422 pr_err("Error:: unsupported usage %d\n", usage);
2423 return -EFAULT;
2424 }
2425
2426 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2427 ireq.flags = flags;
2428
Mona Hossainc92629e2013-04-01 13:37:46 -07002429 __qseecom_enable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002430 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_DELETE_KEY,
2431 &ireq, sizeof(struct qseecom_key_delete_ireq),
2432 &resp, sizeof(struct qseecom_command_scm_resp));
2433 if (ret) {
2434 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002435 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002436 return ret;
2437 }
2438
2439 switch (resp.result) {
2440 case QSEOS_RESULT_SUCCESS:
2441 break;
2442 case QSEOS_RESULT_INCOMPLETE:
2443 ret = __qseecom_process_incomplete_cmd(data, &resp);
2444 if (ret)
2445 pr_err("process_incomplete_cmd FAILED\n");
2446 break;
2447 case QSEOS_RESULT_FAILURE:
2448 default:
2449 pr_err("Delete key scm call failed resp.result %d\n",
2450 resp.result);
2451 ret = -EINVAL;
2452 break;
2453 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002454 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002455 return ret;
2456}
2457
2458static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2459 enum qseecom_key_management_usage_type usage,
2460 struct qseecom_set_key_parameter *set_key_para)
2461{
2462 struct qseecom_key_select_ireq ireq;
2463 struct qseecom_command_scm_resp resp;
2464 int ret;
2465
2466 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2467 pr_err("Error:: unsupported usage %d\n", usage);
2468 return -EFAULT;
2469 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002470
2471 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2472 __qseecom_enable_clk(CLK_QSEE);
2473 else
2474 __qseecom_enable_clk(CLK_CE_DRV);
2475
Mona Hossain4cf78a92013-02-14 12:06:41 -08002476 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
2477 ireq.ce = set_key_para->ce_hw;
2478 ireq.pipe = set_key_para->pipe;
2479 ireq.flags = set_key_para->flags;
2480
2481 if (set_key_para->set_clear_key_flag ==
2482 QSEECOM_SET_CE_KEY_CMD)
2483 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2484 QSEECOM_HASH_SIZE);
2485 else
2486 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2487
2488 ret = scm_call(SCM_SVC_CRYPTO, QSEOS_SET_KEY,
2489 &ireq, sizeof(struct qseecom_key_select_ireq),
2490 &resp, sizeof(struct qseecom_command_scm_resp));
2491 if (ret) {
2492 pr_err("scm call to set key failed : %d\n", ret);
2493 return ret;
2494 }
2495
2496 switch (resp.result) {
2497 case QSEOS_RESULT_SUCCESS:
2498 break;
2499 case QSEOS_RESULT_INCOMPLETE:
2500 ret = __qseecom_process_incomplete_cmd(data, &resp);
2501 if (ret)
2502 pr_err("process_incomplete_cmd FAILED\n");
2503 break;
2504 case QSEOS_RESULT_FAILURE:
2505 default:
2506 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2507 ret = -EINVAL;
2508 break;
2509 }
2510
Mona Hossainc92629e2013-04-01 13:37:46 -07002511 if (qseecom.qsee.instance == qseecom.ce_drv.instance)
2512 __qseecom_disable_clk(CLK_QSEE);
2513 else
2514 __qseecom_disable_clk(CLK_CE_DRV);
2515
Mona Hossain4cf78a92013-02-14 12:06:41 -08002516 return ret;
2517}
2518
2519static int qseecom_create_key(struct qseecom_dev_handle *data,
2520 void __user *argp)
2521{
2522 uint32_t ce_hw = 0;
2523 uint32_t pipe = 0;
2524 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2525 int ret = 0;
2526 uint32_t flags = 0;
2527 struct qseecom_set_key_parameter set_key_para;
2528 struct qseecom_create_key_req create_key_req;
2529
2530 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2531 if (ret) {
2532 pr_err("copy_from_user failed\n");
2533 return ret;
2534 }
2535
2536 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2537 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2538 return -EFAULT;
2539 }
2540
2541 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2542 if (ret) {
2543 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2544 return -EINVAL;
2545 }
2546
2547 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2548 key_id, flags);
2549 if (ret) {
2550 pr_err("Failed to generate key on storage: %d\n", ret);
2551 return -EFAULT;
2552 }
2553
2554 set_key_para.ce_hw = ce_hw;
2555 set_key_para.pipe = pipe;
2556 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2557 set_key_para.flags = flags;
2558 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2559 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2560 QSEECOM_HASH_SIZE);
2561
2562 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2563 &set_key_para);
2564 if (ret) {
2565 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2566 pipe, ce_hw, ret);
2567 return -EFAULT;
2568 }
2569
2570 return ret;
2571}
2572
2573static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2574 void __user *argp)
2575{
2576 uint32_t ce_hw = 0;
2577 uint32_t pipe = 0;
2578 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2579 int ret = 0;
2580 uint32_t flags = 0;
2581 int i;
2582 struct qseecom_wipe_key_req wipe_key_req;
2583 struct qseecom_set_key_parameter clear_key_para;
2584
2585 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2586 if (ret) {
2587 pr_err("copy_from_user failed\n");
2588 return ret;
2589 }
2590
2591 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2592 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2593 return -EFAULT;
2594 }
2595
2596 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2597 if (ret) {
2598 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2599 return -EINVAL;
2600 }
2601
2602 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2603 flags);
2604 if (ret) {
2605 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2606 return -EFAULT;
2607 }
2608
2609 /* an invalid key_id 0xff is used to indicate clear key*/
2610 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2611 clear_key_para.key_id[i] = 0xff;
2612 clear_key_para.ce_hw = ce_hw;
2613 clear_key_para.pipe = pipe;
2614 clear_key_para.flags = flags;
2615 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2616 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2617 &clear_key_para);
2618 if (ret) {
2619 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2620 pipe, ce_hw, ret);
2621 return -EFAULT;
2622 }
2623
2624 return ret;
2625}
2626
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002627static int qseecom_is_es_activated(void __user *argp)
2628{
2629 struct qseecom_is_es_activated_req req;
2630 int ret;
2631 int resp_buf;
2632
2633 if (qseecom.qsee_version < QSEE_VERSION_04) {
2634 pr_err("invalid qsee version");
2635 return -ENODEV;
2636 }
2637
2638 if (argp == NULL) {
2639 pr_err("arg is null");
2640 return -EINVAL;
2641 }
2642
2643 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2644 (void *) &resp_buf, sizeof(resp_buf));
2645 if (ret) {
2646 pr_err("scm_call failed");
2647 return ret;
2648 }
2649
2650 req.is_activated = resp_buf;
2651 ret = copy_to_user(argp, &req, sizeof(req));
2652 if (ret) {
2653 pr_err("copy_to_user failed");
2654 return ret;
2655 }
2656
2657 return 0;
2658}
2659
2660static int qseecom_save_partition_hash(void __user *argp)
2661{
2662 struct qseecom_save_partition_hash_req req;
2663 int ret;
2664
2665 if (qseecom.qsee_version < QSEE_VERSION_04) {
2666 pr_err("invalid qsee version ");
2667 return -ENODEV;
2668 }
2669
2670 if (argp == NULL) {
2671 pr_err("arg is null");
2672 return -EINVAL;
2673 }
2674
2675 ret = copy_from_user(&req, argp, sizeof(req));
2676 if (ret) {
2677 pr_err("copy_from_user failed");
2678 return ret;
2679 }
2680
2681 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2682 (void *) &req, sizeof(req), NULL, 0);
2683 if (ret) {
2684 pr_err("scm_call failed");
2685 return ret;
2686 }
2687
2688 return 0;
2689}
2690
Mona Hossain2892b6b2012-02-17 13:53:11 -08002691static long qseecom_ioctl(struct file *file, unsigned cmd,
2692 unsigned long arg)
2693{
2694 int ret = 0;
2695 struct qseecom_dev_handle *data = file->private_data;
2696 void __user *argp = (void __user *) arg;
2697
2698 if (data->abort) {
2699 pr_err("Aborting qseecom driver\n");
2700 return -ENODEV;
2701 }
2702
2703 switch (cmd) {
2704 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
2705 pr_debug("ioctl register_listener_req()\n");
2706 atomic_inc(&data->ioctl_count);
2707 ret = qseecom_register_listener(data, argp);
2708 atomic_dec(&data->ioctl_count);
2709 wake_up_all(&data->abort_wq);
2710 if (ret)
2711 pr_err("failed qseecom_register_listener: %d\n", ret);
2712 break;
2713 }
2714 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
2715 pr_debug("ioctl unregister_listener_req()\n");
2716 atomic_inc(&data->ioctl_count);
2717 ret = qseecom_unregister_listener(data);
2718 atomic_dec(&data->ioctl_count);
2719 wake_up_all(&data->abort_wq);
2720 if (ret)
2721 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2722 break;
2723 }
2724 case QSEECOM_IOCTL_SEND_CMD_REQ: {
2725 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002726 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002727 atomic_inc(&data->ioctl_count);
2728 ret = qseecom_send_cmd(data, argp);
2729 atomic_dec(&data->ioctl_count);
2730 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002731 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002732 if (ret)
2733 pr_err("failed qseecom_send_cmd: %d\n", ret);
2734 break;
2735 }
2736 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
2737 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002738 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002739 atomic_inc(&data->ioctl_count);
2740 ret = qseecom_send_modfd_cmd(data, argp);
2741 atomic_dec(&data->ioctl_count);
2742 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002743 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002744 if (ret)
2745 pr_err("failed qseecom_send_cmd: %d\n", ret);
2746 break;
2747 }
2748 case QSEECOM_IOCTL_RECEIVE_REQ: {
2749 atomic_inc(&data->ioctl_count);
2750 ret = qseecom_receive_req(data);
2751 atomic_dec(&data->ioctl_count);
2752 wake_up_all(&data->abort_wq);
2753 if (ret)
2754 pr_err("failed qseecom_receive_req: %d\n", ret);
2755 break;
2756 }
2757 case QSEECOM_IOCTL_SEND_RESP_REQ: {
2758 atomic_inc(&data->ioctl_count);
2759 ret = qseecom_send_resp();
2760 atomic_dec(&data->ioctl_count);
2761 wake_up_all(&data->abort_wq);
2762 if (ret)
2763 pr_err("failed qseecom_send_resp: %d\n", ret);
2764 break;
2765 }
2766 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
2767 ret = qseecom_set_client_mem_param(data, argp);
2768 if (ret)
2769 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2770 ret);
2771 break;
2772 }
2773 case QSEECOM_IOCTL_LOAD_APP_REQ: {
2774 mutex_lock(&app_access_lock);
2775 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002776 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2777 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002778 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002779 if (ret == 0)
2780 qseecom.commonlib_loaded = true;
2781 }
2782 }
2783 if (ret == 0)
2784 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002785 atomic_dec(&data->ioctl_count);
2786 mutex_unlock(&app_access_lock);
2787 if (ret)
2788 pr_err("failed load_app request: %d\n", ret);
2789 break;
2790 }
2791 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
2792 mutex_lock(&app_access_lock);
2793 atomic_inc(&data->ioctl_count);
2794 ret = qseecom_unload_app(data);
2795 atomic_dec(&data->ioctl_count);
2796 mutex_unlock(&app_access_lock);
2797 if (ret)
2798 pr_err("failed unload_app request: %d\n", ret);
2799 break;
2800 }
2801 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2802 atomic_inc(&data->ioctl_count);
2803 ret = qseecom_get_qseos_version(data, argp);
2804 if (ret)
2805 pr_err("qseecom_get_qseos_version: %d\n", ret);
2806 atomic_dec(&data->ioctl_count);
2807 break;
2808 }
2809 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
2810 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002811 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002812 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002813 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002814 ret = qsee_vote_for_clock(data, CLK_SFPB);
2815 if (ret)
2816 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002817 atomic_dec(&data->ioctl_count);
2818 break;
2819 }
2820 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
2821 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002822 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002823 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002824 atomic_dec(&data->ioctl_count);
2825 break;
2826 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002827 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
2828 data->released = true;
2829 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2830 pr_err("Loading External elf image unsupported in rev 0x13\n");
2831 ret = -EINVAL;
2832 break;
2833 }
2834 mutex_lock(&app_access_lock);
2835 atomic_inc(&data->ioctl_count);
2836 ret = qseecom_load_external_elf(data, argp);
2837 atomic_dec(&data->ioctl_count);
2838 mutex_unlock(&app_access_lock);
2839 if (ret)
2840 pr_err("failed load_external_elf request: %d\n", ret);
2841 break;
2842 }
2843 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
2844 data->released = true;
2845 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2846 pr_err("Unloading External elf image unsupported in rev 0x13\n");
2847 ret = -EINVAL;
2848 break;
2849 }
2850 mutex_lock(&app_access_lock);
2851 atomic_inc(&data->ioctl_count);
2852 ret = qseecom_unload_external_elf(data);
2853 atomic_dec(&data->ioctl_count);
2854 mutex_unlock(&app_access_lock);
2855 if (ret)
2856 pr_err("failed unload_app request: %d\n", ret);
2857 break;
2858 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002859 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
2860 mutex_lock(&app_access_lock);
2861 atomic_inc(&data->ioctl_count);
2862 ret = qseecom_query_app_loaded(data, argp);
2863 atomic_dec(&data->ioctl_count);
2864 mutex_unlock(&app_access_lock);
2865 break;
2866 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002867 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
2868 if (qseecom.qsee_version < QSEE_VERSION_03) {
2869 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
2870 qseecom.qsee_version);
2871 return -EINVAL;
2872 }
2873 mutex_lock(&app_access_lock);
2874 atomic_inc(&data->ioctl_count);
2875 ret = qseecom_send_service_cmd(data, argp);
2876 atomic_dec(&data->ioctl_count);
2877 mutex_unlock(&app_access_lock);
2878 break;
2879 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002880 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
2881 data->released = true;
2882 mutex_lock(&app_access_lock);
2883 atomic_inc(&data->ioctl_count);
2884 ret = qseecom_create_key(data, argp);
2885 if (ret)
2886 pr_err("failed to create encryption key: %d\n", ret);
2887
2888 atomic_dec(&data->ioctl_count);
2889 mutex_unlock(&app_access_lock);
2890 break;
2891 }
2892 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
2893 data->released = true;
2894 mutex_lock(&app_access_lock);
2895 atomic_inc(&data->ioctl_count);
2896 ret = qseecom_wipe_key(data, argp);
2897 if (ret)
2898 pr_err("failed to wipe encryption key: %d\n", ret);
2899 atomic_dec(&data->ioctl_count);
2900 mutex_unlock(&app_access_lock);
2901 break;
2902 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002903 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
2904 data->released = true;
2905 mutex_lock(&app_access_lock);
2906 atomic_inc(&data->ioctl_count);
2907 ret = qseecom_save_partition_hash(argp);
2908 atomic_dec(&data->ioctl_count);
2909 mutex_unlock(&app_access_lock);
2910 break;
2911 }
2912 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
2913 data->released = true;
2914 mutex_lock(&app_access_lock);
2915 atomic_inc(&data->ioctl_count);
2916 ret = qseecom_is_es_activated(argp);
2917 atomic_dec(&data->ioctl_count);
2918 mutex_unlock(&app_access_lock);
2919 break;
2920 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002921 default:
2922 return -EINVAL;
2923 }
2924 return ret;
2925}
2926
2927static int qseecom_open(struct inode *inode, struct file *file)
2928{
2929 int ret = 0;
2930 struct qseecom_dev_handle *data;
2931
2932 data = kzalloc(sizeof(*data), GFP_KERNEL);
2933 if (!data) {
2934 pr_err("kmalloc failed\n");
2935 return -ENOMEM;
2936 }
2937 file->private_data = data;
2938 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002939 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002940 data->released = false;
2941 init_waitqueue_head(&data->abort_wq);
2942 atomic_set(&data->ioctl_count, 0);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002943 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2944 int pil_error;
2945 mutex_lock(&pil_access_lock);
2946 if (pil_ref_cnt == 0) {
Stephen Boyd77db8bb2012-06-27 15:15:16 -07002947 pil = subsystem_get("tzapps");
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002948 if (IS_ERR(pil)) {
2949 pr_err("Playready PIL image load failed\n");
2950 pil_error = PTR_ERR(pil);
2951 pil = NULL;
2952 pr_debug("tzapps image load FAILED\n");
2953 mutex_unlock(&pil_access_lock);
2954 return pil_error;
2955 }
2956 }
2957 pil_ref_cnt++;
2958 mutex_unlock(&pil_access_lock);
2959 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002960 return ret;
2961}
2962
2963static int qseecom_release(struct inode *inode, struct file *file)
2964{
2965 struct qseecom_dev_handle *data = file->private_data;
2966 int ret = 0;
2967
2968 if (data->released == false) {
2969 pr_warn("data->released == false\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002970 switch (data->type) {
2971 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002972 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002973 break;
2974 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08002975 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002976 break;
2977 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07002978 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002979 ret = qseecom_unmap_ion_allocated_memory(data);
2980 if (ret) {
2981 pr_err("Close failed\n");
2982 return ret;
2983 }
2984 break;
2985 default:
2986 pr_err("Unsupported clnt_handle_type %d",
2987 data->type);
2988 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002989 }
2990 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002991
Mona Hossainc9c83c72013-04-11 12:43:48 -07002992 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002993 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07002994 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08002995 qsee_disable_clock_vote(data, CLK_DFAB);
2996
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07002997 if (qseecom.qseos_version == QSEOS_VERSION_13) {
2998 mutex_lock(&pil_access_lock);
2999 if (pil_ref_cnt == 1)
Stephen Boyd77db8bb2012-06-27 15:15:16 -07003000 subsystem_put(pil);
Mona Hossain7cdbfaf2012-03-15 18:56:10 -07003001 pil_ref_cnt--;
3002 mutex_unlock(&pil_access_lock);
3003 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003004 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003005
Mona Hossain2892b6b2012-02-17 13:53:11 -08003006 return ret;
3007}
3008
Mona Hossain2892b6b2012-02-17 13:53:11 -08003009static const struct file_operations qseecom_fops = {
3010 .owner = THIS_MODULE,
3011 .unlocked_ioctl = qseecom_ioctl,
3012 .open = qseecom_open,
3013 .release = qseecom_release
3014};
3015
Mona Hossainc92629e2013-04-01 13:37:46 -07003016static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003017{
3018 int rc = 0;
3019 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003020 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003021 char *core_clk_src = NULL;
3022 char *core_clk = NULL;
3023 char *iface_clk = NULL;
3024 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003025
Mona Hossainc92629e2013-04-01 13:37:46 -07003026 switch (ce) {
3027 case CLK_QSEE: {
3028 core_clk_src = "core_clk_src";
3029 core_clk = "core_clk";
3030 iface_clk = "iface_clk";
3031 bus_clk = "bus_clk";
3032 qclk = &qseecom.qsee;
3033 qclk->instance = CLK_QSEE;
3034 break;
3035 };
3036 case CLK_CE_DRV: {
3037 core_clk_src = "ce_drv_core_clk_src";
3038 core_clk = "ce_drv_core_clk";
3039 iface_clk = "ce_drv_iface_clk";
3040 bus_clk = "ce_drv_bus_clk";
3041 qclk = &qseecom.ce_drv;
3042 qclk->instance = CLK_CE_DRV;
3043 break;
3044 };
3045 default:
3046 pr_err("Invalid ce hw instance: %d!\n", ce);
3047 return -EIO;
3048 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003049 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003050
Mona Hossainc92629e2013-04-01 13:37:46 -07003051 /* Get CE3 src core clk. */
3052 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003053 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003054 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003055 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003056 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003057 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003058 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003059 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003060 }
3061 } else {
3062 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003063 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003064 }
3065
3066 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003067 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003068 if (IS_ERR(qclk->ce_core_clk)) {
3069 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003070 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003071 if (qclk->ce_core_src_clk != NULL)
3072 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003073 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003074 }
3075
3076 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003077 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003078 if (IS_ERR(qclk->ce_clk)) {
3079 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003080 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003081 if (qclk->ce_core_src_clk != NULL)
3082 clk_put(qclk->ce_core_src_clk);
3083 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003084 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003085 }
3086
3087 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003088 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003089 if (IS_ERR(qclk->ce_bus_clk)) {
3090 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003091 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003092 if (qclk->ce_core_src_clk != NULL)
3093 clk_put(qclk->ce_core_src_clk);
3094 clk_put(qclk->ce_core_clk);
3095 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003096 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003097 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003098 return rc;
3099}
3100
Mona Hossainc92629e2013-04-01 13:37:46 -07003101static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003102{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003103 struct qseecom_clk *qclk;
3104
Mona Hossainc92629e2013-04-01 13:37:46 -07003105 if (ce == CLK_QSEE)
3106 qclk = &qseecom.qsee;
3107 else
3108 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003109
3110 if (qclk->ce_clk != NULL) {
3111 clk_put(qclk->ce_clk);
3112 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003113 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003114 if (qclk->ce_core_clk != NULL) {
3115 clk_put(qclk->ce_core_clk);
3116 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003117 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003118 if (qclk->ce_bus_clk != NULL) {
3119 clk_put(qclk->ce_bus_clk);
3120 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003121 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003122 if (qclk->ce_core_src_clk != NULL) {
3123 clk_put(qclk->ce_core_src_clk);
3124 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003125 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003126}
3127
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003128static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003129{
3130 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003131 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003132 struct device *class_dev;
3133 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003134 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003135 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3136
Mona Hossain17a4faf2013-03-22 16:40:56 -07003137 qseecom.qsee_bw_count = 0;
3138 qseecom.qsee_perf_client = 0;
3139 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003140
Mona Hossain17a4faf2013-03-22 16:40:56 -07003141 qseecom.qsee.ce_core_clk = NULL;
3142 qseecom.qsee.ce_clk = NULL;
3143 qseecom.qsee.ce_core_src_clk = NULL;
3144 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003145
Mona Hossainc92629e2013-04-01 13:37:46 -07003146 qseecom.ce_drv.ce_core_clk = NULL;
3147 qseecom.ce_drv.ce_clk = NULL;
3148 qseecom.ce_drv.ce_core_src_clk = NULL;
3149 qseecom.ce_drv.ce_bus_clk = NULL;
3150
Mona Hossain2892b6b2012-02-17 13:53:11 -08003151 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3152 if (rc < 0) {
3153 pr_err("alloc_chrdev_region failed %d\n", rc);
3154 return rc;
3155 }
3156
3157 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3158 if (IS_ERR(driver_class)) {
3159 rc = -ENOMEM;
3160 pr_err("class_create failed %d\n", rc);
3161 goto unregister_chrdev_region;
3162 }
3163
3164 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3165 QSEECOM_DEV);
3166 if (!class_dev) {
3167 pr_err("class_device_create failed %d\n", rc);
3168 rc = -ENOMEM;
3169 goto class_destroy;
3170 }
3171
3172 cdev_init(&qseecom_cdev, &qseecom_fops);
3173 qseecom_cdev.owner = THIS_MODULE;
3174
3175 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
3176 if (rc < 0) {
3177 pr_err("cdev_add failed %d\n", rc);
3178 goto err;
3179 }
3180
3181 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3182 spin_lock_init(&qseecom.registered_listener_list_lock);
3183 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3184 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003185 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3186 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003187 init_waitqueue_head(&qseecom.send_resp_wq);
3188 qseecom.send_resp_flag = 0;
3189
3190 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3191 &qsee_not_legacy, sizeof(qsee_not_legacy));
3192 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003193 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003194 goto err;
3195 }
Mona Hossain05c73562012-10-29 17:49:01 -07003196 if (qsee_not_legacy) {
3197 uint32_t feature = 10;
3198
3199 qseecom.qsee_version = QSEEE_VERSION_00;
3200 rc = scm_call(6, 3, &feature, sizeof(feature),
3201 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3202 if (rc) {
3203 pr_err("Failed to get QSEE version info %d\n", rc);
3204 goto err;
3205 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003206 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003207 } else {
Mona Hossain2892b6b2012-02-17 13:53:11 -08003208 qseecom.qseos_version = QSEOS_VERSION_13;
Mona Hossain05c73562012-10-29 17:49:01 -07003209 qseecom.qsee_version = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003210 pil = NULL;
3211 pil_ref_cnt = 0;
3212 }
Mona Hossain05c73562012-10-29 17:49:01 -07003213 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003214 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003215 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003216 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003217 if (qseecom.ion_clnt == NULL) {
3218 pr_err("Ion client cannot be created\n");
3219 rc = -ENOMEM;
3220 goto err;
3221 }
3222
3223 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003224 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003225
Mona Hossain4cf78a92013-02-14 12:06:41 -08003226 if (of_property_read_u32((&pdev->dev)->of_node,
3227 "qcom,disk-encrypt-pipe-pair",
3228 &qseecom.ce_info.disk_encrypt_pipe)) {
3229 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3230 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3231 rc = -EINVAL;
3232 goto err;
3233 } else {
3234 pr_warn("bam_pipe_pair=0x%x",
3235 qseecom.ce_info.disk_encrypt_pipe);
3236 }
3237
3238 if (of_property_read_u32((&pdev->dev)->of_node,
3239 "qcom,qsee-ce-hw-instance",
3240 &qseecom.ce_info.qsee_ce_hw_instance)) {
3241 pr_err("Fail to get qsee ce hw instance information.\n");
3242 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3243 rc = -EINVAL;
3244 goto err;
3245 } else {
3246 pr_warn("qsee-ce-hw-instance=0x%x",
3247 qseecom.ce_info.qsee_ce_hw_instance);
3248 }
3249
3250 if (of_property_read_u32((&pdev->dev)->of_node,
3251 "qcom,hlos-ce-hw-instance",
3252 &qseecom.ce_info.hlos_ce_hw_instance)) {
3253 pr_err("Fail to get hlos ce hw instance information.\n");
3254 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3255 rc = -EINVAL;
3256 goto err;
3257 } else {
3258 pr_warn("hlos-ce-hw-instance=0x%x",
3259 qseecom.ce_info.hlos_ce_hw_instance);
3260 }
3261
Mona Hossainc92629e2013-04-01 13:37:46 -07003262 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3263 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3264
3265 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003266 if (ret)
3267 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003268
Mona Hossainc92629e2013-04-01 13:37:46 -07003269 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3270 ret = __qseecom_init_clk(CLK_CE_DRV);
3271 if (ret) {
3272 __qseecom_deinit_clk(CLK_QSEE);
3273 goto err;
3274 }
3275 } else {
3276 struct qseecom_clk *qclk;
3277
3278 qclk = &qseecom.qsee;
3279 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3280 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3281 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3282 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3283 }
3284
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003285 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3286 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003287 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3288 struct resource *resource = NULL;
3289 struct qsee_apps_region_info_ireq req;
3290 struct qseecom_command_scm_resp resp;
3291
3292 resource = platform_get_resource_byname(pdev,
3293 IORESOURCE_MEM, "secapp-region");
3294 if (resource) {
3295 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3296 req.addr = resource->start;
3297 req.size = resource_size(resource);
3298 pr_warn("secure app region addr=0x%x size=0x%x",
3299 req.addr, req.size);
3300 } else {
3301 pr_err("Fail to get secure app region info\n");
3302 rc = -EINVAL;
3303 goto err;
3304 }
3305 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3306 &resp, sizeof(resp));
3307 if (rc) {
3308 pr_err("Failed to send secapp region info %d\n",
3309 rc);
3310 goto err;
3311 }
3312 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003313 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003314 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3315 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003316 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003317
Mona Hossain17a4faf2013-03-22 16:40:56 -07003318 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003319 qseecom_platform_support);
3320
Mona Hossain17a4faf2013-03-22 16:40:56 -07003321 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003322 pr_err("Unable to register bus client\n");
3323 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003324err:
3325 device_destroy(driver_class, qseecom_device_no);
3326class_destroy:
3327 class_destroy(driver_class);
3328unregister_chrdev_region:
3329 unregister_chrdev_region(qseecom_device_no, 1);
3330 return rc;
3331}
3332
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003333static int __devinit qseecom_remove(struct platform_device *pdev)
3334{
Mona Hossaind44a3842012-10-15 09:41:35 -07003335 struct qseecom_registered_kclient_list *kclient = NULL;
3336 unsigned long flags = 0;
3337 int ret = 0;
3338
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003339 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003340 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003341
3342 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3343 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3344 struct qseecom_registered_kclient_list, list);
3345 if (list_empty(&kclient->list)) {
3346 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3347 flags);
3348 return 0;
3349 }
3350 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3351 list) {
3352 if (kclient)
3353 list_del(&kclient->list);
3354 break;
3355 }
3356 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3357
3358
3359 while (kclient->handle != NULL) {
3360 ret = qseecom_unload_app(kclient->handle->dev);
3361 if (ret == 0) {
3362 kzfree(kclient->handle->dev);
3363 kzfree(kclient->handle);
3364 kzfree(kclient);
3365 }
3366 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3367 kclient = list_entry(
3368 (&qseecom.registered_kclient_list_head)->next,
3369 struct qseecom_registered_kclient_list, list);
3370 if (list_empty(&kclient->list)) {
3371 spin_unlock_irqrestore(
3372 &qseecom.registered_kclient_list_lock, flags);
3373 return 0;
3374 }
3375 list_for_each_entry(kclient,
3376 &qseecom.registered_kclient_list_head, list) {
3377 if (kclient)
3378 list_del(&kclient->list);
3379 break;
3380 }
3381 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3382 flags);
3383 if (!kclient) {
3384 ret = 0;
3385 break;
3386 }
3387 }
Mona Hossain05c73562012-10-29 17:49:01 -07003388 if (qseecom.qseos_version > QSEEE_VERSION_00)
3389 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003390
Mona Hossain17a4faf2013-03-22 16:40:56 -07003391 if (qseecom.qsee_perf_client)
3392 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3393 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003394 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003395 if (pdev->dev.of_node) {
3396 __qseecom_deinit_clk(CLK_QSEE);
3397 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3398 __qseecom_deinit_clk(CLK_CE_DRV);
3399 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003400 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003401};
3402
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003403static struct of_device_id qseecom_match[] = {
3404 {
3405 .compatible = "qcom,qseecom",
3406 },
3407 {}
3408};
3409
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003410static struct platform_driver qseecom_plat_driver = {
3411 .probe = qseecom_probe,
3412 .remove = qseecom_remove,
3413 .driver = {
3414 .name = "qseecom",
3415 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003416 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003417 },
3418};
3419
3420static int __devinit qseecom_init(void)
3421{
3422 return platform_driver_register(&qseecom_plat_driver);
3423}
3424
3425static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003426{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003427 device_destroy(driver_class, qseecom_device_no);
3428 class_destroy(driver_class);
3429 unregister_chrdev_region(qseecom_device_no, 1);
3430 ion_client_destroy(qseecom.ion_clnt);
3431}
3432
3433MODULE_LICENSE("GPL v2");
3434MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3435
3436module_init(qseecom_init);
3437module_exit(qseecom_exit);