blob: 05a15b16de6e60e25289243b9d233b5b6848463a [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");
568 return -ERESTARTSYS;
569 }
570
571 if (data->abort) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700572 pr_err("Aborting listener service %d\n",
573 data->listener.id);
Mona Hossain0b3a2792013-02-05 17:38:55 -0800574 rc = -ENODEV;
575 send_data_rsp.status = QSEOS_RESULT_FAILURE;
576 } else {
577 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800578 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800579
Mona Hossain2892b6b2012-02-17 13:53:11 -0800580 qseecom.send_resp_flag = 0;
581 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
582 send_data_rsp.listener_id = lstnr ;
583
584 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
585 (const void *)&send_data_rsp,
586 sizeof(send_data_rsp), resp,
587 sizeof(*resp));
588 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700589 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800590 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800591 return ret;
592 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800593 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
594 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
595 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
596 resp->result, data->client.app_id, lstnr);
597 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700598 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800599 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800600 if (rc)
601 return rc;
602
Mona Hossain2892b6b2012-02-17 13:53:11 -0800603 return ret;
604}
605
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700606static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
607{
608 int32_t ret;
609 struct qseecom_command_scm_resp resp;
610
611 /* SCM_CALL to check if app_id for the mentioned app exists */
612 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
613 sizeof(struct qseecom_check_app_ireq),
614 &resp, sizeof(resp));
615 if (ret) {
616 pr_err("scm_call to check if app is already loaded failed\n");
617 return -EINVAL;
618 }
619
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700620 if (resp.result == QSEOS_RESULT_FAILURE) {
621 return 0;
622 } else {
623 switch (resp.resp_type) {
624 /*qsee returned listener type response */
625 case QSEOS_LISTENER_ID:
626 pr_err("resp type is of listener type instead of app");
627 return -EINVAL;
628 break;
629 case QSEOS_APP_ID:
630 return resp.data;
631 default:
632 pr_err("invalid resp type (%d) from qsee",
633 resp.resp_type);
634 return -ENODEV;
635 break;
636 }
637 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700638}
639
Mona Hossain2892b6b2012-02-17 13:53:11 -0800640static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
641{
642 struct qseecom_registered_app_list *entry = NULL;
643 unsigned long flags = 0;
644 u32 app_id = 0;
645 struct ion_handle *ihandle; /* Ion handle */
646 struct qseecom_load_img_req load_img_req;
647 int32_t ret;
648 ion_phys_addr_t pa = 0;
649 uint32_t len;
650 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800651 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700652 struct qseecom_load_app_ireq load_req;
653
Mona Hossain2892b6b2012-02-17 13:53:11 -0800654 /* Copy the relevant information needed for loading the image */
655 if (__copy_from_user(&load_img_req,
656 (void __user *)argp,
657 sizeof(struct qseecom_load_img_req))) {
658 pr_err("copy_from_user failed\n");
659 return -EFAULT;
660 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700661 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800662 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700663 if (ret)
664 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800665 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
666 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800667
Mona Hossain436b75f2012-11-20 17:10:40 -0800668 ret = __qseecom_check_app_exists(req);
669 if (ret < 0)
670 return ret;
671 else
672 app_id = ret;
673
674 if (app_id) {
675 pr_warn("App id %d (%s) already exists\n", app_id,
676 (char *)(req.app_name));
677 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
678 list_for_each_entry(entry,
679 &qseecom.registered_app_list_head, list){
680 if (entry->app_id == app_id) {
681 entry->ref_cnt++;
682 break;
683 }
684 }
685 spin_unlock_irqrestore(
686 &qseecom.registered_app_list_lock, flags);
687 } else {
688 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700689 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800690 /* Get the handle of the shared fd */
691 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800692 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800693 if (IS_ERR_OR_NULL(ihandle)) {
694 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800695 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800696 return -ENOMEM;
697 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800698
Mona Hossain436b75f2012-11-20 17:10:40 -0800699 /* Get the physical address of the ION BUF */
700 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800701
Mona Hossain436b75f2012-11-20 17:10:40 -0800702 /* Populate the structure for sending scm call to load image */
703 memcpy(load_req.app_name, load_img_req.img_name,
704 MAX_APP_NAME_SIZE);
705 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
706 load_req.mdt_len = load_img_req.mdt_len;
707 load_req.img_len = load_img_req.img_len;
708 load_req.phy_addr = pa;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800709
Mona Hossain436b75f2012-11-20 17:10:40 -0800710 /* SCM_CALL to load the app and get the app_id back */
711 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700712 sizeof(struct qseecom_load_app_ireq),
713 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700714 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800715 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800716 if (!IS_ERR_OR_NULL(ihandle))
717 ion_free(qseecom.ion_clnt, ihandle);
718 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800719 return -EINVAL;
720 }
721
722 if (resp.result == QSEOS_RESULT_FAILURE) {
723 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700724 if (!IS_ERR_OR_NULL(ihandle))
725 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800726 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800727 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700728 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700729
Mona Hossain436b75f2012-11-20 17:10:40 -0800730 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
731 ret = __qseecom_process_incomplete_cmd(data, &resp);
732 if (ret) {
733 pr_err("process_incomplete_cmd failed err: %d\n",
734 ret);
735 if (!IS_ERR_OR_NULL(ihandle))
736 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800737 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800738 return ret;
739 }
740 }
741
742 if (resp.result != QSEOS_RESULT_SUCCESS) {
743 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700744 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800745 if (!IS_ERR_OR_NULL(ihandle))
746 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800747 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800748 return -EFAULT;
749 }
750
751 app_id = resp.data;
752
753 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
754 if (!entry) {
755 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800756 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800757 return -ENOMEM;
758 }
759 entry->app_id = app_id;
760 entry->ref_cnt = 1;
761
762 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700763 if (!IS_ERR_OR_NULL(ihandle))
764 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700765
Mona Hossain436b75f2012-11-20 17:10:40 -0800766 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
767 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
768 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
769 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700770
Mona Hossain436b75f2012-11-20 17:10:40 -0800771 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700772 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800773 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800774 data->client.app_id = app_id;
775 load_img_req.app_id = app_id;
776 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
777 pr_err("copy_to_user failed\n");
778 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800779 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800780 return -EFAULT;
781 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800782 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800783 return 0;
784}
785
786static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
787{
788 wake_up_all(&qseecom.send_resp_wq);
789 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700790 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800791 atomic_read(&data->ioctl_count) <= 1)) {
792 pr_err("Interrupted from abort\n");
793 return -ERESTARTSYS;
794 break;
795 }
796 }
797 /* Set unload app */
798 return 1;
799}
800
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800801static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
802{
803 int ret = 0;
804 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
805 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
806 ion_free(qseecom.ion_clnt, data->client.ihandle);
807 data->client.ihandle = NULL;
808 }
809 return ret;
810}
811
Mona Hossain2892b6b2012-02-17 13:53:11 -0800812static int qseecom_unload_app(struct qseecom_dev_handle *data)
813{
814 unsigned long flags;
815 int ret = 0;
816 struct qseecom_command_scm_resp resp;
817 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700818 bool unload = false;
819 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800820
Mona Hossain1fb538f2012-08-30 16:19:38 -0700821 if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
822 (data->client.app_id > 0)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800823 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
824 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
825 list) {
826 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700827 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800828 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700829 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800830 break;
831 } else {
832 ptr_app->ref_cnt--;
Mona Hossain1fb538f2012-08-30 16:19:38 -0700833 pr_warn("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700834 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800835 break;
836 }
837 }
838 }
839 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
840 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700841 if (found_app == false) {
842 pr_err("Cannot find app with id = %d\n",
843 data->client.app_id);
844 return -EINVAL;
845 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800846 }
847
848 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
849 struct qseecom_unload_app_ireq req;
850
Mona Hossain340dba82012-08-07 19:54:46 -0700851 __qseecom_cleanup_app(data);
852 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
853 list_del(&ptr_app->list);
854 kzfree(ptr_app);
855 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
856 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800857 /* Populate the structure for sending scm call to load image */
858 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
859 req.app_id = data->client.app_id;
860
861 /* SCM_CALL to unload the app */
862 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
863 sizeof(struct qseecom_unload_app_ireq),
864 &resp, sizeof(resp));
865 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700866 pr_err("scm_call to unload app (id = %d) failed\n",
867 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800868 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700869 } else {
870 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800871 }
872 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
873 ret = __qseecom_process_incomplete_cmd(data, &resp);
874 if (ret) {
875 pr_err("process_incomplete_cmd fail err: %d\n",
876 ret);
877 return ret;
878 }
879 }
880 }
881
882 if (qseecom.qseos_version == QSEOS_VERSION_13) {
883 data->abort = 1;
884 wake_up_all(&qseecom.send_resp_wq);
885 while (atomic_read(&data->ioctl_count) > 0) {
Mona Hossainacea1022012-04-09 13:37:27 -0700886 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800887 atomic_read(&data->ioctl_count) <= 0)) {
888 pr_err("Interrupted from abort\n");
889 ret = -ERESTARTSYS;
890 break;
891 }
892 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800893 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800894 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800895 data->released = true;
896 return ret;
897}
898
899static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
900 uint32_t virt)
901{
902 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
903}
904
905static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
906 struct qseecom_send_cmd_req *req)
907{
908 int ret = 0;
909 unsigned long flags;
910 u32 reqd_len_sb_in = 0;
911 struct qseecom_command cmd;
912 struct qseecom_response resp;
913
914
915 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
916 pr_err("cmd buffer or response buffer is null\n");
917 return -EINVAL;
918 }
919
920 if (req->cmd_req_len <= 0 ||
921 req->resp_len <= 0 ||
922 req->cmd_req_len > data->client.sb_length ||
923 req->resp_len > data->client.sb_length) {
924 pr_err("cmd buffer length or "
925 "response buffer length not valid\n");
926 return -EINVAL;
927 }
928
929 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
930 if (reqd_len_sb_in > data->client.sb_length) {
931 pr_debug("Not enough memory to fit cmd_buf and "
932 "resp_buf. Required: %u, Available: %u\n",
933 reqd_len_sb_in, data->client.sb_length);
934 return -ENOMEM;
935 }
936 cmd.cmd_type = TZ_SCHED_CMD_NEW;
937 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
938 cmd.sb_in_cmd_len = req->cmd_req_len;
939
940 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
941 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
942 resp.sb_in_rsp_len = req->resp_len;
943
944 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
945 sizeof(cmd), &resp, sizeof(resp));
946
947 if (ret) {
948 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
949 return ret;
950 }
951
952 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
953 /*
954 * If cmd is incomplete, get the callback cmd out from SB out
955 * and put it on the list
956 */
957 struct qseecom_registered_listener_list *ptr_svc = NULL;
958 /*
959 * We don't know which service can handle the command. so we
960 * wake up all blocking services and let them figure out if
961 * they can handle the given command.
962 */
963 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
964 flags);
965 list_for_each_entry(ptr_svc,
966 &qseecom.registered_listener_list_head, list) {
967 ptr_svc->rcv_req_flag = 1;
968 wake_up_interruptible(&ptr_svc->rcv_req_wq);
969 }
970 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
971 flags);
972
973 pr_debug("waking up rcv_req_wq and "
974 "waiting for send_resp_wq\n");
Mona Hossainacea1022012-04-09 13:37:27 -0700975 if (wait_event_freezable(qseecom.send_resp_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800976 __qseecom_listener_has_sent_rsp(data))) {
977 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
978 return -ERESTARTSYS;
979 }
980
981 if (data->abort) {
982 pr_err("Aborting driver\n");
983 return -ENODEV;
984 }
985 qseecom.send_resp_flag = 0;
986 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
987 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
988 sizeof(cmd), &resp, sizeof(resp));
989 if (ret) {
990 pr_err("qseecom_scm_call failed with err: %d\n", ret);
991 return ret;
992 }
993 }
994 return ret;
995}
996
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800997int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
998 struct qseecom_send_svc_cmd_req *req_ptr,
999 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1000{
1001 int ret = 0;
1002 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1003 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1004 req_ptr, send_svc_ireq_ptr);
1005 return -EINVAL;
1006 }
1007 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1008 send_svc_ireq_ptr->key_type =
1009 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
1010 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1011 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1012 (uint32_t)req_ptr->resp_buf));
1013 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1014
1015 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1016 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1017 return ret;
1018}
1019
1020static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1021 void __user *argp)
1022{
1023 int ret = 0;
1024 struct qseecom_client_send_service_ireq send_svc_ireq;
1025 struct qseecom_command_scm_resp resp;
1026 struct qseecom_send_svc_cmd_req req;
1027 /*struct qseecom_command_scm_resp resp;*/
1028
1029 if (__copy_from_user(&req,
1030 (void __user *)argp,
1031 sizeof(req))) {
1032 pr_err("copy_from_user failed\n");
1033 return -EFAULT;
1034 }
1035
1036 if (req.resp_buf == NULL) {
1037 pr_err("cmd buffer or response buffer is null\n");
1038 return -EINVAL;
1039 }
1040
1041 data->type = QSEECOM_SECURE_SERVICE;
1042
1043 switch (req.cmd_id) {
1044 case QSEE_RPMB_PROVISION_KEY_COMMAND:
1045 case QSEE_RPMB_ERASE_COMMAND:
1046 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1047 &send_svc_ireq))
1048 return -EINVAL;
1049 break;
1050 default:
1051 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1052 return -EINVAL;
1053 }
1054
1055 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1056 sizeof(send_svc_ireq),
1057 &resp, sizeof(resp));
1058 if (ret) {
1059 pr_err("qseecom_scm_call failed with err: %d\n", ret);
1060 return ret;
1061 }
1062
1063 switch (resp.result) {
1064 case QSEOS_RESULT_SUCCESS:
1065 break;
1066 case QSEOS_RESULT_INCOMPLETE:
1067 pr_err("qseos_result_incomplete\n");
1068 ret = __qseecom_process_incomplete_cmd(data, &resp);
1069 if (ret) {
1070 pr_err("process_incomplete_cmd fail: err: %d\n",
1071 ret);
1072 }
1073 break;
1074 case QSEOS_RESULT_FAILURE:
1075 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1076 break;
1077 default:
1078 pr_err("Response result %d not supported\n",
1079 resp.result);
1080 ret = -EINVAL;
1081 break;
1082 }
1083 return ret;
1084
1085}
1086
Mona Hossain2892b6b2012-02-17 13:53:11 -08001087static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1088 struct qseecom_send_cmd_req *req)
1089{
1090 int ret = 0;
1091 u32 reqd_len_sb_in = 0;
1092 struct qseecom_client_send_data_ireq send_data_req;
1093 struct qseecom_command_scm_resp resp;
1094
1095 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1096 pr_err("cmd buffer or response buffer is null\n");
1097 return -EINVAL;
1098 }
1099
1100 if (req->cmd_req_len <= 0 ||
1101 req->resp_len <= 0 ||
1102 req->cmd_req_len > data->client.sb_length ||
1103 req->resp_len > data->client.sb_length) {
1104 pr_err("cmd buffer length or "
1105 "response buffer length not valid\n");
1106 return -EINVAL;
1107 }
1108
1109 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1110 if (reqd_len_sb_in > data->client.sb_length) {
1111 pr_debug("Not enough memory to fit cmd_buf and "
1112 "resp_buf. Required: %u, Available: %u\n",
1113 reqd_len_sb_in, data->client.sb_length);
1114 return -ENOMEM;
1115 }
1116
1117 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1118 send_data_req.app_id = data->client.app_id;
1119 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1120 (uint32_t)req->cmd_req_buf));
1121 send_data_req.req_len = req->cmd_req_len;
1122 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1123 (uint32_t)req->resp_buf));
1124 send_data_req.rsp_len = req->resp_len;
1125
1126 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1127 sizeof(send_data_req),
1128 &resp, sizeof(resp));
1129 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001130 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1131 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001132 return ret;
1133 }
1134
1135 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1136 ret = __qseecom_process_incomplete_cmd(data, &resp);
1137 if (ret) {
1138 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1139 return ret;
1140 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001141 } else {
1142 if (resp.result != QSEOS_RESULT_SUCCESS) {
1143 pr_err("Response result %d not supported\n",
1144 resp.result);
1145 ret = -EINVAL;
1146 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001147 }
1148 return ret;
1149}
1150
1151
1152static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1153{
1154 int ret = 0;
1155 struct qseecom_send_cmd_req req;
1156
1157 ret = copy_from_user(&req, argp, sizeof(req));
1158 if (ret) {
1159 pr_err("copy_from_user failed\n");
1160 return ret;
1161 }
1162 if (qseecom.qseos_version == QSEOS_VERSION_14)
1163 ret = __qseecom_send_cmd(data, &req);
1164 else
1165 ret = __qseecom_send_cmd_legacy(data, &req);
1166 if (ret)
1167 return ret;
1168
1169 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1170 req.resp_len, req.resp_buf);
1171 return ret;
1172}
1173
1174static int __qseecom_send_cmd_req_clean_up(
1175 struct qseecom_send_modfd_cmd_req *req)
1176{
1177 char *field;
1178 uint32_t *update;
1179 int ret = 0;
1180 int i = 0;
1181
1182 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001183 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001184 field = (char *)req->cmd_req_buf +
1185 req->ifd_data[i].cmd_buf_offset;
1186 update = (uint32_t *) field;
1187 *update = 0;
1188 }
1189 }
1190 return ret;
1191}
1192
1193static int __qseecom_update_with_phy_addr(
1194 struct qseecom_send_modfd_cmd_req *req)
1195{
1196 struct ion_handle *ihandle;
1197 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001198 int ret = 0;
1199 int i = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001200
1201 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001202 struct sg_table *sg_ptr = NULL;
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001203 if (req->ifd_data[i].fd > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001204 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08001205 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001206 req->ifd_data[i].fd);
1207 if (IS_ERR_OR_NULL(ihandle)) {
1208 pr_err("Ion client can't retrieve the handle\n");
1209 return -ENOMEM;
1210 }
1211 field = (char *) req->cmd_req_buf +
1212 req->ifd_data[i].cmd_buf_offset;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001213
1214 /* Populate the cmd data structure with the phys_addr */
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001215 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1216 if (sg_ptr == NULL) {
1217 pr_err("IOn client could not retrieve sg table\n");
1218 goto err;
1219 }
1220 if (sg_ptr->nents == 0) {
1221 pr_err("Num of scattered entries is 0\n");
1222 goto err;
1223 }
1224 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1225 pr_err("Num of scattered entries");
1226 pr_err(" (%d) is greater than max supported %d\n",
1227 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1228 goto err;
1229 }
1230 if (sg_ptr->nents == 1) {
1231 uint32_t *update;
1232 update = (uint32_t *) field;
1233 *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
1234 } else {
1235 struct qseecom_sg_entry *update;
1236 struct scatterlist *sg;
1237 int j = 0;
1238 update = (struct qseecom_sg_entry *) field;
1239 sg = sg_ptr->sgl;
1240 for (j = 0; j < sg_ptr->nents; j++) {
1241 update->phys_addr = (uint32_t)
1242 sg_dma_address(sg);
1243 update->len = (uint32_t)sg->length;
1244 update++;
1245 sg = sg_next(sg);
1246 }
1247 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001248 /* Deallocate the handle */
1249 if (!IS_ERR_OR_NULL(ihandle))
1250 ion_free(qseecom.ion_clnt, ihandle);
1251 }
1252 }
1253 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001254err:
1255 if (!IS_ERR_OR_NULL(ihandle))
1256 ion_free(qseecom.ion_clnt, ihandle);
1257 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001258}
1259
1260static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1261 void __user *argp)
1262{
1263 int ret = 0;
1264 struct qseecom_send_modfd_cmd_req req;
1265 struct qseecom_send_cmd_req send_cmd_req;
1266
1267 ret = copy_from_user(&req, argp, sizeof(req));
1268 if (ret) {
1269 pr_err("copy_from_user failed\n");
1270 return ret;
1271 }
1272 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1273 send_cmd_req.cmd_req_len = req.cmd_req_len;
1274 send_cmd_req.resp_buf = req.resp_buf;
1275 send_cmd_req.resp_len = req.resp_len;
1276
1277 ret = __qseecom_update_with_phy_addr(&req);
1278 if (ret)
1279 return ret;
1280 if (qseecom.qseos_version == QSEOS_VERSION_14)
1281 ret = __qseecom_send_cmd(data, &send_cmd_req);
1282 else
1283 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1284 __qseecom_send_cmd_req_clean_up(&req);
1285
1286 if (ret)
1287 return ret;
1288
1289 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1290 req.resp_len, req.resp_buf);
1291 return ret;
1292}
1293
1294static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1295 struct qseecom_registered_listener_list *svc)
1296{
1297 int ret;
1298 ret = (svc->rcv_req_flag != 0);
1299 return ret || data->abort;
1300}
1301
1302static int qseecom_receive_req(struct qseecom_dev_handle *data)
1303{
1304 int ret = 0;
1305 struct qseecom_registered_listener_list *this_lstnr;
1306
1307 this_lstnr = __qseecom_find_svc(data->listener.id);
1308 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001309 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001310 __qseecom_listener_has_rcvd_req(data,
1311 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001312 pr_warning("Interrupted: exiting Listener Service = %d\n",
1313 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001314 /* woken up for different reason */
1315 return -ERESTARTSYS;
1316 }
1317
1318 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001319 pr_err("Aborting Listener Service = %d\n",
1320 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001321 return -ENODEV;
1322 }
1323 this_lstnr->rcv_req_flag = 0;
1324 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1325 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1326 break;
1327 } else {
1328 break;
1329 }
1330 }
1331 return ret;
1332}
1333
Mona Hossaind44a3842012-10-15 09:41:35 -07001334static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1335{
1336 struct elf32_hdr *ehdr;
1337
1338 if (fw_entry->size < sizeof(*ehdr)) {
1339 pr_err("%s: Not big enough to be an elf header\n",
1340 qseecom.pdev->init_name);
1341 return false;
1342 }
1343 ehdr = (struct elf32_hdr *)fw_entry->data;
1344 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1345 pr_err("%s: Not an elf header\n",
1346 qseecom.pdev->init_name);
1347 return false;
1348 }
1349
1350 if (ehdr->e_phnum == 0) {
1351 pr_err("%s: No loadable segments\n",
1352 qseecom.pdev->init_name);
1353 return false;
1354 }
1355 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1356 sizeof(struct elf32_hdr) > fw_entry->size) {
1357 pr_err("%s: Program headers not within mdt\n",
1358 qseecom.pdev->init_name);
1359 return false;
1360 }
1361 return true;
1362}
1363
1364static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1365{
1366 int ret = -1;
1367 int i = 0, rc = 0;
1368 const struct firmware *fw_entry = NULL;
1369 struct elf32_phdr *phdr;
1370 char fw_name[MAX_APP_NAME_SIZE];
1371 struct elf32_hdr *ehdr;
1372 int num_images = 0;
1373
1374 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1375 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1376 if (rc) {
1377 pr_err("error with request_firmware\n");
1378 ret = -EIO;
1379 goto err;
1380 }
1381 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1382 ret = -EIO;
1383 goto err;
1384 }
1385 *fw_size = fw_entry->size;
1386 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1387 ehdr = (struct elf32_hdr *)fw_entry->data;
1388 num_images = ehdr->e_phnum;
1389 release_firmware(fw_entry);
1390 for (i = 0; i < num_images; i++, phdr++) {
1391 memset(fw_name, 0, sizeof(fw_name));
1392 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1393 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1394 if (ret)
1395 goto err;
1396 *fw_size += fw_entry->size;
1397 release_firmware(fw_entry);
1398 }
1399 return ret;
1400err:
1401 if (fw_entry)
1402 release_firmware(fw_entry);
1403 *fw_size = 0;
1404 return ret;
1405}
1406
1407static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1408 struct qseecom_load_app_ireq *load_req)
1409{
1410 int ret = -1;
1411 int i = 0, rc = 0;
1412 const struct firmware *fw_entry = NULL;
1413 char fw_name[MAX_APP_NAME_SIZE];
1414 u8 *img_data_ptr = img_data;
1415 struct elf32_hdr *ehdr;
1416 int num_images = 0;
1417
1418 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1419 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1420 if (rc) {
1421 ret = -EIO;
1422 goto err;
1423 }
1424 load_req->img_len = fw_entry->size;
1425 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1426 img_data_ptr = img_data_ptr + fw_entry->size;
1427 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1428 ehdr = (struct elf32_hdr *)fw_entry->data;
1429 num_images = ehdr->e_phnum;
1430 release_firmware(fw_entry);
1431 for (i = 0; i < num_images; i++) {
1432 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1433 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1434 if (ret) {
1435 pr_err("Failed to locate blob %s\n", fw_name);
1436 goto err;
1437 }
1438 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1439 img_data_ptr = img_data_ptr + fw_entry->size;
1440 load_req->img_len += fw_entry->size;
1441 release_firmware(fw_entry);
1442 }
1443 load_req->phy_addr = virt_to_phys(img_data);
1444 return ret;
1445err:
1446 release_firmware(fw_entry);
1447 return ret;
1448}
1449
1450static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1451{
1452 int ret = -1;
1453 uint32_t fw_size = 0;
1454 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1455 struct qseecom_command_scm_resp resp;
1456 u8 *img_data = NULL;
1457
1458 if (__qseecom_get_fw_size(appname, &fw_size))
1459 return -EIO;
1460
1461 img_data = kzalloc(fw_size, GFP_KERNEL);
1462 if (!img_data) {
1463 pr_err("Failied to allocate memory for copying image data\n");
1464 return -ENOMEM;
1465 }
1466 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1467 if (ret) {
1468 kzfree(img_data);
1469 return -EIO;
1470 }
1471
1472 /* Populate the remaining parameters */
1473 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1474 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001475 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001476 if (ret) {
1477 kzfree(img_data);
1478 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001479 return -EIO;
1480 }
1481
Mona Hossaind44a3842012-10-15 09:41:35 -07001482 /* SCM_CALL to load the image */
1483 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1484 sizeof(struct qseecom_load_app_ireq),
1485 &resp, sizeof(resp));
1486 kzfree(img_data);
1487 if (ret) {
1488 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001489 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001490 return -EIO;
1491 }
1492
1493 switch (resp.result) {
1494 case QSEOS_RESULT_SUCCESS:
1495 ret = resp.data;
1496 break;
1497 case QSEOS_RESULT_INCOMPLETE:
1498 ret = __qseecom_process_incomplete_cmd(data, &resp);
1499 if (ret)
1500 pr_err("process_incomplete_cmd FAILED\n");
1501 else
1502 ret = resp.data;
1503 break;
1504 case QSEOS_RESULT_FAILURE:
1505 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1506 break;
1507 default:
1508 pr_err("scm call return unknown response %d\n", resp.result);
1509 ret = -EINVAL;
1510 break;
1511 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001512 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001513
Mona Hossaind44a3842012-10-15 09:41:35 -07001514 return ret;
1515}
1516
Mona Hossain9498f5e2013-01-23 18:08:45 -08001517static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001518{
1519 int32_t ret = 0;
1520 uint32_t fw_size = 0;
1521 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1522 struct qseecom_command_scm_resp resp;
1523 u8 *img_data = NULL;
1524
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001525 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001526 return -EIO;
1527
1528 img_data = kzalloc(fw_size, GFP_KERNEL);
1529 if (!img_data) {
1530 pr_err("Mem allocation for lib image data failed\n");
1531 return -ENOMEM;
1532 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001533 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001534 if (ret) {
1535 kzfree(img_data);
1536 return -EIO;
1537 }
1538 /* Populate the remaining parameters */
1539 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001540 /* Vote for the SFPB clock */
1541 ret = qsee_vote_for_clock(data, CLK_SFPB);
1542 if (ret) {
1543 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1544 kzfree(img_data);
1545 return -EIO;
1546 }
1547
Mona Hossain05c73562012-10-29 17:49:01 -07001548 /* SCM_CALL to load the image */
1549 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1550 sizeof(struct qseecom_load_lib_image_ireq),
1551 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001552 if (ret) {
1553 pr_err("scm_call to load failed : ret %d\n", ret);
1554 ret = -EIO;
1555 } else {
1556 switch (resp.result) {
1557 case QSEOS_RESULT_SUCCESS:
1558 break;
1559 case QSEOS_RESULT_FAILURE:
1560 pr_err("scm call failed w/response result%d\n",
1561 resp.result);
1562 ret = -EINVAL;
1563 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001564 case QSEOS_RESULT_INCOMPLETE:
1565 ret = __qseecom_process_incomplete_cmd(data, &resp);
1566 if (ret)
1567 pr_err("process_incomplete_cmd failed err: %d\n",
1568 ret);
1569 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001570 default:
1571 pr_err("scm call return unknown response %d\n",
1572 resp.result);
1573 ret = -EINVAL;
1574 break;
1575 }
1576 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001577 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001578 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001579 return ret;
1580}
1581
1582static int qseecom_unload_commonlib_image(void)
1583{
1584 int ret = -EINVAL;
1585 struct qseecom_unload_lib_image_ireq unload_req = {0};
1586 struct qseecom_command_scm_resp resp;
1587
1588 /* Populate the remaining parameters */
1589 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1590 /* SCM_CALL to load the image */
1591 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1592 sizeof(struct qseecom_unload_lib_image_ireq),
1593 &resp, sizeof(resp));
1594 if (ret) {
1595 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1596 ret = -EIO;
1597 } else {
1598 switch (resp.result) {
1599 case QSEOS_RESULT_SUCCESS:
1600 break;
1601 case QSEOS_RESULT_FAILURE:
1602 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1603 break;
1604 default:
1605 pr_err("scm call return unknown response %d\n",
1606 resp.result);
1607 ret = -EINVAL;
1608 break;
1609 }
1610 }
1611 return ret;
1612}
1613
Mona Hossaind44a3842012-10-15 09:41:35 -07001614int qseecom_start_app(struct qseecom_handle **handle,
1615 char *app_name, uint32_t size)
1616{
Mona Hossain05c73562012-10-29 17:49:01 -07001617 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001618 unsigned long flags = 0;
1619 struct qseecom_dev_handle *data = NULL;
1620 struct qseecom_check_app_ireq app_ireq;
1621 struct qseecom_registered_app_list *entry = NULL;
1622 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1623 bool found_app = false;
1624 uint32_t len;
1625 ion_phys_addr_t pa;
1626
1627 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1628 pr_err("This functionality is UNSUPPORTED in version 1.3\n");
1629 return -EINVAL;
1630 }
1631
Mona Hossain823f9882012-11-23 14:42:20 -08001632 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1633 if (!(*handle)) {
1634 pr_err("failed to allocate memory for kernel client handle\n");
1635 return -ENOMEM;
1636 }
1637
Mona Hossaind44a3842012-10-15 09:41:35 -07001638 data = kzalloc(sizeof(*data), GFP_KERNEL);
1639 if (!data) {
1640 pr_err("kmalloc failed\n");
1641 if (ret == 0) {
1642 kfree(*handle);
1643 *handle = NULL;
1644 }
1645 return -ENOMEM;
1646 }
1647 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001648 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001649 data->released = false;
1650 data->client.app_id = ret;
1651 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 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001695
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) {
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002318 pr_warn("App id %d (%s) already exists\n", ret,
2319 (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);