blob: a1c7aac765e5172df79c647492e7893eecc9a511 [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 *
Zhen Kongca39e442013-12-25 22:57:08 -08003 * Copyright (c) 2012-2014, 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
Zhen Kong2edf90d2013-08-27 12:05:06 -070074#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
75#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
76
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070077enum qseecom_clk_definitions {
78 CLK_DFAB = 0,
79 CLK_SFPB,
80};
81
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080082enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053083 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080084 QSEECOM_LISTENER_SERVICE,
85 QSEECOM_SECURE_SERVICE,
86 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053087 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080088};
89
Mona Hossainc92629e2013-04-01 13:37:46 -070090enum qseecom_ce_hw_instance {
91 CLK_QSEE = 0,
92 CLK_CE_DRV,
93};
94
Mona Hossain2892b6b2012-02-17 13:53:11 -080095static struct class *driver_class;
96static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -080097
Mona Hossain2892b6b2012-02-17 13:53:11 -080098static DEFINE_MUTEX(qsee_bw_mutex);
99static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -0700100static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800101
Mona Hossain2892b6b2012-02-17 13:53:11 -0800102struct qseecom_registered_listener_list {
103 struct list_head list;
104 struct qseecom_register_listener_req svc;
Zhen Kongf4948192013-11-25 13:05:35 -0800105 uint32_t user_virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800106 u8 *sb_virt;
107 s32 sb_phys;
108 size_t sb_length;
109 struct ion_handle *ihandle; /* Retrieve phy addr */
110
111 wait_queue_head_t rcv_req_wq;
112 int rcv_req_flag;
113};
114
115struct qseecom_registered_app_list {
116 struct list_head list;
117 u32 app_id;
118 u32 ref_cnt;
119};
120
Mona Hossaind44a3842012-10-15 09:41:35 -0700121struct qseecom_registered_kclient_list {
122 struct list_head list;
123 struct qseecom_handle *handle;
124};
125
Mona Hossain4cf78a92013-02-14 12:06:41 -0800126struct ce_hw_usage_info {
127 uint32_t qsee_ce_hw_instance;
128 uint32_t hlos_ce_hw_instance;
129 uint32_t disk_encrypt_pipe;
130};
131
Mona Hossain17a4faf2013-03-22 16:40:56 -0700132struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700133 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700134 struct clk *ce_core_clk;
135 struct clk *ce_clk;
136 struct clk *ce_core_src_clk;
137 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700138 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700139};
140
Mona Hossain2892b6b2012-02-17 13:53:11 -0800141struct qseecom_control {
142 struct ion_client *ion_clnt; /* Ion client */
143 struct list_head registered_listener_list_head;
144 spinlock_t registered_listener_list_lock;
145
146 struct list_head registered_app_list_head;
147 spinlock_t registered_app_list_lock;
148
Mona Hossaind44a3842012-10-15 09:41:35 -0700149 struct list_head registered_kclient_list_head;
150 spinlock_t registered_kclient_list_lock;
151
Mona Hossain2892b6b2012-02-17 13:53:11 -0800152 wait_queue_head_t send_resp_wq;
153 int send_resp_flag;
154
155 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700156 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700157 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700158 bool commonlib_loaded;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800159 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700160
161 int qsee_bw_count;
162 int qsee_sfpb_bw_count;
163
164 uint32_t qsee_perf_client;
165 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700166 struct qseecom_clk ce_drv;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700167
168 bool support_bus_scaling;
169 uint32_t cumulative_mode;
170 enum qseecom_bandwidth_request_mode current_mode;
171 struct timer_list bw_scale_down_timer;
172 struct work_struct bw_inactive_req_ws;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800173 struct cdev cdev;
174 bool timer_running;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800175};
176
177struct qseecom_client_handle {
178 u32 app_id;
179 u8 *sb_virt;
180 s32 sb_phys;
181 uint32_t user_virt_sb_base;
182 size_t sb_length;
183 struct ion_handle *ihandle; /* Retrieve phy addr */
184};
185
186struct qseecom_listener_handle {
187 u32 id;
188};
189
190static struct qseecom_control qseecom;
191
192struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800193 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800194 union {
195 struct qseecom_client_handle client;
196 struct qseecom_listener_handle listener;
197 };
198 bool released;
199 int abort;
200 wait_queue_head_t abort_wq;
201 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700202 bool perf_enabled;
203 bool fast_load_enabled;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700204 enum qseecom_bandwidth_request_mode mode;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800205};
206
Mona Hossain4cf78a92013-02-14 12:06:41 -0800207enum qseecom_set_clear_key_flag {
208 QSEECOM_CLEAR_CE_KEY_CMD = 0,
209 QSEECOM_SET_CE_KEY_CMD,
210};
211
212struct qseecom_set_key_parameter {
213 uint32_t ce_hw;
214 uint32_t pipe;
215 uint32_t flags;
216 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
217 unsigned char hash32[QSEECOM_HASH_SIZE];
218 enum qseecom_set_clear_key_flag set_clear_key_flag;
219};
220
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800221struct qseecom_sg_entry {
222 uint32_t phys_addr;
223 uint32_t len;
224};
225
Zhen Kong9730ddf2013-12-17 16:49:43 -0800226uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = {
227 "Disk Encryption"
228};
229
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700230/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800231static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
232static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700233static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
234static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700235
Mona Hossain2892b6b2012-02-17 13:53:11 -0800236static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800237 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800238{
239 struct qseecom_registered_listener_list *ptr;
240 int unique = 1;
241 unsigned long flags;
242
243 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
244 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800245 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800246 pr_err("Service id: %u is already registered\n",
247 ptr->svc.listener_id);
248 unique = 0;
249 break;
250 }
251 }
252 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
253 return unique;
254}
255
256static struct qseecom_registered_listener_list *__qseecom_find_svc(
257 int32_t listener_id)
258{
259 struct qseecom_registered_listener_list *entry = NULL;
260 unsigned long flags;
261
262 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
263 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
264 {
265 if (entry->svc.listener_id == listener_id)
266 break;
267 }
268 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530269
270 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
271 pr_err("Service id: %u is not found\n", listener_id);
272 return NULL;
273 }
274
Mona Hossain2892b6b2012-02-17 13:53:11 -0800275 return entry;
276}
277
278static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
279 struct qseecom_dev_handle *handle,
280 struct qseecom_register_listener_req *listener)
281{
282 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800283 struct qseecom_register_listener_ireq req;
284 struct qseecom_command_scm_resp resp;
285 ion_phys_addr_t pa;
286
287 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800288 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
289 listener->ifd_data_fd);
Hariprasad Dhalinarasimha1401bc02014-02-18 13:46:37 -0800290 if (IS_ERR_OR_NULL(svc->ihandle)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800291 pr_err("Ion client could not retrieve the handle\n");
292 return -ENOMEM;
293 }
294
295 /* Get the physical address of the ION BUF */
296 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
297
298 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700299 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800300 svc->sb_phys = pa;
301
Mona Hossaind4613de2013-05-15 16:49:29 -0700302 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
303 req.listener_id = svc->svc.listener_id;
304 req.sb_len = svc->sb_length;
305 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800306
Mona Hossaind4613de2013-05-15 16:49:29 -0700307 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800308
Mona Hossaind4613de2013-05-15 16:49:29 -0700309 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800310 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700311 if (ret) {
312 pr_err("qseecom_scm_call failed with err: %d\n", ret);
313 return -EINVAL;
314 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800315
Mona Hossaind4613de2013-05-15 16:49:29 -0700316 if (resp.result != QSEOS_RESULT_SUCCESS) {
317 pr_err("Error SB registration req: resp.result = %d\n",
318 resp.result);
319 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800320 }
321 return 0;
322}
323
324static int qseecom_register_listener(struct qseecom_dev_handle *data,
325 void __user *argp)
326{
327 int ret = 0;
328 unsigned long flags;
329 struct qseecom_register_listener_req rcvd_lstnr;
330 struct qseecom_registered_listener_list *new_entry;
331
332 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
333 if (ret) {
334 pr_err("copy_from_user failed\n");
335 return ret;
336 }
Zhen Kongf4948192013-11-25 13:05:35 -0800337 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
338 rcvd_lstnr.sb_size))
339 return -EFAULT;
340
Mona Hossain0af10ab2012-02-28 18:26:41 -0800341 data->listener.id = 0;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700342 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800343 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800344 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800345 data->released = true;
346 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800347 }
348
349 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
350 if (!new_entry) {
351 pr_err("kmalloc failed\n");
352 return -ENOMEM;
353 }
354 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
355 new_entry->rcv_req_flag = 0;
356
357 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
358 new_entry->sb_length = rcvd_lstnr.sb_size;
Zhen Kongf4948192013-11-25 13:05:35 -0800359 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800360 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
361 pr_err("qseecom_set_sb_memoryfailed\n");
362 kzfree(new_entry);
363 return -ENOMEM;
364 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800365
Mona Hossain2892b6b2012-02-17 13:53:11 -0800366 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800367 init_waitqueue_head(&new_entry->rcv_req_wq);
368
369 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
370 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
371 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800372
Mona Hossain2892b6b2012-02-17 13:53:11 -0800373 return ret;
374}
375
376static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
377{
378 int ret = 0;
379 unsigned long flags;
380 uint32_t unmap_mem = 0;
381 struct qseecom_register_listener_ireq req;
382 struct qseecom_registered_listener_list *ptr_svc = NULL;
383 struct qseecom_command_scm_resp resp;
384 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
385
Mona Hossaind4613de2013-05-15 16:49:29 -0700386 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
387 req.listener_id = data->listener.id;
388 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800389
Mona Hossaind4613de2013-05-15 16:49:29 -0700390 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800391 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700392 if (ret) {
393 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
394 ret, data->listener.id);
395 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800396 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700397
398 if (resp.result != QSEOS_RESULT_SUCCESS) {
399 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
400 resp.result, data->listener.id);
401 return -EPERM;
402 }
403
Mona Hossain2892b6b2012-02-17 13:53:11 -0800404 data->abort = 1;
405 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
406 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
407 list) {
408 if (ptr_svc->svc.listener_id == data->listener.id) {
409 wake_up_all(&ptr_svc->rcv_req_wq);
410 break;
411 }
412 }
413 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
414
415 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700416 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800417 atomic_read(&data->ioctl_count) <= 1)) {
418 pr_err("Interrupted from abort\n");
419 ret = -ERESTARTSYS;
420 break;
421 }
422 }
423
424 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
425 list_for_each_entry(ptr_svc,
426 &qseecom.registered_listener_list_head,
427 list)
428 {
429 if (ptr_svc->svc.listener_id == data->listener.id) {
430 if (ptr_svc->sb_virt) {
431 unmap_mem = 1;
432 ihandle = ptr_svc->ihandle;
433 }
434 list_del(&ptr_svc->list);
435 kzfree(ptr_svc);
436 break;
437 }
438 }
439 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
440
441 /* Unmap the memory */
442 if (unmap_mem) {
443 if (!IS_ERR_OR_NULL(ihandle)) {
444 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
445 ion_free(qseecom.ion_clnt, ihandle);
446 }
447 }
448 data->released = true;
449 return ret;
450}
451
Zhen Kong2edf90d2013-08-27 12:05:06 -0700452static int __qseecom_set_msm_bus_request(uint32_t mode)
453{
454 int ret = 0;
455 struct qseecom_clk *qclk;
456
457 qclk = &qseecom.qsee;
458 if (qclk->ce_core_src_clk != NULL) {
459 if (mode == INACTIVE) {
460 __qseecom_disable_clk(CLK_QSEE);
461 } else {
462 ret = __qseecom_enable_clk(CLK_QSEE);
463 if (ret)
464 pr_err("CLK enabling failed (%d) MODE (%d)\n",
465 ret, mode);
466 }
467 }
468
469 if ((!ret) && (qseecom.current_mode != mode)) {
470 ret = msm_bus_scale_client_update_request(
471 qseecom.qsee_perf_client, mode);
472 if (ret) {
473 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
474 ret, mode);
475 if (qclk->ce_core_src_clk != NULL) {
476 if (mode == INACTIVE)
477 __qseecom_enable_clk(CLK_QSEE);
478 else
479 __qseecom_disable_clk(CLK_QSEE);
480 }
481 }
482 qseecom.current_mode = mode;
483 }
484 return ret;
485}
486
487static void qseecom_bw_inactive_req_work(struct work_struct *work)
488{
489 mutex_lock(&app_access_lock);
490 mutex_lock(&qsee_bw_mutex);
491 __qseecom_set_msm_bus_request(INACTIVE);
492 pr_debug("current_mode = %d, cumulative_mode = %d\n",
493 qseecom.current_mode, qseecom.cumulative_mode);
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800494 qseecom.timer_running = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700495 mutex_unlock(&qsee_bw_mutex);
496 mutex_unlock(&app_access_lock);
497 return;
498}
499
500static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
501{
502 schedule_work(&qseecom.bw_inactive_req_ws);
503 return;
504}
505
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800506static void __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
507{
508 struct qseecom_clk *qclk;
509 mutex_lock(&clk_access_lock);
510 if (ce == CLK_QSEE)
511 qclk = &qseecom.qsee;
512 else
513 qclk = &qseecom.ce_drv;
514
515 if (qclk->clk_access_cnt == 0) {
516 mutex_unlock(&clk_access_lock);
517 return;
518 }
519 qclk->clk_access_cnt--;
520 mutex_unlock(&clk_access_lock);
521 return;
522}
523
524
Zhen Kong2edf90d2013-08-27 12:05:06 -0700525static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
526{
527 int32_t ret = 0;
528 int32_t request_mode = INACTIVE;
529
530 mutex_lock(&qsee_bw_mutex);
531 if (mode == 0) {
532 if (qseecom.cumulative_mode > MEDIUM)
533 request_mode = HIGH;
534 else
535 request_mode = qseecom.cumulative_mode;
536 } else {
537 request_mode = mode;
538 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700539
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800540 __qseecom_set_msm_bus_request(request_mode);
541 if (qseecom.timer_running) {
542 __qseecom_decrease_clk_ref_count(CLK_QSEE);
543 del_timer_sync(&(qseecom.bw_scale_down_timer));
544 }
Zhen Konge8a02082014-03-11 17:36:50 -0700545 qseecom.bw_scale_down_timer.expires = jiffies +
546 msecs_to_jiffies(duration);
547 add_timer(&(qseecom.bw_scale_down_timer));
548 qseecom.timer_running = true;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700549 mutex_unlock(&qsee_bw_mutex);
550 return ret;
551}
552
553
554static int qseecom_unregister_bus_bandwidth_needs(
555 struct qseecom_dev_handle *data)
556{
557 int32_t ret = 0;
558
559 qseecom.cumulative_mode -= data->mode;
560 data->mode = INACTIVE;
561
562 return ret;
563}
564
565static int __qseecom_register_bus_bandwidth_needs(
566 struct qseecom_dev_handle *data, uint32_t request_mode)
567{
568 int32_t ret = 0;
569
570 if (data->mode == INACTIVE) {
571 qseecom.cumulative_mode += request_mode;
572 data->mode = request_mode;
573 } else {
574 if (data->mode != request_mode) {
575 qseecom.cumulative_mode -= data->mode;
576 qseecom.cumulative_mode += request_mode;
577 data->mode = request_mode;
578 }
579 }
580 return ret;
581}
582
583static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
584 void __user *argp)
585{
586 int32_t ret = 0;
587 int32_t req_mode;
588
589 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
590 if (ret) {
591 pr_err("copy_from_user failed\n");
592 return ret;
593 }
594 if (req_mode > HIGH) {
595 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
596 return ret;
597 }
598 mutex_lock(&qsee_bw_mutex);
599 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
600 mutex_unlock(&qsee_bw_mutex);
601
602 return ret;
603}
604
605static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
606{
607 if (!qseecom.support_bus_scaling)
608 qsee_disable_clock_vote(data, CLK_SFPB);
609 return;
610}
611
612static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
613{
614 int ret = 0;
615 if (qseecom.support_bus_scaling) {
616 qseecom_scale_bus_bandwidth_timer(
617 MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
618 } else {
619 ret = qsee_vote_for_clock(data, CLK_SFPB);
620 if (ret)
621 pr_err("Fail vote for clk SFPB ret %d\n", ret);
622 }
623 return ret;
624}
625
Mona Hossain2892b6b2012-02-17 13:53:11 -0800626static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
627 void __user *argp)
628{
629 ion_phys_addr_t pa;
630 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800631 struct qseecom_set_sb_mem_param_req req;
632 uint32_t len;
633
634 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700635 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800636 return -EFAULT;
637
Mona Hossaina1124de2013-10-01 13:41:09 -0700638 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
639 (req.sb_len == 0)) {
640 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
641 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
642 return -EFAULT;
643 }
Zhen Kongf4948192013-11-25 13:05:35 -0800644 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
645 req.sb_len))
646 return -EFAULT;
647
Mona Hossain2892b6b2012-02-17 13:53:11 -0800648 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800649 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
650 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800651 if (IS_ERR_OR_NULL(data->client.ihandle)) {
652 pr_err("Ion client could not retrieve the handle\n");
653 return -ENOMEM;
654 }
655 /* Get the physical address of the ION BUF */
656 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
657 /* Populate the structure for sending scm call to load image */
658 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700659 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800660 data->client.sb_phys = pa;
661 data->client.sb_length = req.sb_len;
662 data->client.user_virt_sb_base = req.virt_sb_base;
663 return 0;
664}
665
Mona Hossain2892b6b2012-02-17 13:53:11 -0800666static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
667{
668 int ret;
669 ret = (qseecom.send_resp_flag != 0);
670 return ret || data->abort;
671}
672
673static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
674 struct qseecom_command_scm_resp *resp)
675{
676 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800677 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800678 uint32_t lstnr;
679 unsigned long flags;
680 struct qseecom_client_listener_data_irsp send_data_rsp;
681 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700682 sigset_t new_sigset;
683 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800684
Mona Hossain2892b6b2012-02-17 13:53:11 -0800685 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
686 lstnr = resp->data;
687 /*
688 * Wake up blocking lsitener service with the lstnr id
689 */
690 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
691 flags);
692 list_for_each_entry(ptr_svc,
693 &qseecom.registered_listener_list_head, list) {
694 if (ptr_svc->svc.listener_id == lstnr) {
695 ptr_svc->rcv_req_flag = 1;
696 wake_up_interruptible(&ptr_svc->rcv_req_wq);
697 break;
698 }
699 }
700 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
701 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700702
703 if (ptr_svc == NULL) {
704 pr_err("Listener Svc %d does not exist\n", lstnr);
705 return -EINVAL;
706 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800707 if (ptr_svc->svc.listener_id != lstnr) {
708 pr_warning("Service requested for does on exist\n");
709 return -ERESTARTSYS;
710 }
711 pr_debug("waking up rcv_req_wq and "
712 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800713
Mona Hossain91da2c52013-03-29 17:28:31 -0700714 /* initialize the new signal mask with all signals*/
715 sigfillset(&new_sigset);
716 /* block all signals */
717 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
718
719 do {
720 if (!wait_event_freezable(qseecom.send_resp_wq,
721 __qseecom_listener_has_sent_rsp(data)))
722 break;
723 } while (1);
724
725 /* restore signal mask */
726 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
727 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700728 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
729 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700730 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800731 send_data_rsp.status = QSEOS_RESULT_FAILURE;
732 } else {
733 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800734 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800735
Mona Hossain2892b6b2012-02-17 13:53:11 -0800736 qseecom.send_resp_flag = 0;
737 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
738 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700739 if (ptr_svc)
740 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
741 ptr_svc->sb_virt, ptr_svc->sb_length,
742 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700743
744 if (lstnr == RPMB_SERVICE)
745 __qseecom_enable_clk(CLK_QSEE);
746
Mona Hossain2892b6b2012-02-17 13:53:11 -0800747 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
748 (const void *)&send_data_rsp,
749 sizeof(send_data_rsp), resp,
750 sizeof(*resp));
751 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700752 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800753 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700754 if (lstnr == RPMB_SERVICE)
755 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800756 return ret;
757 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800758 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
759 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
760 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
761 resp->result, data->client.app_id, lstnr);
762 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700763 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700764 if (lstnr == RPMB_SERVICE)
765 __qseecom_disable_clk(CLK_QSEE);
766
Mona Hossain2892b6b2012-02-17 13:53:11 -0800767 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800768 if (rc)
769 return rc;
770
Mona Hossain2892b6b2012-02-17 13:53:11 -0800771 return ret;
772}
773
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700774static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
775{
776 int32_t ret;
777 struct qseecom_command_scm_resp resp;
778
779 /* SCM_CALL to check if app_id for the mentioned app exists */
780 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
781 sizeof(struct qseecom_check_app_ireq),
782 &resp, sizeof(resp));
783 if (ret) {
784 pr_err("scm_call to check if app is already loaded failed\n");
785 return -EINVAL;
786 }
787
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700788 if (resp.result == QSEOS_RESULT_FAILURE) {
789 return 0;
790 } else {
791 switch (resp.resp_type) {
792 /*qsee returned listener type response */
793 case QSEOS_LISTENER_ID:
794 pr_err("resp type is of listener type instead of app");
795 return -EINVAL;
796 break;
797 case QSEOS_APP_ID:
798 return resp.data;
799 default:
800 pr_err("invalid resp type (%d) from qsee",
801 resp.resp_type);
802 return -ENODEV;
803 break;
804 }
805 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700806}
807
Mona Hossain2892b6b2012-02-17 13:53:11 -0800808static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
809{
810 struct qseecom_registered_app_list *entry = NULL;
811 unsigned long flags = 0;
812 u32 app_id = 0;
813 struct ion_handle *ihandle; /* Ion handle */
814 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700815 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800816 ion_phys_addr_t pa = 0;
817 uint32_t len;
818 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800819 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700820 struct qseecom_load_app_ireq load_req;
821
Mona Hossain2892b6b2012-02-17 13:53:11 -0800822 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700823 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800824 (void __user *)argp,
825 sizeof(struct qseecom_load_img_req))) {
826 pr_err("copy_from_user failed\n");
827 return -EFAULT;
828 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700829 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700830 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700831 if (ret)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700832 return ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800833 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700834 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800835 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800836
Mona Hossain436b75f2012-11-20 17:10:40 -0800837 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530838 if (ret < 0) {
Zhen Kong2edf90d2013-08-27 12:05:06 -0700839 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800840 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530841 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800842
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530843 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800844 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700845 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800846 (char *)(req.app_name));
847 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
848 list_for_each_entry(entry,
849 &qseecom.registered_app_list_head, list){
850 if (entry->app_id == app_id) {
851 entry->ref_cnt++;
852 break;
853 }
854 }
855 spin_unlock_irqrestore(
856 &qseecom.registered_app_list_lock, flags);
857 } else {
858 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700859 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800860 /* Get the handle of the shared fd */
861 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800862 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800863 if (IS_ERR_OR_NULL(ihandle)) {
864 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700865 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800866 return -ENOMEM;
867 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800868
Mona Hossain436b75f2012-11-20 17:10:40 -0800869 /* Get the physical address of the ION BUF */
870 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800871
Mona Hossain436b75f2012-11-20 17:10:40 -0800872 /* Populate the structure for sending scm call to load image */
873 memcpy(load_req.app_name, load_img_req.img_name,
874 MAX_APP_NAME_SIZE);
875 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
876 load_req.mdt_len = load_img_req.mdt_len;
877 load_req.img_len = load_img_req.img_len;
878 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700879 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
880 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800881
Mona Hossain436b75f2012-11-20 17:10:40 -0800882 /* SCM_CALL to load the app and get the app_id back */
883 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700884 sizeof(struct qseecom_load_app_ireq),
885 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700886 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800887 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800888 if (!IS_ERR_OR_NULL(ihandle))
889 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700890 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800891 return -EINVAL;
892 }
893
894 if (resp.result == QSEOS_RESULT_FAILURE) {
895 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700896 if (!IS_ERR_OR_NULL(ihandle))
897 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700898 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800899 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700900 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700901
Mona Hossain436b75f2012-11-20 17:10:40 -0800902 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
903 ret = __qseecom_process_incomplete_cmd(data, &resp);
904 if (ret) {
905 pr_err("process_incomplete_cmd failed err: %d\n",
906 ret);
907 if (!IS_ERR_OR_NULL(ihandle))
908 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700909 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800910 return ret;
911 }
912 }
913
914 if (resp.result != QSEOS_RESULT_SUCCESS) {
915 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700916 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800917 if (!IS_ERR_OR_NULL(ihandle))
918 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700919 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800920 return -EFAULT;
921 }
922
923 app_id = resp.data;
924
925 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
926 if (!entry) {
927 pr_err("kmalloc failed\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700928 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800929 return -ENOMEM;
930 }
931 entry->app_id = app_id;
932 entry->ref_cnt = 1;
933
934 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700935 if (!IS_ERR_OR_NULL(ihandle))
936 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700937
Mona Hossain436b75f2012-11-20 17:10:40 -0800938 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
939 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
940 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
941 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700942
Mona Hossain436b75f2012-11-20 17:10:40 -0800943 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700944 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800945 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800946 data->client.app_id = app_id;
947 load_img_req.app_id = app_id;
948 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
949 pr_err("copy_to_user failed\n");
950 kzfree(entry);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700951 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800952 return -EFAULT;
953 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700954 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800955 return 0;
956}
957
958static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
959{
960 wake_up_all(&qseecom.send_resp_wq);
961 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700962 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800963 atomic_read(&data->ioctl_count) <= 1)) {
964 pr_err("Interrupted from abort\n");
965 return -ERESTARTSYS;
966 break;
967 }
968 }
969 /* Set unload app */
970 return 1;
971}
972
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800973static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
974{
975 int ret = 0;
976 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
977 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
978 ion_free(qseecom.ion_clnt, data->client.ihandle);
979 data->client.ihandle = NULL;
980 }
981 return ret;
982}
983
Mona Hossain2892b6b2012-02-17 13:53:11 -0800984static int qseecom_unload_app(struct qseecom_dev_handle *data)
985{
986 unsigned long flags;
987 int ret = 0;
988 struct qseecom_command_scm_resp resp;
989 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700990 bool unload = false;
991 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800992
Mona Hossaind4613de2013-05-15 16:49:29 -0700993 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800994 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
995 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
996 list) {
997 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700998 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800999 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -07001000 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001001 break;
1002 } else {
1003 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -07001004 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001005 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001006 break;
1007 }
1008 }
1009 }
1010 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1011 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001012 if (found_app == false) {
1013 pr_err("Cannot find app with id = %d\n",
1014 data->client.app_id);
1015 return -EINVAL;
1016 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001017 }
1018
Mona Hossaind4613de2013-05-15 16:49:29 -07001019 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001020 struct qseecom_unload_app_ireq req;
1021
Mona Hossain340dba82012-08-07 19:54:46 -07001022 __qseecom_cleanup_app(data);
1023 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1024 list_del(&ptr_app->list);
1025 kzfree(ptr_app);
1026 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1027 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001028 /* Populate the structure for sending scm call to load image */
1029 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1030 req.app_id = data->client.app_id;
1031
1032 /* SCM_CALL to unload the app */
1033 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1034 sizeof(struct qseecom_unload_app_ireq),
1035 &resp, sizeof(resp));
1036 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001037 pr_err("scm_call to unload app (id = %d) failed\n",
1038 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001039 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001040 } else {
1041 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001042 }
1043 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1044 ret = __qseecom_process_incomplete_cmd(data, &resp);
1045 if (ret) {
1046 pr_err("process_incomplete_cmd fail err: %d\n",
1047 ret);
1048 return ret;
1049 }
1050 }
1051 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001052 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001053 data->released = true;
1054 return ret;
1055}
1056
1057static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1058 uint32_t virt)
1059{
1060 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1061}
1062
Zhen Kongf4948192013-11-25 13:05:35 -08001063static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1064 uint32_t virt)
1065{
1066 return (uint32_t)data->client.sb_virt +
1067 (virt - data->client.user_virt_sb_base);
1068}
1069
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001070int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1071 struct qseecom_send_svc_cmd_req *req_ptr,
1072 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1073{
1074 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001075 void *req_buf = NULL;
1076
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001077 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1078 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1079 req_ptr, send_svc_ireq_ptr);
1080 return -EINVAL;
1081 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001082
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -08001083 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
1084 pr_err("Invalid req/resp buffer, exiting\n");
1085 return -EINVAL;
1086 }
1087
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001088 /* Clients need to ensure req_buf is at base offset of shared buffer */
1089 if ((uint32_t)req_ptr->cmd_req_buf !=
1090 data_ptr->client.user_virt_sb_base) {
1091 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001092 return -EINVAL;
1093 }
1094
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001095 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1096 || ((uint32_t)req_ptr->resp_buf >=
1097 (data_ptr->client.user_virt_sb_base +
1098 data_ptr->client.sb_length))){
1099 pr_err("response buffer address not within shared bufffer\n");
1100 return -EINVAL;
1101 }
1102
1103 req_buf = data_ptr->client.sb_virt;
1104
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001105 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1106 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001107 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001108 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1109 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1110 (uint32_t)req_ptr->resp_buf));
1111 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1112
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001113 return ret;
1114}
1115
1116static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1117 void __user *argp)
1118{
1119 int ret = 0;
1120 struct qseecom_client_send_service_ireq send_svc_ireq;
1121 struct qseecom_command_scm_resp resp;
1122 struct qseecom_send_svc_cmd_req req;
1123 /*struct qseecom_command_scm_resp resp;*/
1124
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001125 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001126 (void __user *)argp,
1127 sizeof(req))) {
1128 pr_err("copy_from_user failed\n");
1129 return -EFAULT;
1130 }
1131
1132 if (req.resp_buf == NULL) {
1133 pr_err("cmd buffer or response buffer is null\n");
1134 return -EINVAL;
1135 }
1136
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001137 if (data->client.sb_virt == NULL) {
1138 pr_err("sb_virt null\n");
1139 return -EINVAL;
1140 }
1141
1142 if (data->client.user_virt_sb_base == 0) {
1143 pr_err("user_virt_sb_base is null\n");
1144 return -EINVAL;
1145 }
1146
1147 if (data->client.sb_length == 0) {
1148 pr_err("sb_length is 0\n");
1149 return -EINVAL;
1150 }
1151
Zhen Kong2edf90d2013-08-27 12:05:06 -07001152 data->type = QSEECOM_SECURE_SERVICE;
1153
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001154 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001155 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1156 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001157 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1158 &send_svc_ireq))
1159 return -EINVAL;
1160 break;
1161 default:
1162 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1163 return -EINVAL;
1164 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301165
Zhen Kong2edf90d2013-08-27 12:05:06 -07001166 if (qseecom.support_bus_scaling) {
1167 qseecom_scale_bus_bandwidth_timer(HIGH,
1168 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1169 if (ret) {
1170 pr_err("Fail to set bw HIGH%d\n", ret);
1171 return ret;
1172 }
1173 } else {
1174 ret = qsee_vote_for_clock(data, CLK_DFAB);
1175 if (ret) {
1176 pr_err("Failed to vote for DFAB clock%d\n", ret);
1177 return ret;
1178 }
1179 ret = qsee_vote_for_clock(data, CLK_SFPB);
1180 if (ret) {
1181 qsee_disable_clock_vote(data, CLK_DFAB);
1182 pr_err("Failed to vote for SFPB clock%d\n", ret);
1183 goto exit;
1184 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301185 }
1186
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001187 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1188 data->client.sb_virt, data->client.sb_length,
1189 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001190 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1191 sizeof(send_svc_ireq),
1192 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001193 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1194 data->client.sb_virt, data->client.sb_length,
1195 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001196 if (ret) {
1197 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001198 if (!qseecom.support_bus_scaling) {
1199 qsee_disable_clock_vote(data, CLK_DFAB);
1200 qsee_disable_clock_vote(data, CLK_SFPB);
1201 }
1202 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001203 }
1204
1205 switch (resp.result) {
1206 case QSEOS_RESULT_SUCCESS:
1207 break;
1208 case QSEOS_RESULT_INCOMPLETE:
1209 pr_err("qseos_result_incomplete\n");
1210 ret = __qseecom_process_incomplete_cmd(data, &resp);
1211 if (ret) {
1212 pr_err("process_incomplete_cmd fail: err: %d\n",
1213 ret);
1214 }
1215 break;
1216 case QSEOS_RESULT_FAILURE:
1217 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1218 break;
1219 default:
1220 pr_err("Response result %d not supported\n",
1221 resp.result);
1222 ret = -EINVAL;
1223 break;
1224 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001225exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001226 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001227}
1228
Mona Hossain2892b6b2012-02-17 13:53:11 -08001229static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1230 struct qseecom_send_cmd_req *req)
1231{
1232 int ret = 0;
1233 u32 reqd_len_sb_in = 0;
1234 struct qseecom_client_send_data_ireq send_data_req;
1235 struct qseecom_command_scm_resp resp;
1236
1237 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1238 pr_err("cmd buffer or response buffer is null\n");
1239 return -EINVAL;
1240 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001241 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1242 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1243 data->client.sb_length))) {
1244 pr_err("cmd buffer address not within shared bufffer\n");
1245 return -EINVAL;
1246 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001247
Mona Hossaindddf4442013-10-01 14:08:20 -07001248
1249 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1250 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1251 data->client.sb_length))){
1252 pr_err("response buffer address not within shared bufffer\n");
1253 return -EINVAL;
1254 }
1255
1256 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001257 req->cmd_req_len > data->client.sb_length ||
1258 req->resp_len > data->client.sb_length) {
1259 pr_err("cmd buffer length or "
1260 "response buffer length not valid\n");
1261 return -EINVAL;
1262 }
1263
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001264 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1265 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1266 return -EINVAL;
1267 }
1268
Mona Hossain2892b6b2012-02-17 13:53:11 -08001269 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1270 if (reqd_len_sb_in > data->client.sb_length) {
1271 pr_debug("Not enough memory to fit cmd_buf and "
1272 "resp_buf. Required: %u, Available: %u\n",
1273 reqd_len_sb_in, data->client.sb_length);
1274 return -ENOMEM;
1275 }
1276
1277 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1278 send_data_req.app_id = data->client.app_id;
1279 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1280 (uint32_t)req->cmd_req_buf));
1281 send_data_req.req_len = req->cmd_req_len;
1282 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1283 (uint32_t)req->resp_buf));
1284 send_data_req.rsp_len = req->resp_len;
1285
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001286 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1287 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001288 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001289 ION_IOC_CLEAN_INV_CACHES);
1290
Mona Hossain2892b6b2012-02-17 13:53:11 -08001291 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1292 sizeof(send_data_req),
1293 &resp, sizeof(resp));
1294 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001295 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1296 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001297 return ret;
1298 }
1299
1300 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1301 ret = __qseecom_process_incomplete_cmd(data, &resp);
1302 if (ret) {
1303 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1304 return ret;
1305 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001306 } else {
1307 if (resp.result != QSEOS_RESULT_SUCCESS) {
1308 pr_err("Response result %d not supported\n",
1309 resp.result);
1310 ret = -EINVAL;
1311 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001312 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001313 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1314 data->client.sb_virt, data->client.sb_length,
1315 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001316 return ret;
1317}
1318
Mona Hossain2892b6b2012-02-17 13:53:11 -08001319static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1320{
1321 int ret = 0;
1322 struct qseecom_send_cmd_req req;
1323
1324 ret = copy_from_user(&req, argp, sizeof(req));
1325 if (ret) {
1326 pr_err("copy_from_user failed\n");
1327 return ret;
1328 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001329 ret = __qseecom_send_cmd(data, &req);
1330
Mona Hossain2892b6b2012-02-17 13:53:11 -08001331 if (ret)
1332 return ret;
1333
Mona Hossain2892b6b2012-02-17 13:53:11 -08001334 return ret;
1335}
1336
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001337static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1338 struct qseecom_dev_handle *data,
1339 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001340{
1341 struct ion_handle *ihandle;
1342 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001343 int ret = 0;
1344 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001345 uint32_t len = 0;
1346 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001347 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1348 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1349 struct qseecom_registered_listener_list *this_lstnr = NULL;
1350
1351 if (msg == NULL) {
1352 pr_err("Invalid address\n");
1353 return -EINVAL;
1354 }
1355 if (listener_svc) {
1356 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1357 this_lstnr = __qseecom_find_svc(data->listener.id);
1358 if (IS_ERR_OR_NULL(this_lstnr)) {
1359 pr_err("Invalid listener ID\n");
1360 return -ENOMEM;
1361 }
1362 } else {
1363 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1364 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001365
1366 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001367 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001368 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001369 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001370 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001371 if (IS_ERR_OR_NULL(ihandle)) {
1372 pr_err("Ion client can't retrieve the handle\n");
1373 return -ENOMEM;
1374 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001375 field = (char *) cmd_req->cmd_req_buf +
1376 cmd_req->ifd_data[i].cmd_buf_offset;
1377 } else if ((listener_svc) &&
1378 (lstnr_resp->ifd_data[i].fd > 0)) {
1379 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1380 lstnr_resp->ifd_data[i].fd);
1381 if (IS_ERR_OR_NULL(ihandle)) {
1382 pr_err("Ion client can't retrieve the handle\n");
1383 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001384 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001385 field = lstnr_resp->resp_buf_ptr +
1386 lstnr_resp->ifd_data[i].cmd_buf_offset;
1387 } else {
1388 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001389 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001390 /* Populate the cmd data structure with the phys_addr */
1391 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1392 if (sg_ptr == NULL) {
1393 pr_err("IOn client could not retrieve sg table\n");
1394 goto err;
1395 }
1396 if (sg_ptr->nents == 0) {
1397 pr_err("Num of scattered entries is 0\n");
1398 goto err;
1399 }
1400 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1401 pr_err("Num of scattered entries");
1402 pr_err(" (%d) is greater than max supported %d\n",
1403 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1404 goto err;
1405 }
1406 sg = sg_ptr->sgl;
1407 if (sg_ptr->nents == 1) {
1408 uint32_t *update;
1409 update = (uint32_t *) field;
1410 if (cleanup)
1411 *update = 0;
1412 else
1413 *update = (uint32_t)sg_dma_address(
1414 sg_ptr->sgl);
1415 len += (uint32_t)sg->length;
1416 } else {
1417 struct qseecom_sg_entry *update;
1418 int j = 0;
1419 update = (struct qseecom_sg_entry *) field;
1420 for (j = 0; j < sg_ptr->nents; j++) {
1421 if (cleanup) {
1422 update->phys_addr = 0;
1423 update->len = 0;
1424 } else {
1425 update->phys_addr = (uint32_t)
1426 sg_dma_address(sg);
1427 update->len = sg->length;
1428 }
1429 len += sg->length;
1430 update++;
1431 sg = sg_next(sg);
1432 }
1433 }
1434 if (cleanup)
1435 msm_ion_do_cache_op(qseecom.ion_clnt,
1436 ihandle, NULL, len,
1437 ION_IOC_INV_CACHES);
1438 else
1439 msm_ion_do_cache_op(qseecom.ion_clnt,
1440 ihandle, NULL, len,
1441 ION_IOC_CLEAN_INV_CACHES);
1442 /* Deallocate the handle */
1443 if (!IS_ERR_OR_NULL(ihandle))
1444 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001445 }
1446 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001447err:
1448 if (!IS_ERR_OR_NULL(ihandle))
1449 ion_free(qseecom.ion_clnt, ihandle);
1450 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001451}
1452
1453static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1454 void __user *argp)
1455{
1456 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001457 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001458 struct qseecom_send_modfd_cmd_req req;
1459 struct qseecom_send_cmd_req send_cmd_req;
1460
1461 ret = copy_from_user(&req, argp, sizeof(req));
1462 if (ret) {
1463 pr_err("copy_from_user failed\n");
1464 return ret;
1465 }
Zhen Kongf4948192013-11-25 13:05:35 -08001466
1467 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1468 pr_err("cmd buffer or response buffer is null\n");
1469 return -EINVAL;
1470 }
1471 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1472 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1473 data->client.sb_length))) {
1474 pr_err("cmd buffer address not within shared bufffer\n");
1475 return -EINVAL;
1476 }
1477
1478 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1479 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1480 data->client.sb_length))){
1481 pr_err("response buffer address not within shared bufffer\n");
1482 return -EINVAL;
1483 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001484 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1485 send_cmd_req.cmd_req_len = req.cmd_req_len;
1486 send_cmd_req.resp_buf = req.resp_buf;
1487 send_cmd_req.resp_len = req.resp_len;
1488
Mona Hossaindddf4442013-10-01 14:08:20 -07001489 /* validate offsets */
1490 for (i = 0; i < MAX_ION_FD; i++) {
1491 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1492 pr_err("Invalid offset %d = 0x%x\n",
1493 i, req.ifd_data[i].cmd_buf_offset);
1494 return -EINVAL;
1495 }
1496 }
Zhen Kongf4948192013-11-25 13:05:35 -08001497 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1498 (uint32_t)req.cmd_req_buf);
1499 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1500 (uint32_t)req.resp_buf);
1501
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001502 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001503 if (ret)
1504 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001505 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001506 if (ret)
1507 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001508 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001509 if (ret)
1510 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001511
Mona Hossain2892b6b2012-02-17 13:53:11 -08001512 return ret;
1513}
1514
1515static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1516 struct qseecom_registered_listener_list *svc)
1517{
1518 int ret;
1519 ret = (svc->rcv_req_flag != 0);
1520 return ret || data->abort;
1521}
1522
1523static int qseecom_receive_req(struct qseecom_dev_handle *data)
1524{
1525 int ret = 0;
1526 struct qseecom_registered_listener_list *this_lstnr;
1527
1528 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301529 if (!this_lstnr) {
1530 pr_err("Invalid listener ID\n");
1531 return -ENODATA;
1532 }
1533
Mona Hossain2892b6b2012-02-17 13:53:11 -08001534 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001535 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001536 __qseecom_listener_has_rcvd_req(data,
1537 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001538 pr_warning("Interrupted: exiting Listener Service = %d\n",
1539 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001540 /* woken up for different reason */
1541 return -ERESTARTSYS;
1542 }
1543
1544 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001545 pr_err("Aborting Listener Service = %d\n",
1546 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001547 return -ENODEV;
1548 }
1549 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001550 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001551 }
1552 return ret;
1553}
1554
Mona Hossaind44a3842012-10-15 09:41:35 -07001555static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1556{
1557 struct elf32_hdr *ehdr;
1558
1559 if (fw_entry->size < sizeof(*ehdr)) {
1560 pr_err("%s: Not big enough to be an elf header\n",
1561 qseecom.pdev->init_name);
1562 return false;
1563 }
1564 ehdr = (struct elf32_hdr *)fw_entry->data;
1565 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1566 pr_err("%s: Not an elf header\n",
1567 qseecom.pdev->init_name);
1568 return false;
1569 }
1570
1571 if (ehdr->e_phnum == 0) {
1572 pr_err("%s: No loadable segments\n",
1573 qseecom.pdev->init_name);
1574 return false;
1575 }
1576 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1577 sizeof(struct elf32_hdr) > fw_entry->size) {
1578 pr_err("%s: Program headers not within mdt\n",
1579 qseecom.pdev->init_name);
1580 return false;
1581 }
1582 return true;
1583}
1584
1585static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1586{
1587 int ret = -1;
1588 int i = 0, rc = 0;
1589 const struct firmware *fw_entry = NULL;
1590 struct elf32_phdr *phdr;
1591 char fw_name[MAX_APP_NAME_SIZE];
1592 struct elf32_hdr *ehdr;
1593 int num_images = 0;
1594
1595 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1596 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1597 if (rc) {
1598 pr_err("error with request_firmware\n");
1599 ret = -EIO;
1600 goto err;
1601 }
1602 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1603 ret = -EIO;
1604 goto err;
1605 }
1606 *fw_size = fw_entry->size;
1607 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1608 ehdr = (struct elf32_hdr *)fw_entry->data;
1609 num_images = ehdr->e_phnum;
1610 release_firmware(fw_entry);
1611 for (i = 0; i < num_images; i++, phdr++) {
1612 memset(fw_name, 0, sizeof(fw_name));
1613 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1614 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1615 if (ret)
1616 goto err;
1617 *fw_size += fw_entry->size;
1618 release_firmware(fw_entry);
1619 }
1620 return ret;
1621err:
1622 if (fw_entry)
1623 release_firmware(fw_entry);
1624 *fw_size = 0;
1625 return ret;
1626}
1627
1628static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1629 struct qseecom_load_app_ireq *load_req)
1630{
1631 int ret = -1;
1632 int i = 0, rc = 0;
1633 const struct firmware *fw_entry = NULL;
1634 char fw_name[MAX_APP_NAME_SIZE];
1635 u8 *img_data_ptr = img_data;
1636 struct elf32_hdr *ehdr;
1637 int num_images = 0;
1638
1639 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1640 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1641 if (rc) {
1642 ret = -EIO;
1643 goto err;
1644 }
1645 load_req->img_len = fw_entry->size;
1646 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1647 img_data_ptr = img_data_ptr + fw_entry->size;
1648 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1649 ehdr = (struct elf32_hdr *)fw_entry->data;
1650 num_images = ehdr->e_phnum;
1651 release_firmware(fw_entry);
1652 for (i = 0; i < num_images; i++) {
1653 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1654 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1655 if (ret) {
1656 pr_err("Failed to locate blob %s\n", fw_name);
1657 goto err;
1658 }
1659 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1660 img_data_ptr = img_data_ptr + fw_entry->size;
1661 load_req->img_len += fw_entry->size;
1662 release_firmware(fw_entry);
1663 }
1664 load_req->phy_addr = virt_to_phys(img_data);
1665 return ret;
1666err:
1667 release_firmware(fw_entry);
1668 return ret;
1669}
1670
1671static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1672{
1673 int ret = -1;
1674 uint32_t fw_size = 0;
1675 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1676 struct qseecom_command_scm_resp resp;
1677 u8 *img_data = NULL;
1678
1679 if (__qseecom_get_fw_size(appname, &fw_size))
1680 return -EIO;
1681
1682 img_data = kzalloc(fw_size, GFP_KERNEL);
1683 if (!img_data) {
1684 pr_err("Failied to allocate memory for copying image data\n");
1685 return -ENOMEM;
1686 }
1687 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1688 if (ret) {
1689 kzfree(img_data);
1690 return -EIO;
1691 }
1692
1693 /* Populate the remaining parameters */
1694 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1695 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001696 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001697 if (ret) {
1698 kzfree(img_data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001699 return -EIO;
1700 }
1701
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001702 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001703 /* SCM_CALL to load the image */
1704 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1705 sizeof(struct qseecom_load_app_ireq),
1706 &resp, sizeof(resp));
1707 kzfree(img_data);
1708 if (ret) {
1709 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001710 __qseecom_disable_clk_scale_down(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001711 return -EIO;
1712 }
1713
1714 switch (resp.result) {
1715 case QSEOS_RESULT_SUCCESS:
1716 ret = resp.data;
1717 break;
1718 case QSEOS_RESULT_INCOMPLETE:
1719 ret = __qseecom_process_incomplete_cmd(data, &resp);
1720 if (ret)
1721 pr_err("process_incomplete_cmd FAILED\n");
1722 else
1723 ret = resp.data;
1724 break;
1725 case QSEOS_RESULT_FAILURE:
1726 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1727 break;
1728 default:
1729 pr_err("scm call return unknown response %d\n", resp.result);
1730 ret = -EINVAL;
1731 break;
1732 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001733 __qseecom_disable_clk_scale_down(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001734
Mona Hossaind44a3842012-10-15 09:41:35 -07001735 return ret;
1736}
1737
Mona Hossain9498f5e2013-01-23 18:08:45 -08001738static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001739{
1740 int32_t ret = 0;
1741 uint32_t fw_size = 0;
1742 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1743 struct qseecom_command_scm_resp resp;
1744 u8 *img_data = NULL;
1745
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001746 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001747 return -EIO;
1748
1749 img_data = kzalloc(fw_size, GFP_KERNEL);
1750 if (!img_data) {
1751 pr_err("Mem allocation for lib image data failed\n");
1752 return -ENOMEM;
1753 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001754 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001755 if (ret) {
1756 kzfree(img_data);
1757 return -EIO;
1758 }
1759 /* Populate the remaining parameters */
1760 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001761 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001762 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001763 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08001764 kzfree(img_data);
1765 return -EIO;
1766 }
1767
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001768 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001769 /* SCM_CALL to load the image */
1770 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1771 sizeof(struct qseecom_load_lib_image_ireq),
1772 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001773 if (ret) {
1774 pr_err("scm_call to load failed : ret %d\n", ret);
1775 ret = -EIO;
1776 } else {
1777 switch (resp.result) {
1778 case QSEOS_RESULT_SUCCESS:
1779 break;
1780 case QSEOS_RESULT_FAILURE:
1781 pr_err("scm call failed w/response result%d\n",
1782 resp.result);
1783 ret = -EINVAL;
1784 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001785 case QSEOS_RESULT_INCOMPLETE:
1786 ret = __qseecom_process_incomplete_cmd(data, &resp);
1787 if (ret)
1788 pr_err("process_incomplete_cmd failed err: %d\n",
1789 ret);
1790 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001791 default:
1792 pr_err("scm call return unknown response %d\n",
1793 resp.result);
1794 ret = -EINVAL;
1795 break;
1796 }
1797 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001798 kzfree(img_data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001799 __qseecom_disable_clk_scale_down(data);
Mona Hossain05c73562012-10-29 17:49:01 -07001800 return ret;
1801}
1802
1803static int qseecom_unload_commonlib_image(void)
1804{
1805 int ret = -EINVAL;
1806 struct qseecom_unload_lib_image_ireq unload_req = {0};
1807 struct qseecom_command_scm_resp resp;
1808
1809 /* Populate the remaining parameters */
1810 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1811 /* SCM_CALL to load the image */
1812 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1813 sizeof(struct qseecom_unload_lib_image_ireq),
1814 &resp, sizeof(resp));
1815 if (ret) {
1816 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1817 ret = -EIO;
1818 } else {
1819 switch (resp.result) {
1820 case QSEOS_RESULT_SUCCESS:
1821 break;
1822 case QSEOS_RESULT_FAILURE:
1823 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1824 break;
1825 default:
1826 pr_err("scm call return unknown response %d\n",
1827 resp.result);
1828 ret = -EINVAL;
1829 break;
1830 }
1831 }
1832 return ret;
1833}
1834
Mona Hossaind44a3842012-10-15 09:41:35 -07001835int qseecom_start_app(struct qseecom_handle **handle,
1836 char *app_name, uint32_t size)
1837{
Mona Hossain05c73562012-10-29 17:49:01 -07001838 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001839 unsigned long flags = 0;
1840 struct qseecom_dev_handle *data = NULL;
1841 struct qseecom_check_app_ireq app_ireq;
1842 struct qseecom_registered_app_list *entry = NULL;
1843 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1844 bool found_app = false;
1845 uint32_t len;
1846 ion_phys_addr_t pa;
1847
Mona Hossain823f9882012-11-23 14:42:20 -08001848 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1849 if (!(*handle)) {
1850 pr_err("failed to allocate memory for kernel client handle\n");
1851 return -ENOMEM;
1852 }
1853
Mona Hossaind44a3842012-10-15 09:41:35 -07001854 data = kzalloc(sizeof(*data), GFP_KERNEL);
1855 if (!data) {
1856 pr_err("kmalloc failed\n");
1857 if (ret == 0) {
1858 kfree(*handle);
1859 *handle = NULL;
1860 }
1861 return -ENOMEM;
1862 }
1863 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001864 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001865 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001866 data->client.sb_length = size;
1867 data->client.user_virt_sb_base = 0;
1868 data->client.ihandle = NULL;
1869
1870 init_waitqueue_head(&data->abort_wq);
1871 atomic_set(&data->ioctl_count, 0);
1872
1873 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1874 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1875 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1876 pr_err("Ion client could not retrieve the handle\n");
1877 kfree(data);
1878 kfree(*handle);
1879 *handle = NULL;
1880 return -EINVAL;
1881 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001882 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001883 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001884 if (qseecom.commonlib_loaded == false) {
1885 ret = qseecom_load_commonlib_image(data);
1886 if (ret == 0)
1887 qseecom.commonlib_loaded = true;
1888 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001889 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001890 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001891 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001892 ret = -EIO;
1893 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001894 }
1895
1896 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1897 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1898 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001899 if (ret < 0)
1900 goto err;
1901
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001902 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001903 if (ret > 0) {
1904 pr_warn("App id %d for [%s] app exists\n", ret,
1905 (char *)app_ireq.app_name);
1906 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1907 list_for_each_entry(entry,
1908 &qseecom.registered_app_list_head, list){
1909 if (entry->app_id == ret) {
1910 entry->ref_cnt++;
1911 found_app = true;
1912 break;
1913 }
1914 }
1915 spin_unlock_irqrestore(
1916 &qseecom.registered_app_list_lock, flags);
1917 if (!found_app)
1918 pr_warn("App_id %d [%s] was loaded but not registered\n",
1919 ret, (char *)app_ireq.app_name);
1920 } else {
1921 /* load the app and get the app_id */
1922 pr_debug("%s: Loading app for the first time'\n",
1923 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001924 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001925 if (ret < 0)
1926 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001927 data->client.app_id = ret;
1928 }
1929 if (!found_app) {
1930 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1931 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001932 pr_err("kmalloc for app entry failed\n");
1933 ret = -ENOMEM;
1934 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001935 }
1936 entry->app_id = ret;
1937 entry->ref_cnt = 1;
1938
1939 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1940 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1941 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1942 flags);
1943 }
1944
1945 /* Get the physical address of the ION BUF */
1946 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1947 /* Populate the structure for sending scm call to load image */
1948 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1949 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001950 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001951 data->client.sb_phys = pa;
1952 (*handle)->dev = (void *)data;
1953 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1954 (*handle)->sbuf_len = data->client.sb_length;
1955
1956 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1957 if (!kclient_entry) {
1958 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001959 ret = -ENOMEM;
1960 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001961 }
1962 kclient_entry->handle = *handle;
1963
1964 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1965 list_add_tail(&kclient_entry->list,
1966 &qseecom.registered_kclient_list_head);
1967 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1968
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001969 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001970 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001971
1972err:
1973 kfree(data);
1974 kfree(*handle);
1975 *handle = NULL;
1976 mutex_unlock(&app_access_lock);
1977 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001978}
1979EXPORT_SYMBOL(qseecom_start_app);
1980
1981int qseecom_shutdown_app(struct qseecom_handle **handle)
1982{
1983 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001984 struct qseecom_dev_handle *data;
1985
Mona Hossaind44a3842012-10-15 09:41:35 -07001986 struct qseecom_registered_kclient_list *kclient = NULL;
1987 unsigned long flags = 0;
1988 bool found_handle = false;
1989
Mona Hossain33824022013-02-25 09:32:33 -08001990 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001991 pr_err("Handle is not initialized\n");
1992 return -EINVAL;
1993 }
Mona Hossain33824022013-02-25 09:32:33 -08001994 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001995 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1996 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1997 list) {
1998 if (kclient->handle == (*handle)) {
1999 list_del(&kclient->list);
2000 found_handle = true;
2001 break;
2002 }
2003 }
2004 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2005 if (!found_handle)
2006 pr_err("Unable to find the handle, exiting\n");
2007 else
2008 ret = qseecom_unload_app(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002009
2010 if (qseecom.support_bus_scaling) {
2011 mutex_lock(&qsee_bw_mutex);
2012 if (data->mode != INACTIVE) {
2013 qseecom_unregister_bus_bandwidth_needs(data);
2014 if (qseecom.cumulative_mode == INACTIVE) {
2015 ret = __qseecom_set_msm_bus_request(INACTIVE);
2016 if (ret)
2017 pr_err("Fail to scale down bus\n");
2018 }
2019 }
2020 mutex_unlock(&qsee_bw_mutex);
2021 } else {
2022 if (data->fast_load_enabled == true)
2023 qsee_disable_clock_vote(data, CLK_SFPB);
2024 if (data->perf_enabled == true)
2025 qsee_disable_clock_vote(data, CLK_DFAB);
2026 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002027 if (ret == 0) {
2028 kzfree(data);
2029 kzfree(*handle);
2030 kzfree(kclient);
2031 *handle = NULL;
2032 }
2033 return ret;
2034}
2035EXPORT_SYMBOL(qseecom_shutdown_app);
2036
2037int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2038 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2039{
2040 int ret = 0;
2041 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2042 struct qseecom_dev_handle *data;
2043
Mona Hossaind44a3842012-10-15 09:41:35 -07002044 if (handle == NULL) {
2045 pr_err("Handle is not initialized\n");
2046 return -EINVAL;
2047 }
2048 data = handle->dev;
2049
2050 req.cmd_req_len = sbuf_len;
2051 req.resp_len = rbuf_len;
2052 req.cmd_req_buf = send_buf;
2053 req.resp_buf = resp_buf;
2054
2055 mutex_lock(&app_access_lock);
2056 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002057 if (qseecom.support_bus_scaling)
2058 qseecom_scale_bus_bandwidth_timer(INACTIVE,
2059 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002060 ret = __qseecom_send_cmd(data, &req);
2061
2062 atomic_dec(&data->ioctl_count);
2063 mutex_unlock(&app_access_lock);
2064
2065 if (ret)
2066 return ret;
2067
2068 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2069 req.resp_len, req.resp_buf);
2070 return ret;
2071}
2072EXPORT_SYMBOL(qseecom_send_command);
2073
Mona Hossain91a8fc92012-11-07 19:58:30 -08002074int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2075{
Mona Hossainfca6f422013-01-12 13:00:35 -08002076 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002077 if ((handle == NULL) || (handle->dev == NULL)) {
2078 pr_err("No valid kernel client\n");
2079 return -EINVAL;
2080 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002081 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002082 if (qseecom.support_bus_scaling) {
2083 mutex_lock(&qsee_bw_mutex);
2084 __qseecom_register_bus_bandwidth_needs(handle->dev,
2085 HIGH);
2086 mutex_unlock(&qsee_bw_mutex);
2087 if (ret)
2088 pr_err("Failed to scale bus (med) %d\n", ret);
2089 } else {
2090 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2091 if (ret)
2092 pr_err("Failed to vote for DFAB clock%d\n",
2093 ret);
2094 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2095 if (ret) {
2096 pr_err("Failed to vote for SFPB clock%d\n",
2097 ret);
2098 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2099 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002100 }
2101 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002102 if (!qseecom.support_bus_scaling) {
2103 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2104 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
2105 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002106 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002107 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002108}
2109EXPORT_SYMBOL(qseecom_set_bandwidth);
2110
Mona Hossain2892b6b2012-02-17 13:53:11 -08002111static int qseecom_send_resp(void)
2112{
2113 qseecom.send_resp_flag = 1;
2114 wake_up_interruptible(&qseecom.send_resp_wq);
2115 return 0;
2116}
2117
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002118
2119static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2120 void __user *argp)
2121{
2122 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002123 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002124 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002125
2126 if (copy_from_user(&resp, argp, sizeof(resp))) {
2127 pr_err("copy_from_user failed");
2128 return -EINVAL;
2129 }
Zhen Kongf4948192013-11-25 13:05:35 -08002130 this_lstnr = __qseecom_find_svc(data->listener.id);
2131 if (this_lstnr == NULL)
2132 return -EINVAL;
2133
2134 if (resp.resp_buf_ptr == NULL) {
2135 pr_err("Invalid resp_buf_ptr\n");
2136 return -EINVAL;
2137 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002138 /* validate offsets */
2139 for (i = 0; i < MAX_ION_FD; i++) {
2140 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2141 pr_err("Invalid offset %d = 0x%x\n",
2142 i, resp.ifd_data[i].cmd_buf_offset);
2143 return -EINVAL;
2144 }
2145 }
Zhen Kongf4948192013-11-25 13:05:35 -08002146
2147 if (((uint32_t)resp.resp_buf_ptr <
2148 this_lstnr->user_virt_sb_base)
2149 || ((uint32_t)resp.resp_buf_ptr >=
2150 (this_lstnr->user_virt_sb_base +
2151 this_lstnr->sb_length))) {
2152 pr_err("resp_buf_ptr address not within shared buffer\n");
2153 return -EINVAL;
2154 }
2155 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2156 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002157 __qseecom_update_cmd_buf(&resp, false, data, true);
2158 qseecom.send_resp_flag = 1;
2159 wake_up_interruptible(&qseecom.send_resp_wq);
2160 return 0;
2161}
2162
2163
Mona Hossain2892b6b2012-02-17 13:53:11 -08002164static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2165 void __user *argp)
2166{
2167 struct qseecom_qseos_version_req req;
2168
2169 if (copy_from_user(&req, argp, sizeof(req))) {
2170 pr_err("copy_from_user failed");
2171 return -EINVAL;
2172 }
2173 req.qseos_version = qseecom.qseos_version;
2174 if (copy_to_user(argp, &req, sizeof(req))) {
2175 pr_err("copy_to_user failed");
2176 return -EINVAL;
2177 }
2178 return 0;
2179}
2180
Mona Hossainc92629e2013-04-01 13:37:46 -07002181static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002182{
2183 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002184 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002185
Mona Hossainc92629e2013-04-01 13:37:46 -07002186 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002187 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002188 else
2189 qclk = &qseecom.ce_drv;
2190
2191 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002192
2193 if (qclk->clk_access_cnt == ULONG_MAX)
2194 goto err;
2195
Mona Hossainc92629e2013-04-01 13:37:46 -07002196 if (qclk->clk_access_cnt > 0) {
2197 qclk->clk_access_cnt++;
2198 mutex_unlock(&clk_access_lock);
2199 return rc;
2200 }
2201
Mona Hossain6311d572013-03-01 15:54:02 -08002202 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002203 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002204 if (rc) {
2205 pr_err("Unable to enable/prepare CE core clk\n");
2206 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002207 }
2208 /* Enable CE clk */
2209 rc = clk_prepare_enable(qclk->ce_clk);
2210 if (rc) {
2211 pr_err("Unable to enable/prepare CE iface clk\n");
2212 goto ce_clk_err;
2213 }
2214 /* Enable AXI clk */
2215 rc = clk_prepare_enable(qclk->ce_bus_clk);
2216 if (rc) {
2217 pr_err("Unable to enable/prepare CE bus clk\n");
2218 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002219 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002220 qclk->clk_access_cnt++;
2221 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002222 return 0;
2223
2224ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002225 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002226ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002227 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002228err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002229 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002230 return -EIO;
2231}
2232
Mona Hossainc92629e2013-04-01 13:37:46 -07002233static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002234{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002235 struct qseecom_clk *qclk;
2236
Mona Hossainc92629e2013-04-01 13:37:46 -07002237 if (ce == CLK_QSEE)
2238 qclk = &qseecom.qsee;
2239 else
2240 qclk = &qseecom.ce_drv;
2241
2242 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002243
2244 if (qclk->clk_access_cnt == 0) {
2245 mutex_unlock(&clk_access_lock);
2246 return;
2247 }
2248
Mona Hossainc92629e2013-04-01 13:37:46 -07002249 if (qclk->clk_access_cnt == 1) {
2250 if (qclk->ce_clk != NULL)
2251 clk_disable_unprepare(qclk->ce_clk);
2252 if (qclk->ce_core_clk != NULL)
2253 clk_disable_unprepare(qclk->ce_core_clk);
2254 if (qclk->ce_bus_clk != NULL)
2255 clk_disable_unprepare(qclk->ce_bus_clk);
2256 }
2257 qclk->clk_access_cnt--;
2258 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002259}
2260
Mona Hossain04d3fac2012-12-03 10:10:37 -08002261static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2262 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002263{
2264 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002265 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002266
Mona Hossain17a4faf2013-03-22 16:40:56 -07002267 qclk = &qseecom.qsee;
2268 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002269 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002270
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002271 switch (clk_type) {
2272 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002273 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002274 if (!qseecom.qsee_bw_count) {
2275 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002276 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002277 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002278 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002279 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002280 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002281 if (!ret) {
2282 ret =
2283 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002284 qseecom.qsee_perf_client, 1);
2285 if ((ret) &&
2286 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002287 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002288 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002289 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002290 if (ret)
2291 pr_err("DFAB Bandwidth req failed (%d)\n",
2292 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002293 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002294 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002295 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002296 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002297 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002298 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002299 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002300 }
2301 mutex_unlock(&qsee_bw_mutex);
2302 break;
2303 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002304 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002305 if (!qseecom.qsee_sfpb_bw_count) {
2306 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002307 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002308 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002309 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002310 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002311 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002312 if (!ret) {
2313 ret =
2314 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002315 qseecom.qsee_perf_client, 2);
2316 if ((ret) &&
2317 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002318 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002319 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002320 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002321
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002322 if (ret)
2323 pr_err("SFPB Bandwidth req failed (%d)\n",
2324 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002325 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002326 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002327 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002328 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002329 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002330 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002331 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002332 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002333 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002334 break;
2335 default:
2336 pr_err("Clock type not defined\n");
2337 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002338 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002339 return ret;
2340}
2341
Mona Hossain04d3fac2012-12-03 10:10:37 -08002342static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2343 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002344{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002345 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002346 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002347
Mona Hossain17a4faf2013-03-22 16:40:56 -07002348 qclk = &qseecom.qsee;
2349 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002350 return;
2351
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002352 switch (clk_type) {
2353 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002354 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002355 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002356 pr_err("Client error.Extra call to disable DFAB clk\n");
2357 mutex_unlock(&qsee_bw_mutex);
2358 return;
2359 }
2360
Mona Hossain17a4faf2013-03-22 16:40:56 -07002361 if (qseecom.qsee_bw_count == 1) {
2362 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002363 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002364 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002365 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002366 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002367 qseecom.qsee_perf_client, 0);
2368 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002369 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002370 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002371 if (ret)
2372 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002373 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002374 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002375 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002376 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002377 }
2378 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002379 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002380 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002381 }
2382 mutex_unlock(&qsee_bw_mutex);
2383 break;
2384 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002385 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002386 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002387 pr_err("Client error.Extra call to disable SFPB clk\n");
2388 mutex_unlock(&qsee_bw_mutex);
2389 return;
2390 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002391 if (qseecom.qsee_sfpb_bw_count == 1) {
2392 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002393 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002394 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002395 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002396 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002397 qseecom.qsee_perf_client, 0);
2398 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002399 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002400 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002401 if (ret)
2402 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002403 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002404 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002405 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002406 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002407 }
2408 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002409 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002410 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002411 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002412 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002413 break;
2414 default:
2415 pr_err("Clock type not defined\n");
2416 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002417 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002418
Mona Hossain2892b6b2012-02-17 13:53:11 -08002419}
2420
Mona Hossain5ab9d772012-04-11 21:00:40 -07002421static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2422 void __user *argp)
2423{
2424 struct ion_handle *ihandle; /* Ion handle */
2425 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002426 int ret;
2427 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002428 ion_phys_addr_t pa = 0;
2429 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002430 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002431 struct qseecom_load_app_ireq load_req;
2432 struct qseecom_command_scm_resp resp;
2433
2434 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002435 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002436 (void __user *)argp,
2437 sizeof(struct qseecom_load_img_req))) {
2438 pr_err("copy_from_user failed\n");
2439 return -EFAULT;
2440 }
2441
2442 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002443 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002444 load_img_req.ifd_data_fd);
2445 if (IS_ERR_OR_NULL(ihandle)) {
2446 pr_err("Ion client could not retrieve the handle\n");
2447 return -ENOMEM;
2448 }
2449
2450 /* Get the physical address of the ION BUF */
2451 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2452
2453 /* Populate the structure for sending scm call to load image */
2454 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2455 load_req.mdt_len = load_img_req.mdt_len;
2456 load_req.img_len = load_img_req.img_len;
2457 load_req.phy_addr = pa;
2458
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002459 /* SCM_CALL tied to Core0 */
2460 mask = CPU_MASK_CPU0;
2461 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2462 if (set_cpu_ret) {
2463 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2464 set_cpu_ret);
2465 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302466 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002467 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302468
Mona Hossain6311d572013-03-01 15:54:02 -08002469 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002470 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002471 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002472 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302473 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002474 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002475 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2476 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002477 /* SCM_CALL to load the external elf */
2478 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2479 sizeof(struct qseecom_load_app_ireq),
2480 &resp, sizeof(resp));
2481 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002482 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002483 ret);
2484 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302485 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002486 }
2487
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302488 switch (resp.result) {
2489 case QSEOS_RESULT_SUCCESS:
2490 break;
2491 case QSEOS_RESULT_INCOMPLETE:
2492 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002493 ret = __qseecom_process_incomplete_cmd(data, &resp);
2494 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302495 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2496 break;
2497 case QSEOS_RESULT_FAILURE:
2498 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2499 ret = -EFAULT;
2500 break;
2501 default:
2502 pr_err("scm_call response result %d not supported\n",
2503 resp.result);
2504 ret = -EFAULT;
2505 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002506 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002507
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302508exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002509 __qseecom_disable_clk_scale_down(data);
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302510exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002511 /* Restore the CPU mask */
2512 mask = CPU_MASK_ALL;
2513 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2514 if (set_cpu_ret) {
2515 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2516 set_cpu_ret);
2517 ret = -EFAULT;
2518 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302519exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002520 /* Deallocate the handle */
2521 if (!IS_ERR_OR_NULL(ihandle))
2522 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002523 return ret;
2524}
2525
2526static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2527{
2528 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002529 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002530 struct qseecom_command_scm_resp resp;
2531 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002532 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002533
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302534 /* unavailable client app */
2535 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2536
Mona Hossain5ab9d772012-04-11 21:00:40 -07002537 /* Populate the structure for sending scm call to unload image */
2538 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002539
2540 /* SCM_CALL tied to Core0 */
2541 mask = CPU_MASK_CPU0;
2542 ret = set_cpus_allowed_ptr(current, &mask);
2543 if (ret) {
2544 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2545 ret);
2546 return -EFAULT;
2547 }
2548
Mona Hossain5ab9d772012-04-11 21:00:40 -07002549 /* SCM_CALL to unload the external elf */
2550 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2551 sizeof(struct qseecom_unload_app_ireq),
2552 &resp, sizeof(resp));
2553 if (ret) {
2554 pr_err("scm_call to unload failed : ret %d\n",
2555 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002556 ret = -EFAULT;
2557 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002558 }
2559 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2560 ret = __qseecom_process_incomplete_cmd(data, &resp);
2561 if (ret)
2562 pr_err("process_incomplete_cmd fail err: %d\n",
2563 ret);
2564 } else {
2565 if (resp.result != QSEOS_RESULT_SUCCESS) {
2566 pr_err("scm_call to unload image failed resp.result =%d\n",
2567 resp.result);
2568 ret = -EFAULT;
2569 }
2570 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002571
2572qseecom_unload_external_elf_scm_err:
2573 /* Restore the CPU mask */
2574 mask = CPU_MASK_ALL;
2575 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2576 if (set_cpu_ret) {
2577 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2578 set_cpu_ret);
2579 ret = -EFAULT;
2580 }
2581
Mona Hossain5ab9d772012-04-11 21:00:40 -07002582 return ret;
2583}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002584
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002585static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2586 void __user *argp)
2587{
2588
2589 int32_t ret;
2590 struct qseecom_qseos_app_load_query query_req;
2591 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002592 struct qseecom_registered_app_list *entry = NULL;
2593 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002594
2595 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002596 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002597 (void __user *)argp,
2598 sizeof(struct qseecom_qseos_app_load_query))) {
2599 pr_err("copy_from_user failed\n");
2600 return -EFAULT;
2601 }
2602
2603 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002604 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002605 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2606
2607 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002608
2609 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002610 pr_err(" scm call to check if app is loaded failed");
2611 return ret; /* scm call failed */
2612 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002613 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002614 (char *)(req.app_name));
2615 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2616 list_for_each_entry(entry,
2617 &qseecom.registered_app_list_head, list){
2618 if (entry->app_id == ret) {
2619 entry->ref_cnt++;
2620 break;
2621 }
2622 }
2623 spin_unlock_irqrestore(
2624 &qseecom.registered_app_list_lock, flags);
2625 data->client.app_id = ret;
2626 query_req.app_id = ret;
2627
2628 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2629 pr_err("copy_to_user failed\n");
2630 return -EFAULT;
2631 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002632 return -EEXIST; /* app already loaded */
2633 } else {
2634 return 0; /* app not loaded */
2635 }
2636}
2637
Mona Hossain4cf78a92013-02-14 12:06:41 -08002638static int __qseecom_get_ce_pipe_info(
2639 enum qseecom_key_management_usage_type usage,
2640 uint32_t *pipe, uint32_t *ce_hw)
2641{
2642 int ret;
2643 switch (usage) {
2644 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2645 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2646 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2647 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2648 qseecom.ce_info.disk_encrypt_pipe,
2649 qseecom.ce_info.hlos_ce_hw_instance);
2650 ret = -EINVAL;
2651 } else {
2652 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2653 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2654 ret = 0;
2655 }
2656 break;
2657 default:
2658 ret = -EINVAL;
2659 break;
2660 }
2661 return ret;
2662}
2663
2664static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2665 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002666 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002667{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002668 struct qseecom_command_scm_resp resp;
2669 int ret;
2670
Zhen Kong9730ddf2013-12-17 16:49:43 -08002671 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2672 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002673 pr_err("Error:: unsupported usage %d\n", usage);
2674 return -EFAULT;
2675 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002676 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002677
2678 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002679 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002680 &resp, sizeof(resp));
2681 if (ret) {
2682 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002683 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002684 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002685 }
2686
2687 switch (resp.result) {
2688 case QSEOS_RESULT_SUCCESS:
2689 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002690 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002691 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002692 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002693 case QSEOS_RESULT_INCOMPLETE:
2694 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002695 if (ret) {
2696 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002697 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002698 ret = 0;
2699 } else {
2700 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2701 resp.result);
2702 }
2703 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002704 break;
2705 case QSEOS_RESULT_FAILURE:
2706 default:
2707 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2708 ret = -EINVAL;
2709 break;
2710 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002711 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002712 return ret;
2713}
2714
2715static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2716 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002717 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002718{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002719 struct qseecom_command_scm_resp resp;
2720 int ret;
2721
2722 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2723 pr_err("Error:: unsupported usage %d\n", usage);
2724 return -EFAULT;
2725 }
2726
Mona Hossainc92629e2013-04-01 13:37:46 -07002727 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002728
2729 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002730 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002731 &resp, sizeof(struct qseecom_command_scm_resp));
2732 if (ret) {
2733 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002734 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002735 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002736 }
2737
2738 switch (resp.result) {
2739 case QSEOS_RESULT_SUCCESS:
2740 break;
2741 case QSEOS_RESULT_INCOMPLETE:
2742 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002743 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002744 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2745 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002746 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2747 pr_debug("Max attempts to input password reached.\n");
2748 ret = -ERANGE;
2749 }
2750 }
2751 break;
2752 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2753 pr_debug("Max attempts to input password reached.\n");
2754 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002755 break;
2756 case QSEOS_RESULT_FAILURE:
2757 default:
2758 pr_err("Delete key scm call failed resp.result %d\n",
2759 resp.result);
2760 ret = -EINVAL;
2761 break;
2762 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002763 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002764 return ret;
2765}
2766
2767static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2768 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002769 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002770{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002771 struct qseecom_command_scm_resp resp;
2772 int ret;
2773
Zhen Kong9730ddf2013-12-17 16:49:43 -08002774 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2775 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002776 pr_err("Error:: unsupported usage %d\n", usage);
2777 return -EFAULT;
2778 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002779
Zhen Kongdb2bf742013-05-13 23:55:42 -07002780 __qseecom_enable_clk(CLK_QSEE);
2781 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002782 __qseecom_enable_clk(CLK_CE_DRV);
2783
Zhen Kong336636e2013-04-15 11:04:54 -07002784 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002785 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002786 &resp, sizeof(struct qseecom_command_scm_resp));
2787 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002788 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002789 __qseecom_disable_clk(CLK_QSEE);
2790 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2791 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002792 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07002793 }
2794
Mona Hossain4cf78a92013-02-14 12:06:41 -08002795 switch (resp.result) {
2796 case QSEOS_RESULT_SUCCESS:
2797 break;
2798 case QSEOS_RESULT_INCOMPLETE:
2799 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002800 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002801 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2802 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002803 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2804 pr_debug("Max attempts to input password reached.\n");
2805 ret = -ERANGE;
2806 }
2807 }
2808 break;
2809 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2810 pr_debug("Max attempts to input password reached.\n");
2811 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002812 break;
2813 case QSEOS_RESULT_FAILURE:
2814 default:
2815 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2816 ret = -EINVAL;
2817 break;
2818 }
2819
Zhen Kongdb2bf742013-05-13 23:55:42 -07002820 __qseecom_disable_clk(CLK_QSEE);
2821 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002822 __qseecom_disable_clk(CLK_CE_DRV);
2823
Mona Hossain4cf78a92013-02-14 12:06:41 -08002824 return ret;
2825}
2826
Zhen Kong9730ddf2013-12-17 16:49:43 -08002827static int __qseecom_update_current_key_user_info(
2828 struct qseecom_dev_handle *data,
2829 enum qseecom_key_management_usage_type usage,
2830 struct qseecom_key_userinfo_update_ireq *ireq)
2831{
2832 struct qseecom_command_scm_resp resp;
2833 int ret;
2834
2835 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2836 usage >= QSEOS_KM_USAGE_MAX) {
2837 pr_err("Error:: unsupported usage %d\n", usage);
2838 return -EFAULT;
2839 }
2840
2841 __qseecom_enable_clk(CLK_QSEE);
2842
2843 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
2844 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
2845 &resp, sizeof(struct qseecom_command_scm_resp));
2846 if (ret) {
2847 pr_err("scm call to update key userinfo failed : %d\n", ret);
2848 __qseecom_disable_clk(CLK_QSEE);
2849 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2850 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002851 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002852 }
2853
2854 switch (resp.result) {
2855 case QSEOS_RESULT_SUCCESS:
2856 break;
2857 case QSEOS_RESULT_INCOMPLETE:
2858 ret = __qseecom_process_incomplete_cmd(data, &resp);
2859 if (ret)
2860 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2861 resp.result);
2862 break;
2863 case QSEOS_RESULT_FAILURE:
2864 default:
2865 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2866 ret = -EINVAL;
2867 break;
2868 }
2869
2870 __qseecom_disable_clk(CLK_QSEE);
2871 return ret;
2872}
2873
Mona Hossain4cf78a92013-02-14 12:06:41 -08002874static int qseecom_create_key(struct qseecom_dev_handle *data,
2875 void __user *argp)
2876{
2877 uint32_t ce_hw = 0;
2878 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002879 int ret = 0;
2880 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002881 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002882 struct qseecom_key_generate_ireq generate_key_ireq;
2883 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002884
2885 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2886 if (ret) {
2887 pr_err("copy_from_user failed\n");
2888 return ret;
2889 }
2890
Zhen Kong9730ddf2013-12-17 16:49:43 -08002891 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2892 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002893 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2894 return -EFAULT;
2895 }
2896
2897 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2898 if (ret) {
2899 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2900 return -EINVAL;
2901 }
2902
Zhen Kong9730ddf2013-12-17 16:49:43 -08002903 generate_key_ireq.flags = flags;
2904 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
2905 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2906 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2907 memcpy((void *)generate_key_ireq.key_id,
2908 (void *)key_id_array[create_key_req.usage - 1],
2909 QSEECOM_KEY_ID_SIZE);
2910 memcpy((void *)generate_key_ireq.hash32,
2911 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
2912
Mona Hossain4cf78a92013-02-14 12:06:41 -08002913 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002914 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002915 if (ret) {
2916 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002917 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002918 }
2919
Zhen Kong9730ddf2013-12-17 16:49:43 -08002920 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2921 set_key_ireq.ce = ce_hw;
2922 set_key_ireq.pipe = pipe;
2923 set_key_ireq.flags = flags;
2924
2925 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2926 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
2927 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2928 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2929 memcpy((void *)set_key_ireq.key_id,
2930 (void *)key_id_array[create_key_req.usage - 1],
2931 QSEECOM_KEY_ID_SIZE);
2932 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002933 QSEECOM_HASH_SIZE);
2934
2935 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002936 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002937 if (ret) {
2938 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2939 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002940 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002941 }
2942
2943 return ret;
2944}
2945
2946static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2947 void __user *argp)
2948{
2949 uint32_t ce_hw = 0;
2950 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002951 int ret = 0;
2952 uint32_t flags = 0;
2953 int i;
2954 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002955 struct qseecom_key_delete_ireq delete_key_ireq;
2956 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002957
2958 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2959 if (ret) {
2960 pr_err("copy_from_user failed\n");
2961 return ret;
2962 }
2963
Zhen Kong9730ddf2013-12-17 16:49:43 -08002964 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2965 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002966 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2967 return -EFAULT;
2968 }
2969
2970 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2971 if (ret) {
2972 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2973 return -EINVAL;
2974 }
2975
Zhen Kong9730ddf2013-12-17 16:49:43 -08002976 delete_key_ireq.flags = flags;
2977 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
2978 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2979 memcpy((void *)delete_key_ireq.key_id,
2980 (void *)key_id_array[wipe_key_req.usage - 1],
2981 QSEECOM_KEY_ID_SIZE);
2982 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2983
2984 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
2985 &delete_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002986 if (ret) {
2987 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2988 return -EFAULT;
2989 }
2990
Zhen Kong9730ddf2013-12-17 16:49:43 -08002991 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2992 clear_key_ireq.ce = ce_hw;
2993 clear_key_ireq.pipe = pipe;
2994 clear_key_ireq.flags = flags;
2995 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002996 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kong9730ddf2013-12-17 16:49:43 -08002997 clear_key_ireq.key_id[i] = 0xff;
2998 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2999
Mona Hossain4cf78a92013-02-14 12:06:41 -08003000 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003001 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003002 if (ret) {
3003 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3004 pipe, ce_hw, ret);
3005 return -EFAULT;
3006 }
3007
3008 return ret;
3009}
3010
Zhen Kong9730ddf2013-12-17 16:49:43 -08003011static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3012 void __user *argp)
3013{
3014 int ret = 0;
3015 uint32_t flags = 0;
3016 struct qseecom_update_key_userinfo_req update_key_req;
3017 struct qseecom_key_userinfo_update_ireq ireq;
3018
3019 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3020 if (ret) {
3021 pr_err("copy_from_user failed\n");
3022 return ret;
3023 }
3024
3025 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3026 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3027 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3028 return -EFAULT;
3029 }
3030
3031 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3032 ireq.flags = flags;
3033 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3034 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3035 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
3036 memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
3037 QSEECOM_KEY_ID_SIZE);
3038 memcpy((void *)ireq.current_hash32,
3039 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3040 memcpy((void *)ireq.new_hash32,
3041 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3042
3043 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3044 &ireq);
3045 if (ret) {
3046 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003047 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003048 }
3049 return ret;
3050
3051}
3052
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003053static int qseecom_is_es_activated(void __user *argp)
3054{
3055 struct qseecom_is_es_activated_req req;
3056 int ret;
3057 int resp_buf;
3058
3059 if (qseecom.qsee_version < QSEE_VERSION_04) {
3060 pr_err("invalid qsee version");
3061 return -ENODEV;
3062 }
3063
3064 if (argp == NULL) {
3065 pr_err("arg is null");
3066 return -EINVAL;
3067 }
3068
3069 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3070 (void *) &resp_buf, sizeof(resp_buf));
3071 if (ret) {
3072 pr_err("scm_call failed");
3073 return ret;
3074 }
3075
3076 req.is_activated = resp_buf;
3077 ret = copy_to_user(argp, &req, sizeof(req));
3078 if (ret) {
3079 pr_err("copy_to_user failed");
3080 return ret;
3081 }
3082
3083 return 0;
3084}
3085
3086static int qseecom_save_partition_hash(void __user *argp)
3087{
3088 struct qseecom_save_partition_hash_req req;
3089 int ret;
3090
3091 if (qseecom.qsee_version < QSEE_VERSION_04) {
3092 pr_err("invalid qsee version ");
3093 return -ENODEV;
3094 }
3095
3096 if (argp == NULL) {
3097 pr_err("arg is null");
3098 return -EINVAL;
3099 }
3100
3101 ret = copy_from_user(&req, argp, sizeof(req));
3102 if (ret) {
3103 pr_err("copy_from_user failed");
3104 return ret;
3105 }
3106
3107 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3108 (void *) &req, sizeof(req), NULL, 0);
3109 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003110 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003111 return ret;
3112 }
3113
3114 return 0;
3115}
3116
Mona Hossain2892b6b2012-02-17 13:53:11 -08003117static long qseecom_ioctl(struct file *file, unsigned cmd,
3118 unsigned long arg)
3119{
3120 int ret = 0;
3121 struct qseecom_dev_handle *data = file->private_data;
3122 void __user *argp = (void __user *) arg;
3123
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303124 if (!data) {
3125 pr_err("Invalid/uninitialized device handle\n");
3126 return -EINVAL;
3127 }
3128
Mona Hossain2892b6b2012-02-17 13:53:11 -08003129 if (data->abort) {
3130 pr_err("Aborting qseecom driver\n");
3131 return -ENODEV;
3132 }
3133
3134 switch (cmd) {
3135 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003136 if (data->type != QSEECOM_GENERIC) {
3137 pr_err("reg lstnr req: invalid handle (%d)\n",
3138 data->type);
3139 ret = -EINVAL;
3140 break;
3141 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003142 pr_debug("ioctl register_listener_req()\n");
3143 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003144 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003145 ret = qseecom_register_listener(data, argp);
3146 atomic_dec(&data->ioctl_count);
3147 wake_up_all(&data->abort_wq);
3148 if (ret)
3149 pr_err("failed qseecom_register_listener: %d\n", ret);
3150 break;
3151 }
3152 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003153 if ((data->listener.id == 0) ||
3154 (data->type != QSEECOM_LISTENER_SERVICE)) {
3155 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3156 data->type, data->listener.id);
3157 ret = -EINVAL;
3158 break;
3159 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003160 pr_debug("ioctl unregister_listener_req()\n");
3161 atomic_inc(&data->ioctl_count);
3162 ret = qseecom_unregister_listener(data);
3163 atomic_dec(&data->ioctl_count);
3164 wake_up_all(&data->abort_wq);
3165 if (ret)
3166 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3167 break;
3168 }
3169 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003170 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003171 if ((data->client.app_id == 0) ||
3172 (data->type != QSEECOM_CLIENT_APP)) {
3173 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3174 data->type, data->client.app_id);
3175 ret = -EINVAL;
3176 break;
3177 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003178 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003179 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003180 if (qseecom.support_bus_scaling)
3181 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3182 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003183 atomic_inc(&data->ioctl_count);
3184 ret = qseecom_send_cmd(data, argp);
3185 atomic_dec(&data->ioctl_count);
3186 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003187 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003188 if (ret)
3189 pr_err("failed qseecom_send_cmd: %d\n", ret);
3190 break;
3191 }
3192 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003193 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003194 if ((data->client.app_id == 0) ||
3195 (data->type != QSEECOM_CLIENT_APP)) {
3196 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3197 data->type, data->client.app_id);
3198 ret = -EINVAL;
3199 break;
3200 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003201 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003202 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003203 if (qseecom.support_bus_scaling)
3204 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3205 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003206 atomic_inc(&data->ioctl_count);
3207 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Konge8a02082014-03-11 17:36:50 -07003208 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003209 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003210 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003211 if (ret)
3212 pr_err("failed qseecom_send_cmd: %d\n", ret);
3213 break;
3214 }
3215 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003216 if ((data->listener.id == 0) ||
3217 (data->type != QSEECOM_LISTENER_SERVICE)) {
3218 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3219 data->type, data->listener.id);
3220 ret = -EINVAL;
3221 break;
3222 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003223 atomic_inc(&data->ioctl_count);
3224 ret = qseecom_receive_req(data);
3225 atomic_dec(&data->ioctl_count);
3226 wake_up_all(&data->abort_wq);
3227 if (ret)
3228 pr_err("failed qseecom_receive_req: %d\n", ret);
3229 break;
3230 }
3231 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003232 if ((data->listener.id == 0) ||
3233 (data->type != QSEECOM_LISTENER_SERVICE)) {
3234 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3235 data->type, data->listener.id);
3236 ret = -EINVAL;
3237 break;
3238 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003239 atomic_inc(&data->ioctl_count);
3240 ret = qseecom_send_resp();
3241 atomic_dec(&data->ioctl_count);
3242 wake_up_all(&data->abort_wq);
3243 if (ret)
3244 pr_err("failed qseecom_send_resp: %d\n", ret);
3245 break;
3246 }
3247 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003248 if ((data->type != QSEECOM_CLIENT_APP) &&
3249 (data->type != QSEECOM_GENERIC) &&
3250 (data->type != QSEECOM_SECURE_SERVICE)) {
3251 pr_err("set mem param req: invalid handle (%d)\n",
3252 data->type);
3253 ret = -EINVAL;
3254 break;
3255 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003256 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003257 ret = qseecom_set_client_mem_param(data, argp);
3258 if (ret)
3259 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3260 ret);
3261 break;
3262 }
3263 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003264 if ((data->type != QSEECOM_GENERIC) &&
3265 (data->type != QSEECOM_CLIENT_APP)) {
3266 pr_err("load app req: invalid handle (%d)\n",
3267 data->type);
3268 ret = -EINVAL;
3269 break;
3270 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003271 data->type = QSEECOM_CLIENT_APP;
3272 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003273 mutex_lock(&app_access_lock);
3274 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003275 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3276 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003277 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003278 if (ret == 0)
3279 qseecom.commonlib_loaded = true;
3280 }
3281 }
3282 if (ret == 0)
3283 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003284 atomic_dec(&data->ioctl_count);
3285 mutex_unlock(&app_access_lock);
3286 if (ret)
3287 pr_err("failed load_app request: %d\n", ret);
3288 break;
3289 }
3290 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003291 if ((data->client.app_id == 0) ||
3292 (data->type != QSEECOM_CLIENT_APP)) {
3293 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3294 data->type, data->client.app_id);
3295 ret = -EINVAL;
3296 break;
3297 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003298 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003299 mutex_lock(&app_access_lock);
3300 atomic_inc(&data->ioctl_count);
3301 ret = qseecom_unload_app(data);
3302 atomic_dec(&data->ioctl_count);
3303 mutex_unlock(&app_access_lock);
3304 if (ret)
3305 pr_err("failed unload_app request: %d\n", ret);
3306 break;
3307 }
3308 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3309 atomic_inc(&data->ioctl_count);
3310 ret = qseecom_get_qseos_version(data, argp);
3311 if (ret)
3312 pr_err("qseecom_get_qseos_version: %d\n", ret);
3313 atomic_dec(&data->ioctl_count);
3314 break;
3315 }
3316 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003317 if ((data->type != QSEECOM_GENERIC) &&
3318 (data->type != QSEECOM_CLIENT_APP)) {
3319 pr_err("perf enable req: invalid handle (%d)\n",
3320 data->type);
3321 ret = -EINVAL;
3322 break;
3323 }
3324 if ((data->type == QSEECOM_CLIENT_APP) &&
3325 (data->client.app_id == 0)) {
3326 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3327 data->type, data->client.app_id);
3328 ret = -EINVAL;
3329 break;
3330 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003331 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003332 if (qseecom.support_bus_scaling) {
3333 mutex_lock(&qsee_bw_mutex);
3334 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3335 mutex_unlock(&qsee_bw_mutex);
3336 } else {
3337 ret = qsee_vote_for_clock(data, CLK_DFAB);
3338 if (ret)
3339 pr_err("Fail to vote for DFAB clock%d\n", ret);
3340 ret = qsee_vote_for_clock(data, CLK_SFPB);
3341 if (ret)
3342 pr_err("Fail to vote for SFPB clock%d\n", ret);
3343 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003344 atomic_dec(&data->ioctl_count);
3345 break;
3346 }
3347 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003348 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3349 (data->type != QSEECOM_CLIENT_APP)) {
3350 pr_err("perf disable req: invalid handle (%d)\n",
3351 data->type);
3352 ret = -EINVAL;
3353 break;
3354 }
3355 if ((data->type == QSEECOM_CLIENT_APP) &&
3356 (data->client.app_id == 0)) {
3357 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3358 data->type, data->client.app_id);
3359 ret = -EINVAL;
3360 break;
3361 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003362 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003363 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003364 qsee_disable_clock_vote(data, CLK_DFAB);
3365 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003366 }
3367 atomic_dec(&data->ioctl_count);
3368 break;
3369 }
3370
3371 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3372 if ((data->client.app_id == 0) ||
3373 (data->type != QSEECOM_CLIENT_APP)) {
3374 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3375 data->type, data->client.app_id);
3376 ret = -EINVAL;
3377 break;
3378 }
3379 atomic_inc(&data->ioctl_count);
3380 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003381 atomic_dec(&data->ioctl_count);
3382 break;
3383 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003384 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003385 if (data->type != QSEECOM_GENERIC) {
3386 pr_err("load ext elf req: invalid client handle (%d)\n",
3387 data->type);
3388 ret = -EINVAL;
3389 break;
3390 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003391 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003392 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003393 mutex_lock(&app_access_lock);
3394 atomic_inc(&data->ioctl_count);
3395 ret = qseecom_load_external_elf(data, argp);
3396 atomic_dec(&data->ioctl_count);
3397 mutex_unlock(&app_access_lock);
3398 if (ret)
3399 pr_err("failed load_external_elf request: %d\n", ret);
3400 break;
3401 }
3402 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003403 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3404 pr_err("unload ext elf req: invalid handle (%d)\n",
3405 data->type);
3406 ret = -EINVAL;
3407 break;
3408 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003409 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003410 mutex_lock(&app_access_lock);
3411 atomic_inc(&data->ioctl_count);
3412 ret = qseecom_unload_external_elf(data);
3413 atomic_dec(&data->ioctl_count);
3414 mutex_unlock(&app_access_lock);
3415 if (ret)
3416 pr_err("failed unload_app request: %d\n", ret);
3417 break;
3418 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003419 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003420 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003421 mutex_lock(&app_access_lock);
3422 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003423 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003424 ret = qseecom_query_app_loaded(data, argp);
3425 atomic_dec(&data->ioctl_count);
3426 mutex_unlock(&app_access_lock);
3427 break;
3428 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003429 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003430 if (data->type != QSEECOM_GENERIC) {
3431 pr_err("send cmd svc req: invalid handle (%d)\n",
3432 data->type);
3433 ret = -EINVAL;
3434 break;
3435 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003436 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003437 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003438 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003439 qseecom.qsee_version);
3440 return -EINVAL;
3441 }
3442 mutex_lock(&app_access_lock);
3443 atomic_inc(&data->ioctl_count);
3444 ret = qseecom_send_service_cmd(data, argp);
3445 atomic_dec(&data->ioctl_count);
3446 mutex_unlock(&app_access_lock);
3447 break;
3448 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003449 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003450 if (data->type != QSEECOM_GENERIC) {
3451 pr_err("create key req: invalid handle (%d)\n",
3452 data->type);
3453 ret = -EINVAL;
3454 break;
3455 }
Zhen Kong336636e2013-04-15 11:04:54 -07003456 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003457 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003458 qseecom.qsee_version);
3459 return -EINVAL;
3460 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003461 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003462 atomic_inc(&data->ioctl_count);
3463 ret = qseecom_create_key(data, argp);
3464 if (ret)
3465 pr_err("failed to create encryption key: %d\n", ret);
3466
3467 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003468 break;
3469 }
3470 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003471 if (data->type != QSEECOM_GENERIC) {
3472 pr_err("wipe key req: invalid handle (%d)\n",
3473 data->type);
3474 ret = -EINVAL;
3475 break;
3476 }
Zhen Kong336636e2013-04-15 11:04:54 -07003477 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003478 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003479 qseecom.qsee_version);
3480 return -EINVAL;
3481 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003482 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003483 atomic_inc(&data->ioctl_count);
3484 ret = qseecom_wipe_key(data, argp);
3485 if (ret)
3486 pr_err("failed to wipe encryption key: %d\n", ret);
3487 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003488 break;
3489 }
3490 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
3491 if (data->type != QSEECOM_GENERIC) {
3492 pr_err("update key req: invalid handle (%d)\n",
3493 data->type);
3494 ret = -EINVAL;
3495 break;
3496 }
3497 if (qseecom.qsee_version < QSEE_VERSION_05) {
3498 pr_err("Update Key feature unsupported in qsee ver %u\n",
3499 qseecom.qsee_version);
3500 return -EINVAL;
3501 }
3502 data->released = true;
3503 atomic_inc(&data->ioctl_count);
3504 ret = qseecom_update_key_user_info(data, argp);
3505 if (ret)
3506 pr_err("failed to update key user info: %d\n", ret);
3507 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003508 break;
3509 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003510 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003511 if (data->type != QSEECOM_GENERIC) {
3512 pr_err("save part hash req: invalid handle (%d)\n",
3513 data->type);
3514 ret = -EINVAL;
3515 break;
3516 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003517 data->released = true;
3518 mutex_lock(&app_access_lock);
3519 atomic_inc(&data->ioctl_count);
3520 ret = qseecom_save_partition_hash(argp);
3521 atomic_dec(&data->ioctl_count);
3522 mutex_unlock(&app_access_lock);
3523 break;
3524 }
3525 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003526 if (data->type != QSEECOM_GENERIC) {
3527 pr_err("ES activated req: invalid handle (%d)\n",
3528 data->type);
3529 ret = -EINVAL;
3530 break;
3531 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003532 data->released = true;
3533 mutex_lock(&app_access_lock);
3534 atomic_inc(&data->ioctl_count);
3535 ret = qseecom_is_es_activated(argp);
3536 atomic_dec(&data->ioctl_count);
3537 mutex_unlock(&app_access_lock);
3538 break;
3539 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003540 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003541 if ((data->listener.id == 0) ||
3542 (data->type != QSEECOM_LISTENER_SERVICE)) {
3543 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3544 data->type, data->listener.id);
3545 ret = -EINVAL;
3546 break;
3547 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003548 /* Only one client allowed here at a time */
3549 atomic_inc(&data->ioctl_count);
3550 ret = qseecom_send_modfd_resp(data, argp);
3551 atomic_dec(&data->ioctl_count);
3552 wake_up_all(&data->abort_wq);
3553 if (ret)
3554 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3555 break;
3556 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003557 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003558 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003559 return -EINVAL;
3560 }
3561 return ret;
3562}
3563
3564static int qseecom_open(struct inode *inode, struct file *file)
3565{
3566 int ret = 0;
3567 struct qseecom_dev_handle *data;
3568
3569 data = kzalloc(sizeof(*data), GFP_KERNEL);
3570 if (!data) {
3571 pr_err("kmalloc failed\n");
3572 return -ENOMEM;
3573 }
3574 file->private_data = data;
3575 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003576 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003577 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003578 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003579 init_waitqueue_head(&data->abort_wq);
3580 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003581
Mona Hossain2892b6b2012-02-17 13:53:11 -08003582 return ret;
3583}
3584
3585static int qseecom_release(struct inode *inode, struct file *file)
3586{
3587 struct qseecom_dev_handle *data = file->private_data;
3588 int ret = 0;
3589
3590 if (data->released == false) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003591 pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
3592 data->type, data->mode, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003593 switch (data->type) {
3594 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003595 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003596 break;
3597 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003598 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003599 break;
3600 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003601 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003602 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003603 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003604 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003605 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303606 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3607 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003608 default:
3609 pr_err("Unsupported clnt_handle_type %d",
3610 data->type);
3611 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003612 }
3613 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003614
Zhen Kong2edf90d2013-08-27 12:05:06 -07003615 if (qseecom.support_bus_scaling) {
3616 mutex_lock(&qsee_bw_mutex);
3617 if (data->mode != INACTIVE) {
3618 qseecom_unregister_bus_bandwidth_needs(data);
3619 if (qseecom.cumulative_mode == INACTIVE) {
3620 ret = __qseecom_set_msm_bus_request(INACTIVE);
3621 if (ret)
3622 pr_err("Fail to scale down bus\n");
3623 }
3624 }
3625 mutex_unlock(&qsee_bw_mutex);
3626 } else {
3627 if (data->fast_load_enabled == true)
3628 qsee_disable_clock_vote(data, CLK_SFPB);
3629 if (data->perf_enabled == true)
3630 qsee_disable_clock_vote(data, CLK_DFAB);
3631 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003632 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003633
Mona Hossain2892b6b2012-02-17 13:53:11 -08003634 return ret;
3635}
3636
Mona Hossain2892b6b2012-02-17 13:53:11 -08003637static const struct file_operations qseecom_fops = {
3638 .owner = THIS_MODULE,
3639 .unlocked_ioctl = qseecom_ioctl,
3640 .open = qseecom_open,
3641 .release = qseecom_release
3642};
3643
Mona Hossainc92629e2013-04-01 13:37:46 -07003644static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003645{
3646 int rc = 0;
3647 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003648 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003649 char *core_clk_src = NULL;
3650 char *core_clk = NULL;
3651 char *iface_clk = NULL;
3652 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003653
Mona Hossainc92629e2013-04-01 13:37:46 -07003654 switch (ce) {
3655 case CLK_QSEE: {
3656 core_clk_src = "core_clk_src";
3657 core_clk = "core_clk";
3658 iface_clk = "iface_clk";
3659 bus_clk = "bus_clk";
3660 qclk = &qseecom.qsee;
3661 qclk->instance = CLK_QSEE;
3662 break;
3663 };
3664 case CLK_CE_DRV: {
3665 core_clk_src = "ce_drv_core_clk_src";
3666 core_clk = "ce_drv_core_clk";
3667 iface_clk = "ce_drv_iface_clk";
3668 bus_clk = "ce_drv_bus_clk";
3669 qclk = &qseecom.ce_drv;
3670 qclk->instance = CLK_CE_DRV;
3671 break;
3672 };
3673 default:
3674 pr_err("Invalid ce hw instance: %d!\n", ce);
3675 return -EIO;
3676 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003677 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003678
Mona Hossainc92629e2013-04-01 13:37:46 -07003679 /* Get CE3 src core clk. */
3680 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003681 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003682 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003683 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003684 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003685 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003686 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003687 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003688 }
3689 } else {
3690 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003691 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003692 }
3693
3694 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003695 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003696 if (IS_ERR(qclk->ce_core_clk)) {
3697 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003698 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003699 if (qclk->ce_core_src_clk != NULL)
3700 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003701 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003702 }
3703
3704 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003705 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003706 if (IS_ERR(qclk->ce_clk)) {
3707 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003708 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003709 if (qclk->ce_core_src_clk != NULL)
3710 clk_put(qclk->ce_core_src_clk);
3711 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003712 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003713 }
3714
3715 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003716 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003717 if (IS_ERR(qclk->ce_bus_clk)) {
3718 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003719 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003720 if (qclk->ce_core_src_clk != NULL)
3721 clk_put(qclk->ce_core_src_clk);
3722 clk_put(qclk->ce_core_clk);
3723 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003724 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003725 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003726 return rc;
3727}
3728
Mona Hossainc92629e2013-04-01 13:37:46 -07003729static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003730{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003731 struct qseecom_clk *qclk;
3732
Mona Hossainc92629e2013-04-01 13:37:46 -07003733 if (ce == CLK_QSEE)
3734 qclk = &qseecom.qsee;
3735 else
3736 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003737
3738 if (qclk->ce_clk != NULL) {
3739 clk_put(qclk->ce_clk);
3740 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003741 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003742 if (qclk->ce_core_clk != NULL) {
3743 clk_put(qclk->ce_core_clk);
3744 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003745 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003746 if (qclk->ce_bus_clk != NULL) {
3747 clk_put(qclk->ce_bus_clk);
3748 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003749 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003750 if (qclk->ce_core_src_clk != NULL) {
3751 clk_put(qclk->ce_core_src_clk);
3752 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003753 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003754}
3755
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003756static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003757{
3758 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003759 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003760 struct device *class_dev;
3761 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003762 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003763 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3764
Mona Hossain17a4faf2013-03-22 16:40:56 -07003765 qseecom.qsee_bw_count = 0;
3766 qseecom.qsee_perf_client = 0;
3767 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003768
Mona Hossain17a4faf2013-03-22 16:40:56 -07003769 qseecom.qsee.ce_core_clk = NULL;
3770 qseecom.qsee.ce_clk = NULL;
3771 qseecom.qsee.ce_core_src_clk = NULL;
3772 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003773
Zhen Kong2edf90d2013-08-27 12:05:06 -07003774 qseecom.cumulative_mode = 0;
3775 qseecom.current_mode = INACTIVE;
3776 qseecom.support_bus_scaling = false;
3777
Mona Hossainc92629e2013-04-01 13:37:46 -07003778 qseecom.ce_drv.ce_core_clk = NULL;
3779 qseecom.ce_drv.ce_clk = NULL;
3780 qseecom.ce_drv.ce_core_src_clk = NULL;
3781 qseecom.ce_drv.ce_bus_clk = NULL;
3782
Mona Hossain2892b6b2012-02-17 13:53:11 -08003783 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3784 if (rc < 0) {
3785 pr_err("alloc_chrdev_region failed %d\n", rc);
3786 return rc;
3787 }
3788
3789 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3790 if (IS_ERR(driver_class)) {
3791 rc = -ENOMEM;
3792 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303793 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003794 }
3795
3796 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3797 QSEECOM_DEV);
3798 if (!class_dev) {
3799 pr_err("class_device_create failed %d\n", rc);
3800 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303801 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003802 }
3803
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303804 cdev_init(&qseecom.cdev, &qseecom_fops);
3805 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003806
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303807 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003808 if (rc < 0) {
3809 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303810 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003811 }
3812
3813 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3814 spin_lock_init(&qseecom.registered_listener_list_lock);
3815 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3816 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003817 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3818 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003819 init_waitqueue_head(&qseecom.send_resp_wq);
3820 qseecom.send_resp_flag = 0;
3821
3822 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3823 &qsee_not_legacy, sizeof(qsee_not_legacy));
3824 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003825 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303826 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003827 }
Mona Hossain05c73562012-10-29 17:49:01 -07003828 if (qsee_not_legacy) {
3829 uint32_t feature = 10;
3830
3831 qseecom.qsee_version = QSEEE_VERSION_00;
3832 rc = scm_call(6, 3, &feature, sizeof(feature),
3833 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3834 if (rc) {
3835 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303836 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003837 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003838 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003839 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003840 pr_err("QSEE legacy version is not supported:");
3841 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3842 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303843 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003844 }
Mona Hossain05c73562012-10-29 17:49:01 -07003845 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003846 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003847 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003848 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003849 if (qseecom.ion_clnt == NULL) {
3850 pr_err("Ion client cannot be created\n");
3851 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303852 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003853 }
3854
3855 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003856 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05303857 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003858 qseecom.support_bus_scaling =
3859 of_property_read_bool((&pdev->dev)->of_node,
3860 "qcom,support-bus-scaling");
3861 pr_warn("support_bus_scaling=0x%x",
3862 qseecom.support_bus_scaling);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003863 if (of_property_read_u32((&pdev->dev)->of_node,
3864 "qcom,disk-encrypt-pipe-pair",
3865 &qseecom.ce_info.disk_encrypt_pipe)) {
3866 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3867 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3868 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303869 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003870 } else {
3871 pr_warn("bam_pipe_pair=0x%x",
3872 qseecom.ce_info.disk_encrypt_pipe);
3873 }
3874
3875 if (of_property_read_u32((&pdev->dev)->of_node,
3876 "qcom,qsee-ce-hw-instance",
3877 &qseecom.ce_info.qsee_ce_hw_instance)) {
3878 pr_err("Fail to get qsee ce hw instance information.\n");
3879 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3880 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303881 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003882 } else {
3883 pr_warn("qsee-ce-hw-instance=0x%x",
3884 qseecom.ce_info.qsee_ce_hw_instance);
3885 }
3886
3887 if (of_property_read_u32((&pdev->dev)->of_node,
3888 "qcom,hlos-ce-hw-instance",
3889 &qseecom.ce_info.hlos_ce_hw_instance)) {
3890 pr_err("Fail to get hlos ce hw instance information.\n");
3891 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3892 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303893 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003894 } else {
3895 pr_warn("hlos-ce-hw-instance=0x%x",
3896 qseecom.ce_info.hlos_ce_hw_instance);
3897 }
3898
Mona Hossainc92629e2013-04-01 13:37:46 -07003899 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3900 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3901
3902 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003903 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303904 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003905
Mona Hossainc92629e2013-04-01 13:37:46 -07003906 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3907 ret = __qseecom_init_clk(CLK_CE_DRV);
3908 if (ret) {
3909 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303910 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003911 }
3912 } else {
3913 struct qseecom_clk *qclk;
3914
3915 qclk = &qseecom.qsee;
3916 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3917 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3918 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3919 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3920 }
3921
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003922 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3923 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003924 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3925 struct resource *resource = NULL;
3926 struct qsee_apps_region_info_ireq req;
3927 struct qseecom_command_scm_resp resp;
3928
3929 resource = platform_get_resource_byname(pdev,
3930 IORESOURCE_MEM, "secapp-region");
3931 if (resource) {
3932 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3933 req.addr = resource->start;
3934 req.size = resource_size(resource);
3935 pr_warn("secure app region addr=0x%x size=0x%x",
3936 req.addr, req.size);
3937 } else {
3938 pr_err("Fail to get secure app region info\n");
3939 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303940 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003941 }
3942 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3943 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003944 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3945 pr_err("send secapp reg fail %d resp.res %d\n",
3946 rc, resp.result);
3947 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303948 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003949 }
3950 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003951 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003952 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3953 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003954 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07003955 if (qseecom.support_bus_scaling) {
3956 init_timer(&(qseecom.bw_scale_down_timer));
3957 INIT_WORK(&qseecom.bw_inactive_req_ws,
3958 qseecom_bw_inactive_req_work);
3959 qseecom.bw_scale_down_timer.function =
3960 qseecom_scale_bus_bandwidth_timer_callback;
3961 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08003962 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003963 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003964 qseecom_platform_support);
3965
Mona Hossain17a4faf2013-03-22 16:40:56 -07003966 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003967 pr_err("Unable to register bus client\n");
3968 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303969
3970exit_destroy_ion_client:
3971 ion_client_destroy(qseecom.ion_clnt);
3972exit_del_cdev:
3973 cdev_del(&qseecom.cdev);
3974exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003975 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303976exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003977 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303978exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003979 unregister_chrdev_region(qseecom_device_no, 1);
3980 return rc;
3981}
3982
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003983static int __devinit qseecom_remove(struct platform_device *pdev)
3984{
Mona Hossaind44a3842012-10-15 09:41:35 -07003985 struct qseecom_registered_kclient_list *kclient = NULL;
3986 unsigned long flags = 0;
3987 int ret = 0;
3988
Mona Hossaind44a3842012-10-15 09:41:35 -07003989 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303990
Mona Hossaind44a3842012-10-15 09:41:35 -07003991 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303992 list) {
3993 if (!kclient)
3994 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07003995
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303996 /* Break the loop if client handle is NULL */
3997 if (!kclient->handle)
3998 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07003999
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304000 if (list_empty(&kclient->list))
4001 goto exit_free_kc_handle;
4002
4003 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07004004 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304005 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004006 kzfree(kclient->handle->dev);
4007 kzfree(kclient->handle);
4008 kzfree(kclient);
4009 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004010 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304011
4012exit_free_kc_handle:
4013 kzfree(kclient->handle);
4014exit_free_kclient:
4015 kzfree(kclient);
4016exit_irqrestore:
4017 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4018
4019 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004020 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004021
Mona Hossain17a4faf2013-03-22 16:40:56 -07004022 if (qseecom.qsee_perf_client)
4023 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4024 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304025 if (pdev->dev.platform_data != NULL)
4026 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4027
Zhen Kong2edf90d2013-08-27 12:05:06 -07004028 if (qseecom.support_bus_scaling) {
4029 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4030 del_timer_sync(&qseecom.bw_scale_down_timer);
4031 }
4032
Mona Hossaind39e33b2012-11-05 13:36:40 -08004033 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004034 if (pdev->dev.of_node) {
4035 __qseecom_deinit_clk(CLK_QSEE);
4036 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
4037 __qseecom_deinit_clk(CLK_CE_DRV);
4038 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304039
4040 ion_client_destroy(qseecom.ion_clnt);
4041
4042 cdev_del(&qseecom.cdev);
4043
4044 device_destroy(driver_class, qseecom_device_no);
4045
4046 class_destroy(driver_class);
4047
4048 unregister_chrdev_region(qseecom_device_no, 1);
4049
Mona Hossaind44a3842012-10-15 09:41:35 -07004050 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304051}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004052
Zhen Konga0944b82013-11-06 17:02:00 -08004053static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4054{
4055 int ret = 0;
4056 struct qseecom_clk *qclk;
4057 qclk = &qseecom.qsee;
4058
4059 if (qseecom.cumulative_mode != INACTIVE) {
4060 ret = __qseecom_set_msm_bus_request(INACTIVE);
4061 if (ret)
4062 pr_err("Fail to scale down bus\n");
4063 }
4064 mutex_lock(&clk_access_lock);
4065 if (qclk->clk_access_cnt) {
4066 if (qclk->ce_clk != NULL)
4067 clk_disable_unprepare(qclk->ce_clk);
4068 if (qclk->ce_core_clk != NULL)
4069 clk_disable_unprepare(qclk->ce_core_clk);
4070 if (qclk->ce_bus_clk != NULL)
4071 clk_disable_unprepare(qclk->ce_bus_clk);
4072 }
4073 mutex_unlock(&clk_access_lock);
4074 return 0;
4075}
4076
4077static int qseecom_resume(struct platform_device *pdev)
4078{
4079 int mode = 0;
4080 int ret = 0;
4081 struct qseecom_clk *qclk;
4082 qclk = &qseecom.qsee;
4083
4084 if (qseecom.cumulative_mode >= HIGH)
4085 mode = HIGH;
4086 else
4087 mode = qseecom.cumulative_mode;
4088
4089 if (qseecom.cumulative_mode != INACTIVE) {
4090 ret = __qseecom_set_msm_bus_request(mode);
4091 if (ret)
4092 pr_err("Fail to scale down bus\n");
4093 }
4094
4095 mutex_lock(&clk_access_lock);
4096 if (qclk->clk_access_cnt) {
4097
4098 ret = clk_prepare_enable(qclk->ce_core_clk);
4099 if (ret) {
4100 pr_err("Unable to enable/prepare CE core clk\n");
4101 qclk->clk_access_cnt = 0;
4102 goto err;
4103 }
4104
4105 ret = clk_prepare_enable(qclk->ce_clk);
4106 if (ret) {
4107 pr_err("Unable to enable/prepare CE iface clk\n");
4108 qclk->clk_access_cnt = 0;
4109 goto ce_clk_err;
4110 }
4111
4112 ret = clk_prepare_enable(qclk->ce_bus_clk);
4113 if (ret) {
4114 pr_err("Unable to enable/prepare CE bus clk\n");
4115 qclk->clk_access_cnt = 0;
4116 goto ce_bus_clk_err;
4117 }
4118 }
4119 mutex_unlock(&clk_access_lock);
4120 return 0;
4121
4122ce_bus_clk_err:
4123 clk_disable_unprepare(qclk->ce_clk);
4124ce_clk_err:
4125 clk_disable_unprepare(qclk->ce_core_clk);
4126err:
4127 mutex_unlock(&clk_access_lock);
4128 return -EIO;
4129}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004130static struct of_device_id qseecom_match[] = {
4131 {
4132 .compatible = "qcom,qseecom",
4133 },
4134 {}
4135};
4136
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004137static struct platform_driver qseecom_plat_driver = {
4138 .probe = qseecom_probe,
4139 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004140 .suspend = qseecom_suspend,
4141 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004142 .driver = {
4143 .name = "qseecom",
4144 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004145 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004146 },
4147};
4148
4149static int __devinit qseecom_init(void)
4150{
4151 return platform_driver_register(&qseecom_plat_driver);
4152}
4153
4154static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004155{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304156 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004157}
4158
4159MODULE_LICENSE("GPL v2");
4160MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4161
4162module_init(qseecom_init);
4163module_exit(qseecom_exit);