blob: 000e5b1b00b1a2a05f28be652f1f55018a78832a [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);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800290 if (svc->ihandle == NULL) {
291 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 Kong2edf90d2013-08-27 12:05:06 -0700545 qseecom.bw_scale_down_timer.expires = jiffies +
546 msecs_to_jiffies(duration);
547 add_timer(&(qseecom.bw_scale_down_timer));
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800548 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 Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001088 if (((uint32_t)req_ptr->cmd_req_buf <
1089 data_ptr->client.user_virt_sb_base)
1090 || ((uint32_t)req_ptr->cmd_req_buf >=
1091 (data_ptr->client.user_virt_sb_base +
1092 data_ptr->client.sb_length))) {
1093 pr_err("cmd buffer address not within shared bufffer\n");
1094 return -EINVAL;
1095 }
1096
1097
1098 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1099 || ((uint32_t)req_ptr->resp_buf >=
1100 (data_ptr->client.user_virt_sb_base +
1101 data_ptr->client.sb_length))){
1102 pr_err("response buffer address not within shared bufffer\n");
1103 return -EINVAL;
1104 }
1105
1106 req_buf = data_ptr->client.sb_virt;
1107
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001108 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1109 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001110 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001111 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1112 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1113 (uint32_t)req_ptr->resp_buf));
1114 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1115
1116 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
1117 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
1118 return ret;
1119}
1120
1121static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1122 void __user *argp)
1123{
1124 int ret = 0;
1125 struct qseecom_client_send_service_ireq send_svc_ireq;
1126 struct qseecom_command_scm_resp resp;
1127 struct qseecom_send_svc_cmd_req req;
1128 /*struct qseecom_command_scm_resp resp;*/
1129
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001130 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001131 (void __user *)argp,
1132 sizeof(req))) {
1133 pr_err("copy_from_user failed\n");
1134 return -EFAULT;
1135 }
1136
1137 if (req.resp_buf == NULL) {
1138 pr_err("cmd buffer or response buffer is null\n");
1139 return -EINVAL;
1140 }
1141
Zhen Kong2edf90d2013-08-27 12:05:06 -07001142 data->type = QSEECOM_SECURE_SERVICE;
1143
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001144 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001145 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1146 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001147 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1148 &send_svc_ireq))
1149 return -EINVAL;
1150 break;
1151 default:
1152 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1153 return -EINVAL;
1154 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301155
Zhen Kong2edf90d2013-08-27 12:05:06 -07001156 if (qseecom.support_bus_scaling) {
1157 qseecom_scale_bus_bandwidth_timer(HIGH,
1158 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1159 if (ret) {
1160 pr_err("Fail to set bw HIGH%d\n", ret);
1161 return ret;
1162 }
1163 } else {
1164 ret = qsee_vote_for_clock(data, CLK_DFAB);
1165 if (ret) {
1166 pr_err("Failed to vote for DFAB clock%d\n", ret);
1167 return ret;
1168 }
1169 ret = qsee_vote_for_clock(data, CLK_SFPB);
1170 if (ret) {
1171 qsee_disable_clock_vote(data, CLK_DFAB);
1172 pr_err("Failed to vote for SFPB clock%d\n", ret);
1173 goto exit;
1174 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301175 }
1176
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001177 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1178 data->client.sb_virt, data->client.sb_length,
1179 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001180 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1181 sizeof(send_svc_ireq),
1182 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001183 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1184 data->client.sb_virt, data->client.sb_length,
1185 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001186 if (ret) {
1187 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001188 if (!qseecom.support_bus_scaling) {
1189 qsee_disable_clock_vote(data, CLK_DFAB);
1190 qsee_disable_clock_vote(data, CLK_SFPB);
1191 }
1192 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001193 }
1194
1195 switch (resp.result) {
1196 case QSEOS_RESULT_SUCCESS:
1197 break;
1198 case QSEOS_RESULT_INCOMPLETE:
1199 pr_err("qseos_result_incomplete\n");
1200 ret = __qseecom_process_incomplete_cmd(data, &resp);
1201 if (ret) {
1202 pr_err("process_incomplete_cmd fail: err: %d\n",
1203 ret);
1204 }
1205 break;
1206 case QSEOS_RESULT_FAILURE:
1207 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1208 break;
1209 default:
1210 pr_err("Response result %d not supported\n",
1211 resp.result);
1212 ret = -EINVAL;
1213 break;
1214 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001215exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001216 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001217}
1218
Mona Hossain2892b6b2012-02-17 13:53:11 -08001219static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1220 struct qseecom_send_cmd_req *req)
1221{
1222 int ret = 0;
1223 u32 reqd_len_sb_in = 0;
1224 struct qseecom_client_send_data_ireq send_data_req;
1225 struct qseecom_command_scm_resp resp;
1226
1227 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1228 pr_err("cmd buffer or response buffer is null\n");
1229 return -EINVAL;
1230 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001231 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1232 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1233 data->client.sb_length))) {
1234 pr_err("cmd buffer address not within shared bufffer\n");
1235 return -EINVAL;
1236 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001237
Mona Hossaindddf4442013-10-01 14:08:20 -07001238
1239 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1240 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1241 data->client.sb_length))){
1242 pr_err("response buffer address not within shared bufffer\n");
1243 return -EINVAL;
1244 }
1245
1246 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001247 req->cmd_req_len > data->client.sb_length ||
1248 req->resp_len > data->client.sb_length) {
1249 pr_err("cmd buffer length or "
1250 "response buffer length not valid\n");
1251 return -EINVAL;
1252 }
1253
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001254 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1255 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1256 return -EINVAL;
1257 }
1258
Mona Hossain2892b6b2012-02-17 13:53:11 -08001259 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1260 if (reqd_len_sb_in > data->client.sb_length) {
1261 pr_debug("Not enough memory to fit cmd_buf and "
1262 "resp_buf. Required: %u, Available: %u\n",
1263 reqd_len_sb_in, data->client.sb_length);
1264 return -ENOMEM;
1265 }
1266
1267 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1268 send_data_req.app_id = data->client.app_id;
1269 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1270 (uint32_t)req->cmd_req_buf));
1271 send_data_req.req_len = req->cmd_req_len;
1272 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1273 (uint32_t)req->resp_buf));
1274 send_data_req.rsp_len = req->resp_len;
1275
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001276 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1277 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001278 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001279 ION_IOC_CLEAN_INV_CACHES);
1280
Mona Hossain2892b6b2012-02-17 13:53:11 -08001281 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1282 sizeof(send_data_req),
1283 &resp, sizeof(resp));
1284 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001285 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1286 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001287 return ret;
1288 }
1289
1290 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1291 ret = __qseecom_process_incomplete_cmd(data, &resp);
1292 if (ret) {
1293 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1294 return ret;
1295 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001296 } else {
1297 if (resp.result != QSEOS_RESULT_SUCCESS) {
1298 pr_err("Response result %d not supported\n",
1299 resp.result);
1300 ret = -EINVAL;
1301 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001302 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001303 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1304 data->client.sb_virt, data->client.sb_length,
1305 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001306 return ret;
1307}
1308
Mona Hossain2892b6b2012-02-17 13:53:11 -08001309static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1310{
1311 int ret = 0;
1312 struct qseecom_send_cmd_req req;
1313
1314 ret = copy_from_user(&req, argp, sizeof(req));
1315 if (ret) {
1316 pr_err("copy_from_user failed\n");
1317 return ret;
1318 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001319 ret = __qseecom_send_cmd(data, &req);
1320
Mona Hossain2892b6b2012-02-17 13:53:11 -08001321 if (ret)
1322 return ret;
1323
Mona Hossain2892b6b2012-02-17 13:53:11 -08001324 return ret;
1325}
1326
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001327static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1328 struct qseecom_dev_handle *data,
1329 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001330{
1331 struct ion_handle *ihandle;
1332 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001333 int ret = 0;
1334 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001335 uint32_t len = 0;
1336 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001337 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1338 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1339 struct qseecom_registered_listener_list *this_lstnr = NULL;
1340
1341 if (msg == NULL) {
1342 pr_err("Invalid address\n");
1343 return -EINVAL;
1344 }
1345 if (listener_svc) {
1346 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1347 this_lstnr = __qseecom_find_svc(data->listener.id);
1348 if (IS_ERR_OR_NULL(this_lstnr)) {
1349 pr_err("Invalid listener ID\n");
1350 return -ENOMEM;
1351 }
1352 } else {
1353 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1354 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001355
1356 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001357 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001358 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001359 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001360 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001361 if (IS_ERR_OR_NULL(ihandle)) {
1362 pr_err("Ion client can't retrieve the handle\n");
1363 return -ENOMEM;
1364 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001365 field = (char *) cmd_req->cmd_req_buf +
1366 cmd_req->ifd_data[i].cmd_buf_offset;
1367 } else if ((listener_svc) &&
1368 (lstnr_resp->ifd_data[i].fd > 0)) {
1369 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1370 lstnr_resp->ifd_data[i].fd);
1371 if (IS_ERR_OR_NULL(ihandle)) {
1372 pr_err("Ion client can't retrieve the handle\n");
1373 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001374 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001375 field = lstnr_resp->resp_buf_ptr +
1376 lstnr_resp->ifd_data[i].cmd_buf_offset;
1377 } else {
1378 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001379 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001380 /* Populate the cmd data structure with the phys_addr */
1381 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1382 if (sg_ptr == NULL) {
1383 pr_err("IOn client could not retrieve sg table\n");
1384 goto err;
1385 }
1386 if (sg_ptr->nents == 0) {
1387 pr_err("Num of scattered entries is 0\n");
1388 goto err;
1389 }
1390 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1391 pr_err("Num of scattered entries");
1392 pr_err(" (%d) is greater than max supported %d\n",
1393 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1394 goto err;
1395 }
1396 sg = sg_ptr->sgl;
1397 if (sg_ptr->nents == 1) {
1398 uint32_t *update;
1399 update = (uint32_t *) field;
1400 if (cleanup)
1401 *update = 0;
1402 else
1403 *update = (uint32_t)sg_dma_address(
1404 sg_ptr->sgl);
1405 len += (uint32_t)sg->length;
1406 } else {
1407 struct qseecom_sg_entry *update;
1408 int j = 0;
1409 update = (struct qseecom_sg_entry *) field;
1410 for (j = 0; j < sg_ptr->nents; j++) {
1411 if (cleanup) {
1412 update->phys_addr = 0;
1413 update->len = 0;
1414 } else {
1415 update->phys_addr = (uint32_t)
1416 sg_dma_address(sg);
1417 update->len = sg->length;
1418 }
1419 len += sg->length;
1420 update++;
1421 sg = sg_next(sg);
1422 }
1423 }
1424 if (cleanup)
1425 msm_ion_do_cache_op(qseecom.ion_clnt,
1426 ihandle, NULL, len,
1427 ION_IOC_INV_CACHES);
1428 else
1429 msm_ion_do_cache_op(qseecom.ion_clnt,
1430 ihandle, NULL, len,
1431 ION_IOC_CLEAN_INV_CACHES);
1432 /* Deallocate the handle */
1433 if (!IS_ERR_OR_NULL(ihandle))
1434 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001435 }
1436 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001437err:
1438 if (!IS_ERR_OR_NULL(ihandle))
1439 ion_free(qseecom.ion_clnt, ihandle);
1440 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001441}
1442
1443static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1444 void __user *argp)
1445{
1446 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001447 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001448 struct qseecom_send_modfd_cmd_req req;
1449 struct qseecom_send_cmd_req send_cmd_req;
1450
1451 ret = copy_from_user(&req, argp, sizeof(req));
1452 if (ret) {
1453 pr_err("copy_from_user failed\n");
1454 return ret;
1455 }
Zhen Kongf4948192013-11-25 13:05:35 -08001456
1457 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1458 pr_err("cmd buffer or response buffer is null\n");
1459 return -EINVAL;
1460 }
1461 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1462 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1463 data->client.sb_length))) {
1464 pr_err("cmd buffer address not within shared bufffer\n");
1465 return -EINVAL;
1466 }
1467
1468 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1469 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1470 data->client.sb_length))){
1471 pr_err("response buffer address not within shared bufffer\n");
1472 return -EINVAL;
1473 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001474 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1475 send_cmd_req.cmd_req_len = req.cmd_req_len;
1476 send_cmd_req.resp_buf = req.resp_buf;
1477 send_cmd_req.resp_len = req.resp_len;
1478
Mona Hossaindddf4442013-10-01 14:08:20 -07001479 /* validate offsets */
1480 for (i = 0; i < MAX_ION_FD; i++) {
1481 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1482 pr_err("Invalid offset %d = 0x%x\n",
1483 i, req.ifd_data[i].cmd_buf_offset);
1484 return -EINVAL;
1485 }
1486 }
Zhen Kongf4948192013-11-25 13:05:35 -08001487 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1488 (uint32_t)req.cmd_req_buf);
1489 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1490 (uint32_t)req.resp_buf);
1491
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001492 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001493 if (ret)
1494 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001495 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001496 if (ret)
1497 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001498 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001499 if (ret)
1500 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001501
Mona Hossain2892b6b2012-02-17 13:53:11 -08001502 return ret;
1503}
1504
1505static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1506 struct qseecom_registered_listener_list *svc)
1507{
1508 int ret;
1509 ret = (svc->rcv_req_flag != 0);
1510 return ret || data->abort;
1511}
1512
1513static int qseecom_receive_req(struct qseecom_dev_handle *data)
1514{
1515 int ret = 0;
1516 struct qseecom_registered_listener_list *this_lstnr;
1517
1518 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301519 if (!this_lstnr) {
1520 pr_err("Invalid listener ID\n");
1521 return -ENODATA;
1522 }
1523
Mona Hossain2892b6b2012-02-17 13:53:11 -08001524 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001525 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001526 __qseecom_listener_has_rcvd_req(data,
1527 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001528 pr_warning("Interrupted: exiting Listener Service = %d\n",
1529 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001530 /* woken up for different reason */
1531 return -ERESTARTSYS;
1532 }
1533
1534 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001535 pr_err("Aborting Listener Service = %d\n",
1536 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001537 return -ENODEV;
1538 }
1539 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001540 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001541 }
1542 return ret;
1543}
1544
Mona Hossaind44a3842012-10-15 09:41:35 -07001545static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1546{
1547 struct elf32_hdr *ehdr;
1548
1549 if (fw_entry->size < sizeof(*ehdr)) {
1550 pr_err("%s: Not big enough to be an elf header\n",
1551 qseecom.pdev->init_name);
1552 return false;
1553 }
1554 ehdr = (struct elf32_hdr *)fw_entry->data;
1555 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1556 pr_err("%s: Not an elf header\n",
1557 qseecom.pdev->init_name);
1558 return false;
1559 }
1560
1561 if (ehdr->e_phnum == 0) {
1562 pr_err("%s: No loadable segments\n",
1563 qseecom.pdev->init_name);
1564 return false;
1565 }
1566 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1567 sizeof(struct elf32_hdr) > fw_entry->size) {
1568 pr_err("%s: Program headers not within mdt\n",
1569 qseecom.pdev->init_name);
1570 return false;
1571 }
1572 return true;
1573}
1574
1575static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1576{
1577 int ret = -1;
1578 int i = 0, rc = 0;
1579 const struct firmware *fw_entry = NULL;
1580 struct elf32_phdr *phdr;
1581 char fw_name[MAX_APP_NAME_SIZE];
1582 struct elf32_hdr *ehdr;
1583 int num_images = 0;
1584
1585 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1586 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1587 if (rc) {
1588 pr_err("error with request_firmware\n");
1589 ret = -EIO;
1590 goto err;
1591 }
1592 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1593 ret = -EIO;
1594 goto err;
1595 }
1596 *fw_size = fw_entry->size;
1597 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1598 ehdr = (struct elf32_hdr *)fw_entry->data;
1599 num_images = ehdr->e_phnum;
1600 release_firmware(fw_entry);
1601 for (i = 0; i < num_images; i++, phdr++) {
1602 memset(fw_name, 0, sizeof(fw_name));
1603 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1604 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1605 if (ret)
1606 goto err;
1607 *fw_size += fw_entry->size;
1608 release_firmware(fw_entry);
1609 }
1610 return ret;
1611err:
1612 if (fw_entry)
1613 release_firmware(fw_entry);
1614 *fw_size = 0;
1615 return ret;
1616}
1617
1618static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1619 struct qseecom_load_app_ireq *load_req)
1620{
1621 int ret = -1;
1622 int i = 0, rc = 0;
1623 const struct firmware *fw_entry = NULL;
1624 char fw_name[MAX_APP_NAME_SIZE];
1625 u8 *img_data_ptr = img_data;
1626 struct elf32_hdr *ehdr;
1627 int num_images = 0;
1628
1629 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1630 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1631 if (rc) {
1632 ret = -EIO;
1633 goto err;
1634 }
1635 load_req->img_len = fw_entry->size;
1636 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1637 img_data_ptr = img_data_ptr + fw_entry->size;
1638 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1639 ehdr = (struct elf32_hdr *)fw_entry->data;
1640 num_images = ehdr->e_phnum;
1641 release_firmware(fw_entry);
1642 for (i = 0; i < num_images; i++) {
1643 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1644 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1645 if (ret) {
1646 pr_err("Failed to locate blob %s\n", fw_name);
1647 goto err;
1648 }
1649 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1650 img_data_ptr = img_data_ptr + fw_entry->size;
1651 load_req->img_len += fw_entry->size;
1652 release_firmware(fw_entry);
1653 }
1654 load_req->phy_addr = virt_to_phys(img_data);
1655 return ret;
1656err:
1657 release_firmware(fw_entry);
1658 return ret;
1659}
1660
1661static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1662{
1663 int ret = -1;
1664 uint32_t fw_size = 0;
1665 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1666 struct qseecom_command_scm_resp resp;
1667 u8 *img_data = NULL;
1668
1669 if (__qseecom_get_fw_size(appname, &fw_size))
1670 return -EIO;
1671
1672 img_data = kzalloc(fw_size, GFP_KERNEL);
1673 if (!img_data) {
1674 pr_err("Failied to allocate memory for copying image data\n");
1675 return -ENOMEM;
1676 }
1677 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1678 if (ret) {
1679 kzfree(img_data);
1680 return -EIO;
1681 }
1682
1683 /* Populate the remaining parameters */
1684 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1685 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001686 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001687 if (ret) {
1688 kzfree(img_data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001689 return -EIO;
1690 }
1691
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001692 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001693 /* SCM_CALL to load the image */
1694 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1695 sizeof(struct qseecom_load_app_ireq),
1696 &resp, sizeof(resp));
1697 kzfree(img_data);
1698 if (ret) {
1699 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001700 __qseecom_disable_clk_scale_down(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001701 return -EIO;
1702 }
1703
1704 switch (resp.result) {
1705 case QSEOS_RESULT_SUCCESS:
1706 ret = resp.data;
1707 break;
1708 case QSEOS_RESULT_INCOMPLETE:
1709 ret = __qseecom_process_incomplete_cmd(data, &resp);
1710 if (ret)
1711 pr_err("process_incomplete_cmd FAILED\n");
1712 else
1713 ret = resp.data;
1714 break;
1715 case QSEOS_RESULT_FAILURE:
1716 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1717 break;
1718 default:
1719 pr_err("scm call return unknown response %d\n", resp.result);
1720 ret = -EINVAL;
1721 break;
1722 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001723 __qseecom_disable_clk_scale_down(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001724
Mona Hossaind44a3842012-10-15 09:41:35 -07001725 return ret;
1726}
1727
Mona Hossain9498f5e2013-01-23 18:08:45 -08001728static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001729{
1730 int32_t ret = 0;
1731 uint32_t fw_size = 0;
1732 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1733 struct qseecom_command_scm_resp resp;
1734 u8 *img_data = NULL;
1735
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001736 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001737 return -EIO;
1738
1739 img_data = kzalloc(fw_size, GFP_KERNEL);
1740 if (!img_data) {
1741 pr_err("Mem allocation for lib image data failed\n");
1742 return -ENOMEM;
1743 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001744 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001745 if (ret) {
1746 kzfree(img_data);
1747 return -EIO;
1748 }
1749 /* Populate the remaining parameters */
1750 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001751 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001752 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001753 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08001754 kzfree(img_data);
1755 return -EIO;
1756 }
1757
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001758 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001759 /* SCM_CALL to load the image */
1760 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1761 sizeof(struct qseecom_load_lib_image_ireq),
1762 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001763 if (ret) {
1764 pr_err("scm_call to load failed : ret %d\n", ret);
1765 ret = -EIO;
1766 } else {
1767 switch (resp.result) {
1768 case QSEOS_RESULT_SUCCESS:
1769 break;
1770 case QSEOS_RESULT_FAILURE:
1771 pr_err("scm call failed w/response result%d\n",
1772 resp.result);
1773 ret = -EINVAL;
1774 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001775 case QSEOS_RESULT_INCOMPLETE:
1776 ret = __qseecom_process_incomplete_cmd(data, &resp);
1777 if (ret)
1778 pr_err("process_incomplete_cmd failed err: %d\n",
1779 ret);
1780 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001781 default:
1782 pr_err("scm call return unknown response %d\n",
1783 resp.result);
1784 ret = -EINVAL;
1785 break;
1786 }
1787 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001788 kzfree(img_data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001789 __qseecom_disable_clk_scale_down(data);
Mona Hossain05c73562012-10-29 17:49:01 -07001790 return ret;
1791}
1792
1793static int qseecom_unload_commonlib_image(void)
1794{
1795 int ret = -EINVAL;
1796 struct qseecom_unload_lib_image_ireq unload_req = {0};
1797 struct qseecom_command_scm_resp resp;
1798
1799 /* Populate the remaining parameters */
1800 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1801 /* SCM_CALL to load the image */
1802 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1803 sizeof(struct qseecom_unload_lib_image_ireq),
1804 &resp, sizeof(resp));
1805 if (ret) {
1806 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1807 ret = -EIO;
1808 } else {
1809 switch (resp.result) {
1810 case QSEOS_RESULT_SUCCESS:
1811 break;
1812 case QSEOS_RESULT_FAILURE:
1813 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1814 break;
1815 default:
1816 pr_err("scm call return unknown response %d\n",
1817 resp.result);
1818 ret = -EINVAL;
1819 break;
1820 }
1821 }
1822 return ret;
1823}
1824
Mona Hossaind44a3842012-10-15 09:41:35 -07001825int qseecom_start_app(struct qseecom_handle **handle,
1826 char *app_name, uint32_t size)
1827{
Mona Hossain05c73562012-10-29 17:49:01 -07001828 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001829 unsigned long flags = 0;
1830 struct qseecom_dev_handle *data = NULL;
1831 struct qseecom_check_app_ireq app_ireq;
1832 struct qseecom_registered_app_list *entry = NULL;
1833 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1834 bool found_app = false;
1835 uint32_t len;
1836 ion_phys_addr_t pa;
1837
Mona Hossain823f9882012-11-23 14:42:20 -08001838 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1839 if (!(*handle)) {
1840 pr_err("failed to allocate memory for kernel client handle\n");
1841 return -ENOMEM;
1842 }
1843
Mona Hossaind44a3842012-10-15 09:41:35 -07001844 data = kzalloc(sizeof(*data), GFP_KERNEL);
1845 if (!data) {
1846 pr_err("kmalloc failed\n");
1847 if (ret == 0) {
1848 kfree(*handle);
1849 *handle = NULL;
1850 }
1851 return -ENOMEM;
1852 }
1853 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001854 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001855 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001856 data->client.sb_length = size;
1857 data->client.user_virt_sb_base = 0;
1858 data->client.ihandle = NULL;
1859
1860 init_waitqueue_head(&data->abort_wq);
1861 atomic_set(&data->ioctl_count, 0);
1862
1863 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1864 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1865 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1866 pr_err("Ion client could not retrieve the handle\n");
1867 kfree(data);
1868 kfree(*handle);
1869 *handle = NULL;
1870 return -EINVAL;
1871 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001872 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001873 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001874 if (qseecom.commonlib_loaded == false) {
1875 ret = qseecom_load_commonlib_image(data);
1876 if (ret == 0)
1877 qseecom.commonlib_loaded = true;
1878 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001879 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001880 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001881 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001882 ret = -EIO;
1883 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001884 }
1885
1886 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1887 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1888 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001889 if (ret < 0)
1890 goto err;
1891
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001892 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001893 if (ret > 0) {
1894 pr_warn("App id %d for [%s] app exists\n", ret,
1895 (char *)app_ireq.app_name);
1896 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1897 list_for_each_entry(entry,
1898 &qseecom.registered_app_list_head, list){
1899 if (entry->app_id == ret) {
1900 entry->ref_cnt++;
1901 found_app = true;
1902 break;
1903 }
1904 }
1905 spin_unlock_irqrestore(
1906 &qseecom.registered_app_list_lock, flags);
1907 if (!found_app)
1908 pr_warn("App_id %d [%s] was loaded but not registered\n",
1909 ret, (char *)app_ireq.app_name);
1910 } else {
1911 /* load the app and get the app_id */
1912 pr_debug("%s: Loading app for the first time'\n",
1913 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001914 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001915 if (ret < 0)
1916 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001917 data->client.app_id = ret;
1918 }
1919 if (!found_app) {
1920 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1921 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001922 pr_err("kmalloc for app entry failed\n");
1923 ret = -ENOMEM;
1924 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001925 }
1926 entry->app_id = ret;
1927 entry->ref_cnt = 1;
1928
1929 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1930 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1931 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1932 flags);
1933 }
1934
1935 /* Get the physical address of the ION BUF */
1936 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1937 /* Populate the structure for sending scm call to load image */
1938 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1939 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001940 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001941 data->client.sb_phys = pa;
1942 (*handle)->dev = (void *)data;
1943 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1944 (*handle)->sbuf_len = data->client.sb_length;
1945
1946 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1947 if (!kclient_entry) {
1948 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001949 ret = -ENOMEM;
1950 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001951 }
1952 kclient_entry->handle = *handle;
1953
1954 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1955 list_add_tail(&kclient_entry->list,
1956 &qseecom.registered_kclient_list_head);
1957 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1958
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001959 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001960 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001961
1962err:
1963 kfree(data);
1964 kfree(*handle);
1965 *handle = NULL;
1966 mutex_unlock(&app_access_lock);
1967 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001968}
1969EXPORT_SYMBOL(qseecom_start_app);
1970
1971int qseecom_shutdown_app(struct qseecom_handle **handle)
1972{
1973 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001974 struct qseecom_dev_handle *data;
1975
Mona Hossaind44a3842012-10-15 09:41:35 -07001976 struct qseecom_registered_kclient_list *kclient = NULL;
1977 unsigned long flags = 0;
1978 bool found_handle = false;
1979
Mona Hossain33824022013-02-25 09:32:33 -08001980 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001981 pr_err("Handle is not initialized\n");
1982 return -EINVAL;
1983 }
Mona Hossain33824022013-02-25 09:32:33 -08001984 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001985 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1986 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1987 list) {
1988 if (kclient->handle == (*handle)) {
1989 list_del(&kclient->list);
1990 found_handle = true;
1991 break;
1992 }
1993 }
1994 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1995 if (!found_handle)
1996 pr_err("Unable to find the handle, exiting\n");
1997 else
1998 ret = qseecom_unload_app(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001999
2000 if (qseecom.support_bus_scaling) {
2001 mutex_lock(&qsee_bw_mutex);
2002 if (data->mode != INACTIVE) {
2003 qseecom_unregister_bus_bandwidth_needs(data);
2004 if (qseecom.cumulative_mode == INACTIVE) {
2005 ret = __qseecom_set_msm_bus_request(INACTIVE);
2006 if (ret)
2007 pr_err("Fail to scale down bus\n");
2008 }
2009 }
2010 mutex_unlock(&qsee_bw_mutex);
2011 } else {
2012 if (data->fast_load_enabled == true)
2013 qsee_disable_clock_vote(data, CLK_SFPB);
2014 if (data->perf_enabled == true)
2015 qsee_disable_clock_vote(data, CLK_DFAB);
2016 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002017 if (ret == 0) {
2018 kzfree(data);
2019 kzfree(*handle);
2020 kzfree(kclient);
2021 *handle = NULL;
2022 }
2023 return ret;
2024}
2025EXPORT_SYMBOL(qseecom_shutdown_app);
2026
2027int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2028 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2029{
2030 int ret = 0;
2031 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2032 struct qseecom_dev_handle *data;
2033
Mona Hossaind44a3842012-10-15 09:41:35 -07002034 if (handle == NULL) {
2035 pr_err("Handle is not initialized\n");
2036 return -EINVAL;
2037 }
2038 data = handle->dev;
2039
2040 req.cmd_req_len = sbuf_len;
2041 req.resp_len = rbuf_len;
2042 req.cmd_req_buf = send_buf;
2043 req.resp_buf = resp_buf;
2044
2045 mutex_lock(&app_access_lock);
2046 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002047 if (qseecom.support_bus_scaling)
2048 qseecom_scale_bus_bandwidth_timer(INACTIVE,
2049 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002050 ret = __qseecom_send_cmd(data, &req);
2051
2052 atomic_dec(&data->ioctl_count);
2053 mutex_unlock(&app_access_lock);
2054
2055 if (ret)
2056 return ret;
2057
2058 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2059 req.resp_len, req.resp_buf);
2060 return ret;
2061}
2062EXPORT_SYMBOL(qseecom_send_command);
2063
Mona Hossain91a8fc92012-11-07 19:58:30 -08002064int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2065{
Mona Hossainfca6f422013-01-12 13:00:35 -08002066 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002067 if ((handle == NULL) || (handle->dev == NULL)) {
2068 pr_err("No valid kernel client\n");
2069 return -EINVAL;
2070 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002071 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002072 if (qseecom.support_bus_scaling) {
2073 mutex_lock(&qsee_bw_mutex);
2074 __qseecom_register_bus_bandwidth_needs(handle->dev,
2075 HIGH);
2076 mutex_unlock(&qsee_bw_mutex);
2077 if (ret)
2078 pr_err("Failed to scale bus (med) %d\n", ret);
2079 } else {
2080 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2081 if (ret)
2082 pr_err("Failed to vote for DFAB clock%d\n",
2083 ret);
2084 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2085 if (ret) {
2086 pr_err("Failed to vote for SFPB clock%d\n",
2087 ret);
2088 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2089 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002090 }
2091 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002092 if (!qseecom.support_bus_scaling) {
2093 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2094 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
2095 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002096 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002097 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002098}
2099EXPORT_SYMBOL(qseecom_set_bandwidth);
2100
Mona Hossain2892b6b2012-02-17 13:53:11 -08002101static int qseecom_send_resp(void)
2102{
2103 qseecom.send_resp_flag = 1;
2104 wake_up_interruptible(&qseecom.send_resp_wq);
2105 return 0;
2106}
2107
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002108
2109static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2110 void __user *argp)
2111{
2112 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002113 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002114 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002115
2116 if (copy_from_user(&resp, argp, sizeof(resp))) {
2117 pr_err("copy_from_user failed");
2118 return -EINVAL;
2119 }
Zhen Kongf4948192013-11-25 13:05:35 -08002120 this_lstnr = __qseecom_find_svc(data->listener.id);
2121 if (this_lstnr == NULL)
2122 return -EINVAL;
2123
2124 if (resp.resp_buf_ptr == NULL) {
2125 pr_err("Invalid resp_buf_ptr\n");
2126 return -EINVAL;
2127 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002128 /* validate offsets */
2129 for (i = 0; i < MAX_ION_FD; i++) {
2130 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2131 pr_err("Invalid offset %d = 0x%x\n",
2132 i, resp.ifd_data[i].cmd_buf_offset);
2133 return -EINVAL;
2134 }
2135 }
Zhen Kongf4948192013-11-25 13:05:35 -08002136
2137 if (((uint32_t)resp.resp_buf_ptr <
2138 this_lstnr->user_virt_sb_base)
2139 || ((uint32_t)resp.resp_buf_ptr >=
2140 (this_lstnr->user_virt_sb_base +
2141 this_lstnr->sb_length))) {
2142 pr_err("resp_buf_ptr address not within shared buffer\n");
2143 return -EINVAL;
2144 }
2145 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2146 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002147 __qseecom_update_cmd_buf(&resp, false, data, true);
2148 qseecom.send_resp_flag = 1;
2149 wake_up_interruptible(&qseecom.send_resp_wq);
2150 return 0;
2151}
2152
2153
Mona Hossain2892b6b2012-02-17 13:53:11 -08002154static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2155 void __user *argp)
2156{
2157 struct qseecom_qseos_version_req req;
2158
2159 if (copy_from_user(&req, argp, sizeof(req))) {
2160 pr_err("copy_from_user failed");
2161 return -EINVAL;
2162 }
2163 req.qseos_version = qseecom.qseos_version;
2164 if (copy_to_user(argp, &req, sizeof(req))) {
2165 pr_err("copy_to_user failed");
2166 return -EINVAL;
2167 }
2168 return 0;
2169}
2170
Mona Hossainc92629e2013-04-01 13:37:46 -07002171static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002172{
2173 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002174 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002175
Mona Hossainc92629e2013-04-01 13:37:46 -07002176 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002177 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002178 else
2179 qclk = &qseecom.ce_drv;
2180
2181 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002182
2183 if (qclk->clk_access_cnt == ULONG_MAX)
2184 goto err;
2185
Mona Hossainc92629e2013-04-01 13:37:46 -07002186 if (qclk->clk_access_cnt > 0) {
2187 qclk->clk_access_cnt++;
2188 mutex_unlock(&clk_access_lock);
2189 return rc;
2190 }
2191
Mona Hossain6311d572013-03-01 15:54:02 -08002192 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002193 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002194 if (rc) {
2195 pr_err("Unable to enable/prepare CE core clk\n");
2196 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002197 }
2198 /* Enable CE clk */
2199 rc = clk_prepare_enable(qclk->ce_clk);
2200 if (rc) {
2201 pr_err("Unable to enable/prepare CE iface clk\n");
2202 goto ce_clk_err;
2203 }
2204 /* Enable AXI clk */
2205 rc = clk_prepare_enable(qclk->ce_bus_clk);
2206 if (rc) {
2207 pr_err("Unable to enable/prepare CE bus clk\n");
2208 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002209 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002210 qclk->clk_access_cnt++;
2211 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002212 return 0;
2213
2214ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002215 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002216ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002217 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002218err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002219 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002220 return -EIO;
2221}
2222
Mona Hossainc92629e2013-04-01 13:37:46 -07002223static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002224{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002225 struct qseecom_clk *qclk;
2226
Mona Hossainc92629e2013-04-01 13:37:46 -07002227 if (ce == CLK_QSEE)
2228 qclk = &qseecom.qsee;
2229 else
2230 qclk = &qseecom.ce_drv;
2231
2232 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002233
2234 if (qclk->clk_access_cnt == 0) {
2235 mutex_unlock(&clk_access_lock);
2236 return;
2237 }
2238
Mona Hossainc92629e2013-04-01 13:37:46 -07002239 if (qclk->clk_access_cnt == 1) {
2240 if (qclk->ce_clk != NULL)
2241 clk_disable_unprepare(qclk->ce_clk);
2242 if (qclk->ce_core_clk != NULL)
2243 clk_disable_unprepare(qclk->ce_core_clk);
2244 if (qclk->ce_bus_clk != NULL)
2245 clk_disable_unprepare(qclk->ce_bus_clk);
2246 }
2247 qclk->clk_access_cnt--;
2248 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002249}
2250
Mona Hossain04d3fac2012-12-03 10:10:37 -08002251static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2252 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002253{
2254 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002255 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002256
Mona Hossain17a4faf2013-03-22 16:40:56 -07002257 qclk = &qseecom.qsee;
2258 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002259 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002260
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002261 switch (clk_type) {
2262 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002263 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002264 if (!qseecom.qsee_bw_count) {
2265 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002266 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002267 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002268 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002269 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002270 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002271 if (!ret) {
2272 ret =
2273 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002274 qseecom.qsee_perf_client, 1);
2275 if ((ret) &&
2276 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002277 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002278 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002279 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002280 if (ret)
2281 pr_err("DFAB Bandwidth req failed (%d)\n",
2282 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002283 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002284 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002285 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002286 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002287 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002288 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002289 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002290 }
2291 mutex_unlock(&qsee_bw_mutex);
2292 break;
2293 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002294 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002295 if (!qseecom.qsee_sfpb_bw_count) {
2296 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002297 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002298 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002299 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002300 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002301 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002302 if (!ret) {
2303 ret =
2304 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002305 qseecom.qsee_perf_client, 2);
2306 if ((ret) &&
2307 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002308 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002309 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002310 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002311
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002312 if (ret)
2313 pr_err("SFPB Bandwidth req failed (%d)\n",
2314 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002315 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002316 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002317 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002318 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002319 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002320 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002321 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002322 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002323 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002324 break;
2325 default:
2326 pr_err("Clock type not defined\n");
2327 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002328 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002329 return ret;
2330}
2331
Mona Hossain04d3fac2012-12-03 10:10:37 -08002332static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2333 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002334{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002335 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002336 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002337
Mona Hossain17a4faf2013-03-22 16:40:56 -07002338 qclk = &qseecom.qsee;
2339 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002340 return;
2341
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002342 switch (clk_type) {
2343 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002344 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002345 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002346 pr_err("Client error.Extra call to disable DFAB clk\n");
2347 mutex_unlock(&qsee_bw_mutex);
2348 return;
2349 }
2350
Mona Hossain17a4faf2013-03-22 16:40:56 -07002351 if (qseecom.qsee_bw_count == 1) {
2352 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002353 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002354 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002355 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002356 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002357 qseecom.qsee_perf_client, 0);
2358 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002359 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002360 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002361 if (ret)
2362 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002363 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002364 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002365 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002366 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002367 }
2368 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002369 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002370 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002371 }
2372 mutex_unlock(&qsee_bw_mutex);
2373 break;
2374 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002375 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002376 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002377 pr_err("Client error.Extra call to disable SFPB clk\n");
2378 mutex_unlock(&qsee_bw_mutex);
2379 return;
2380 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002381 if (qseecom.qsee_sfpb_bw_count == 1) {
2382 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002383 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002384 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002385 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002386 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002387 qseecom.qsee_perf_client, 0);
2388 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002389 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002390 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002391 if (ret)
2392 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002393 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002394 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002395 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002396 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002397 }
2398 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002399 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002400 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002401 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002402 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002403 break;
2404 default:
2405 pr_err("Clock type not defined\n");
2406 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002407 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002408
Mona Hossain2892b6b2012-02-17 13:53:11 -08002409}
2410
Mona Hossain5ab9d772012-04-11 21:00:40 -07002411static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2412 void __user *argp)
2413{
2414 struct ion_handle *ihandle; /* Ion handle */
2415 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002416 int ret;
2417 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002418 ion_phys_addr_t pa = 0;
2419 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002420 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002421 struct qseecom_load_app_ireq load_req;
2422 struct qseecom_command_scm_resp resp;
2423
2424 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002425 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002426 (void __user *)argp,
2427 sizeof(struct qseecom_load_img_req))) {
2428 pr_err("copy_from_user failed\n");
2429 return -EFAULT;
2430 }
2431
2432 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002433 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002434 load_img_req.ifd_data_fd);
2435 if (IS_ERR_OR_NULL(ihandle)) {
2436 pr_err("Ion client could not retrieve the handle\n");
2437 return -ENOMEM;
2438 }
2439
2440 /* Get the physical address of the ION BUF */
2441 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2442
2443 /* Populate the structure for sending scm call to load image */
2444 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2445 load_req.mdt_len = load_img_req.mdt_len;
2446 load_req.img_len = load_img_req.img_len;
2447 load_req.phy_addr = pa;
2448
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002449 /* SCM_CALL tied to Core0 */
2450 mask = CPU_MASK_CPU0;
2451 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2452 if (set_cpu_ret) {
2453 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2454 set_cpu_ret);
2455 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302456 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002457 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302458
Mona Hossain6311d572013-03-01 15:54:02 -08002459 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002460 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002461 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002462 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302463 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002464 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002465 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2466 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002467 /* SCM_CALL to load the external elf */
2468 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2469 sizeof(struct qseecom_load_app_ireq),
2470 &resp, sizeof(resp));
2471 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002472 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002473 ret);
2474 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302475 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002476 }
2477
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302478 switch (resp.result) {
2479 case QSEOS_RESULT_SUCCESS:
2480 break;
2481 case QSEOS_RESULT_INCOMPLETE:
2482 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002483 ret = __qseecom_process_incomplete_cmd(data, &resp);
2484 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302485 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2486 break;
2487 case QSEOS_RESULT_FAILURE:
2488 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2489 ret = -EFAULT;
2490 break;
2491 default:
2492 pr_err("scm_call response result %d not supported\n",
2493 resp.result);
2494 ret = -EFAULT;
2495 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002496 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002497
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302498exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002499 __qseecom_disable_clk_scale_down(data);
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302500exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002501 /* Restore the CPU mask */
2502 mask = CPU_MASK_ALL;
2503 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2504 if (set_cpu_ret) {
2505 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2506 set_cpu_ret);
2507 ret = -EFAULT;
2508 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302509exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002510 /* Deallocate the handle */
2511 if (!IS_ERR_OR_NULL(ihandle))
2512 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002513 return ret;
2514}
2515
2516static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2517{
2518 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002519 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002520 struct qseecom_command_scm_resp resp;
2521 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002522 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002523
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302524 /* unavailable client app */
2525 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2526
Mona Hossain5ab9d772012-04-11 21:00:40 -07002527 /* Populate the structure for sending scm call to unload image */
2528 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002529
2530 /* SCM_CALL tied to Core0 */
2531 mask = CPU_MASK_CPU0;
2532 ret = set_cpus_allowed_ptr(current, &mask);
2533 if (ret) {
2534 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2535 ret);
2536 return -EFAULT;
2537 }
2538
Mona Hossain5ab9d772012-04-11 21:00:40 -07002539 /* SCM_CALL to unload the external elf */
2540 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2541 sizeof(struct qseecom_unload_app_ireq),
2542 &resp, sizeof(resp));
2543 if (ret) {
2544 pr_err("scm_call to unload failed : ret %d\n",
2545 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002546 ret = -EFAULT;
2547 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002548 }
2549 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2550 ret = __qseecom_process_incomplete_cmd(data, &resp);
2551 if (ret)
2552 pr_err("process_incomplete_cmd fail err: %d\n",
2553 ret);
2554 } else {
2555 if (resp.result != QSEOS_RESULT_SUCCESS) {
2556 pr_err("scm_call to unload image failed resp.result =%d\n",
2557 resp.result);
2558 ret = -EFAULT;
2559 }
2560 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002561
2562qseecom_unload_external_elf_scm_err:
2563 /* Restore the CPU mask */
2564 mask = CPU_MASK_ALL;
2565 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2566 if (set_cpu_ret) {
2567 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2568 set_cpu_ret);
2569 ret = -EFAULT;
2570 }
2571
Mona Hossain5ab9d772012-04-11 21:00:40 -07002572 return ret;
2573}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002574
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002575static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2576 void __user *argp)
2577{
2578
2579 int32_t ret;
2580 struct qseecom_qseos_app_load_query query_req;
2581 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002582 struct qseecom_registered_app_list *entry = NULL;
2583 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002584
2585 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002586 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002587 (void __user *)argp,
2588 sizeof(struct qseecom_qseos_app_load_query))) {
2589 pr_err("copy_from_user failed\n");
2590 return -EFAULT;
2591 }
2592
2593 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002594 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002595 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2596
2597 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002598
2599 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002600 pr_err(" scm call to check if app is loaded failed");
2601 return ret; /* scm call failed */
2602 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002603 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002604 (char *)(req.app_name));
2605 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2606 list_for_each_entry(entry,
2607 &qseecom.registered_app_list_head, list){
2608 if (entry->app_id == ret) {
2609 entry->ref_cnt++;
2610 break;
2611 }
2612 }
2613 spin_unlock_irqrestore(
2614 &qseecom.registered_app_list_lock, flags);
2615 data->client.app_id = ret;
2616 query_req.app_id = ret;
2617
2618 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2619 pr_err("copy_to_user failed\n");
2620 return -EFAULT;
2621 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002622 return -EEXIST; /* app already loaded */
2623 } else {
2624 return 0; /* app not loaded */
2625 }
2626}
2627
Mona Hossain4cf78a92013-02-14 12:06:41 -08002628static int __qseecom_get_ce_pipe_info(
2629 enum qseecom_key_management_usage_type usage,
2630 uint32_t *pipe, uint32_t *ce_hw)
2631{
2632 int ret;
2633 switch (usage) {
2634 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2635 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2636 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2637 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2638 qseecom.ce_info.disk_encrypt_pipe,
2639 qseecom.ce_info.hlos_ce_hw_instance);
2640 ret = -EINVAL;
2641 } else {
2642 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2643 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2644 ret = 0;
2645 }
2646 break;
2647 default:
2648 ret = -EINVAL;
2649 break;
2650 }
2651 return ret;
2652}
2653
2654static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2655 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002656 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002657{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002658 struct qseecom_command_scm_resp resp;
2659 int ret;
2660
Zhen Kong9730ddf2013-12-17 16:49:43 -08002661 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2662 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002663 pr_err("Error:: unsupported usage %d\n", usage);
2664 return -EFAULT;
2665 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002666 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002667
2668 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002669 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002670 &resp, sizeof(resp));
2671 if (ret) {
2672 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002673 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002674 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002675 }
2676
2677 switch (resp.result) {
2678 case QSEOS_RESULT_SUCCESS:
2679 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002680 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002681 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002682 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002683 case QSEOS_RESULT_INCOMPLETE:
2684 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002685 if (ret) {
2686 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002687 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002688 ret = 0;
2689 } else {
2690 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2691 resp.result);
2692 }
2693 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002694 break;
2695 case QSEOS_RESULT_FAILURE:
2696 default:
2697 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2698 ret = -EINVAL;
2699 break;
2700 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002701 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002702 return ret;
2703}
2704
2705static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2706 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002707 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002708{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002709 struct qseecom_command_scm_resp resp;
2710 int ret;
2711
2712 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2713 pr_err("Error:: unsupported usage %d\n", usage);
2714 return -EFAULT;
2715 }
2716
Mona Hossainc92629e2013-04-01 13:37:46 -07002717 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002718
2719 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002720 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002721 &resp, sizeof(struct qseecom_command_scm_resp));
2722 if (ret) {
2723 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002724 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002725 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002726 }
2727
2728 switch (resp.result) {
2729 case QSEOS_RESULT_SUCCESS:
2730 break;
2731 case QSEOS_RESULT_INCOMPLETE:
2732 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002733 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002734 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2735 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002736 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2737 pr_debug("Max attempts to input password reached.\n");
2738 ret = -ERANGE;
2739 }
2740 }
2741 break;
2742 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2743 pr_debug("Max attempts to input password reached.\n");
2744 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002745 break;
2746 case QSEOS_RESULT_FAILURE:
2747 default:
2748 pr_err("Delete key scm call failed resp.result %d\n",
2749 resp.result);
2750 ret = -EINVAL;
2751 break;
2752 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002753 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002754 return ret;
2755}
2756
2757static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2758 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002759 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002760{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002761 struct qseecom_command_scm_resp resp;
2762 int ret;
2763
Zhen Kong9730ddf2013-12-17 16:49:43 -08002764 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2765 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002766 pr_err("Error:: unsupported usage %d\n", usage);
2767 return -EFAULT;
2768 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002769
Zhen Kongdb2bf742013-05-13 23:55:42 -07002770 __qseecom_enable_clk(CLK_QSEE);
2771 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002772 __qseecom_enable_clk(CLK_CE_DRV);
2773
Zhen Kong336636e2013-04-15 11:04:54 -07002774 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002775 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002776 &resp, sizeof(struct qseecom_command_scm_resp));
2777 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002778 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002779 __qseecom_disable_clk(CLK_QSEE);
2780 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2781 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002782 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07002783 }
2784
Mona Hossain4cf78a92013-02-14 12:06:41 -08002785 switch (resp.result) {
2786 case QSEOS_RESULT_SUCCESS:
2787 break;
2788 case QSEOS_RESULT_INCOMPLETE:
2789 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002790 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002791 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2792 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002793 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2794 pr_debug("Max attempts to input password reached.\n");
2795 ret = -ERANGE;
2796 }
2797 }
2798 break;
2799 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2800 pr_debug("Max attempts to input password reached.\n");
2801 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002802 break;
2803 case QSEOS_RESULT_FAILURE:
2804 default:
2805 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2806 ret = -EINVAL;
2807 break;
2808 }
2809
Zhen Kongdb2bf742013-05-13 23:55:42 -07002810 __qseecom_disable_clk(CLK_QSEE);
2811 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002812 __qseecom_disable_clk(CLK_CE_DRV);
2813
Mona Hossain4cf78a92013-02-14 12:06:41 -08002814 return ret;
2815}
2816
Zhen Kong9730ddf2013-12-17 16:49:43 -08002817static int __qseecom_update_current_key_user_info(
2818 struct qseecom_dev_handle *data,
2819 enum qseecom_key_management_usage_type usage,
2820 struct qseecom_key_userinfo_update_ireq *ireq)
2821{
2822 struct qseecom_command_scm_resp resp;
2823 int ret;
2824
2825 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2826 usage >= QSEOS_KM_USAGE_MAX) {
2827 pr_err("Error:: unsupported usage %d\n", usage);
2828 return -EFAULT;
2829 }
2830
2831 __qseecom_enable_clk(CLK_QSEE);
2832
2833 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
2834 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
2835 &resp, sizeof(struct qseecom_command_scm_resp));
2836 if (ret) {
2837 pr_err("scm call to update key userinfo failed : %d\n", ret);
2838 __qseecom_disable_clk(CLK_QSEE);
2839 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2840 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002841 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002842 }
2843
2844 switch (resp.result) {
2845 case QSEOS_RESULT_SUCCESS:
2846 break;
2847 case QSEOS_RESULT_INCOMPLETE:
2848 ret = __qseecom_process_incomplete_cmd(data, &resp);
2849 if (ret)
2850 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2851 resp.result);
2852 break;
2853 case QSEOS_RESULT_FAILURE:
2854 default:
2855 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2856 ret = -EINVAL;
2857 break;
2858 }
2859
2860 __qseecom_disable_clk(CLK_QSEE);
2861 return ret;
2862}
2863
Mona Hossain4cf78a92013-02-14 12:06:41 -08002864static int qseecom_create_key(struct qseecom_dev_handle *data,
2865 void __user *argp)
2866{
2867 uint32_t ce_hw = 0;
2868 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002869 int ret = 0;
2870 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002871 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002872 struct qseecom_key_generate_ireq generate_key_ireq;
2873 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002874
2875 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2876 if (ret) {
2877 pr_err("copy_from_user failed\n");
2878 return ret;
2879 }
2880
Zhen Kong9730ddf2013-12-17 16:49:43 -08002881 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2882 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002883 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2884 return -EFAULT;
2885 }
2886
2887 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2888 if (ret) {
2889 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2890 return -EINVAL;
2891 }
2892
Zhen Kong9730ddf2013-12-17 16:49:43 -08002893 generate_key_ireq.flags = flags;
2894 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
2895 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2896 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2897 memcpy((void *)generate_key_ireq.key_id,
2898 (void *)key_id_array[create_key_req.usage - 1],
2899 QSEECOM_KEY_ID_SIZE);
2900 memcpy((void *)generate_key_ireq.hash32,
2901 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
2902
Mona Hossain4cf78a92013-02-14 12:06:41 -08002903 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002904 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002905 if (ret) {
2906 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002907 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002908 }
2909
Zhen Kong9730ddf2013-12-17 16:49:43 -08002910 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2911 set_key_ireq.ce = ce_hw;
2912 set_key_ireq.pipe = pipe;
2913 set_key_ireq.flags = flags;
2914
2915 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2916 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
2917 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2918 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2919 memcpy((void *)set_key_ireq.key_id,
2920 (void *)key_id_array[create_key_req.usage - 1],
2921 QSEECOM_KEY_ID_SIZE);
2922 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002923 QSEECOM_HASH_SIZE);
2924
2925 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002926 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002927 if (ret) {
2928 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2929 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002930 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002931 }
2932
2933 return ret;
2934}
2935
2936static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2937 void __user *argp)
2938{
2939 uint32_t ce_hw = 0;
2940 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002941 int ret = 0;
2942 uint32_t flags = 0;
2943 int i;
2944 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002945 struct qseecom_key_delete_ireq delete_key_ireq;
2946 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002947
2948 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2949 if (ret) {
2950 pr_err("copy_from_user failed\n");
2951 return ret;
2952 }
2953
Zhen Kong9730ddf2013-12-17 16:49:43 -08002954 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2955 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002956 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2957 return -EFAULT;
2958 }
2959
2960 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2961 if (ret) {
2962 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2963 return -EINVAL;
2964 }
2965
Zhen Kong9730ddf2013-12-17 16:49:43 -08002966 delete_key_ireq.flags = flags;
2967 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
2968 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2969 memcpy((void *)delete_key_ireq.key_id,
2970 (void *)key_id_array[wipe_key_req.usage - 1],
2971 QSEECOM_KEY_ID_SIZE);
2972 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2973
2974 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
2975 &delete_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002976 if (ret) {
2977 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2978 return -EFAULT;
2979 }
2980
Zhen Kong9730ddf2013-12-17 16:49:43 -08002981 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2982 clear_key_ireq.ce = ce_hw;
2983 clear_key_ireq.pipe = pipe;
2984 clear_key_ireq.flags = flags;
2985 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002986 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kong9730ddf2013-12-17 16:49:43 -08002987 clear_key_ireq.key_id[i] = 0xff;
2988 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2989
Mona Hossain4cf78a92013-02-14 12:06:41 -08002990 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002991 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002992 if (ret) {
2993 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2994 pipe, ce_hw, ret);
2995 return -EFAULT;
2996 }
2997
2998 return ret;
2999}
3000
Zhen Kong9730ddf2013-12-17 16:49:43 -08003001static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3002 void __user *argp)
3003{
3004 int ret = 0;
3005 uint32_t flags = 0;
3006 struct qseecom_update_key_userinfo_req update_key_req;
3007 struct qseecom_key_userinfo_update_ireq ireq;
3008
3009 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3010 if (ret) {
3011 pr_err("copy_from_user failed\n");
3012 return ret;
3013 }
3014
3015 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3016 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3017 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3018 return -EFAULT;
3019 }
3020
3021 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3022 ireq.flags = flags;
3023 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3024 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3025 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
3026 memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
3027 QSEECOM_KEY_ID_SIZE);
3028 memcpy((void *)ireq.current_hash32,
3029 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3030 memcpy((void *)ireq.new_hash32,
3031 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3032
3033 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3034 &ireq);
3035 if (ret) {
3036 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003037 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003038 }
3039 return ret;
3040
3041}
3042
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003043static int qseecom_is_es_activated(void __user *argp)
3044{
3045 struct qseecom_is_es_activated_req req;
3046 int ret;
3047 int resp_buf;
3048
3049 if (qseecom.qsee_version < QSEE_VERSION_04) {
3050 pr_err("invalid qsee version");
3051 return -ENODEV;
3052 }
3053
3054 if (argp == NULL) {
3055 pr_err("arg is null");
3056 return -EINVAL;
3057 }
3058
3059 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3060 (void *) &resp_buf, sizeof(resp_buf));
3061 if (ret) {
3062 pr_err("scm_call failed");
3063 return ret;
3064 }
3065
3066 req.is_activated = resp_buf;
3067 ret = copy_to_user(argp, &req, sizeof(req));
3068 if (ret) {
3069 pr_err("copy_to_user failed");
3070 return ret;
3071 }
3072
3073 return 0;
3074}
3075
3076static int qseecom_save_partition_hash(void __user *argp)
3077{
3078 struct qseecom_save_partition_hash_req req;
3079 int ret;
3080
3081 if (qseecom.qsee_version < QSEE_VERSION_04) {
3082 pr_err("invalid qsee version ");
3083 return -ENODEV;
3084 }
3085
3086 if (argp == NULL) {
3087 pr_err("arg is null");
3088 return -EINVAL;
3089 }
3090
3091 ret = copy_from_user(&req, argp, sizeof(req));
3092 if (ret) {
3093 pr_err("copy_from_user failed");
3094 return ret;
3095 }
3096
3097 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3098 (void *) &req, sizeof(req), NULL, 0);
3099 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003100 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003101 return ret;
3102 }
3103
3104 return 0;
3105}
3106
Mona Hossain2892b6b2012-02-17 13:53:11 -08003107static long qseecom_ioctl(struct file *file, unsigned cmd,
3108 unsigned long arg)
3109{
3110 int ret = 0;
3111 struct qseecom_dev_handle *data = file->private_data;
3112 void __user *argp = (void __user *) arg;
3113
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303114 if (!data) {
3115 pr_err("Invalid/uninitialized device handle\n");
3116 return -EINVAL;
3117 }
3118
Mona Hossain2892b6b2012-02-17 13:53:11 -08003119 if (data->abort) {
3120 pr_err("Aborting qseecom driver\n");
3121 return -ENODEV;
3122 }
3123
3124 switch (cmd) {
3125 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003126 if (data->type != QSEECOM_GENERIC) {
3127 pr_err("reg lstnr req: invalid handle (%d)\n",
3128 data->type);
3129 ret = -EINVAL;
3130 break;
3131 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003132 pr_debug("ioctl register_listener_req()\n");
3133 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003134 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003135 ret = qseecom_register_listener(data, argp);
3136 atomic_dec(&data->ioctl_count);
3137 wake_up_all(&data->abort_wq);
3138 if (ret)
3139 pr_err("failed qseecom_register_listener: %d\n", ret);
3140 break;
3141 }
3142 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003143 if ((data->listener.id == 0) ||
3144 (data->type != QSEECOM_LISTENER_SERVICE)) {
3145 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3146 data->type, data->listener.id);
3147 ret = -EINVAL;
3148 break;
3149 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003150 pr_debug("ioctl unregister_listener_req()\n");
3151 atomic_inc(&data->ioctl_count);
3152 ret = qseecom_unregister_listener(data);
3153 atomic_dec(&data->ioctl_count);
3154 wake_up_all(&data->abort_wq);
3155 if (ret)
3156 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3157 break;
3158 }
3159 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003160 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003161 if ((data->client.app_id == 0) ||
3162 (data->type != QSEECOM_CLIENT_APP)) {
3163 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3164 data->type, data->client.app_id);
3165 ret = -EINVAL;
3166 break;
3167 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003168 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003169 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003170 if (qseecom.support_bus_scaling)
3171 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3172 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003173 atomic_inc(&data->ioctl_count);
3174 ret = qseecom_send_cmd(data, argp);
3175 atomic_dec(&data->ioctl_count);
3176 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003177 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003178 if (ret)
3179 pr_err("failed qseecom_send_cmd: %d\n", ret);
3180 break;
3181 }
3182 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003183 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003184 if ((data->client.app_id == 0) ||
3185 (data->type != QSEECOM_CLIENT_APP)) {
3186 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3187 data->type, data->client.app_id);
3188 ret = -EINVAL;
3189 break;
3190 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003191 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003192 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003193 if (qseecom.support_bus_scaling)
3194 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3195 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003196 atomic_inc(&data->ioctl_count);
3197 ret = qseecom_send_modfd_cmd(data, argp);
3198 atomic_dec(&data->ioctl_count);
3199 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003200 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003201 if (ret)
3202 pr_err("failed qseecom_send_cmd: %d\n", ret);
3203 break;
3204 }
3205 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003206 if ((data->listener.id == 0) ||
3207 (data->type != QSEECOM_LISTENER_SERVICE)) {
3208 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3209 data->type, data->listener.id);
3210 ret = -EINVAL;
3211 break;
3212 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003213 atomic_inc(&data->ioctl_count);
3214 ret = qseecom_receive_req(data);
3215 atomic_dec(&data->ioctl_count);
3216 wake_up_all(&data->abort_wq);
3217 if (ret)
3218 pr_err("failed qseecom_receive_req: %d\n", ret);
3219 break;
3220 }
3221 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003222 if ((data->listener.id == 0) ||
3223 (data->type != QSEECOM_LISTENER_SERVICE)) {
3224 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3225 data->type, data->listener.id);
3226 ret = -EINVAL;
3227 break;
3228 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003229 atomic_inc(&data->ioctl_count);
3230 ret = qseecom_send_resp();
3231 atomic_dec(&data->ioctl_count);
3232 wake_up_all(&data->abort_wq);
3233 if (ret)
3234 pr_err("failed qseecom_send_resp: %d\n", ret);
3235 break;
3236 }
3237 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003238 if ((data->type != QSEECOM_CLIENT_APP) &&
3239 (data->type != QSEECOM_GENERIC) &&
3240 (data->type != QSEECOM_SECURE_SERVICE)) {
3241 pr_err("set mem param req: invalid handle (%d)\n",
3242 data->type);
3243 ret = -EINVAL;
3244 break;
3245 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003246 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003247 ret = qseecom_set_client_mem_param(data, argp);
3248 if (ret)
3249 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3250 ret);
3251 break;
3252 }
3253 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003254 if ((data->type != QSEECOM_GENERIC) &&
3255 (data->type != QSEECOM_CLIENT_APP)) {
3256 pr_err("load app req: invalid handle (%d)\n",
3257 data->type);
3258 ret = -EINVAL;
3259 break;
3260 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003261 data->type = QSEECOM_CLIENT_APP;
3262 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003263 mutex_lock(&app_access_lock);
3264 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003265 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3266 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003267 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003268 if (ret == 0)
3269 qseecom.commonlib_loaded = true;
3270 }
3271 }
3272 if (ret == 0)
3273 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003274 atomic_dec(&data->ioctl_count);
3275 mutex_unlock(&app_access_lock);
3276 if (ret)
3277 pr_err("failed load_app request: %d\n", ret);
3278 break;
3279 }
3280 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003281 if ((data->client.app_id == 0) ||
3282 (data->type != QSEECOM_CLIENT_APP)) {
3283 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3284 data->type, data->client.app_id);
3285 ret = -EINVAL;
3286 break;
3287 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003288 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003289 mutex_lock(&app_access_lock);
3290 atomic_inc(&data->ioctl_count);
3291 ret = qseecom_unload_app(data);
3292 atomic_dec(&data->ioctl_count);
3293 mutex_unlock(&app_access_lock);
3294 if (ret)
3295 pr_err("failed unload_app request: %d\n", ret);
3296 break;
3297 }
3298 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3299 atomic_inc(&data->ioctl_count);
3300 ret = qseecom_get_qseos_version(data, argp);
3301 if (ret)
3302 pr_err("qseecom_get_qseos_version: %d\n", ret);
3303 atomic_dec(&data->ioctl_count);
3304 break;
3305 }
3306 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003307 if ((data->type != QSEECOM_GENERIC) &&
3308 (data->type != QSEECOM_CLIENT_APP)) {
3309 pr_err("perf enable req: invalid handle (%d)\n",
3310 data->type);
3311 ret = -EINVAL;
3312 break;
3313 }
3314 if ((data->type == QSEECOM_CLIENT_APP) &&
3315 (data->client.app_id == 0)) {
3316 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3317 data->type, data->client.app_id);
3318 ret = -EINVAL;
3319 break;
3320 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003321 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003322 if (qseecom.support_bus_scaling) {
3323 mutex_lock(&qsee_bw_mutex);
3324 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3325 mutex_unlock(&qsee_bw_mutex);
3326 } else {
3327 ret = qsee_vote_for_clock(data, CLK_DFAB);
3328 if (ret)
3329 pr_err("Fail to vote for DFAB clock%d\n", ret);
3330 ret = qsee_vote_for_clock(data, CLK_SFPB);
3331 if (ret)
3332 pr_err("Fail to vote for SFPB clock%d\n", ret);
3333 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003334 atomic_dec(&data->ioctl_count);
3335 break;
3336 }
3337 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003338 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3339 (data->type != QSEECOM_CLIENT_APP)) {
3340 pr_err("perf disable req: invalid handle (%d)\n",
3341 data->type);
3342 ret = -EINVAL;
3343 break;
3344 }
3345 if ((data->type == QSEECOM_CLIENT_APP) &&
3346 (data->client.app_id == 0)) {
3347 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3348 data->type, data->client.app_id);
3349 ret = -EINVAL;
3350 break;
3351 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003352 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003353 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003354 qsee_disable_clock_vote(data, CLK_DFAB);
3355 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003356 }
3357 atomic_dec(&data->ioctl_count);
3358 break;
3359 }
3360
3361 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3362 if ((data->client.app_id == 0) ||
3363 (data->type != QSEECOM_CLIENT_APP)) {
3364 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3365 data->type, data->client.app_id);
3366 ret = -EINVAL;
3367 break;
3368 }
3369 atomic_inc(&data->ioctl_count);
3370 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003371 atomic_dec(&data->ioctl_count);
3372 break;
3373 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003374 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003375 if (data->type != QSEECOM_GENERIC) {
3376 pr_err("load ext elf req: invalid client handle (%d)\n",
3377 data->type);
3378 ret = -EINVAL;
3379 break;
3380 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003381 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003382 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003383 mutex_lock(&app_access_lock);
3384 atomic_inc(&data->ioctl_count);
3385 ret = qseecom_load_external_elf(data, argp);
3386 atomic_dec(&data->ioctl_count);
3387 mutex_unlock(&app_access_lock);
3388 if (ret)
3389 pr_err("failed load_external_elf request: %d\n", ret);
3390 break;
3391 }
3392 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003393 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3394 pr_err("unload ext elf req: invalid handle (%d)\n",
3395 data->type);
3396 ret = -EINVAL;
3397 break;
3398 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003399 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003400 mutex_lock(&app_access_lock);
3401 atomic_inc(&data->ioctl_count);
3402 ret = qseecom_unload_external_elf(data);
3403 atomic_dec(&data->ioctl_count);
3404 mutex_unlock(&app_access_lock);
3405 if (ret)
3406 pr_err("failed unload_app request: %d\n", ret);
3407 break;
3408 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003409 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003410 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003411 mutex_lock(&app_access_lock);
3412 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003413 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003414 ret = qseecom_query_app_loaded(data, argp);
3415 atomic_dec(&data->ioctl_count);
3416 mutex_unlock(&app_access_lock);
3417 break;
3418 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003419 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003420 if (data->type != QSEECOM_GENERIC) {
3421 pr_err("send cmd svc req: invalid handle (%d)\n",
3422 data->type);
3423 ret = -EINVAL;
3424 break;
3425 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003426 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003427 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003428 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003429 qseecom.qsee_version);
3430 return -EINVAL;
3431 }
3432 mutex_lock(&app_access_lock);
3433 atomic_inc(&data->ioctl_count);
3434 ret = qseecom_send_service_cmd(data, argp);
3435 atomic_dec(&data->ioctl_count);
3436 mutex_unlock(&app_access_lock);
3437 break;
3438 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003439 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003440 if (data->type != QSEECOM_GENERIC) {
3441 pr_err("create key req: invalid handle (%d)\n",
3442 data->type);
3443 ret = -EINVAL;
3444 break;
3445 }
Zhen Kong336636e2013-04-15 11:04:54 -07003446 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003447 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003448 qseecom.qsee_version);
3449 return -EINVAL;
3450 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003451 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003452 atomic_inc(&data->ioctl_count);
3453 ret = qseecom_create_key(data, argp);
3454 if (ret)
3455 pr_err("failed to create encryption key: %d\n", ret);
3456
3457 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003458 break;
3459 }
3460 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003461 if (data->type != QSEECOM_GENERIC) {
3462 pr_err("wipe key req: invalid handle (%d)\n",
3463 data->type);
3464 ret = -EINVAL;
3465 break;
3466 }
Zhen Kong336636e2013-04-15 11:04:54 -07003467 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003468 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003469 qseecom.qsee_version);
3470 return -EINVAL;
3471 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003472 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003473 atomic_inc(&data->ioctl_count);
3474 ret = qseecom_wipe_key(data, argp);
3475 if (ret)
3476 pr_err("failed to wipe encryption key: %d\n", ret);
3477 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003478 break;
3479 }
3480 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
3481 if (data->type != QSEECOM_GENERIC) {
3482 pr_err("update key req: invalid handle (%d)\n",
3483 data->type);
3484 ret = -EINVAL;
3485 break;
3486 }
3487 if (qseecom.qsee_version < QSEE_VERSION_05) {
3488 pr_err("Update Key feature unsupported in qsee ver %u\n",
3489 qseecom.qsee_version);
3490 return -EINVAL;
3491 }
3492 data->released = true;
3493 atomic_inc(&data->ioctl_count);
3494 ret = qseecom_update_key_user_info(data, argp);
3495 if (ret)
3496 pr_err("failed to update key user info: %d\n", ret);
3497 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003498 break;
3499 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003500 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003501 if (data->type != QSEECOM_GENERIC) {
3502 pr_err("save part hash req: invalid handle (%d)\n",
3503 data->type);
3504 ret = -EINVAL;
3505 break;
3506 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003507 data->released = true;
3508 mutex_lock(&app_access_lock);
3509 atomic_inc(&data->ioctl_count);
3510 ret = qseecom_save_partition_hash(argp);
3511 atomic_dec(&data->ioctl_count);
3512 mutex_unlock(&app_access_lock);
3513 break;
3514 }
3515 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003516 if (data->type != QSEECOM_GENERIC) {
3517 pr_err("ES activated req: invalid handle (%d)\n",
3518 data->type);
3519 ret = -EINVAL;
3520 break;
3521 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003522 data->released = true;
3523 mutex_lock(&app_access_lock);
3524 atomic_inc(&data->ioctl_count);
3525 ret = qseecom_is_es_activated(argp);
3526 atomic_dec(&data->ioctl_count);
3527 mutex_unlock(&app_access_lock);
3528 break;
3529 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003530 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003531 if ((data->listener.id == 0) ||
3532 (data->type != QSEECOM_LISTENER_SERVICE)) {
3533 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3534 data->type, data->listener.id);
3535 ret = -EINVAL;
3536 break;
3537 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003538 /* Only one client allowed here at a time */
3539 atomic_inc(&data->ioctl_count);
3540 ret = qseecom_send_modfd_resp(data, argp);
3541 atomic_dec(&data->ioctl_count);
3542 wake_up_all(&data->abort_wq);
3543 if (ret)
3544 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3545 break;
3546 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003547 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003548 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003549 return -EINVAL;
3550 }
3551 return ret;
3552}
3553
3554static int qseecom_open(struct inode *inode, struct file *file)
3555{
3556 int ret = 0;
3557 struct qseecom_dev_handle *data;
3558
3559 data = kzalloc(sizeof(*data), GFP_KERNEL);
3560 if (!data) {
3561 pr_err("kmalloc failed\n");
3562 return -ENOMEM;
3563 }
3564 file->private_data = data;
3565 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003566 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003567 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003568 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003569 init_waitqueue_head(&data->abort_wq);
3570 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003571
Mona Hossain2892b6b2012-02-17 13:53:11 -08003572 return ret;
3573}
3574
3575static int qseecom_release(struct inode *inode, struct file *file)
3576{
3577 struct qseecom_dev_handle *data = file->private_data;
3578 int ret = 0;
3579
3580 if (data->released == false) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003581 pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
3582 data->type, data->mode, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003583 switch (data->type) {
3584 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003585 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003586 break;
3587 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003588 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003589 break;
3590 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003591 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003592 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003593 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003594 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003595 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303596 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3597 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003598 default:
3599 pr_err("Unsupported clnt_handle_type %d",
3600 data->type);
3601 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003602 }
3603 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003604
Zhen Kong2edf90d2013-08-27 12:05:06 -07003605 if (qseecom.support_bus_scaling) {
3606 mutex_lock(&qsee_bw_mutex);
3607 if (data->mode != INACTIVE) {
3608 qseecom_unregister_bus_bandwidth_needs(data);
3609 if (qseecom.cumulative_mode == INACTIVE) {
3610 ret = __qseecom_set_msm_bus_request(INACTIVE);
3611 if (ret)
3612 pr_err("Fail to scale down bus\n");
3613 }
3614 }
3615 mutex_unlock(&qsee_bw_mutex);
3616 } else {
3617 if (data->fast_load_enabled == true)
3618 qsee_disable_clock_vote(data, CLK_SFPB);
3619 if (data->perf_enabled == true)
3620 qsee_disable_clock_vote(data, CLK_DFAB);
3621 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003622 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003623
Mona Hossain2892b6b2012-02-17 13:53:11 -08003624 return ret;
3625}
3626
Mona Hossain2892b6b2012-02-17 13:53:11 -08003627static const struct file_operations qseecom_fops = {
3628 .owner = THIS_MODULE,
3629 .unlocked_ioctl = qseecom_ioctl,
3630 .open = qseecom_open,
3631 .release = qseecom_release
3632};
3633
Mona Hossainc92629e2013-04-01 13:37:46 -07003634static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003635{
3636 int rc = 0;
3637 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003638 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003639 char *core_clk_src = NULL;
3640 char *core_clk = NULL;
3641 char *iface_clk = NULL;
3642 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003643
Mona Hossainc92629e2013-04-01 13:37:46 -07003644 switch (ce) {
3645 case CLK_QSEE: {
3646 core_clk_src = "core_clk_src";
3647 core_clk = "core_clk";
3648 iface_clk = "iface_clk";
3649 bus_clk = "bus_clk";
3650 qclk = &qseecom.qsee;
3651 qclk->instance = CLK_QSEE;
3652 break;
3653 };
3654 case CLK_CE_DRV: {
3655 core_clk_src = "ce_drv_core_clk_src";
3656 core_clk = "ce_drv_core_clk";
3657 iface_clk = "ce_drv_iface_clk";
3658 bus_clk = "ce_drv_bus_clk";
3659 qclk = &qseecom.ce_drv;
3660 qclk->instance = CLK_CE_DRV;
3661 break;
3662 };
3663 default:
3664 pr_err("Invalid ce hw instance: %d!\n", ce);
3665 return -EIO;
3666 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003667 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003668
Mona Hossainc92629e2013-04-01 13:37:46 -07003669 /* Get CE3 src core clk. */
3670 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003671 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003672 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003673 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003674 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003675 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003676 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003677 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003678 }
3679 } else {
3680 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003681 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003682 }
3683
3684 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003685 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003686 if (IS_ERR(qclk->ce_core_clk)) {
3687 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003688 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003689 if (qclk->ce_core_src_clk != NULL)
3690 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003691 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003692 }
3693
3694 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003695 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003696 if (IS_ERR(qclk->ce_clk)) {
3697 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003698 pr_err("Unable to get CE interface 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);
3701 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003702 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003703 }
3704
3705 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003706 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003707 if (IS_ERR(qclk->ce_bus_clk)) {
3708 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003709 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003710 if (qclk->ce_core_src_clk != NULL)
3711 clk_put(qclk->ce_core_src_clk);
3712 clk_put(qclk->ce_core_clk);
3713 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003714 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003715 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003716 return rc;
3717}
3718
Mona Hossainc92629e2013-04-01 13:37:46 -07003719static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003720{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003721 struct qseecom_clk *qclk;
3722
Mona Hossainc92629e2013-04-01 13:37:46 -07003723 if (ce == CLK_QSEE)
3724 qclk = &qseecom.qsee;
3725 else
3726 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003727
3728 if (qclk->ce_clk != NULL) {
3729 clk_put(qclk->ce_clk);
3730 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003731 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003732 if (qclk->ce_core_clk != NULL) {
3733 clk_put(qclk->ce_core_clk);
3734 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003735 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003736 if (qclk->ce_bus_clk != NULL) {
3737 clk_put(qclk->ce_bus_clk);
3738 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003739 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003740 if (qclk->ce_core_src_clk != NULL) {
3741 clk_put(qclk->ce_core_src_clk);
3742 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003743 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003744}
3745
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003746static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003747{
3748 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003749 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003750 struct device *class_dev;
3751 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003752 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003753 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3754
Mona Hossain17a4faf2013-03-22 16:40:56 -07003755 qseecom.qsee_bw_count = 0;
3756 qseecom.qsee_perf_client = 0;
3757 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003758
Mona Hossain17a4faf2013-03-22 16:40:56 -07003759 qseecom.qsee.ce_core_clk = NULL;
3760 qseecom.qsee.ce_clk = NULL;
3761 qseecom.qsee.ce_core_src_clk = NULL;
3762 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003763
Zhen Kong2edf90d2013-08-27 12:05:06 -07003764 qseecom.cumulative_mode = 0;
3765 qseecom.current_mode = INACTIVE;
3766 qseecom.support_bus_scaling = false;
3767
Mona Hossainc92629e2013-04-01 13:37:46 -07003768 qseecom.ce_drv.ce_core_clk = NULL;
3769 qseecom.ce_drv.ce_clk = NULL;
3770 qseecom.ce_drv.ce_core_src_clk = NULL;
3771 qseecom.ce_drv.ce_bus_clk = NULL;
3772
Mona Hossain2892b6b2012-02-17 13:53:11 -08003773 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3774 if (rc < 0) {
3775 pr_err("alloc_chrdev_region failed %d\n", rc);
3776 return rc;
3777 }
3778
3779 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3780 if (IS_ERR(driver_class)) {
3781 rc = -ENOMEM;
3782 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303783 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003784 }
3785
3786 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3787 QSEECOM_DEV);
3788 if (!class_dev) {
3789 pr_err("class_device_create failed %d\n", rc);
3790 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303791 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003792 }
3793
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303794 cdev_init(&qseecom.cdev, &qseecom_fops);
3795 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003796
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303797 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003798 if (rc < 0) {
3799 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303800 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003801 }
3802
3803 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3804 spin_lock_init(&qseecom.registered_listener_list_lock);
3805 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3806 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003807 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3808 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003809 init_waitqueue_head(&qseecom.send_resp_wq);
3810 qseecom.send_resp_flag = 0;
3811
3812 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3813 &qsee_not_legacy, sizeof(qsee_not_legacy));
3814 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003815 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303816 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003817 }
Mona Hossain05c73562012-10-29 17:49:01 -07003818 if (qsee_not_legacy) {
3819 uint32_t feature = 10;
3820
3821 qseecom.qsee_version = QSEEE_VERSION_00;
3822 rc = scm_call(6, 3, &feature, sizeof(feature),
3823 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3824 if (rc) {
3825 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303826 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003827 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003828 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003829 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003830 pr_err("QSEE legacy version is not supported:");
3831 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3832 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303833 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003834 }
Mona Hossain05c73562012-10-29 17:49:01 -07003835 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003836 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003837 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003838 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003839 if (qseecom.ion_clnt == NULL) {
3840 pr_err("Ion client cannot be created\n");
3841 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303842 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003843 }
3844
3845 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003846 if (pdev->dev.of_node) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003847 qseecom.support_bus_scaling =
3848 of_property_read_bool((&pdev->dev)->of_node,
3849 "qcom,support-bus-scaling");
3850 pr_warn("support_bus_scaling=0x%x",
3851 qseecom.support_bus_scaling);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003852 if (of_property_read_u32((&pdev->dev)->of_node,
3853 "qcom,disk-encrypt-pipe-pair",
3854 &qseecom.ce_info.disk_encrypt_pipe)) {
3855 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3856 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3857 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303858 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003859 } else {
3860 pr_warn("bam_pipe_pair=0x%x",
3861 qseecom.ce_info.disk_encrypt_pipe);
3862 }
3863
3864 if (of_property_read_u32((&pdev->dev)->of_node,
3865 "qcom,qsee-ce-hw-instance",
3866 &qseecom.ce_info.qsee_ce_hw_instance)) {
3867 pr_err("Fail to get qsee ce hw instance information.\n");
3868 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3869 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303870 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003871 } else {
3872 pr_warn("qsee-ce-hw-instance=0x%x",
3873 qseecom.ce_info.qsee_ce_hw_instance);
3874 }
3875
3876 if (of_property_read_u32((&pdev->dev)->of_node,
3877 "qcom,hlos-ce-hw-instance",
3878 &qseecom.ce_info.hlos_ce_hw_instance)) {
3879 pr_err("Fail to get hlos ce hw instance information.\n");
3880 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3881 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303882 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003883 } else {
3884 pr_warn("hlos-ce-hw-instance=0x%x",
3885 qseecom.ce_info.hlos_ce_hw_instance);
3886 }
3887
Mona Hossainc92629e2013-04-01 13:37:46 -07003888 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3889 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3890
3891 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003892 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303893 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003894
Mona Hossainc92629e2013-04-01 13:37:46 -07003895 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3896 ret = __qseecom_init_clk(CLK_CE_DRV);
3897 if (ret) {
3898 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303899 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003900 }
3901 } else {
3902 struct qseecom_clk *qclk;
3903
3904 qclk = &qseecom.qsee;
3905 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3906 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3907 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3908 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3909 }
3910
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003911 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3912 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003913 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3914 struct resource *resource = NULL;
3915 struct qsee_apps_region_info_ireq req;
3916 struct qseecom_command_scm_resp resp;
3917
3918 resource = platform_get_resource_byname(pdev,
3919 IORESOURCE_MEM, "secapp-region");
3920 if (resource) {
3921 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3922 req.addr = resource->start;
3923 req.size = resource_size(resource);
3924 pr_warn("secure app region addr=0x%x size=0x%x",
3925 req.addr, req.size);
3926 } else {
3927 pr_err("Fail to get secure app region info\n");
3928 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303929 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003930 }
3931 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3932 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003933 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3934 pr_err("send secapp reg fail %d resp.res %d\n",
3935 rc, resp.result);
3936 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303937 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003938 }
3939 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003940 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003941 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3942 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003943 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07003944 if (qseecom.support_bus_scaling) {
3945 init_timer(&(qseecom.bw_scale_down_timer));
3946 INIT_WORK(&qseecom.bw_inactive_req_ws,
3947 qseecom_bw_inactive_req_work);
3948 qseecom.bw_scale_down_timer.function =
3949 qseecom_scale_bus_bandwidth_timer_callback;
3950 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08003951 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003952 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003953 qseecom_platform_support);
3954
Mona Hossain17a4faf2013-03-22 16:40:56 -07003955 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003956 pr_err("Unable to register bus client\n");
3957 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303958
3959exit_destroy_ion_client:
3960 ion_client_destroy(qseecom.ion_clnt);
3961exit_del_cdev:
3962 cdev_del(&qseecom.cdev);
3963exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003964 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303965exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003966 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303967exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003968 unregister_chrdev_region(qseecom_device_no, 1);
3969 return rc;
3970}
3971
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003972static int __devinit qseecom_remove(struct platform_device *pdev)
3973{
Mona Hossaind44a3842012-10-15 09:41:35 -07003974 struct qseecom_registered_kclient_list *kclient = NULL;
3975 unsigned long flags = 0;
3976 int ret = 0;
3977
Mona Hossaind44a3842012-10-15 09:41:35 -07003978 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303979
Mona Hossaind44a3842012-10-15 09:41:35 -07003980 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303981 list) {
3982 if (!kclient)
3983 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07003984
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303985 /* Break the loop if client handle is NULL */
3986 if (!kclient->handle)
3987 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07003988
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303989 if (list_empty(&kclient->list))
3990 goto exit_free_kc_handle;
3991
3992 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07003993 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303994 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07003995 kzfree(kclient->handle->dev);
3996 kzfree(kclient->handle);
3997 kzfree(kclient);
3998 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003999 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304000
4001exit_free_kc_handle:
4002 kzfree(kclient->handle);
4003exit_free_kclient:
4004 kzfree(kclient);
4005exit_irqrestore:
4006 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4007
4008 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004009 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004010
Mona Hossain17a4faf2013-03-22 16:40:56 -07004011 if (qseecom.qsee_perf_client)
4012 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4013 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304014 if (pdev->dev.platform_data != NULL)
4015 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4016
Zhen Kong2edf90d2013-08-27 12:05:06 -07004017 if (qseecom.support_bus_scaling) {
4018 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4019 del_timer_sync(&qseecom.bw_scale_down_timer);
4020 }
4021
Mona Hossaind39e33b2012-11-05 13:36:40 -08004022 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004023 if (pdev->dev.of_node) {
4024 __qseecom_deinit_clk(CLK_QSEE);
4025 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
4026 __qseecom_deinit_clk(CLK_CE_DRV);
4027 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304028
4029 ion_client_destroy(qseecom.ion_clnt);
4030
4031 cdev_del(&qseecom.cdev);
4032
4033 device_destroy(driver_class, qseecom_device_no);
4034
4035 class_destroy(driver_class);
4036
4037 unregister_chrdev_region(qseecom_device_no, 1);
4038
Mona Hossaind44a3842012-10-15 09:41:35 -07004039 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304040}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004041
Zhen Konga0944b82013-11-06 17:02:00 -08004042static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4043{
4044 int ret = 0;
4045 struct qseecom_clk *qclk;
4046 qclk = &qseecom.qsee;
4047
4048 if (qseecom.cumulative_mode != INACTIVE) {
4049 ret = __qseecom_set_msm_bus_request(INACTIVE);
4050 if (ret)
4051 pr_err("Fail to scale down bus\n");
4052 }
4053 mutex_lock(&clk_access_lock);
4054 if (qclk->clk_access_cnt) {
4055 if (qclk->ce_clk != NULL)
4056 clk_disable_unprepare(qclk->ce_clk);
4057 if (qclk->ce_core_clk != NULL)
4058 clk_disable_unprepare(qclk->ce_core_clk);
4059 if (qclk->ce_bus_clk != NULL)
4060 clk_disable_unprepare(qclk->ce_bus_clk);
4061 }
4062 mutex_unlock(&clk_access_lock);
4063 return 0;
4064}
4065
4066static int qseecom_resume(struct platform_device *pdev)
4067{
4068 int mode = 0;
4069 int ret = 0;
4070 struct qseecom_clk *qclk;
4071 qclk = &qseecom.qsee;
4072
4073 if (qseecom.cumulative_mode >= HIGH)
4074 mode = HIGH;
4075 else
4076 mode = qseecom.cumulative_mode;
4077
4078 if (qseecom.cumulative_mode != INACTIVE) {
4079 ret = __qseecom_set_msm_bus_request(mode);
4080 if (ret)
4081 pr_err("Fail to scale down bus\n");
4082 }
4083
4084 mutex_lock(&clk_access_lock);
4085 if (qclk->clk_access_cnt) {
4086
4087 ret = clk_prepare_enable(qclk->ce_core_clk);
4088 if (ret) {
4089 pr_err("Unable to enable/prepare CE core clk\n");
4090 qclk->clk_access_cnt = 0;
4091 goto err;
4092 }
4093
4094 ret = clk_prepare_enable(qclk->ce_clk);
4095 if (ret) {
4096 pr_err("Unable to enable/prepare CE iface clk\n");
4097 qclk->clk_access_cnt = 0;
4098 goto ce_clk_err;
4099 }
4100
4101 ret = clk_prepare_enable(qclk->ce_bus_clk);
4102 if (ret) {
4103 pr_err("Unable to enable/prepare CE bus clk\n");
4104 qclk->clk_access_cnt = 0;
4105 goto ce_bus_clk_err;
4106 }
4107 }
4108 mutex_unlock(&clk_access_lock);
4109 return 0;
4110
4111ce_bus_clk_err:
4112 clk_disable_unprepare(qclk->ce_clk);
4113ce_clk_err:
4114 clk_disable_unprepare(qclk->ce_core_clk);
4115err:
4116 mutex_unlock(&clk_access_lock);
4117 return -EIO;
4118}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004119static struct of_device_id qseecom_match[] = {
4120 {
4121 .compatible = "qcom,qseecom",
4122 },
4123 {}
4124};
4125
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004126static struct platform_driver qseecom_plat_driver = {
4127 .probe = qseecom_probe,
4128 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004129 .suspend = qseecom_suspend,
4130 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004131 .driver = {
4132 .name = "qseecom",
4133 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004134 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004135 },
4136};
4137
4138static int __devinit qseecom_init(void)
4139{
4140 return platform_driver_register(&qseecom_plat_driver);
4141}
4142
4143static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004144{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304145 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004146}
4147
4148MODULE_LICENSE("GPL v2");
4149MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4150
4151module_init(qseecom_init);
4152module_exit(qseecom_exit);