blob: a30607ce76c50a8b906f2f674cfba7c38dd4f1ff [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>
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -070044#include <asm/cacheflush.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080045#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070046#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080047
48#define QSEECOM_DEV "qseecom"
Mona Hossain2892b6b2012-02-17 13:53:11 -080049#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070050#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080051#define QSEE_VERSION_01 0x401000
52#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080053#define QSEE_VERSION_03 0x403000
Amir Samuelovd1fc7412013-03-10 16:56:13 +020054#define QSEE_VERSION_04 0x404000
Zhen Kong336636e2013-04-15 11:04:54 -070055#define QSEE_VERSION_05 0x405000
56
Mona Hossain5b76a622012-11-15 20:09:08 -080057
Mona Hossain05c73562012-10-29 17:49:01 -070058
59#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080060
Mona Hossaind39e33b2012-11-05 13:36:40 -080061#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080062
Mona Hossain13dd8922013-01-03 06:11:09 -080063#define QSEECOM_MAX_SG_ENTRY 512
Mona Hossain4cf78a92013-02-14 12:06:41 -080064#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
Mona Hossainf1f2ed62012-11-15 19:51:33 -080065
Amir Samuelovd1fc7412013-03-10 16:56:13 +020066/* Save partition image hash for authentication check */
67#define SCM_SAVE_PARTITION_HASH_ID 0x01
68
69/* Check if enterprise security is activate */
70#define SCM_IS_ACTIVATED_ID 0x02
71
Zhen Kong7812dc12013-07-09 17:12:55 -070072#define RPMB_SERVICE 0x2000
73
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070074enum qseecom_clk_definitions {
75 CLK_DFAB = 0,
76 CLK_SFPB,
77};
78
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080079enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053080 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080081 QSEECOM_LISTENER_SERVICE,
82 QSEECOM_SECURE_SERVICE,
83 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053084 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080085};
86
Mona Hossainc92629e2013-04-01 13:37:46 -070087enum qseecom_ce_hw_instance {
88 CLK_QSEE = 0,
89 CLK_CE_DRV,
90};
91
Mona Hossain2892b6b2012-02-17 13:53:11 -080092static struct class *driver_class;
93static dev_t qseecom_device_no;
94static struct cdev qseecom_cdev;
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);
Zhen Kong7812dc12013-07-09 17:12:55 -0700218static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
219static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700220
Mona Hossain2892b6b2012-02-17 13:53:11 -0800221static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800222 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800223{
224 struct qseecom_registered_listener_list *ptr;
225 int unique = 1;
226 unsigned long flags;
227
228 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
229 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800230 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800231 pr_err("Service id: %u is already registered\n",
232 ptr->svc.listener_id);
233 unique = 0;
234 break;
235 }
236 }
237 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
238 return unique;
239}
240
241static struct qseecom_registered_listener_list *__qseecom_find_svc(
242 int32_t listener_id)
243{
244 struct qseecom_registered_listener_list *entry = NULL;
245 unsigned long flags;
246
247 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
248 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
249 {
250 if (entry->svc.listener_id == listener_id)
251 break;
252 }
253 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
254 return entry;
255}
256
257static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
258 struct qseecom_dev_handle *handle,
259 struct qseecom_register_listener_req *listener)
260{
261 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800262 struct qseecom_register_listener_ireq req;
263 struct qseecom_command_scm_resp resp;
264 ion_phys_addr_t pa;
265
266 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800267 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
268 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800269 if (svc->ihandle == NULL) {
270 pr_err("Ion client could not retrieve the handle\n");
271 return -ENOMEM;
272 }
273
274 /* Get the physical address of the ION BUF */
275 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
276
277 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700278 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800279 svc->sb_phys = pa;
280
Mona Hossaind4613de2013-05-15 16:49:29 -0700281 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
282 req.listener_id = svc->svc.listener_id;
283 req.sb_len = svc->sb_length;
284 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800285
Mona Hossaind4613de2013-05-15 16:49:29 -0700286 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800287
Mona Hossaind4613de2013-05-15 16:49:29 -0700288 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800289 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700290 if (ret) {
291 pr_err("qseecom_scm_call failed with err: %d\n", ret);
292 return -EINVAL;
293 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800294
Mona Hossaind4613de2013-05-15 16:49:29 -0700295 if (resp.result != QSEOS_RESULT_SUCCESS) {
296 pr_err("Error SB registration req: resp.result = %d\n",
297 resp.result);
298 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800299 }
300 return 0;
301}
302
303static int qseecom_register_listener(struct qseecom_dev_handle *data,
304 void __user *argp)
305{
306 int ret = 0;
307 unsigned long flags;
308 struct qseecom_register_listener_req rcvd_lstnr;
309 struct qseecom_registered_listener_list *new_entry;
310
311 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
312 if (ret) {
313 pr_err("copy_from_user failed\n");
314 return ret;
315 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800316 data->listener.id = 0;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800317 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800318 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800319 data->released = true;
320 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800321 }
322
323 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
324 if (!new_entry) {
325 pr_err("kmalloc failed\n");
326 return -ENOMEM;
327 }
328 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
329 new_entry->rcv_req_flag = 0;
330
331 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
332 new_entry->sb_length = rcvd_lstnr.sb_size;
333 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
334 pr_err("qseecom_set_sb_memoryfailed\n");
335 kzfree(new_entry);
336 return -ENOMEM;
337 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800338
Mona Hossain2892b6b2012-02-17 13:53:11 -0800339 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800340 init_waitqueue_head(&new_entry->rcv_req_wq);
341
342 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
343 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
344 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800345
Mona Hossain2892b6b2012-02-17 13:53:11 -0800346 return ret;
347}
348
349static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
350{
351 int ret = 0;
352 unsigned long flags;
353 uint32_t unmap_mem = 0;
354 struct qseecom_register_listener_ireq req;
355 struct qseecom_registered_listener_list *ptr_svc = NULL;
356 struct qseecom_command_scm_resp resp;
357 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
358
Mona Hossaind4613de2013-05-15 16:49:29 -0700359 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
360 req.listener_id = data->listener.id;
361 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800362
Mona Hossaind4613de2013-05-15 16:49:29 -0700363 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800364 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700365 if (ret) {
366 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
367 ret, data->listener.id);
368 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800369 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700370
371 if (resp.result != QSEOS_RESULT_SUCCESS) {
372 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
373 resp.result, data->listener.id);
374 return -EPERM;
375 }
376
Mona Hossain2892b6b2012-02-17 13:53:11 -0800377 data->abort = 1;
378 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
379 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
380 list) {
381 if (ptr_svc->svc.listener_id == data->listener.id) {
382 wake_up_all(&ptr_svc->rcv_req_wq);
383 break;
384 }
385 }
386 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
387
388 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700389 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800390 atomic_read(&data->ioctl_count) <= 1)) {
391 pr_err("Interrupted from abort\n");
392 ret = -ERESTARTSYS;
393 break;
394 }
395 }
396
397 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
398 list_for_each_entry(ptr_svc,
399 &qseecom.registered_listener_list_head,
400 list)
401 {
402 if (ptr_svc->svc.listener_id == data->listener.id) {
403 if (ptr_svc->sb_virt) {
404 unmap_mem = 1;
405 ihandle = ptr_svc->ihandle;
406 }
407 list_del(&ptr_svc->list);
408 kzfree(ptr_svc);
409 break;
410 }
411 }
412 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
413
414 /* Unmap the memory */
415 if (unmap_mem) {
416 if (!IS_ERR_OR_NULL(ihandle)) {
417 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
418 ion_free(qseecom.ion_clnt, ihandle);
419 }
420 }
421 data->released = true;
422 return ret;
423}
424
425static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
426 void __user *argp)
427{
428 ion_phys_addr_t pa;
429 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800430 struct qseecom_set_sb_mem_param_req req;
431 uint32_t len;
432
433 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700434 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800435 return -EFAULT;
436
Mona Hossaina1124de2013-10-01 13:41:09 -0700437 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
438 (req.sb_len == 0)) {
439 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
440 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
441 return -EFAULT;
442 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800443 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800444 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
445 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800446 if (IS_ERR_OR_NULL(data->client.ihandle)) {
447 pr_err("Ion client could not retrieve the handle\n");
448 return -ENOMEM;
449 }
450 /* Get the physical address of the ION BUF */
451 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
452 /* Populate the structure for sending scm call to load image */
453 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700454 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800455 data->client.sb_phys = pa;
456 data->client.sb_length = req.sb_len;
457 data->client.user_virt_sb_base = req.virt_sb_base;
458 return 0;
459}
460
Mona Hossain2892b6b2012-02-17 13:53:11 -0800461static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
462{
463 int ret;
464 ret = (qseecom.send_resp_flag != 0);
465 return ret || data->abort;
466}
467
468static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
469 struct qseecom_command_scm_resp *resp)
470{
471 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800472 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800473 uint32_t lstnr;
474 unsigned long flags;
475 struct qseecom_client_listener_data_irsp send_data_rsp;
476 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700477 sigset_t new_sigset;
478 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800479
Mona Hossain2892b6b2012-02-17 13:53:11 -0800480 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
481 lstnr = resp->data;
482 /*
483 * Wake up blocking lsitener service with the lstnr id
484 */
485 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
486 flags);
487 list_for_each_entry(ptr_svc,
488 &qseecom.registered_listener_list_head, list) {
489 if (ptr_svc->svc.listener_id == lstnr) {
490 ptr_svc->rcv_req_flag = 1;
491 wake_up_interruptible(&ptr_svc->rcv_req_wq);
492 break;
493 }
494 }
495 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
496 flags);
497 if (ptr_svc->svc.listener_id != lstnr) {
498 pr_warning("Service requested for does on exist\n");
499 return -ERESTARTSYS;
500 }
501 pr_debug("waking up rcv_req_wq and "
502 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800503
Mona Hossain91da2c52013-03-29 17:28:31 -0700504 /* initialize the new signal mask with all signals*/
505 sigfillset(&new_sigset);
506 /* block all signals */
507 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
508
509 do {
510 if (!wait_event_freezable(qseecom.send_resp_wq,
511 __qseecom_listener_has_sent_rsp(data)))
512 break;
513 } while (1);
514
515 /* restore signal mask */
516 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
517 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700518 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
519 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700520 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800521 send_data_rsp.status = QSEOS_RESULT_FAILURE;
522 } else {
523 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800524 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800525
Mona Hossain2892b6b2012-02-17 13:53:11 -0800526 qseecom.send_resp_flag = 0;
527 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
528 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700529 if (ptr_svc)
530 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
531 ptr_svc->sb_virt, ptr_svc->sb_length,
532 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700533
534 if (lstnr == RPMB_SERVICE)
535 __qseecom_enable_clk(CLK_QSEE);
536
Mona Hossain2892b6b2012-02-17 13:53:11 -0800537 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
538 (const void *)&send_data_rsp,
539 sizeof(send_data_rsp), resp,
540 sizeof(*resp));
541 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700542 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800543 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700544 if (lstnr == RPMB_SERVICE)
545 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800546 return ret;
547 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800548 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
549 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
550 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
551 resp->result, data->client.app_id, lstnr);
552 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700553 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700554 if (lstnr == RPMB_SERVICE)
555 __qseecom_disable_clk(CLK_QSEE);
556
Mona Hossain2892b6b2012-02-17 13:53:11 -0800557 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800558 if (rc)
559 return rc;
560
Mona Hossain2892b6b2012-02-17 13:53:11 -0800561 return ret;
562}
563
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700564static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
565{
566 int32_t ret;
567 struct qseecom_command_scm_resp resp;
568
569 /* SCM_CALL to check if app_id for the mentioned app exists */
570 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
571 sizeof(struct qseecom_check_app_ireq),
572 &resp, sizeof(resp));
573 if (ret) {
574 pr_err("scm_call to check if app is already loaded failed\n");
575 return -EINVAL;
576 }
577
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700578 if (resp.result == QSEOS_RESULT_FAILURE) {
579 return 0;
580 } else {
581 switch (resp.resp_type) {
582 /*qsee returned listener type response */
583 case QSEOS_LISTENER_ID:
584 pr_err("resp type is of listener type instead of app");
585 return -EINVAL;
586 break;
587 case QSEOS_APP_ID:
588 return resp.data;
589 default:
590 pr_err("invalid resp type (%d) from qsee",
591 resp.resp_type);
592 return -ENODEV;
593 break;
594 }
595 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700596}
597
Mona Hossain2892b6b2012-02-17 13:53:11 -0800598static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
599{
600 struct qseecom_registered_app_list *entry = NULL;
601 unsigned long flags = 0;
602 u32 app_id = 0;
603 struct ion_handle *ihandle; /* Ion handle */
604 struct qseecom_load_img_req load_img_req;
605 int32_t ret;
606 ion_phys_addr_t pa = 0;
607 uint32_t len;
608 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800609 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700610 struct qseecom_load_app_ireq load_req;
611
Mona Hossain2892b6b2012-02-17 13:53:11 -0800612 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700613 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800614 (void __user *)argp,
615 sizeof(struct qseecom_load_img_req))) {
616 pr_err("copy_from_user failed\n");
617 return -EFAULT;
618 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700619 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800620 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700621 if (ret)
622 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800623 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700624 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800625 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800626
Mona Hossain436b75f2012-11-20 17:10:40 -0800627 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530628 if (ret < 0) {
629 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800630 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530631 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800632
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530633 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800634 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700635 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800636 (char *)(req.app_name));
637 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
638 list_for_each_entry(entry,
639 &qseecom.registered_app_list_head, list){
640 if (entry->app_id == app_id) {
641 entry->ref_cnt++;
642 break;
643 }
644 }
645 spin_unlock_irqrestore(
646 &qseecom.registered_app_list_lock, flags);
647 } else {
648 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700649 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800650 /* Get the handle of the shared fd */
651 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800652 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800653 if (IS_ERR_OR_NULL(ihandle)) {
654 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800655 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800656 return -ENOMEM;
657 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800658
Mona Hossain436b75f2012-11-20 17:10:40 -0800659 /* Get the physical address of the ION BUF */
660 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800661
Mona Hossain436b75f2012-11-20 17:10:40 -0800662 /* Populate the structure for sending scm call to load image */
663 memcpy(load_req.app_name, load_img_req.img_name,
664 MAX_APP_NAME_SIZE);
665 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
666 load_req.mdt_len = load_img_req.mdt_len;
667 load_req.img_len = load_img_req.img_len;
668 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700669 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
670 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800671
Mona Hossain436b75f2012-11-20 17:10:40 -0800672 /* SCM_CALL to load the app and get the app_id back */
673 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700674 sizeof(struct qseecom_load_app_ireq),
675 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700676 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800677 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800678 if (!IS_ERR_OR_NULL(ihandle))
679 ion_free(qseecom.ion_clnt, ihandle);
680 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800681 return -EINVAL;
682 }
683
684 if (resp.result == QSEOS_RESULT_FAILURE) {
685 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700686 if (!IS_ERR_OR_NULL(ihandle))
687 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800688 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800689 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700690 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700691
Mona Hossain436b75f2012-11-20 17:10:40 -0800692 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
693 ret = __qseecom_process_incomplete_cmd(data, &resp);
694 if (ret) {
695 pr_err("process_incomplete_cmd failed err: %d\n",
696 ret);
697 if (!IS_ERR_OR_NULL(ihandle))
698 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800699 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800700 return ret;
701 }
702 }
703
704 if (resp.result != QSEOS_RESULT_SUCCESS) {
705 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700706 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800707 if (!IS_ERR_OR_NULL(ihandle))
708 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800709 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800710 return -EFAULT;
711 }
712
713 app_id = resp.data;
714
715 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
716 if (!entry) {
717 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800718 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800719 return -ENOMEM;
720 }
721 entry->app_id = app_id;
722 entry->ref_cnt = 1;
723
724 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700725 if (!IS_ERR_OR_NULL(ihandle))
726 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700727
Mona Hossain436b75f2012-11-20 17:10:40 -0800728 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
729 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
730 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
731 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700732
Mona Hossain436b75f2012-11-20 17:10:40 -0800733 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700734 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800735 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800736 data->client.app_id = app_id;
737 load_img_req.app_id = app_id;
738 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
739 pr_err("copy_to_user failed\n");
740 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800741 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800742 return -EFAULT;
743 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800744 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800745 return 0;
746}
747
748static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
749{
750 wake_up_all(&qseecom.send_resp_wq);
751 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700752 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800753 atomic_read(&data->ioctl_count) <= 1)) {
754 pr_err("Interrupted from abort\n");
755 return -ERESTARTSYS;
756 break;
757 }
758 }
759 /* Set unload app */
760 return 1;
761}
762
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800763static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
764{
765 int ret = 0;
766 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
767 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
768 ion_free(qseecom.ion_clnt, data->client.ihandle);
769 data->client.ihandle = NULL;
770 }
771 return ret;
772}
773
Mona Hossain2892b6b2012-02-17 13:53:11 -0800774static int qseecom_unload_app(struct qseecom_dev_handle *data)
775{
776 unsigned long flags;
777 int ret = 0;
778 struct qseecom_command_scm_resp resp;
779 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700780 bool unload = false;
781 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800782
Mona Hossaind4613de2013-05-15 16:49:29 -0700783 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800784 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
785 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
786 list) {
787 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700788 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800789 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700790 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800791 break;
792 } else {
793 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700794 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700795 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800796 break;
797 }
798 }
799 }
800 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
801 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700802 if (found_app == false) {
803 pr_err("Cannot find app with id = %d\n",
804 data->client.app_id);
805 return -EINVAL;
806 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800807 }
808
Mona Hossaind4613de2013-05-15 16:49:29 -0700809 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800810 struct qseecom_unload_app_ireq req;
811
Mona Hossain340dba82012-08-07 19:54:46 -0700812 __qseecom_cleanup_app(data);
813 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
814 list_del(&ptr_app->list);
815 kzfree(ptr_app);
816 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
817 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800818 /* Populate the structure for sending scm call to load image */
819 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
820 req.app_id = data->client.app_id;
821
822 /* SCM_CALL to unload the app */
823 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
824 sizeof(struct qseecom_unload_app_ireq),
825 &resp, sizeof(resp));
826 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700827 pr_err("scm_call to unload app (id = %d) failed\n",
828 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800829 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700830 } else {
831 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800832 }
833 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
834 ret = __qseecom_process_incomplete_cmd(data, &resp);
835 if (ret) {
836 pr_err("process_incomplete_cmd fail err: %d\n",
837 ret);
838 return ret;
839 }
840 }
841 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800842 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800843 data->released = true;
844 return ret;
845}
846
847static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
848 uint32_t virt)
849{
850 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
851}
852
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800853int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
854 struct qseecom_send_svc_cmd_req *req_ptr,
855 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
856{
857 int ret = 0;
858 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
859 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
860 req_ptr, send_svc_ireq_ptr);
861 return -EINVAL;
862 }
863 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
864 send_svc_ireq_ptr->key_type =
865 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
866 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
867 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
868 (uint32_t)req_ptr->resp_buf));
869 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
870
871 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
872 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
873 return ret;
874}
875
876static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
877 void __user *argp)
878{
879 int ret = 0;
880 struct qseecom_client_send_service_ireq send_svc_ireq;
881 struct qseecom_command_scm_resp resp;
882 struct qseecom_send_svc_cmd_req req;
883 /*struct qseecom_command_scm_resp resp;*/
884
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700885 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800886 (void __user *)argp,
887 sizeof(req))) {
888 pr_err("copy_from_user failed\n");
889 return -EFAULT;
890 }
891
892 if (req.resp_buf == NULL) {
893 pr_err("cmd buffer or response buffer is null\n");
894 return -EINVAL;
895 }
896
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800897 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -0700898 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
899 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800900 if (__qseecom_process_rpmb_svc_cmd(data, &req,
901 &send_svc_ireq))
902 return -EINVAL;
903 break;
904 default:
905 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
906 return -EINVAL;
907 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530908
909 ret = qsee_vote_for_clock(data, CLK_DFAB);
910 if (ret) {
911 pr_err("Failed to vote for DFAB clock%d\n", ret);
912 return ret;
913 }
914 ret = qsee_vote_for_clock(data, CLK_SFPB);
915 if (ret) {
916 pr_err("Failed to vote for SFPB clock%d\n", ret);
917 goto exit_reset_dfab_freq;
918 }
919
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700920 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
921 data->client.sb_virt, data->client.sb_length,
922 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800923 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
924 sizeof(send_svc_ireq),
925 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700926 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
927 data->client.sb_virt, data->client.sb_length,
928 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800929 if (ret) {
930 pr_err("qseecom_scm_call failed with err: %d\n", ret);
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530931 goto exit_reset_sdfab_freq;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800932 }
933
934 switch (resp.result) {
935 case QSEOS_RESULT_SUCCESS:
936 break;
937 case QSEOS_RESULT_INCOMPLETE:
938 pr_err("qseos_result_incomplete\n");
939 ret = __qseecom_process_incomplete_cmd(data, &resp);
940 if (ret) {
941 pr_err("process_incomplete_cmd fail: err: %d\n",
942 ret);
943 }
944 break;
945 case QSEOS_RESULT_FAILURE:
946 pr_err("process_incomplete_cmd failed err: %d\n", ret);
947 break;
948 default:
949 pr_err("Response result %d not supported\n",
950 resp.result);
951 ret = -EINVAL;
952 break;
953 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530954exit_reset_sdfab_freq:
955 qsee_disable_clock_vote(data, CLK_SFPB);
956exit_reset_dfab_freq:
957 qsee_disable_clock_vote(data, CLK_DFAB);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800958 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800959}
960
Mona Hossain2892b6b2012-02-17 13:53:11 -0800961static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
962 struct qseecom_send_cmd_req *req)
963{
964 int ret = 0;
965 u32 reqd_len_sb_in = 0;
966 struct qseecom_client_send_data_ireq send_data_req;
967 struct qseecom_command_scm_resp resp;
968
969 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
970 pr_err("cmd buffer or response buffer is null\n");
971 return -EINVAL;
972 }
Mona Hossaindddf4442013-10-01 14:08:20 -0700973 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
974 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
975 data->client.sb_length))) {
976 pr_err("cmd buffer address not within shared bufffer\n");
977 return -EINVAL;
978 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800979
Mona Hossaindddf4442013-10-01 14:08:20 -0700980
981 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
982 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
983 data->client.sb_length))){
984 pr_err("response buffer address not within shared bufffer\n");
985 return -EINVAL;
986 }
987
988 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -0800989 req->cmd_req_len > data->client.sb_length ||
990 req->resp_len > data->client.sb_length) {
991 pr_err("cmd buffer length or "
992 "response buffer length not valid\n");
993 return -EINVAL;
994 }
995
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -0700996 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
997 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
998 return -EINVAL;
999 }
1000
Mona Hossain2892b6b2012-02-17 13:53:11 -08001001 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1002 if (reqd_len_sb_in > data->client.sb_length) {
1003 pr_debug("Not enough memory to fit cmd_buf and "
1004 "resp_buf. Required: %u, Available: %u\n",
1005 reqd_len_sb_in, data->client.sb_length);
1006 return -ENOMEM;
1007 }
1008
1009 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1010 send_data_req.app_id = data->client.app_id;
1011 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1012 (uint32_t)req->cmd_req_buf));
1013 send_data_req.req_len = req->cmd_req_len;
1014 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1015 (uint32_t)req->resp_buf));
1016 send_data_req.rsp_len = req->resp_len;
1017
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001018 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1019 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001020 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001021 ION_IOC_CLEAN_INV_CACHES);
1022
Mona Hossain2892b6b2012-02-17 13:53:11 -08001023 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1024 sizeof(send_data_req),
1025 &resp, sizeof(resp));
1026 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001027 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1028 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001029 return ret;
1030 }
1031
1032 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1033 ret = __qseecom_process_incomplete_cmd(data, &resp);
1034 if (ret) {
1035 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1036 return ret;
1037 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001038 } else {
1039 if (resp.result != QSEOS_RESULT_SUCCESS) {
1040 pr_err("Response result %d not supported\n",
1041 resp.result);
1042 ret = -EINVAL;
1043 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001044 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001045 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1046 data->client.sb_virt, data->client.sb_length,
1047 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001048 return ret;
1049}
1050
Mona Hossain2892b6b2012-02-17 13:53:11 -08001051static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1052{
1053 int ret = 0;
1054 struct qseecom_send_cmd_req req;
1055
1056 ret = copy_from_user(&req, argp, sizeof(req));
1057 if (ret) {
1058 pr_err("copy_from_user failed\n");
1059 return ret;
1060 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001061 ret = __qseecom_send_cmd(data, &req);
1062
Mona Hossain2892b6b2012-02-17 13:53:11 -08001063 if (ret)
1064 return ret;
1065
1066 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1067 req.resp_len, req.resp_buf);
1068 return ret;
1069}
1070
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001071static int qseecom_unprotect_buffer(void __user *argp)
1072{
1073 int ret = 0;
1074 struct ion_handle *ihandle;
1075 int32_t ion_fd;
1076
1077 ret = copy_from_user(&ion_fd, argp, sizeof(ion_fd));
1078 if (ret) {
1079 pr_err("copy_from_user failed");
1080 return ret;
1081 }
1082
1083 ihandle = ion_import_dma_buf(qseecom.ion_clnt, ion_fd);
1084
1085 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt, ihandle);
1086 if (ret)
1087 return -EINVAL;
1088 return 0;
1089}
1090
1091static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1092 struct qseecom_dev_handle *data,
1093 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001094{
1095 struct ion_handle *ihandle;
1096 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001097 int ret = 0;
1098 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001099 uint32_t len = 0;
1100 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001101 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1102 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1103 struct qseecom_registered_listener_list *this_lstnr = NULL;
1104
1105 if (msg == NULL) {
1106 pr_err("Invalid address\n");
1107 return -EINVAL;
1108 }
1109 if (listener_svc) {
1110 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1111 this_lstnr = __qseecom_find_svc(data->listener.id);
1112 if (IS_ERR_OR_NULL(this_lstnr)) {
1113 pr_err("Invalid listener ID\n");
1114 return -ENOMEM;
1115 }
1116 } else {
1117 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1118 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001119
1120 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001121 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001122 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001123 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001124 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001125 if (IS_ERR_OR_NULL(ihandle)) {
1126 pr_err("Ion client can't retrieve the handle\n");
1127 return -ENOMEM;
1128 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001129 field = (char *) cmd_req->cmd_req_buf +
1130 cmd_req->ifd_data[i].cmd_buf_offset;
1131 } else if ((listener_svc) &&
1132 (lstnr_resp->ifd_data[i].fd > 0)) {
1133 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1134 lstnr_resp->ifd_data[i].fd);
1135 if (IS_ERR_OR_NULL(ihandle)) {
1136 pr_err("Ion client can't retrieve the handle\n");
1137 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001138 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001139 switch (lstnr_resp->protection_mode) {
1140 case QSEOS_PROTECT_BUFFER:
1141 ret = msm_ion_secure_buffer(qseecom.ion_clnt,
1142 ihandle,
1143 VIDEO_PIXEL,
1144 0);
1145 break;
1146 case QSEOS_UNPROTECT_PROTECTED_BUFFER:
1147 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt,
1148 ihandle);
1149 break;
1150 case QSEOS_UNPROTECTED_BUFFER:
1151 default:
1152 break;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001153 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001154 field = lstnr_resp->resp_buf_ptr +
1155 lstnr_resp->ifd_data[i].cmd_buf_offset;
1156 } else {
1157 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001158 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001159 /* Populate the cmd data structure with the phys_addr */
1160 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1161 if (sg_ptr == NULL) {
1162 pr_err("IOn client could not retrieve sg table\n");
1163 goto err;
1164 }
1165 if (sg_ptr->nents == 0) {
1166 pr_err("Num of scattered entries is 0\n");
1167 goto err;
1168 }
1169 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1170 pr_err("Num of scattered entries");
1171 pr_err(" (%d) is greater than max supported %d\n",
1172 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1173 goto err;
1174 }
1175 sg = sg_ptr->sgl;
1176 if (sg_ptr->nents == 1) {
1177 uint32_t *update;
1178 update = (uint32_t *) field;
1179 if (cleanup)
1180 *update = 0;
1181 else
1182 *update = (uint32_t)sg_dma_address(
1183 sg_ptr->sgl);
1184 len += (uint32_t)sg->length;
1185 } else {
1186 struct qseecom_sg_entry *update;
1187 int j = 0;
1188 update = (struct qseecom_sg_entry *) field;
1189 for (j = 0; j < sg_ptr->nents; j++) {
1190 if (cleanup) {
1191 update->phys_addr = 0;
1192 update->len = 0;
1193 } else {
1194 update->phys_addr = (uint32_t)
1195 sg_dma_address(sg);
1196 update->len = sg->length;
1197 }
1198 len += sg->length;
1199 update++;
1200 sg = sg_next(sg);
1201 }
1202 }
1203 if (cleanup)
1204 msm_ion_do_cache_op(qseecom.ion_clnt,
1205 ihandle, NULL, len,
1206 ION_IOC_INV_CACHES);
1207 else
1208 msm_ion_do_cache_op(qseecom.ion_clnt,
1209 ihandle, NULL, len,
1210 ION_IOC_CLEAN_INV_CACHES);
1211 /* Deallocate the handle */
1212 if (!IS_ERR_OR_NULL(ihandle))
1213 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001214 }
1215 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001216err:
1217 if (!IS_ERR_OR_NULL(ihandle))
1218 ion_free(qseecom.ion_clnt, ihandle);
1219 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001220}
1221
1222static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1223 void __user *argp)
1224{
1225 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001226 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001227 struct qseecom_send_modfd_cmd_req req;
1228 struct qseecom_send_cmd_req send_cmd_req;
1229
1230 ret = copy_from_user(&req, argp, sizeof(req));
1231 if (ret) {
1232 pr_err("copy_from_user failed\n");
1233 return ret;
1234 }
1235 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1236 send_cmd_req.cmd_req_len = req.cmd_req_len;
1237 send_cmd_req.resp_buf = req.resp_buf;
1238 send_cmd_req.resp_len = req.resp_len;
1239
Mona Hossaindddf4442013-10-01 14:08:20 -07001240 /* validate offsets */
1241 for (i = 0; i < MAX_ION_FD; i++) {
1242 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1243 pr_err("Invalid offset %d = 0x%x\n",
1244 i, req.ifd_data[i].cmd_buf_offset);
1245 return -EINVAL;
1246 }
1247 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001248 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001249 if (ret)
1250 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001251 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001252 if (ret)
1253 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001254 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001255 if (ret)
1256 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001257 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1258 req.resp_len, req.resp_buf);
1259 return ret;
1260}
1261
1262static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1263 struct qseecom_registered_listener_list *svc)
1264{
1265 int ret;
1266 ret = (svc->rcv_req_flag != 0);
1267 return ret || data->abort;
1268}
1269
1270static int qseecom_receive_req(struct qseecom_dev_handle *data)
1271{
1272 int ret = 0;
1273 struct qseecom_registered_listener_list *this_lstnr;
1274
1275 this_lstnr = __qseecom_find_svc(data->listener.id);
1276 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001277 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001278 __qseecom_listener_has_rcvd_req(data,
1279 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001280 pr_warning("Interrupted: exiting Listener Service = %d\n",
1281 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001282 /* woken up for different reason */
1283 return -ERESTARTSYS;
1284 }
1285
1286 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001287 pr_err("Aborting Listener Service = %d\n",
1288 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001289 return -ENODEV;
1290 }
1291 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001292 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001293 }
1294 return ret;
1295}
1296
Mona Hossaind44a3842012-10-15 09:41:35 -07001297static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1298{
1299 struct elf32_hdr *ehdr;
1300
1301 if (fw_entry->size < sizeof(*ehdr)) {
1302 pr_err("%s: Not big enough to be an elf header\n",
1303 qseecom.pdev->init_name);
1304 return false;
1305 }
1306 ehdr = (struct elf32_hdr *)fw_entry->data;
1307 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1308 pr_err("%s: Not an elf header\n",
1309 qseecom.pdev->init_name);
1310 return false;
1311 }
1312
1313 if (ehdr->e_phnum == 0) {
1314 pr_err("%s: No loadable segments\n",
1315 qseecom.pdev->init_name);
1316 return false;
1317 }
1318 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1319 sizeof(struct elf32_hdr) > fw_entry->size) {
1320 pr_err("%s: Program headers not within mdt\n",
1321 qseecom.pdev->init_name);
1322 return false;
1323 }
1324 return true;
1325}
1326
1327static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1328{
1329 int ret = -1;
1330 int i = 0, rc = 0;
1331 const struct firmware *fw_entry = NULL;
1332 struct elf32_phdr *phdr;
1333 char fw_name[MAX_APP_NAME_SIZE];
1334 struct elf32_hdr *ehdr;
1335 int num_images = 0;
1336
1337 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1338 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1339 if (rc) {
1340 pr_err("error with request_firmware\n");
1341 ret = -EIO;
1342 goto err;
1343 }
1344 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1345 ret = -EIO;
1346 goto err;
1347 }
1348 *fw_size = fw_entry->size;
1349 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1350 ehdr = (struct elf32_hdr *)fw_entry->data;
1351 num_images = ehdr->e_phnum;
1352 release_firmware(fw_entry);
1353 for (i = 0; i < num_images; i++, phdr++) {
1354 memset(fw_name, 0, sizeof(fw_name));
1355 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1356 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1357 if (ret)
1358 goto err;
1359 *fw_size += fw_entry->size;
1360 release_firmware(fw_entry);
1361 }
1362 return ret;
1363err:
1364 if (fw_entry)
1365 release_firmware(fw_entry);
1366 *fw_size = 0;
1367 return ret;
1368}
1369
1370static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1371 struct qseecom_load_app_ireq *load_req)
1372{
1373 int ret = -1;
1374 int i = 0, rc = 0;
1375 const struct firmware *fw_entry = NULL;
1376 char fw_name[MAX_APP_NAME_SIZE];
1377 u8 *img_data_ptr = img_data;
1378 struct elf32_hdr *ehdr;
1379 int num_images = 0;
1380
1381 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1382 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1383 if (rc) {
1384 ret = -EIO;
1385 goto err;
1386 }
1387 load_req->img_len = fw_entry->size;
1388 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1389 img_data_ptr = img_data_ptr + fw_entry->size;
1390 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1391 ehdr = (struct elf32_hdr *)fw_entry->data;
1392 num_images = ehdr->e_phnum;
1393 release_firmware(fw_entry);
1394 for (i = 0; i < num_images; i++) {
1395 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1396 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1397 if (ret) {
1398 pr_err("Failed to locate blob %s\n", fw_name);
1399 goto err;
1400 }
1401 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1402 img_data_ptr = img_data_ptr + fw_entry->size;
1403 load_req->img_len += fw_entry->size;
1404 release_firmware(fw_entry);
1405 }
1406 load_req->phy_addr = virt_to_phys(img_data);
1407 return ret;
1408err:
1409 release_firmware(fw_entry);
1410 return ret;
1411}
1412
1413static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1414{
1415 int ret = -1;
1416 uint32_t fw_size = 0;
1417 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1418 struct qseecom_command_scm_resp resp;
1419 u8 *img_data = NULL;
1420
1421 if (__qseecom_get_fw_size(appname, &fw_size))
1422 return -EIO;
1423
1424 img_data = kzalloc(fw_size, GFP_KERNEL);
1425 if (!img_data) {
1426 pr_err("Failied to allocate memory for copying image data\n");
1427 return -ENOMEM;
1428 }
1429 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1430 if (ret) {
1431 kzfree(img_data);
1432 return -EIO;
1433 }
1434
1435 /* Populate the remaining parameters */
1436 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1437 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001438 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001439 if (ret) {
1440 kzfree(img_data);
1441 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001442 return -EIO;
1443 }
1444
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001445 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001446 /* SCM_CALL to load the image */
1447 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1448 sizeof(struct qseecom_load_app_ireq),
1449 &resp, sizeof(resp));
1450 kzfree(img_data);
1451 if (ret) {
1452 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001453 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001454 return -EIO;
1455 }
1456
1457 switch (resp.result) {
1458 case QSEOS_RESULT_SUCCESS:
1459 ret = resp.data;
1460 break;
1461 case QSEOS_RESULT_INCOMPLETE:
1462 ret = __qseecom_process_incomplete_cmd(data, &resp);
1463 if (ret)
1464 pr_err("process_incomplete_cmd FAILED\n");
1465 else
1466 ret = resp.data;
1467 break;
1468 case QSEOS_RESULT_FAILURE:
1469 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1470 break;
1471 default:
1472 pr_err("scm call return unknown response %d\n", resp.result);
1473 ret = -EINVAL;
1474 break;
1475 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001476 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001477
Mona Hossaind44a3842012-10-15 09:41:35 -07001478 return ret;
1479}
1480
Mona Hossain9498f5e2013-01-23 18:08:45 -08001481static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001482{
1483 int32_t ret = 0;
1484 uint32_t fw_size = 0;
1485 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1486 struct qseecom_command_scm_resp resp;
1487 u8 *img_data = NULL;
1488
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001489 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001490 return -EIO;
1491
1492 img_data = kzalloc(fw_size, GFP_KERNEL);
1493 if (!img_data) {
1494 pr_err("Mem allocation for lib image data failed\n");
1495 return -ENOMEM;
1496 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001497 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001498 if (ret) {
1499 kzfree(img_data);
1500 return -EIO;
1501 }
1502 /* Populate the remaining parameters */
1503 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001504 /* Vote for the SFPB clock */
1505 ret = qsee_vote_for_clock(data, CLK_SFPB);
1506 if (ret) {
1507 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1508 kzfree(img_data);
1509 return -EIO;
1510 }
1511
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001512 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001513 /* SCM_CALL to load the image */
1514 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1515 sizeof(struct qseecom_load_lib_image_ireq),
1516 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001517 if (ret) {
1518 pr_err("scm_call to load failed : ret %d\n", ret);
1519 ret = -EIO;
1520 } else {
1521 switch (resp.result) {
1522 case QSEOS_RESULT_SUCCESS:
1523 break;
1524 case QSEOS_RESULT_FAILURE:
1525 pr_err("scm call failed w/response result%d\n",
1526 resp.result);
1527 ret = -EINVAL;
1528 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001529 case QSEOS_RESULT_INCOMPLETE:
1530 ret = __qseecom_process_incomplete_cmd(data, &resp);
1531 if (ret)
1532 pr_err("process_incomplete_cmd failed err: %d\n",
1533 ret);
1534 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001535 default:
1536 pr_err("scm call return unknown response %d\n",
1537 resp.result);
1538 ret = -EINVAL;
1539 break;
1540 }
1541 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001542 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001543 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001544 return ret;
1545}
1546
1547static int qseecom_unload_commonlib_image(void)
1548{
1549 int ret = -EINVAL;
1550 struct qseecom_unload_lib_image_ireq unload_req = {0};
1551 struct qseecom_command_scm_resp resp;
1552
1553 /* Populate the remaining parameters */
1554 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1555 /* SCM_CALL to load the image */
1556 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1557 sizeof(struct qseecom_unload_lib_image_ireq),
1558 &resp, sizeof(resp));
1559 if (ret) {
1560 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1561 ret = -EIO;
1562 } else {
1563 switch (resp.result) {
1564 case QSEOS_RESULT_SUCCESS:
1565 break;
1566 case QSEOS_RESULT_FAILURE:
1567 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1568 break;
1569 default:
1570 pr_err("scm call return unknown response %d\n",
1571 resp.result);
1572 ret = -EINVAL;
1573 break;
1574 }
1575 }
1576 return ret;
1577}
1578
Mona Hossaind44a3842012-10-15 09:41:35 -07001579int qseecom_start_app(struct qseecom_handle **handle,
1580 char *app_name, uint32_t size)
1581{
Mona Hossain05c73562012-10-29 17:49:01 -07001582 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001583 unsigned long flags = 0;
1584 struct qseecom_dev_handle *data = NULL;
1585 struct qseecom_check_app_ireq app_ireq;
1586 struct qseecom_registered_app_list *entry = NULL;
1587 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1588 bool found_app = false;
1589 uint32_t len;
1590 ion_phys_addr_t pa;
1591
Mona Hossain823f9882012-11-23 14:42:20 -08001592 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1593 if (!(*handle)) {
1594 pr_err("failed to allocate memory for kernel client handle\n");
1595 return -ENOMEM;
1596 }
1597
Mona Hossaind44a3842012-10-15 09:41:35 -07001598 data = kzalloc(sizeof(*data), GFP_KERNEL);
1599 if (!data) {
1600 pr_err("kmalloc failed\n");
1601 if (ret == 0) {
1602 kfree(*handle);
1603 *handle = NULL;
1604 }
1605 return -ENOMEM;
1606 }
1607 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001608 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001609 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001610 data->client.sb_length = size;
1611 data->client.user_virt_sb_base = 0;
1612 data->client.ihandle = NULL;
1613
1614 init_waitqueue_head(&data->abort_wq);
1615 atomic_set(&data->ioctl_count, 0);
1616
1617 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1618 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1619 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1620 pr_err("Ion client could not retrieve the handle\n");
1621 kfree(data);
1622 kfree(*handle);
1623 *handle = NULL;
1624 return -EINVAL;
1625 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001626 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001627 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001628 if (qseecom.commonlib_loaded == false) {
1629 ret = qseecom_load_commonlib_image(data);
1630 if (ret == 0)
1631 qseecom.commonlib_loaded = true;
1632 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001633 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001634 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001635 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001636 ret = -EIO;
1637 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001638 }
1639
1640 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1641 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1642 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001643 if (ret < 0)
1644 goto err;
1645
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001646 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001647 if (ret > 0) {
1648 pr_warn("App id %d for [%s] app exists\n", ret,
1649 (char *)app_ireq.app_name);
1650 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1651 list_for_each_entry(entry,
1652 &qseecom.registered_app_list_head, list){
1653 if (entry->app_id == ret) {
1654 entry->ref_cnt++;
1655 found_app = true;
1656 break;
1657 }
1658 }
1659 spin_unlock_irqrestore(
1660 &qseecom.registered_app_list_lock, flags);
1661 if (!found_app)
1662 pr_warn("App_id %d [%s] was loaded but not registered\n",
1663 ret, (char *)app_ireq.app_name);
1664 } else {
1665 /* load the app and get the app_id */
1666 pr_debug("%s: Loading app for the first time'\n",
1667 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001668 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001669 if (ret < 0)
1670 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001671 data->client.app_id = ret;
1672 }
1673 if (!found_app) {
1674 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1675 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001676 pr_err("kmalloc for app entry failed\n");
1677 ret = -ENOMEM;
1678 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001679 }
1680 entry->app_id = ret;
1681 entry->ref_cnt = 1;
1682
1683 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1684 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1685 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1686 flags);
1687 }
1688
1689 /* Get the physical address of the ION BUF */
1690 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1691 /* Populate the structure for sending scm call to load image */
1692 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1693 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001694 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001695 data->client.sb_phys = pa;
1696 (*handle)->dev = (void *)data;
1697 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1698 (*handle)->sbuf_len = data->client.sb_length;
1699
1700 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1701 if (!kclient_entry) {
1702 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001703 ret = -ENOMEM;
1704 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001705 }
1706 kclient_entry->handle = *handle;
1707
1708 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1709 list_add_tail(&kclient_entry->list,
1710 &qseecom.registered_kclient_list_head);
1711 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1712
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001713 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001714 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001715
1716err:
1717 kfree(data);
1718 kfree(*handle);
1719 *handle = NULL;
1720 mutex_unlock(&app_access_lock);
1721 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001722}
1723EXPORT_SYMBOL(qseecom_start_app);
1724
1725int qseecom_shutdown_app(struct qseecom_handle **handle)
1726{
1727 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001728 struct qseecom_dev_handle *data;
1729
Mona Hossaind44a3842012-10-15 09:41:35 -07001730 struct qseecom_registered_kclient_list *kclient = NULL;
1731 unsigned long flags = 0;
1732 bool found_handle = false;
1733
Mona Hossain33824022013-02-25 09:32:33 -08001734 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001735 pr_err("Handle is not initialized\n");
1736 return -EINVAL;
1737 }
Mona Hossain33824022013-02-25 09:32:33 -08001738 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001739 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1740 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1741 list) {
1742 if (kclient->handle == (*handle)) {
1743 list_del(&kclient->list);
1744 found_handle = true;
1745 break;
1746 }
1747 }
1748 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1749 if (!found_handle)
1750 pr_err("Unable to find the handle, exiting\n");
1751 else
1752 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001753 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001754 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001755 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001756 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001757 if (ret == 0) {
1758 kzfree(data);
1759 kzfree(*handle);
1760 kzfree(kclient);
1761 *handle = NULL;
1762 }
1763 return ret;
1764}
1765EXPORT_SYMBOL(qseecom_shutdown_app);
1766
1767int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1768 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1769{
1770 int ret = 0;
1771 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1772 struct qseecom_dev_handle *data;
1773
Mona Hossaind44a3842012-10-15 09:41:35 -07001774 if (handle == NULL) {
1775 pr_err("Handle is not initialized\n");
1776 return -EINVAL;
1777 }
1778 data = handle->dev;
1779
1780 req.cmd_req_len = sbuf_len;
1781 req.resp_len = rbuf_len;
1782 req.cmd_req_buf = send_buf;
1783 req.resp_buf = resp_buf;
1784
1785 mutex_lock(&app_access_lock);
1786 atomic_inc(&data->ioctl_count);
1787
1788 ret = __qseecom_send_cmd(data, &req);
1789
1790 atomic_dec(&data->ioctl_count);
1791 mutex_unlock(&app_access_lock);
1792
1793 if (ret)
1794 return ret;
1795
1796 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1797 req.resp_len, req.resp_buf);
1798 return ret;
1799}
1800EXPORT_SYMBOL(qseecom_send_command);
1801
Mona Hossain91a8fc92012-11-07 19:58:30 -08001802int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1803{
Mona Hossainfca6f422013-01-12 13:00:35 -08001804 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001805 if ((handle == NULL) || (handle->dev == NULL)) {
1806 pr_err("No valid kernel client\n");
1807 return -EINVAL;
1808 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001809 if (high) {
1810 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1811 if (ret)
1812 pr_err("Failed to vote for DFAB clock%d\n", ret);
1813 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1814 if (ret) {
1815 pr_err("Failed to vote for SFPB clock%d\n", ret);
1816 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1817 }
1818 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001819 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001820 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001821 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001822 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001823}
1824EXPORT_SYMBOL(qseecom_set_bandwidth);
1825
Mona Hossain2892b6b2012-02-17 13:53:11 -08001826static int qseecom_send_resp(void)
1827{
1828 qseecom.send_resp_flag = 1;
1829 wake_up_interruptible(&qseecom.send_resp_wq);
1830 return 0;
1831}
1832
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001833
1834static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
1835 void __user *argp)
1836{
1837 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07001838 int i;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001839
1840 if (copy_from_user(&resp, argp, sizeof(resp))) {
1841 pr_err("copy_from_user failed");
1842 return -EINVAL;
1843 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001844 /* validate offsets */
1845 for (i = 0; i < MAX_ION_FD; i++) {
1846 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
1847 pr_err("Invalid offset %d = 0x%x\n",
1848 i, resp.ifd_data[i].cmd_buf_offset);
1849 return -EINVAL;
1850 }
1851 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001852 __qseecom_update_cmd_buf(&resp, false, data, true);
1853 qseecom.send_resp_flag = 1;
1854 wake_up_interruptible(&qseecom.send_resp_wq);
1855 return 0;
1856}
1857
1858
Mona Hossain2892b6b2012-02-17 13:53:11 -08001859static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1860 void __user *argp)
1861{
1862 struct qseecom_qseos_version_req req;
1863
1864 if (copy_from_user(&req, argp, sizeof(req))) {
1865 pr_err("copy_from_user failed");
1866 return -EINVAL;
1867 }
1868 req.qseos_version = qseecom.qseos_version;
1869 if (copy_to_user(argp, &req, sizeof(req))) {
1870 pr_err("copy_to_user failed");
1871 return -EINVAL;
1872 }
1873 return 0;
1874}
1875
Mona Hossainc92629e2013-04-01 13:37:46 -07001876static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001877{
1878 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001879 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001880
Mona Hossainc92629e2013-04-01 13:37:46 -07001881 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001882 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001883 else
1884 qclk = &qseecom.ce_drv;
1885
1886 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001887
1888 if (qclk->clk_access_cnt == ULONG_MAX)
1889 goto err;
1890
Mona Hossainc92629e2013-04-01 13:37:46 -07001891 if (qclk->clk_access_cnt > 0) {
1892 qclk->clk_access_cnt++;
1893 mutex_unlock(&clk_access_lock);
1894 return rc;
1895 }
1896
Mona Hossain6311d572013-03-01 15:54:02 -08001897 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001898 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001899 if (rc) {
1900 pr_err("Unable to enable/prepare CE core clk\n");
1901 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001902 }
1903 /* Enable CE clk */
1904 rc = clk_prepare_enable(qclk->ce_clk);
1905 if (rc) {
1906 pr_err("Unable to enable/prepare CE iface clk\n");
1907 goto ce_clk_err;
1908 }
1909 /* Enable AXI clk */
1910 rc = clk_prepare_enable(qclk->ce_bus_clk);
1911 if (rc) {
1912 pr_err("Unable to enable/prepare CE bus clk\n");
1913 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001914 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001915 qclk->clk_access_cnt++;
1916 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001917 return 0;
1918
1919ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001920 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001921ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001922 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001923err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001924 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001925 return -EIO;
1926}
1927
Mona Hossainc92629e2013-04-01 13:37:46 -07001928static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001929{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001930 struct qseecom_clk *qclk;
1931
Mona Hossainc92629e2013-04-01 13:37:46 -07001932 if (ce == CLK_QSEE)
1933 qclk = &qseecom.qsee;
1934 else
1935 qclk = &qseecom.ce_drv;
1936
1937 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001938
1939 if (qclk->clk_access_cnt == 0) {
1940 mutex_unlock(&clk_access_lock);
1941 return;
1942 }
1943
Mona Hossainc92629e2013-04-01 13:37:46 -07001944 if (qclk->clk_access_cnt == 1) {
1945 if (qclk->ce_clk != NULL)
1946 clk_disable_unprepare(qclk->ce_clk);
1947 if (qclk->ce_core_clk != NULL)
1948 clk_disable_unprepare(qclk->ce_core_clk);
1949 if (qclk->ce_bus_clk != NULL)
1950 clk_disable_unprepare(qclk->ce_bus_clk);
1951 }
1952 qclk->clk_access_cnt--;
1953 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001954}
1955
Mona Hossain04d3fac2012-12-03 10:10:37 -08001956static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1957 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001958{
1959 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001960 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001961
Mona Hossain17a4faf2013-03-22 16:40:56 -07001962 qclk = &qseecom.qsee;
1963 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07001964 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001965
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001966 switch (clk_type) {
1967 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001968 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07001969 if (!qseecom.qsee_bw_count) {
1970 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001971 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001972 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08001973 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001974 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07001975 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001976 if (!ret) {
1977 ret =
1978 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07001979 qseecom.qsee_perf_client, 1);
1980 if ((ret) &&
1981 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07001982 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08001983 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08001984 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001985 if (ret)
1986 pr_err("DFAB Bandwidth req failed (%d)\n",
1987 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001988 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001989 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001990 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08001991 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001992 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001993 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07001994 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07001995 }
1996 mutex_unlock(&qsee_bw_mutex);
1997 break;
1998 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07001999 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002000 if (!qseecom.qsee_sfpb_bw_count) {
2001 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002002 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002003 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002004 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002005 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002006 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002007 if (!ret) {
2008 ret =
2009 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002010 qseecom.qsee_perf_client, 2);
2011 if ((ret) &&
2012 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002013 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002014 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002015 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002016
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002017 if (ret)
2018 pr_err("SFPB Bandwidth req failed (%d)\n",
2019 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002020 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002021 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002022 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002023 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002024 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002025 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002026 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002027 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002028 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002029 break;
2030 default:
2031 pr_err("Clock type not defined\n");
2032 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002033 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002034 return ret;
2035}
2036
Mona Hossain04d3fac2012-12-03 10:10:37 -08002037static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2038 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002039{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002040 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002041 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002042
Mona Hossain17a4faf2013-03-22 16:40:56 -07002043 qclk = &qseecom.qsee;
2044 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002045 return;
2046
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002047 switch (clk_type) {
2048 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002049 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002050 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002051 pr_err("Client error.Extra call to disable DFAB clk\n");
2052 mutex_unlock(&qsee_bw_mutex);
2053 return;
2054 }
2055
Mona Hossain17a4faf2013-03-22 16:40:56 -07002056 if (qseecom.qsee_bw_count == 1) {
2057 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002058 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002059 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002060 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002061 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002062 qseecom.qsee_perf_client, 0);
2063 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002064 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002065 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002066 if (ret)
2067 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002068 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002069 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002070 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002071 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002072 }
2073 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002074 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002075 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002076 }
2077 mutex_unlock(&qsee_bw_mutex);
2078 break;
2079 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002080 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002081 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002082 pr_err("Client error.Extra call to disable SFPB clk\n");
2083 mutex_unlock(&qsee_bw_mutex);
2084 return;
2085 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002086 if (qseecom.qsee_sfpb_bw_count == 1) {
2087 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002088 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002089 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002090 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002091 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002092 qseecom.qsee_perf_client, 0);
2093 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002094 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002095 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002096 if (ret)
2097 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002098 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002099 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002100 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002101 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002102 }
2103 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002104 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002105 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002106 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002107 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002108 break;
2109 default:
2110 pr_err("Clock type not defined\n");
2111 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002112 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002113
Mona Hossain2892b6b2012-02-17 13:53:11 -08002114}
2115
Mona Hossain5ab9d772012-04-11 21:00:40 -07002116static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2117 void __user *argp)
2118{
2119 struct ion_handle *ihandle; /* Ion handle */
2120 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002121 int ret;
2122 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002123 ion_phys_addr_t pa = 0;
2124 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002125 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002126 struct qseecom_load_app_ireq load_req;
2127 struct qseecom_command_scm_resp resp;
2128
2129 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002130 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002131 (void __user *)argp,
2132 sizeof(struct qseecom_load_img_req))) {
2133 pr_err("copy_from_user failed\n");
2134 return -EFAULT;
2135 }
2136
2137 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002138 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002139 load_img_req.ifd_data_fd);
2140 if (IS_ERR_OR_NULL(ihandle)) {
2141 pr_err("Ion client could not retrieve the handle\n");
2142 return -ENOMEM;
2143 }
2144
2145 /* Get the physical address of the ION BUF */
2146 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2147
2148 /* Populate the structure for sending scm call to load image */
2149 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2150 load_req.mdt_len = load_img_req.mdt_len;
2151 load_req.img_len = load_img_req.img_len;
2152 load_req.phy_addr = pa;
2153
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002154 /* SCM_CALL tied to Core0 */
2155 mask = CPU_MASK_CPU0;
2156 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2157 if (set_cpu_ret) {
2158 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2159 set_cpu_ret);
2160 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302161 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002162 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302163
Mona Hossain6311d572013-03-01 15:54:02 -08002164 /* Vote for the SFPB clock */
2165 ret = qsee_vote_for_clock(data, CLK_SFPB);
2166 if (ret) {
2167 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2168 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302169 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002170 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002171 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2172 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002173 /* SCM_CALL to load the external elf */
2174 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2175 sizeof(struct qseecom_load_app_ireq),
2176 &resp, sizeof(resp));
2177 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002178 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002179 ret);
2180 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302181 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002182 }
2183
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302184 switch (resp.result) {
2185 case QSEOS_RESULT_SUCCESS:
2186 break;
2187 case QSEOS_RESULT_INCOMPLETE:
2188 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002189 ret = __qseecom_process_incomplete_cmd(data, &resp);
2190 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302191 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2192 break;
2193 case QSEOS_RESULT_FAILURE:
2194 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2195 ret = -EFAULT;
2196 break;
2197 default:
2198 pr_err("scm_call response result %d not supported\n",
2199 resp.result);
2200 ret = -EFAULT;
2201 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002202 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002203
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302204exit_disable_clock:
2205 qsee_disable_clock_vote(data, CLK_SFPB);
2206exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002207 /* Restore the CPU mask */
2208 mask = CPU_MASK_ALL;
2209 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2210 if (set_cpu_ret) {
2211 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2212 set_cpu_ret);
2213 ret = -EFAULT;
2214 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302215exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002216 /* Deallocate the handle */
2217 if (!IS_ERR_OR_NULL(ihandle))
2218 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002219 return ret;
2220}
2221
2222static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2223{
2224 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002225 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002226 struct qseecom_command_scm_resp resp;
2227 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002228 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002229
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302230 /* unavailable client app */
2231 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2232
Mona Hossain5ab9d772012-04-11 21:00:40 -07002233 /* Populate the structure for sending scm call to unload image */
2234 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002235
2236 /* SCM_CALL tied to Core0 */
2237 mask = CPU_MASK_CPU0;
2238 ret = set_cpus_allowed_ptr(current, &mask);
2239 if (ret) {
2240 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2241 ret);
2242 return -EFAULT;
2243 }
2244
Mona Hossain5ab9d772012-04-11 21:00:40 -07002245 /* SCM_CALL to unload the external elf */
2246 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2247 sizeof(struct qseecom_unload_app_ireq),
2248 &resp, sizeof(resp));
2249 if (ret) {
2250 pr_err("scm_call to unload failed : ret %d\n",
2251 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002252 ret = -EFAULT;
2253 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002254 }
2255 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2256 ret = __qseecom_process_incomplete_cmd(data, &resp);
2257 if (ret)
2258 pr_err("process_incomplete_cmd fail err: %d\n",
2259 ret);
2260 } else {
2261 if (resp.result != QSEOS_RESULT_SUCCESS) {
2262 pr_err("scm_call to unload image failed resp.result =%d\n",
2263 resp.result);
2264 ret = -EFAULT;
2265 }
2266 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002267
2268qseecom_unload_external_elf_scm_err:
2269 /* Restore the CPU mask */
2270 mask = CPU_MASK_ALL;
2271 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2272 if (set_cpu_ret) {
2273 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2274 set_cpu_ret);
2275 ret = -EFAULT;
2276 }
2277
Mona Hossain5ab9d772012-04-11 21:00:40 -07002278 return ret;
2279}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002280
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002281static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2282 void __user *argp)
2283{
2284
2285 int32_t ret;
2286 struct qseecom_qseos_app_load_query query_req;
2287 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002288 struct qseecom_registered_app_list *entry = NULL;
2289 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002290
2291 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002292 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002293 (void __user *)argp,
2294 sizeof(struct qseecom_qseos_app_load_query))) {
2295 pr_err("copy_from_user failed\n");
2296 return -EFAULT;
2297 }
2298
2299 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002300 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002301 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2302
2303 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002304
2305 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002306 pr_err(" scm call to check if app is loaded failed");
2307 return ret; /* scm call failed */
2308 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002309 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002310 (char *)(req.app_name));
2311 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2312 list_for_each_entry(entry,
2313 &qseecom.registered_app_list_head, list){
2314 if (entry->app_id == ret) {
2315 entry->ref_cnt++;
2316 break;
2317 }
2318 }
2319 spin_unlock_irqrestore(
2320 &qseecom.registered_app_list_lock, flags);
2321 data->client.app_id = ret;
2322 query_req.app_id = ret;
2323
2324 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2325 pr_err("copy_to_user failed\n");
2326 return -EFAULT;
2327 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002328 return -EEXIST; /* app already loaded */
2329 } else {
2330 return 0; /* app not loaded */
2331 }
2332}
2333
Mona Hossain4cf78a92013-02-14 12:06:41 -08002334static int __qseecom_get_ce_pipe_info(
2335 enum qseecom_key_management_usage_type usage,
2336 uint32_t *pipe, uint32_t *ce_hw)
2337{
2338 int ret;
2339 switch (usage) {
2340 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2341 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2342 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2343 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2344 qseecom.ce_info.disk_encrypt_pipe,
2345 qseecom.ce_info.hlos_ce_hw_instance);
2346 ret = -EINVAL;
2347 } else {
2348 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2349 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2350 ret = 0;
2351 }
2352 break;
2353 default:
2354 ret = -EINVAL;
2355 break;
2356 }
2357 return ret;
2358}
2359
2360static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2361 enum qseecom_key_management_usage_type usage,
2362 uint8_t *key_id, uint32_t flags)
2363{
2364 struct qseecom_key_generate_ireq ireq;
2365 struct qseecom_command_scm_resp resp;
2366 int ret;
2367
2368 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2369 pr_err("Error:: unsupported usage %d\n", usage);
2370 return -EFAULT;
2371 }
2372
2373 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2374 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002375 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002376
Mona Hossainc92629e2013-04-01 13:37:46 -07002377 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002378
2379 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002380 &ireq, sizeof(struct qseecom_key_generate_ireq),
2381 &resp, sizeof(resp));
2382 if (ret) {
2383 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002384 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002385 return ret;
2386 }
2387
2388 switch (resp.result) {
2389 case QSEOS_RESULT_SUCCESS:
2390 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002391 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002392 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002393 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002394 case QSEOS_RESULT_INCOMPLETE:
2395 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002396 if (ret) {
2397 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002398 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002399 ret = 0;
2400 } else {
2401 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2402 resp.result);
2403 }
2404 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002405 break;
2406 case QSEOS_RESULT_FAILURE:
2407 default:
2408 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2409 ret = -EINVAL;
2410 break;
2411 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002412 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002413 return ret;
2414}
2415
2416static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2417 enum qseecom_key_management_usage_type usage,
2418 uint8_t *key_id, uint32_t flags)
2419{
2420 struct qseecom_key_delete_ireq ireq;
2421 struct qseecom_command_scm_resp resp;
2422 int ret;
2423
2424 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2425 pr_err("Error:: unsupported usage %d\n", usage);
2426 return -EFAULT;
2427 }
2428
2429 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2430 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002431 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002432
Mona Hossainc92629e2013-04-01 13:37:46 -07002433 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002434
2435 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002436 &ireq, sizeof(struct qseecom_key_delete_ireq),
2437 &resp, sizeof(struct qseecom_command_scm_resp));
2438 if (ret) {
2439 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002440 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002441 return ret;
2442 }
2443
2444 switch (resp.result) {
2445 case QSEOS_RESULT_SUCCESS:
2446 break;
2447 case QSEOS_RESULT_INCOMPLETE:
2448 ret = __qseecom_process_incomplete_cmd(data, &resp);
2449 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002450 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2451 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002452 break;
2453 case QSEOS_RESULT_FAILURE:
2454 default:
2455 pr_err("Delete key scm call failed resp.result %d\n",
2456 resp.result);
2457 ret = -EINVAL;
2458 break;
2459 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002460 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002461 return ret;
2462}
2463
2464static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2465 enum qseecom_key_management_usage_type usage,
2466 struct qseecom_set_key_parameter *set_key_para)
2467{
2468 struct qseecom_key_select_ireq ireq;
2469 struct qseecom_command_scm_resp resp;
2470 int ret;
2471
2472 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2473 pr_err("Error:: unsupported usage %d\n", usage);
2474 return -EFAULT;
2475 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002476
Zhen Kongdb2bf742013-05-13 23:55:42 -07002477 __qseecom_enable_clk(CLK_QSEE);
2478 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002479 __qseecom_enable_clk(CLK_CE_DRV);
2480
Mona Hossain4cf78a92013-02-14 12:06:41 -08002481 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002482 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002483 ireq.ce = set_key_para->ce_hw;
2484 ireq.pipe = set_key_para->pipe;
2485 ireq.flags = set_key_para->flags;
2486
Zhen Kong1f09c7692013-05-03 17:50:32 -07002487 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2488 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002489
Mona Hossain4cf78a92013-02-14 12:06:41 -08002490 if (set_key_para->set_clear_key_flag ==
2491 QSEECOM_SET_CE_KEY_CMD)
2492 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2493 QSEECOM_HASH_SIZE);
2494 else
2495 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2496
Zhen Kong336636e2013-04-15 11:04:54 -07002497 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002498 &ireq, sizeof(struct qseecom_key_select_ireq),
2499 &resp, sizeof(struct qseecom_command_scm_resp));
2500 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002501 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002502 __qseecom_disable_clk(CLK_QSEE);
2503 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2504 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kong336636e2013-04-15 11:04:54 -07002505 return ret;
2506 }
2507
Mona Hossain4cf78a92013-02-14 12:06:41 -08002508 switch (resp.result) {
2509 case QSEOS_RESULT_SUCCESS:
2510 break;
2511 case QSEOS_RESULT_INCOMPLETE:
2512 ret = __qseecom_process_incomplete_cmd(data, &resp);
2513 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002514 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2515 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002516 break;
2517 case QSEOS_RESULT_FAILURE:
2518 default:
2519 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2520 ret = -EINVAL;
2521 break;
2522 }
2523
Zhen Kongdb2bf742013-05-13 23:55:42 -07002524 __qseecom_disable_clk(CLK_QSEE);
2525 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002526 __qseecom_disable_clk(CLK_CE_DRV);
2527
Mona Hossain4cf78a92013-02-14 12:06:41 -08002528 return ret;
2529}
2530
2531static int qseecom_create_key(struct qseecom_dev_handle *data,
2532 void __user *argp)
2533{
2534 uint32_t ce_hw = 0;
2535 uint32_t pipe = 0;
2536 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2537 int ret = 0;
2538 uint32_t flags = 0;
2539 struct qseecom_set_key_parameter set_key_para;
2540 struct qseecom_create_key_req create_key_req;
2541
2542 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2543 if (ret) {
2544 pr_err("copy_from_user failed\n");
2545 return ret;
2546 }
2547
2548 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2549 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2550 return -EFAULT;
2551 }
2552
2553 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2554 if (ret) {
2555 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2556 return -EINVAL;
2557 }
2558
2559 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2560 key_id, flags);
2561 if (ret) {
2562 pr_err("Failed to generate key on storage: %d\n", ret);
2563 return -EFAULT;
2564 }
2565
2566 set_key_para.ce_hw = ce_hw;
2567 set_key_para.pipe = pipe;
2568 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2569 set_key_para.flags = flags;
2570 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2571 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2572 QSEECOM_HASH_SIZE);
2573
2574 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2575 &set_key_para);
2576 if (ret) {
2577 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2578 pipe, ce_hw, ret);
2579 return -EFAULT;
2580 }
2581
2582 return ret;
2583}
2584
2585static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2586 void __user *argp)
2587{
2588 uint32_t ce_hw = 0;
2589 uint32_t pipe = 0;
2590 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2591 int ret = 0;
2592 uint32_t flags = 0;
2593 int i;
2594 struct qseecom_wipe_key_req wipe_key_req;
2595 struct qseecom_set_key_parameter clear_key_para;
2596
2597 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2598 if (ret) {
2599 pr_err("copy_from_user failed\n");
2600 return ret;
2601 }
2602
2603 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2604 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2605 return -EFAULT;
2606 }
2607
2608 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2609 if (ret) {
2610 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2611 return -EINVAL;
2612 }
2613
2614 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2615 flags);
2616 if (ret) {
2617 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2618 return -EFAULT;
2619 }
2620
2621 /* an invalid key_id 0xff is used to indicate clear key*/
2622 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2623 clear_key_para.key_id[i] = 0xff;
2624 clear_key_para.ce_hw = ce_hw;
2625 clear_key_para.pipe = pipe;
2626 clear_key_para.flags = flags;
2627 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2628 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2629 &clear_key_para);
2630 if (ret) {
2631 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2632 pipe, ce_hw, ret);
2633 return -EFAULT;
2634 }
2635
2636 return ret;
2637}
2638
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002639static int qseecom_is_es_activated(void __user *argp)
2640{
2641 struct qseecom_is_es_activated_req req;
2642 int ret;
2643 int resp_buf;
2644
2645 if (qseecom.qsee_version < QSEE_VERSION_04) {
2646 pr_err("invalid qsee version");
2647 return -ENODEV;
2648 }
2649
2650 if (argp == NULL) {
2651 pr_err("arg is null");
2652 return -EINVAL;
2653 }
2654
2655 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2656 (void *) &resp_buf, sizeof(resp_buf));
2657 if (ret) {
2658 pr_err("scm_call failed");
2659 return ret;
2660 }
2661
2662 req.is_activated = resp_buf;
2663 ret = copy_to_user(argp, &req, sizeof(req));
2664 if (ret) {
2665 pr_err("copy_to_user failed");
2666 return ret;
2667 }
2668
2669 return 0;
2670}
2671
2672static int qseecom_save_partition_hash(void __user *argp)
2673{
2674 struct qseecom_save_partition_hash_req req;
2675 int ret;
2676
2677 if (qseecom.qsee_version < QSEE_VERSION_04) {
2678 pr_err("invalid qsee version ");
2679 return -ENODEV;
2680 }
2681
2682 if (argp == NULL) {
2683 pr_err("arg is null");
2684 return -EINVAL;
2685 }
2686
2687 ret = copy_from_user(&req, argp, sizeof(req));
2688 if (ret) {
2689 pr_err("copy_from_user failed");
2690 return ret;
2691 }
2692
2693 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2694 (void *) &req, sizeof(req), NULL, 0);
2695 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002696 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002697 return ret;
2698 }
2699
2700 return 0;
2701}
2702
Mona Hossain2892b6b2012-02-17 13:53:11 -08002703static long qseecom_ioctl(struct file *file, unsigned cmd,
2704 unsigned long arg)
2705{
2706 int ret = 0;
2707 struct qseecom_dev_handle *data = file->private_data;
2708 void __user *argp = (void __user *) arg;
2709
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05302710 if (!data) {
2711 pr_err("Invalid/uninitialized device handle\n");
2712 return -EINVAL;
2713 }
2714
Mona Hossain2892b6b2012-02-17 13:53:11 -08002715 if (data->abort) {
2716 pr_err("Aborting qseecom driver\n");
2717 return -ENODEV;
2718 }
2719
2720 switch (cmd) {
2721 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002722 if (data->type != QSEECOM_GENERIC) {
2723 pr_err("reg lstnr req: invalid handle (%d)\n",
2724 data->type);
2725 ret = -EINVAL;
2726 break;
2727 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002728 pr_debug("ioctl register_listener_req()\n");
2729 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002730 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002731 ret = qseecom_register_listener(data, argp);
2732 atomic_dec(&data->ioctl_count);
2733 wake_up_all(&data->abort_wq);
2734 if (ret)
2735 pr_err("failed qseecom_register_listener: %d\n", ret);
2736 break;
2737 }
2738 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002739 if ((data->listener.id == 0) ||
2740 (data->type != QSEECOM_LISTENER_SERVICE)) {
2741 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
2742 data->type, data->listener.id);
2743 ret = -EINVAL;
2744 break;
2745 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002746 pr_debug("ioctl unregister_listener_req()\n");
2747 atomic_inc(&data->ioctl_count);
2748 ret = qseecom_unregister_listener(data);
2749 atomic_dec(&data->ioctl_count);
2750 wake_up_all(&data->abort_wq);
2751 if (ret)
2752 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2753 break;
2754 }
2755 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002756 if ((data->client.app_id == 0) ||
2757 (data->type != QSEECOM_CLIENT_APP)) {
2758 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
2759 data->type, data->client.app_id);
2760 ret = -EINVAL;
2761 break;
2762 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002763 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002764 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002765 atomic_inc(&data->ioctl_count);
2766 ret = qseecom_send_cmd(data, argp);
2767 atomic_dec(&data->ioctl_count);
2768 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002769 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002770 if (ret)
2771 pr_err("failed qseecom_send_cmd: %d\n", ret);
2772 break;
2773 }
2774 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002775 if ((data->client.app_id == 0) ||
2776 (data->type != QSEECOM_CLIENT_APP)) {
2777 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
2778 data->type, data->client.app_id);
2779 ret = -EINVAL;
2780 break;
2781 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002782 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002783 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002784 atomic_inc(&data->ioctl_count);
2785 ret = qseecom_send_modfd_cmd(data, argp);
2786 atomic_dec(&data->ioctl_count);
2787 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002788 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002789 if (ret)
2790 pr_err("failed qseecom_send_cmd: %d\n", ret);
2791 break;
2792 }
2793 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002794 if ((data->listener.id == 0) ||
2795 (data->type != QSEECOM_LISTENER_SERVICE)) {
2796 pr_err("receive req: invalid handle (%d), lid(%d)\n",
2797 data->type, data->listener.id);
2798 ret = -EINVAL;
2799 break;
2800 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002801 atomic_inc(&data->ioctl_count);
2802 ret = qseecom_receive_req(data);
2803 atomic_dec(&data->ioctl_count);
2804 wake_up_all(&data->abort_wq);
2805 if (ret)
2806 pr_err("failed qseecom_receive_req: %d\n", ret);
2807 break;
2808 }
2809 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002810 if ((data->listener.id == 0) ||
2811 (data->type != QSEECOM_LISTENER_SERVICE)) {
2812 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
2813 data->type, data->listener.id);
2814 ret = -EINVAL;
2815 break;
2816 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002817 atomic_inc(&data->ioctl_count);
2818 ret = qseecom_send_resp();
2819 atomic_dec(&data->ioctl_count);
2820 wake_up_all(&data->abort_wq);
2821 if (ret)
2822 pr_err("failed qseecom_send_resp: %d\n", ret);
2823 break;
2824 }
2825 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002826 if ((data->type != QSEECOM_CLIENT_APP) &&
2827 (data->type != QSEECOM_GENERIC) &&
2828 (data->type != QSEECOM_SECURE_SERVICE)) {
2829 pr_err("set mem param req: invalid handle (%d)\n",
2830 data->type);
2831 ret = -EINVAL;
2832 break;
2833 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002834 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002835 ret = qseecom_set_client_mem_param(data, argp);
2836 if (ret)
2837 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2838 ret);
2839 break;
2840 }
2841 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002842 if ((data->type != QSEECOM_GENERIC) &&
2843 (data->type != QSEECOM_CLIENT_APP)) {
2844 pr_err("load app req: invalid handle (%d)\n",
2845 data->type);
2846 ret = -EINVAL;
2847 break;
2848 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002849 data->type = QSEECOM_CLIENT_APP;
2850 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002851 mutex_lock(&app_access_lock);
2852 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002853 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2854 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002855 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002856 if (ret == 0)
2857 qseecom.commonlib_loaded = true;
2858 }
2859 }
2860 if (ret == 0)
2861 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002862 atomic_dec(&data->ioctl_count);
2863 mutex_unlock(&app_access_lock);
2864 if (ret)
2865 pr_err("failed load_app request: %d\n", ret);
2866 break;
2867 }
2868 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002869 if ((data->client.app_id == 0) ||
2870 (data->type != QSEECOM_CLIENT_APP)) {
2871 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
2872 data->type, data->client.app_id);
2873 ret = -EINVAL;
2874 break;
2875 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002876 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002877 mutex_lock(&app_access_lock);
2878 atomic_inc(&data->ioctl_count);
2879 ret = qseecom_unload_app(data);
2880 atomic_dec(&data->ioctl_count);
2881 mutex_unlock(&app_access_lock);
2882 if (ret)
2883 pr_err("failed unload_app request: %d\n", ret);
2884 break;
2885 }
2886 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2887 atomic_inc(&data->ioctl_count);
2888 ret = qseecom_get_qseos_version(data, argp);
2889 if (ret)
2890 pr_err("qseecom_get_qseos_version: %d\n", ret);
2891 atomic_dec(&data->ioctl_count);
2892 break;
2893 }
2894 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002895 if ((data->type != QSEECOM_GENERIC) &&
2896 (data->type != QSEECOM_CLIENT_APP)) {
2897 pr_err("perf enable req: invalid handle (%d)\n",
2898 data->type);
2899 ret = -EINVAL;
2900 break;
2901 }
2902 if ((data->type == QSEECOM_CLIENT_APP) &&
2903 (data->client.app_id == 0)) {
2904 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
2905 data->type, data->client.app_id);
2906 ret = -EINVAL;
2907 break;
2908 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002909 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002910 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002911 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002912 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002913 ret = qsee_vote_for_clock(data, CLK_SFPB);
2914 if (ret)
2915 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002916 atomic_dec(&data->ioctl_count);
2917 break;
2918 }
2919 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002920 if ((data->type != QSEECOM_SECURE_SERVICE) &&
2921 (data->type != QSEECOM_CLIENT_APP)) {
2922 pr_err("perf disable req: invalid handle (%d)\n",
2923 data->type);
2924 ret = -EINVAL;
2925 break;
2926 }
2927 if ((data->type == QSEECOM_CLIENT_APP) &&
2928 (data->client.app_id == 0)) {
2929 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
2930 data->type, data->client.app_id);
2931 ret = -EINVAL;
2932 break;
2933 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002934 atomic_inc(&data->ioctl_count);
Mona Hossaina1124de2013-10-01 13:41:09 -07002935 qsee_disable_clock_vote(data, CLK_DFAB);
2936 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002937 atomic_dec(&data->ioctl_count);
2938 break;
2939 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002940 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002941 if (data->type != QSEECOM_GENERIC) {
2942 pr_err("load ext elf req: invalid client handle (%d)\n",
2943 data->type);
2944 ret = -EINVAL;
2945 break;
2946 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002947 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002948 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002949 mutex_lock(&app_access_lock);
2950 atomic_inc(&data->ioctl_count);
2951 ret = qseecom_load_external_elf(data, argp);
2952 atomic_dec(&data->ioctl_count);
2953 mutex_unlock(&app_access_lock);
2954 if (ret)
2955 pr_err("failed load_external_elf request: %d\n", ret);
2956 break;
2957 }
2958 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002959 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
2960 pr_err("unload ext elf req: invalid handle (%d)\n",
2961 data->type);
2962 ret = -EINVAL;
2963 break;
2964 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002965 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002966 mutex_lock(&app_access_lock);
2967 atomic_inc(&data->ioctl_count);
2968 ret = qseecom_unload_external_elf(data);
2969 atomic_dec(&data->ioctl_count);
2970 mutex_unlock(&app_access_lock);
2971 if (ret)
2972 pr_err("failed unload_app request: %d\n", ret);
2973 break;
2974 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002975 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002976 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002977 mutex_lock(&app_access_lock);
2978 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002979 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002980 ret = qseecom_query_app_loaded(data, argp);
2981 atomic_dec(&data->ioctl_count);
2982 mutex_unlock(&app_access_lock);
2983 break;
2984 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002985 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002986 if (data->type != QSEECOM_GENERIC) {
2987 pr_err("send cmd svc req: invalid handle (%d)\n",
2988 data->type);
2989 ret = -EINVAL;
2990 break;
2991 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002992 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002993 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07002994 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002995 qseecom.qsee_version);
2996 return -EINVAL;
2997 }
2998 mutex_lock(&app_access_lock);
2999 atomic_inc(&data->ioctl_count);
3000 ret = qseecom_send_service_cmd(data, argp);
3001 atomic_dec(&data->ioctl_count);
3002 mutex_unlock(&app_access_lock);
3003 break;
3004 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003005 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003006 if (data->type != QSEECOM_GENERIC) {
3007 pr_err("create key req: invalid handle (%d)\n",
3008 data->type);
3009 ret = -EINVAL;
3010 break;
3011 }
Zhen Kong336636e2013-04-15 11:04:54 -07003012 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003013 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003014 qseecom.qsee_version);
3015 return -EINVAL;
3016 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003017 data->released = true;
3018 mutex_lock(&app_access_lock);
3019 atomic_inc(&data->ioctl_count);
3020 ret = qseecom_create_key(data, argp);
3021 if (ret)
3022 pr_err("failed to create encryption key: %d\n", ret);
3023
3024 atomic_dec(&data->ioctl_count);
3025 mutex_unlock(&app_access_lock);
3026 break;
3027 }
3028 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003029 if (data->type != QSEECOM_GENERIC) {
3030 pr_err("wipe key req: invalid handle (%d)\n",
3031 data->type);
3032 ret = -EINVAL;
3033 break;
3034 }
Zhen Kong336636e2013-04-15 11:04:54 -07003035 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003036 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003037 qseecom.qsee_version);
3038 return -EINVAL;
3039 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003040 data->released = true;
3041 mutex_lock(&app_access_lock);
3042 atomic_inc(&data->ioctl_count);
3043 ret = qseecom_wipe_key(data, argp);
3044 if (ret)
3045 pr_err("failed to wipe encryption key: %d\n", ret);
3046 atomic_dec(&data->ioctl_count);
3047 mutex_unlock(&app_access_lock);
3048 break;
3049 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003050 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003051 if (data->type != QSEECOM_GENERIC) {
3052 pr_err("save part hash req: invalid handle (%d)\n",
3053 data->type);
3054 ret = -EINVAL;
3055 break;
3056 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003057 data->released = true;
3058 mutex_lock(&app_access_lock);
3059 atomic_inc(&data->ioctl_count);
3060 ret = qseecom_save_partition_hash(argp);
3061 atomic_dec(&data->ioctl_count);
3062 mutex_unlock(&app_access_lock);
3063 break;
3064 }
3065 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003066 if (data->type != QSEECOM_GENERIC) {
3067 pr_err("ES activated req: invalid handle (%d)\n",
3068 data->type);
3069 ret = -EINVAL;
3070 break;
3071 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003072 data->released = true;
3073 mutex_lock(&app_access_lock);
3074 atomic_inc(&data->ioctl_count);
3075 ret = qseecom_is_es_activated(argp);
3076 atomic_dec(&data->ioctl_count);
3077 mutex_unlock(&app_access_lock);
3078 break;
3079 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003080 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003081 if ((data->listener.id == 0) ||
3082 (data->type != QSEECOM_LISTENER_SERVICE)) {
3083 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3084 data->type, data->listener.id);
3085 ret = -EINVAL;
3086 break;
3087 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003088 /* Only one client allowed here at a time */
3089 atomic_inc(&data->ioctl_count);
3090 ret = qseecom_send_modfd_resp(data, argp);
3091 atomic_dec(&data->ioctl_count);
3092 wake_up_all(&data->abort_wq);
3093 if (ret)
3094 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3095 break;
3096 }
3097 case QSEECOM_IOCTL_UNPROTECT_BUF: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003098 if ((data->listener.id == 0) ||
3099 (data->type != QSEECOM_LISTENER_SERVICE)) {
3100 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3101 data->type, data->listener.id);
3102 ret = -EINVAL;
3103 break;
3104 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003105 /* Only one client allowed here at a time */
3106 atomic_inc(&data->ioctl_count);
3107 ret = qseecom_unprotect_buffer(argp);
3108 atomic_dec(&data->ioctl_count);
3109 wake_up_all(&data->abort_wq);
3110 if (ret)
3111 pr_err("failed qseecom_unprotect: %d\n", ret);
3112 break;
3113 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003114 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003115 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003116 return -EINVAL;
3117 }
3118 return ret;
3119}
3120
3121static int qseecom_open(struct inode *inode, struct file *file)
3122{
3123 int ret = 0;
3124 struct qseecom_dev_handle *data;
3125
3126 data = kzalloc(sizeof(*data), GFP_KERNEL);
3127 if (!data) {
3128 pr_err("kmalloc failed\n");
3129 return -ENOMEM;
3130 }
3131 file->private_data = data;
3132 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003133 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003134 data->released = false;
3135 init_waitqueue_head(&data->abort_wq);
3136 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003137
Mona Hossain2892b6b2012-02-17 13:53:11 -08003138 return ret;
3139}
3140
3141static int qseecom_release(struct inode *inode, struct file *file)
3142{
3143 struct qseecom_dev_handle *data = file->private_data;
3144 int ret = 0;
3145
3146 if (data->released == false) {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003147 pr_warn("data: released = false, type = %d, data = 0x%x\n",
3148 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003149 switch (data->type) {
3150 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003151 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003152 break;
3153 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003154 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003155 break;
3156 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003157 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003158 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003159 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003160 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003161 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303162 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3163 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003164 default:
3165 pr_err("Unsupported clnt_handle_type %d",
3166 data->type);
3167 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003168 }
3169 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003170
Mona Hossainc9c83c72013-04-11 12:43:48 -07003171 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003172 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07003173 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003174 qsee_disable_clock_vote(data, CLK_DFAB);
3175
Mona Hossain2892b6b2012-02-17 13:53:11 -08003176 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003177
Mona Hossain2892b6b2012-02-17 13:53:11 -08003178 return ret;
3179}
3180
Mona Hossain2892b6b2012-02-17 13:53:11 -08003181static const struct file_operations qseecom_fops = {
3182 .owner = THIS_MODULE,
3183 .unlocked_ioctl = qseecom_ioctl,
3184 .open = qseecom_open,
3185 .release = qseecom_release
3186};
3187
Mona Hossainc92629e2013-04-01 13:37:46 -07003188static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003189{
3190 int rc = 0;
3191 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003192 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003193 char *core_clk_src = NULL;
3194 char *core_clk = NULL;
3195 char *iface_clk = NULL;
3196 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003197
Mona Hossainc92629e2013-04-01 13:37:46 -07003198 switch (ce) {
3199 case CLK_QSEE: {
3200 core_clk_src = "core_clk_src";
3201 core_clk = "core_clk";
3202 iface_clk = "iface_clk";
3203 bus_clk = "bus_clk";
3204 qclk = &qseecom.qsee;
3205 qclk->instance = CLK_QSEE;
3206 break;
3207 };
3208 case CLK_CE_DRV: {
3209 core_clk_src = "ce_drv_core_clk_src";
3210 core_clk = "ce_drv_core_clk";
3211 iface_clk = "ce_drv_iface_clk";
3212 bus_clk = "ce_drv_bus_clk";
3213 qclk = &qseecom.ce_drv;
3214 qclk->instance = CLK_CE_DRV;
3215 break;
3216 };
3217 default:
3218 pr_err("Invalid ce hw instance: %d!\n", ce);
3219 return -EIO;
3220 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003221 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003222
Mona Hossainc92629e2013-04-01 13:37:46 -07003223 /* Get CE3 src core clk. */
3224 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003225 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003226 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003227 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003228 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003229 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003230 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003231 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003232 }
3233 } else {
3234 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003235 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003236 }
3237
3238 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003239 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003240 if (IS_ERR(qclk->ce_core_clk)) {
3241 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003242 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003243 if (qclk->ce_core_src_clk != NULL)
3244 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003245 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003246 }
3247
3248 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003249 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003250 if (IS_ERR(qclk->ce_clk)) {
3251 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003252 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003253 if (qclk->ce_core_src_clk != NULL)
3254 clk_put(qclk->ce_core_src_clk);
3255 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003256 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003257 }
3258
3259 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003260 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003261 if (IS_ERR(qclk->ce_bus_clk)) {
3262 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003263 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003264 if (qclk->ce_core_src_clk != NULL)
3265 clk_put(qclk->ce_core_src_clk);
3266 clk_put(qclk->ce_core_clk);
3267 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003268 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003269 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003270 return rc;
3271}
3272
Mona Hossainc92629e2013-04-01 13:37:46 -07003273static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003274{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003275 struct qseecom_clk *qclk;
3276
Mona Hossainc92629e2013-04-01 13:37:46 -07003277 if (ce == CLK_QSEE)
3278 qclk = &qseecom.qsee;
3279 else
3280 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003281
3282 if (qclk->ce_clk != NULL) {
3283 clk_put(qclk->ce_clk);
3284 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003285 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003286 if (qclk->ce_core_clk != NULL) {
3287 clk_put(qclk->ce_core_clk);
3288 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003289 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003290 if (qclk->ce_bus_clk != NULL) {
3291 clk_put(qclk->ce_bus_clk);
3292 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003293 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003294 if (qclk->ce_core_src_clk != NULL) {
3295 clk_put(qclk->ce_core_src_clk);
3296 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003297 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003298}
3299
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003300static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003301{
3302 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003303 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003304 struct device *class_dev;
3305 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003306 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003307 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3308
Mona Hossain17a4faf2013-03-22 16:40:56 -07003309 qseecom.qsee_bw_count = 0;
3310 qseecom.qsee_perf_client = 0;
3311 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003312
Mona Hossain17a4faf2013-03-22 16:40:56 -07003313 qseecom.qsee.ce_core_clk = NULL;
3314 qseecom.qsee.ce_clk = NULL;
3315 qseecom.qsee.ce_core_src_clk = NULL;
3316 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003317
Mona Hossainc92629e2013-04-01 13:37:46 -07003318 qseecom.ce_drv.ce_core_clk = NULL;
3319 qseecom.ce_drv.ce_clk = NULL;
3320 qseecom.ce_drv.ce_core_src_clk = NULL;
3321 qseecom.ce_drv.ce_bus_clk = NULL;
3322
Mona Hossain2892b6b2012-02-17 13:53:11 -08003323 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3324 if (rc < 0) {
3325 pr_err("alloc_chrdev_region failed %d\n", rc);
3326 return rc;
3327 }
3328
3329 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3330 if (IS_ERR(driver_class)) {
3331 rc = -ENOMEM;
3332 pr_err("class_create failed %d\n", rc);
3333 goto unregister_chrdev_region;
3334 }
3335
3336 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3337 QSEECOM_DEV);
3338 if (!class_dev) {
3339 pr_err("class_device_create failed %d\n", rc);
3340 rc = -ENOMEM;
3341 goto class_destroy;
3342 }
3343
3344 cdev_init(&qseecom_cdev, &qseecom_fops);
3345 qseecom_cdev.owner = THIS_MODULE;
3346
3347 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
3348 if (rc < 0) {
3349 pr_err("cdev_add failed %d\n", rc);
3350 goto err;
3351 }
3352
3353 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3354 spin_lock_init(&qseecom.registered_listener_list_lock);
3355 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3356 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003357 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3358 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003359 init_waitqueue_head(&qseecom.send_resp_wq);
3360 qseecom.send_resp_flag = 0;
3361
3362 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3363 &qsee_not_legacy, sizeof(qsee_not_legacy));
3364 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003365 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003366 goto err;
3367 }
Mona Hossain05c73562012-10-29 17:49:01 -07003368 if (qsee_not_legacy) {
3369 uint32_t feature = 10;
3370
3371 qseecom.qsee_version = QSEEE_VERSION_00;
3372 rc = scm_call(6, 3, &feature, sizeof(feature),
3373 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3374 if (rc) {
3375 pr_err("Failed to get QSEE version info %d\n", rc);
3376 goto err;
3377 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003378 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003379 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003380 pr_err("QSEE legacy version is not supported:");
3381 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3382 rc = -EINVAL;
3383 goto err;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003384 }
Mona Hossain05c73562012-10-29 17:49:01 -07003385 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003386 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003387 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003388 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003389 if (qseecom.ion_clnt == NULL) {
3390 pr_err("Ion client cannot be created\n");
3391 rc = -ENOMEM;
3392 goto err;
3393 }
3394
3395 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003396 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003397
Mona Hossain4cf78a92013-02-14 12:06:41 -08003398 if (of_property_read_u32((&pdev->dev)->of_node,
3399 "qcom,disk-encrypt-pipe-pair",
3400 &qseecom.ce_info.disk_encrypt_pipe)) {
3401 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3402 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3403 rc = -EINVAL;
3404 goto err;
3405 } else {
3406 pr_warn("bam_pipe_pair=0x%x",
3407 qseecom.ce_info.disk_encrypt_pipe);
3408 }
3409
3410 if (of_property_read_u32((&pdev->dev)->of_node,
3411 "qcom,qsee-ce-hw-instance",
3412 &qseecom.ce_info.qsee_ce_hw_instance)) {
3413 pr_err("Fail to get qsee ce hw instance information.\n");
3414 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3415 rc = -EINVAL;
3416 goto err;
3417 } else {
3418 pr_warn("qsee-ce-hw-instance=0x%x",
3419 qseecom.ce_info.qsee_ce_hw_instance);
3420 }
3421
3422 if (of_property_read_u32((&pdev->dev)->of_node,
3423 "qcom,hlos-ce-hw-instance",
3424 &qseecom.ce_info.hlos_ce_hw_instance)) {
3425 pr_err("Fail to get hlos ce hw instance information.\n");
3426 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3427 rc = -EINVAL;
3428 goto err;
3429 } else {
3430 pr_warn("hlos-ce-hw-instance=0x%x",
3431 qseecom.ce_info.hlos_ce_hw_instance);
3432 }
3433
Mona Hossainc92629e2013-04-01 13:37:46 -07003434 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3435 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3436
3437 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003438 if (ret)
3439 goto err;
Mona Hossain6311d572013-03-01 15:54:02 -08003440
Mona Hossainc92629e2013-04-01 13:37:46 -07003441 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3442 ret = __qseecom_init_clk(CLK_CE_DRV);
3443 if (ret) {
3444 __qseecom_deinit_clk(CLK_QSEE);
3445 goto err;
3446 }
3447 } else {
3448 struct qseecom_clk *qclk;
3449
3450 qclk = &qseecom.qsee;
3451 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3452 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3453 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3454 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3455 }
3456
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003457 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3458 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003459 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3460 struct resource *resource = NULL;
3461 struct qsee_apps_region_info_ireq req;
3462 struct qseecom_command_scm_resp resp;
3463
3464 resource = platform_get_resource_byname(pdev,
3465 IORESOURCE_MEM, "secapp-region");
3466 if (resource) {
3467 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3468 req.addr = resource->start;
3469 req.size = resource_size(resource);
3470 pr_warn("secure app region addr=0x%x size=0x%x",
3471 req.addr, req.size);
3472 } else {
3473 pr_err("Fail to get secure app region info\n");
3474 rc = -EINVAL;
3475 goto err;
3476 }
3477 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3478 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003479 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3480 pr_err("send secapp reg fail %d resp.res %d\n",
3481 rc, resp.result);
3482 rc = -EINVAL;
Mona Hossain5b76a622012-11-15 20:09:08 -08003483 goto err;
3484 }
3485 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003486 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003487 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3488 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003489 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003490
Mona Hossain17a4faf2013-03-22 16:40:56 -07003491 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003492 qseecom_platform_support);
3493
Mona Hossain17a4faf2013-03-22 16:40:56 -07003494 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003495 pr_err("Unable to register bus client\n");
3496 return 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003497err:
3498 device_destroy(driver_class, qseecom_device_no);
3499class_destroy:
3500 class_destroy(driver_class);
3501unregister_chrdev_region:
3502 unregister_chrdev_region(qseecom_device_no, 1);
3503 return rc;
3504}
3505
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003506static int __devinit qseecom_remove(struct platform_device *pdev)
3507{
Mona Hossaind44a3842012-10-15 09:41:35 -07003508 struct qseecom_registered_kclient_list *kclient = NULL;
3509 unsigned long flags = 0;
3510 int ret = 0;
3511
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003512 if (pdev->dev.platform_data != NULL)
Mona Hossain17a4faf2013-03-22 16:40:56 -07003513 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
Mona Hossaind44a3842012-10-15 09:41:35 -07003514
3515 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3516 kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
3517 struct qseecom_registered_kclient_list, list);
3518 if (list_empty(&kclient->list)) {
3519 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3520 flags);
3521 return 0;
3522 }
3523 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
3524 list) {
3525 if (kclient)
3526 list_del(&kclient->list);
3527 break;
3528 }
3529 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3530
3531
3532 while (kclient->handle != NULL) {
3533 ret = qseecom_unload_app(kclient->handle->dev);
3534 if (ret == 0) {
3535 kzfree(kclient->handle->dev);
3536 kzfree(kclient->handle);
3537 kzfree(kclient);
3538 }
3539 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
3540 kclient = list_entry(
3541 (&qseecom.registered_kclient_list_head)->next,
3542 struct qseecom_registered_kclient_list, list);
3543 if (list_empty(&kclient->list)) {
3544 spin_unlock_irqrestore(
3545 &qseecom.registered_kclient_list_lock, flags);
3546 return 0;
3547 }
3548 list_for_each_entry(kclient,
3549 &qseecom.registered_kclient_list_head, list) {
3550 if (kclient)
3551 list_del(&kclient->list);
3552 break;
3553 }
3554 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
3555 flags);
3556 if (!kclient) {
3557 ret = 0;
3558 break;
3559 }
3560 }
Mona Hossain05c73562012-10-29 17:49:01 -07003561 if (qseecom.qseos_version > QSEEE_VERSION_00)
3562 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003563
Mona Hossain17a4faf2013-03-22 16:40:56 -07003564 if (qseecom.qsee_perf_client)
3565 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3566 0);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003567 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003568 if (pdev->dev.of_node) {
3569 __qseecom_deinit_clk(CLK_QSEE);
3570 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3571 __qseecom_deinit_clk(CLK_CE_DRV);
3572 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003573 return ret;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003574};
3575
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003576static struct of_device_id qseecom_match[] = {
3577 {
3578 .compatible = "qcom,qseecom",
3579 },
3580 {}
3581};
3582
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003583static struct platform_driver qseecom_plat_driver = {
3584 .probe = qseecom_probe,
3585 .remove = qseecom_remove,
3586 .driver = {
3587 .name = "qseecom",
3588 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003589 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003590 },
3591};
3592
3593static int __devinit qseecom_init(void)
3594{
3595 return platform_driver_register(&qseecom_plat_driver);
3596}
3597
3598static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003599{
Mona Hossain2892b6b2012-02-17 13:53:11 -08003600 device_destroy(driver_class, qseecom_device_no);
3601 class_destroy(driver_class);
3602 unregister_chrdev_region(qseecom_device_no, 1);
3603 ion_client_destroy(qseecom.ion_clnt);
3604}
3605
3606MODULE_LICENSE("GPL v2");
3607MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3608
3609module_init(qseecom_init);
3610module_exit(qseecom_exit);