blob: efafa2389c6894093a1ff2edf58ff58294fa5183 [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 mutex_unlock(&qsee_bw_mutex);
546 return ret;
547}
548
549
550static int qseecom_unregister_bus_bandwidth_needs(
551 struct qseecom_dev_handle *data)
552{
553 int32_t ret = 0;
554
555 qseecom.cumulative_mode -= data->mode;
556 data->mode = INACTIVE;
557
558 return ret;
559}
560
561static int __qseecom_register_bus_bandwidth_needs(
562 struct qseecom_dev_handle *data, uint32_t request_mode)
563{
564 int32_t ret = 0;
565
566 if (data->mode == INACTIVE) {
567 qseecom.cumulative_mode += request_mode;
568 data->mode = request_mode;
569 } else {
570 if (data->mode != request_mode) {
571 qseecom.cumulative_mode -= data->mode;
572 qseecom.cumulative_mode += request_mode;
573 data->mode = request_mode;
574 }
575 }
576 return ret;
577}
578
579static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
580 void __user *argp)
581{
582 int32_t ret = 0;
583 int32_t req_mode;
584
585 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
586 if (ret) {
587 pr_err("copy_from_user failed\n");
588 return ret;
589 }
590 if (req_mode > HIGH) {
591 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
592 return ret;
593 }
594 mutex_lock(&qsee_bw_mutex);
595 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
596 mutex_unlock(&qsee_bw_mutex);
597
598 return ret;
599}
600
601static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
602{
603 if (!qseecom.support_bus_scaling)
604 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong06418b72014-02-05 17:36:23 -0800605 else {
606 mutex_lock(&qsee_bw_mutex);
607 qseecom.bw_scale_down_timer.expires = jiffies +
608 msecs_to_jiffies(QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
609 add_timer(&(qseecom.bw_scale_down_timer));
610 qseecom.timer_running = true;
611 mutex_unlock(&qsee_bw_mutex);
612 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700613 return;
614}
615
616static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
617{
618 int ret = 0;
619 if (qseecom.support_bus_scaling) {
620 qseecom_scale_bus_bandwidth_timer(
621 MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
622 } else {
623 ret = qsee_vote_for_clock(data, CLK_SFPB);
624 if (ret)
625 pr_err("Fail vote for clk SFPB ret %d\n", ret);
626 }
627 return ret;
628}
629
Mona Hossain2892b6b2012-02-17 13:53:11 -0800630static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
631 void __user *argp)
632{
633 ion_phys_addr_t pa;
634 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800635 struct qseecom_set_sb_mem_param_req req;
636 uint32_t len;
637
638 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700639 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800640 return -EFAULT;
641
Mona Hossaina1124de2013-10-01 13:41:09 -0700642 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
643 (req.sb_len == 0)) {
644 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
645 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
646 return -EFAULT;
647 }
Zhen Kongf4948192013-11-25 13:05:35 -0800648 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
649 req.sb_len))
650 return -EFAULT;
651
Mona Hossain2892b6b2012-02-17 13:53:11 -0800652 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800653 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
654 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800655 if (IS_ERR_OR_NULL(data->client.ihandle)) {
656 pr_err("Ion client could not retrieve the handle\n");
657 return -ENOMEM;
658 }
659 /* Get the physical address of the ION BUF */
660 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
661 /* Populate the structure for sending scm call to load image */
662 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700663 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800664 data->client.sb_phys = pa;
665 data->client.sb_length = req.sb_len;
666 data->client.user_virt_sb_base = req.virt_sb_base;
667 return 0;
668}
669
Mona Hossain2892b6b2012-02-17 13:53:11 -0800670static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
671{
672 int ret;
673 ret = (qseecom.send_resp_flag != 0);
674 return ret || data->abort;
675}
676
677static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
678 struct qseecom_command_scm_resp *resp)
679{
680 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800681 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800682 uint32_t lstnr;
683 unsigned long flags;
684 struct qseecom_client_listener_data_irsp send_data_rsp;
685 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700686 sigset_t new_sigset;
687 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800688
Mona Hossain2892b6b2012-02-17 13:53:11 -0800689 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
690 lstnr = resp->data;
691 /*
692 * Wake up blocking lsitener service with the lstnr id
693 */
694 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
695 flags);
696 list_for_each_entry(ptr_svc,
697 &qseecom.registered_listener_list_head, list) {
698 if (ptr_svc->svc.listener_id == lstnr) {
699 ptr_svc->rcv_req_flag = 1;
700 wake_up_interruptible(&ptr_svc->rcv_req_wq);
701 break;
702 }
703 }
704 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
705 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700706
707 if (ptr_svc == NULL) {
708 pr_err("Listener Svc %d does not exist\n", lstnr);
709 return -EINVAL;
710 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800711 if (ptr_svc->svc.listener_id != lstnr) {
712 pr_warning("Service requested for does on exist\n");
713 return -ERESTARTSYS;
714 }
715 pr_debug("waking up rcv_req_wq and "
716 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800717
Mona Hossain91da2c52013-03-29 17:28:31 -0700718 /* initialize the new signal mask with all signals*/
719 sigfillset(&new_sigset);
720 /* block all signals */
721 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
722
723 do {
724 if (!wait_event_freezable(qseecom.send_resp_wq,
725 __qseecom_listener_has_sent_rsp(data)))
726 break;
727 } while (1);
728
729 /* restore signal mask */
730 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
731 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700732 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
733 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700734 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800735 send_data_rsp.status = QSEOS_RESULT_FAILURE;
736 } else {
737 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800738 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800739
Mona Hossain2892b6b2012-02-17 13:53:11 -0800740 qseecom.send_resp_flag = 0;
741 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
742 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700743 if (ptr_svc)
744 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
745 ptr_svc->sb_virt, ptr_svc->sb_length,
746 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700747
748 if (lstnr == RPMB_SERVICE)
749 __qseecom_enable_clk(CLK_QSEE);
750
Mona Hossain2892b6b2012-02-17 13:53:11 -0800751 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
752 (const void *)&send_data_rsp,
753 sizeof(send_data_rsp), resp,
754 sizeof(*resp));
755 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700756 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800757 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700758 if (lstnr == RPMB_SERVICE)
759 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800760 return ret;
761 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800762 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
763 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
764 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
765 resp->result, data->client.app_id, lstnr);
766 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700767 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700768 if (lstnr == RPMB_SERVICE)
769 __qseecom_disable_clk(CLK_QSEE);
770
Mona Hossain2892b6b2012-02-17 13:53:11 -0800771 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800772 if (rc)
773 return rc;
774
Mona Hossain2892b6b2012-02-17 13:53:11 -0800775 return ret;
776}
777
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700778static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
779{
780 int32_t ret;
781 struct qseecom_command_scm_resp resp;
782
783 /* SCM_CALL to check if app_id for the mentioned app exists */
784 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
785 sizeof(struct qseecom_check_app_ireq),
786 &resp, sizeof(resp));
787 if (ret) {
788 pr_err("scm_call to check if app is already loaded failed\n");
789 return -EINVAL;
790 }
791
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700792 if (resp.result == QSEOS_RESULT_FAILURE) {
793 return 0;
794 } else {
795 switch (resp.resp_type) {
796 /*qsee returned listener type response */
797 case QSEOS_LISTENER_ID:
798 pr_err("resp type is of listener type instead of app");
799 return -EINVAL;
800 break;
801 case QSEOS_APP_ID:
802 return resp.data;
803 default:
804 pr_err("invalid resp type (%d) from qsee",
805 resp.resp_type);
806 return -ENODEV;
807 break;
808 }
809 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700810}
811
Mona Hossain2892b6b2012-02-17 13:53:11 -0800812static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
813{
814 struct qseecom_registered_app_list *entry = NULL;
815 unsigned long flags = 0;
816 u32 app_id = 0;
817 struct ion_handle *ihandle; /* Ion handle */
818 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700819 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800820 ion_phys_addr_t pa = 0;
821 uint32_t len;
822 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800823 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700824 struct qseecom_load_app_ireq load_req;
825
Mona Hossain2892b6b2012-02-17 13:53:11 -0800826 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700827 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800828 (void __user *)argp,
829 sizeof(struct qseecom_load_img_req))) {
830 pr_err("copy_from_user failed\n");
831 return -EFAULT;
832 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700833 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700834 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700835 if (ret)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700836 return ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800837 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700838 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800839 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800840
Mona Hossain436b75f2012-11-20 17:10:40 -0800841 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530842 if (ret < 0) {
Zhen Kong2edf90d2013-08-27 12:05:06 -0700843 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800844 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530845 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800846
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530847 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800848 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700849 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800850 (char *)(req.app_name));
851 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
852 list_for_each_entry(entry,
853 &qseecom.registered_app_list_head, list){
854 if (entry->app_id == app_id) {
855 entry->ref_cnt++;
856 break;
857 }
858 }
859 spin_unlock_irqrestore(
860 &qseecom.registered_app_list_lock, flags);
861 } else {
862 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700863 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800864 /* Get the handle of the shared fd */
865 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800866 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800867 if (IS_ERR_OR_NULL(ihandle)) {
868 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700869 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800870 return -ENOMEM;
871 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800872
Mona Hossain436b75f2012-11-20 17:10:40 -0800873 /* Get the physical address of the ION BUF */
874 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800875
Mona Hossain436b75f2012-11-20 17:10:40 -0800876 /* Populate the structure for sending scm call to load image */
877 memcpy(load_req.app_name, load_img_req.img_name,
878 MAX_APP_NAME_SIZE);
879 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
880 load_req.mdt_len = load_img_req.mdt_len;
881 load_req.img_len = load_img_req.img_len;
882 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700883 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
884 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800885
Mona Hossain436b75f2012-11-20 17:10:40 -0800886 /* SCM_CALL to load the app and get the app_id back */
887 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700888 sizeof(struct qseecom_load_app_ireq),
889 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700890 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800891 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800892 if (!IS_ERR_OR_NULL(ihandle))
893 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700894 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800895 return -EINVAL;
896 }
897
898 if (resp.result == QSEOS_RESULT_FAILURE) {
899 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700900 if (!IS_ERR_OR_NULL(ihandle))
901 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700902 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800903 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700904 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700905
Mona Hossain436b75f2012-11-20 17:10:40 -0800906 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
907 ret = __qseecom_process_incomplete_cmd(data, &resp);
908 if (ret) {
909 pr_err("process_incomplete_cmd failed err: %d\n",
910 ret);
911 if (!IS_ERR_OR_NULL(ihandle))
912 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700913 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800914 return ret;
915 }
916 }
917
918 if (resp.result != QSEOS_RESULT_SUCCESS) {
919 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700920 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800921 if (!IS_ERR_OR_NULL(ihandle))
922 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700923 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800924 return -EFAULT;
925 }
926
927 app_id = resp.data;
928
929 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
930 if (!entry) {
931 pr_err("kmalloc failed\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700932 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800933 return -ENOMEM;
934 }
935 entry->app_id = app_id;
936 entry->ref_cnt = 1;
937
938 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700939 if (!IS_ERR_OR_NULL(ihandle))
940 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700941
Mona Hossain436b75f2012-11-20 17:10:40 -0800942 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
943 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
944 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
945 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700946
Mona Hossain436b75f2012-11-20 17:10:40 -0800947 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700948 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800949 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800950 data->client.app_id = app_id;
951 load_img_req.app_id = app_id;
952 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
953 pr_err("copy_to_user failed\n");
954 kzfree(entry);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700955 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800956 return -EFAULT;
957 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700958 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800959 return 0;
960}
961
962static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
963{
964 wake_up_all(&qseecom.send_resp_wq);
965 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700966 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800967 atomic_read(&data->ioctl_count) <= 1)) {
968 pr_err("Interrupted from abort\n");
969 return -ERESTARTSYS;
970 break;
971 }
972 }
973 /* Set unload app */
974 return 1;
975}
976
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800977static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
978{
979 int ret = 0;
980 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
981 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
982 ion_free(qseecom.ion_clnt, data->client.ihandle);
983 data->client.ihandle = NULL;
984 }
985 return ret;
986}
987
Mona Hossain2892b6b2012-02-17 13:53:11 -0800988static int qseecom_unload_app(struct qseecom_dev_handle *data)
989{
990 unsigned long flags;
991 int ret = 0;
992 struct qseecom_command_scm_resp resp;
993 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700994 bool unload = false;
995 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800996
Mona Hossaind4613de2013-05-15 16:49:29 -0700997 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800998 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
999 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
1000 list) {
1001 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -07001002 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001003 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -07001004 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001005 break;
1006 } else {
1007 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -07001008 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -07001009 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001010 break;
1011 }
1012 }
1013 }
1014 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1015 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001016 if (found_app == false) {
1017 pr_err("Cannot find app with id = %d\n",
1018 data->client.app_id);
1019 return -EINVAL;
1020 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001021 }
1022
Mona Hossaind4613de2013-05-15 16:49:29 -07001023 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001024 struct qseecom_unload_app_ireq req;
1025
Mona Hossain340dba82012-08-07 19:54:46 -07001026 __qseecom_cleanup_app(data);
1027 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1028 list_del(&ptr_app->list);
1029 kzfree(ptr_app);
1030 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1031 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001032 /* Populate the structure for sending scm call to load image */
1033 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1034 req.app_id = data->client.app_id;
1035
1036 /* SCM_CALL to unload the app */
1037 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1038 sizeof(struct qseecom_unload_app_ireq),
1039 &resp, sizeof(resp));
1040 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001041 pr_err("scm_call to unload app (id = %d) failed\n",
1042 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001043 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001044 } else {
1045 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001046 }
1047 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1048 ret = __qseecom_process_incomplete_cmd(data, &resp);
1049 if (ret) {
1050 pr_err("process_incomplete_cmd fail err: %d\n",
1051 ret);
1052 return ret;
1053 }
1054 }
1055 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001056 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001057 data->released = true;
1058 return ret;
1059}
1060
1061static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1062 uint32_t virt)
1063{
1064 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1065}
1066
Zhen Kongf4948192013-11-25 13:05:35 -08001067static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1068 uint32_t virt)
1069{
1070 return (uint32_t)data->client.sb_virt +
1071 (virt - data->client.user_virt_sb_base);
1072}
1073
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001074int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1075 struct qseecom_send_svc_cmd_req *req_ptr,
1076 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1077{
1078 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001079 void *req_buf = NULL;
1080
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001081 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1082 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1083 req_ptr, send_svc_ireq_ptr);
1084 return -EINVAL;
1085 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001086
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -08001087 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
1088 pr_err("Invalid req/resp buffer, exiting\n");
1089 return -EINVAL;
1090 }
1091
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001092 /* Clients need to ensure req_buf is at base offset of shared buffer */
1093 if ((uint32_t)req_ptr->cmd_req_buf !=
1094 data_ptr->client.user_virt_sb_base) {
1095 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001096 return -EINVAL;
1097 }
1098
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001099 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1100 || ((uint32_t)req_ptr->resp_buf >=
1101 (data_ptr->client.user_virt_sb_base +
1102 data_ptr->client.sb_length))){
1103 pr_err("response buffer address not within shared bufffer\n");
1104 return -EINVAL;
1105 }
1106
1107 req_buf = data_ptr->client.sb_virt;
1108
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001109 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1110 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001111 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001112 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1113 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1114 (uint32_t)req_ptr->resp_buf));
1115 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1116
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001117 return ret;
1118}
1119
1120static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1121 void __user *argp)
1122{
1123 int ret = 0;
1124 struct qseecom_client_send_service_ireq send_svc_ireq;
1125 struct qseecom_command_scm_resp resp;
1126 struct qseecom_send_svc_cmd_req req;
1127 /*struct qseecom_command_scm_resp resp;*/
1128
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001129 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001130 (void __user *)argp,
1131 sizeof(req))) {
1132 pr_err("copy_from_user failed\n");
1133 return -EFAULT;
1134 }
1135
1136 if (req.resp_buf == NULL) {
1137 pr_err("cmd buffer or response buffer is null\n");
1138 return -EINVAL;
1139 }
1140
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001141 if (data->client.sb_virt == NULL) {
1142 pr_err("sb_virt null\n");
1143 return -EINVAL;
1144 }
1145
1146 if (data->client.user_virt_sb_base == 0) {
1147 pr_err("user_virt_sb_base is null\n");
1148 return -EINVAL;
1149 }
1150
1151 if (data->client.sb_length == 0) {
1152 pr_err("sb_length is 0\n");
1153 return -EINVAL;
1154 }
1155
Zhen Kong2edf90d2013-08-27 12:05:06 -07001156 data->type = QSEECOM_SECURE_SERVICE;
1157
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001158 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001159 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1160 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001161 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1162 &send_svc_ireq))
1163 return -EINVAL;
1164 break;
1165 default:
1166 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1167 return -EINVAL;
1168 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301169
Zhen Kong2edf90d2013-08-27 12:05:06 -07001170 if (qseecom.support_bus_scaling) {
1171 qseecom_scale_bus_bandwidth_timer(HIGH,
1172 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1173 if (ret) {
1174 pr_err("Fail to set bw HIGH%d\n", ret);
1175 return ret;
1176 }
1177 } else {
1178 ret = qsee_vote_for_clock(data, CLK_DFAB);
1179 if (ret) {
1180 pr_err("Failed to vote for DFAB clock%d\n", ret);
1181 return ret;
1182 }
1183 ret = qsee_vote_for_clock(data, CLK_SFPB);
1184 if (ret) {
1185 qsee_disable_clock_vote(data, CLK_DFAB);
1186 pr_err("Failed to vote for SFPB clock%d\n", ret);
1187 goto exit;
1188 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301189 }
1190
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001191 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1192 data->client.sb_virt, data->client.sb_length,
1193 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001194 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1195 sizeof(send_svc_ireq),
1196 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001197 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1198 data->client.sb_virt, data->client.sb_length,
1199 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001200 if (ret) {
1201 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001202 if (!qseecom.support_bus_scaling) {
1203 qsee_disable_clock_vote(data, CLK_DFAB);
1204 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong06418b72014-02-05 17:36:23 -08001205 } else {
1206 mutex_lock(&qsee_bw_mutex);
1207 qseecom.bw_scale_down_timer.expires = jiffies +
1208 msecs_to_jiffies(
1209 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1210 add_timer(&(qseecom.bw_scale_down_timer));
1211 qseecom.timer_running = true;
1212 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001213 }
Zhen Kong06418b72014-02-05 17:36:23 -08001214
Zhen Kong2edf90d2013-08-27 12:05:06 -07001215 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001216 }
1217
1218 switch (resp.result) {
1219 case QSEOS_RESULT_SUCCESS:
1220 break;
1221 case QSEOS_RESULT_INCOMPLETE:
1222 pr_err("qseos_result_incomplete\n");
1223 ret = __qseecom_process_incomplete_cmd(data, &resp);
1224 if (ret) {
1225 pr_err("process_incomplete_cmd fail: err: %d\n",
1226 ret);
1227 }
1228 break;
1229 case QSEOS_RESULT_FAILURE:
1230 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1231 break;
1232 default:
1233 pr_err("Response result %d not supported\n",
1234 resp.result);
1235 ret = -EINVAL;
1236 break;
1237 }
Zhen Kong06418b72014-02-05 17:36:23 -08001238 if (!qseecom.support_bus_scaling) {
1239 qsee_disable_clock_vote(data, CLK_DFAB);
1240 qsee_disable_clock_vote(data, CLK_SFPB);
1241 } else {
1242 mutex_lock(&qsee_bw_mutex);
1243 qseecom.bw_scale_down_timer.expires = jiffies +
1244 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1245 add_timer(&(qseecom.bw_scale_down_timer));
1246 qseecom.timer_running = true;
1247 mutex_unlock(&qsee_bw_mutex);
1248 }
1249
Zhen Kong2edf90d2013-08-27 12:05:06 -07001250exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001251 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001252}
1253
Mona Hossain2892b6b2012-02-17 13:53:11 -08001254static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1255 struct qseecom_send_cmd_req *req)
1256{
1257 int ret = 0;
1258 u32 reqd_len_sb_in = 0;
1259 struct qseecom_client_send_data_ireq send_data_req;
1260 struct qseecom_command_scm_resp resp;
1261
1262 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1263 pr_err("cmd buffer or response buffer is null\n");
1264 return -EINVAL;
1265 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001266 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1267 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1268 data->client.sb_length))) {
1269 pr_err("cmd buffer address not within shared bufffer\n");
1270 return -EINVAL;
1271 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001272
Mona Hossaindddf4442013-10-01 14:08:20 -07001273
1274 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1275 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1276 data->client.sb_length))){
1277 pr_err("response buffer address not within shared bufffer\n");
1278 return -EINVAL;
1279 }
1280
1281 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001282 req->cmd_req_len > data->client.sb_length ||
1283 req->resp_len > data->client.sb_length) {
1284 pr_err("cmd buffer length or "
1285 "response buffer length not valid\n");
1286 return -EINVAL;
1287 }
1288
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001289 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1290 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1291 return -EINVAL;
1292 }
1293
Mona Hossain2892b6b2012-02-17 13:53:11 -08001294 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1295 if (reqd_len_sb_in > data->client.sb_length) {
1296 pr_debug("Not enough memory to fit cmd_buf and "
1297 "resp_buf. Required: %u, Available: %u\n",
1298 reqd_len_sb_in, data->client.sb_length);
1299 return -ENOMEM;
1300 }
1301
1302 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1303 send_data_req.app_id = data->client.app_id;
1304 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1305 (uint32_t)req->cmd_req_buf));
1306 send_data_req.req_len = req->cmd_req_len;
1307 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1308 (uint32_t)req->resp_buf));
1309 send_data_req.rsp_len = req->resp_len;
1310
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001311 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1312 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001313 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001314 ION_IOC_CLEAN_INV_CACHES);
1315
Mona Hossain2892b6b2012-02-17 13:53:11 -08001316 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1317 sizeof(send_data_req),
1318 &resp, sizeof(resp));
1319 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001320 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1321 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001322 return ret;
1323 }
1324
1325 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1326 ret = __qseecom_process_incomplete_cmd(data, &resp);
1327 if (ret) {
1328 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1329 return ret;
1330 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001331 } else {
1332 if (resp.result != QSEOS_RESULT_SUCCESS) {
1333 pr_err("Response result %d not supported\n",
1334 resp.result);
1335 ret = -EINVAL;
1336 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001337 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001338 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1339 data->client.sb_virt, data->client.sb_length,
1340 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001341 return ret;
1342}
1343
Mona Hossain2892b6b2012-02-17 13:53:11 -08001344static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1345{
1346 int ret = 0;
1347 struct qseecom_send_cmd_req req;
1348
1349 ret = copy_from_user(&req, argp, sizeof(req));
1350 if (ret) {
1351 pr_err("copy_from_user failed\n");
1352 return ret;
1353 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001354 ret = __qseecom_send_cmd(data, &req);
1355
Mona Hossain2892b6b2012-02-17 13:53:11 -08001356 if (ret)
1357 return ret;
1358
Mona Hossain2892b6b2012-02-17 13:53:11 -08001359 return ret;
1360}
1361
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001362static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1363 struct qseecom_dev_handle *data,
1364 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001365{
1366 struct ion_handle *ihandle;
1367 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001368 int ret = 0;
1369 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001370 uint32_t len = 0;
1371 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001372 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1373 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1374 struct qseecom_registered_listener_list *this_lstnr = NULL;
1375
1376 if (msg == NULL) {
1377 pr_err("Invalid address\n");
1378 return -EINVAL;
1379 }
1380 if (listener_svc) {
1381 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1382 this_lstnr = __qseecom_find_svc(data->listener.id);
1383 if (IS_ERR_OR_NULL(this_lstnr)) {
1384 pr_err("Invalid listener ID\n");
1385 return -ENOMEM;
1386 }
1387 } else {
1388 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1389 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001390
1391 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001392 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001393 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001394 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001395 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001396 if (IS_ERR_OR_NULL(ihandle)) {
1397 pr_err("Ion client can't retrieve the handle\n");
1398 return -ENOMEM;
1399 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001400 field = (char *) cmd_req->cmd_req_buf +
1401 cmd_req->ifd_data[i].cmd_buf_offset;
1402 } else if ((listener_svc) &&
1403 (lstnr_resp->ifd_data[i].fd > 0)) {
1404 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1405 lstnr_resp->ifd_data[i].fd);
1406 if (IS_ERR_OR_NULL(ihandle)) {
1407 pr_err("Ion client can't retrieve the handle\n");
1408 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001409 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001410 field = lstnr_resp->resp_buf_ptr +
1411 lstnr_resp->ifd_data[i].cmd_buf_offset;
1412 } else {
1413 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001414 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001415 /* Populate the cmd data structure with the phys_addr */
1416 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1417 if (sg_ptr == NULL) {
1418 pr_err("IOn client could not retrieve sg table\n");
1419 goto err;
1420 }
1421 if (sg_ptr->nents == 0) {
1422 pr_err("Num of scattered entries is 0\n");
1423 goto err;
1424 }
1425 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1426 pr_err("Num of scattered entries");
1427 pr_err(" (%d) is greater than max supported %d\n",
1428 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1429 goto err;
1430 }
1431 sg = sg_ptr->sgl;
1432 if (sg_ptr->nents == 1) {
1433 uint32_t *update;
1434 update = (uint32_t *) field;
1435 if (cleanup)
1436 *update = 0;
1437 else
1438 *update = (uint32_t)sg_dma_address(
1439 sg_ptr->sgl);
1440 len += (uint32_t)sg->length;
1441 } else {
1442 struct qseecom_sg_entry *update;
1443 int j = 0;
1444 update = (struct qseecom_sg_entry *) field;
1445 for (j = 0; j < sg_ptr->nents; j++) {
1446 if (cleanup) {
1447 update->phys_addr = 0;
1448 update->len = 0;
1449 } else {
1450 update->phys_addr = (uint32_t)
1451 sg_dma_address(sg);
1452 update->len = sg->length;
1453 }
1454 len += sg->length;
1455 update++;
1456 sg = sg_next(sg);
1457 }
1458 }
1459 if (cleanup)
1460 msm_ion_do_cache_op(qseecom.ion_clnt,
1461 ihandle, NULL, len,
1462 ION_IOC_INV_CACHES);
1463 else
1464 msm_ion_do_cache_op(qseecom.ion_clnt,
1465 ihandle, NULL, len,
1466 ION_IOC_CLEAN_INV_CACHES);
1467 /* Deallocate the handle */
1468 if (!IS_ERR_OR_NULL(ihandle))
1469 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001470 }
1471 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001472err:
1473 if (!IS_ERR_OR_NULL(ihandle))
1474 ion_free(qseecom.ion_clnt, ihandle);
1475 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001476}
1477
1478static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1479 void __user *argp)
1480{
1481 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001482 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001483 struct qseecom_send_modfd_cmd_req req;
1484 struct qseecom_send_cmd_req send_cmd_req;
1485
1486 ret = copy_from_user(&req, argp, sizeof(req));
1487 if (ret) {
1488 pr_err("copy_from_user failed\n");
1489 return ret;
1490 }
Zhen Kongf4948192013-11-25 13:05:35 -08001491
1492 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1493 pr_err("cmd buffer or response buffer is null\n");
1494 return -EINVAL;
1495 }
1496 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1497 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1498 data->client.sb_length))) {
1499 pr_err("cmd buffer address not within shared bufffer\n");
1500 return -EINVAL;
1501 }
1502
1503 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1504 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1505 data->client.sb_length))){
1506 pr_err("response buffer address not within shared bufffer\n");
1507 return -EINVAL;
1508 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001509 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1510 send_cmd_req.cmd_req_len = req.cmd_req_len;
1511 send_cmd_req.resp_buf = req.resp_buf;
1512 send_cmd_req.resp_len = req.resp_len;
1513
Mona Hossaindddf4442013-10-01 14:08:20 -07001514 /* validate offsets */
1515 for (i = 0; i < MAX_ION_FD; i++) {
1516 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1517 pr_err("Invalid offset %d = 0x%x\n",
1518 i, req.ifd_data[i].cmd_buf_offset);
1519 return -EINVAL;
1520 }
1521 }
Zhen Kongf4948192013-11-25 13:05:35 -08001522 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1523 (uint32_t)req.cmd_req_buf);
1524 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1525 (uint32_t)req.resp_buf);
1526
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001527 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001528 if (ret)
1529 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001530 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001531 if (ret)
1532 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001533 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001534 if (ret)
1535 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001536
Mona Hossain2892b6b2012-02-17 13:53:11 -08001537 return ret;
1538}
1539
1540static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1541 struct qseecom_registered_listener_list *svc)
1542{
1543 int ret;
1544 ret = (svc->rcv_req_flag != 0);
1545 return ret || data->abort;
1546}
1547
1548static int qseecom_receive_req(struct qseecom_dev_handle *data)
1549{
1550 int ret = 0;
1551 struct qseecom_registered_listener_list *this_lstnr;
1552
1553 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301554 if (!this_lstnr) {
1555 pr_err("Invalid listener ID\n");
1556 return -ENODATA;
1557 }
1558
Mona Hossain2892b6b2012-02-17 13:53:11 -08001559 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001560 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001561 __qseecom_listener_has_rcvd_req(data,
1562 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001563 pr_warning("Interrupted: exiting Listener Service = %d\n",
1564 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001565 /* woken up for different reason */
1566 return -ERESTARTSYS;
1567 }
1568
1569 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001570 pr_err("Aborting Listener Service = %d\n",
1571 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001572 return -ENODEV;
1573 }
1574 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001575 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001576 }
1577 return ret;
1578}
1579
Mona Hossaind44a3842012-10-15 09:41:35 -07001580static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1581{
1582 struct elf32_hdr *ehdr;
1583
1584 if (fw_entry->size < sizeof(*ehdr)) {
1585 pr_err("%s: Not big enough to be an elf header\n",
1586 qseecom.pdev->init_name);
1587 return false;
1588 }
1589 ehdr = (struct elf32_hdr *)fw_entry->data;
1590 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1591 pr_err("%s: Not an elf header\n",
1592 qseecom.pdev->init_name);
1593 return false;
1594 }
1595
1596 if (ehdr->e_phnum == 0) {
1597 pr_err("%s: No loadable segments\n",
1598 qseecom.pdev->init_name);
1599 return false;
1600 }
1601 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1602 sizeof(struct elf32_hdr) > fw_entry->size) {
1603 pr_err("%s: Program headers not within mdt\n",
1604 qseecom.pdev->init_name);
1605 return false;
1606 }
1607 return true;
1608}
1609
1610static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1611{
1612 int ret = -1;
1613 int i = 0, rc = 0;
1614 const struct firmware *fw_entry = NULL;
1615 struct elf32_phdr *phdr;
1616 char fw_name[MAX_APP_NAME_SIZE];
1617 struct elf32_hdr *ehdr;
1618 int num_images = 0;
1619
1620 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1621 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1622 if (rc) {
1623 pr_err("error with request_firmware\n");
1624 ret = -EIO;
1625 goto err;
1626 }
1627 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1628 ret = -EIO;
1629 goto err;
1630 }
1631 *fw_size = fw_entry->size;
1632 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1633 ehdr = (struct elf32_hdr *)fw_entry->data;
1634 num_images = ehdr->e_phnum;
1635 release_firmware(fw_entry);
1636 for (i = 0; i < num_images; i++, phdr++) {
1637 memset(fw_name, 0, sizeof(fw_name));
1638 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1639 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1640 if (ret)
1641 goto err;
1642 *fw_size += fw_entry->size;
1643 release_firmware(fw_entry);
1644 }
1645 return ret;
1646err:
1647 if (fw_entry)
1648 release_firmware(fw_entry);
1649 *fw_size = 0;
1650 return ret;
1651}
1652
1653static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1654 struct qseecom_load_app_ireq *load_req)
1655{
1656 int ret = -1;
1657 int i = 0, rc = 0;
1658 const struct firmware *fw_entry = NULL;
1659 char fw_name[MAX_APP_NAME_SIZE];
1660 u8 *img_data_ptr = img_data;
1661 struct elf32_hdr *ehdr;
1662 int num_images = 0;
1663
1664 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1665 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1666 if (rc) {
1667 ret = -EIO;
1668 goto err;
1669 }
1670 load_req->img_len = fw_entry->size;
1671 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1672 img_data_ptr = img_data_ptr + fw_entry->size;
1673 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1674 ehdr = (struct elf32_hdr *)fw_entry->data;
1675 num_images = ehdr->e_phnum;
1676 release_firmware(fw_entry);
1677 for (i = 0; i < num_images; i++) {
1678 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1679 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1680 if (ret) {
1681 pr_err("Failed to locate blob %s\n", fw_name);
1682 goto err;
1683 }
1684 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1685 img_data_ptr = img_data_ptr + fw_entry->size;
1686 load_req->img_len += fw_entry->size;
1687 release_firmware(fw_entry);
1688 }
1689 load_req->phy_addr = virt_to_phys(img_data);
1690 return ret;
1691err:
1692 release_firmware(fw_entry);
1693 return ret;
1694}
1695
1696static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1697{
1698 int ret = -1;
1699 uint32_t fw_size = 0;
1700 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1701 struct qseecom_command_scm_resp resp;
1702 u8 *img_data = NULL;
1703
1704 if (__qseecom_get_fw_size(appname, &fw_size))
1705 return -EIO;
1706
1707 img_data = kzalloc(fw_size, GFP_KERNEL);
1708 if (!img_data) {
1709 pr_err("Failied to allocate memory for copying image data\n");
1710 return -ENOMEM;
1711 }
1712 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1713 if (ret) {
1714 kzfree(img_data);
1715 return -EIO;
1716 }
1717
1718 /* Populate the remaining parameters */
1719 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1720 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001721 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001722 if (ret) {
1723 kzfree(img_data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001724 return -EIO;
1725 }
1726
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001727 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001728 /* SCM_CALL to load the image */
1729 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1730 sizeof(struct qseecom_load_app_ireq),
1731 &resp, sizeof(resp));
1732 kzfree(img_data);
1733 if (ret) {
1734 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001735 __qseecom_disable_clk_scale_down(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001736 return -EIO;
1737 }
1738
1739 switch (resp.result) {
1740 case QSEOS_RESULT_SUCCESS:
1741 ret = resp.data;
1742 break;
1743 case QSEOS_RESULT_INCOMPLETE:
1744 ret = __qseecom_process_incomplete_cmd(data, &resp);
1745 if (ret)
1746 pr_err("process_incomplete_cmd FAILED\n");
1747 else
1748 ret = resp.data;
1749 break;
1750 case QSEOS_RESULT_FAILURE:
1751 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1752 break;
1753 default:
1754 pr_err("scm call return unknown response %d\n", resp.result);
1755 ret = -EINVAL;
1756 break;
1757 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001758 __qseecom_disable_clk_scale_down(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001759
Mona Hossaind44a3842012-10-15 09:41:35 -07001760 return ret;
1761}
1762
Mona Hossain9498f5e2013-01-23 18:08:45 -08001763static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001764{
1765 int32_t ret = 0;
1766 uint32_t fw_size = 0;
1767 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1768 struct qseecom_command_scm_resp resp;
1769 u8 *img_data = NULL;
1770
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001771 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001772 return -EIO;
1773
1774 img_data = kzalloc(fw_size, GFP_KERNEL);
1775 if (!img_data) {
1776 pr_err("Mem allocation for lib image data failed\n");
1777 return -ENOMEM;
1778 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001779 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001780 if (ret) {
1781 kzfree(img_data);
1782 return -EIO;
1783 }
1784 /* Populate the remaining parameters */
1785 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001786 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001787 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001788 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08001789 kzfree(img_data);
1790 return -EIO;
1791 }
1792
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001793 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001794 /* SCM_CALL to load the image */
1795 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1796 sizeof(struct qseecom_load_lib_image_ireq),
1797 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001798 if (ret) {
1799 pr_err("scm_call to load failed : ret %d\n", ret);
1800 ret = -EIO;
1801 } else {
1802 switch (resp.result) {
1803 case QSEOS_RESULT_SUCCESS:
1804 break;
1805 case QSEOS_RESULT_FAILURE:
1806 pr_err("scm call failed w/response result%d\n",
1807 resp.result);
1808 ret = -EINVAL;
1809 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001810 case QSEOS_RESULT_INCOMPLETE:
1811 ret = __qseecom_process_incomplete_cmd(data, &resp);
1812 if (ret)
1813 pr_err("process_incomplete_cmd failed err: %d\n",
1814 ret);
1815 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001816 default:
1817 pr_err("scm call return unknown response %d\n",
1818 resp.result);
1819 ret = -EINVAL;
1820 break;
1821 }
1822 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001823 kzfree(img_data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001824 __qseecom_disable_clk_scale_down(data);
Mona Hossain05c73562012-10-29 17:49:01 -07001825 return ret;
1826}
1827
1828static int qseecom_unload_commonlib_image(void)
1829{
1830 int ret = -EINVAL;
1831 struct qseecom_unload_lib_image_ireq unload_req = {0};
1832 struct qseecom_command_scm_resp resp;
1833
1834 /* Populate the remaining parameters */
1835 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1836 /* SCM_CALL to load the image */
1837 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1838 sizeof(struct qseecom_unload_lib_image_ireq),
1839 &resp, sizeof(resp));
1840 if (ret) {
1841 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1842 ret = -EIO;
1843 } else {
1844 switch (resp.result) {
1845 case QSEOS_RESULT_SUCCESS:
1846 break;
1847 case QSEOS_RESULT_FAILURE:
1848 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1849 break;
1850 default:
1851 pr_err("scm call return unknown response %d\n",
1852 resp.result);
1853 ret = -EINVAL;
1854 break;
1855 }
1856 }
1857 return ret;
1858}
1859
Mona Hossaind44a3842012-10-15 09:41:35 -07001860int qseecom_start_app(struct qseecom_handle **handle,
1861 char *app_name, uint32_t size)
1862{
Mona Hossain05c73562012-10-29 17:49:01 -07001863 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001864 unsigned long flags = 0;
1865 struct qseecom_dev_handle *data = NULL;
1866 struct qseecom_check_app_ireq app_ireq;
1867 struct qseecom_registered_app_list *entry = NULL;
1868 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1869 bool found_app = false;
1870 uint32_t len;
1871 ion_phys_addr_t pa;
1872
Mona Hossain823f9882012-11-23 14:42:20 -08001873 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1874 if (!(*handle)) {
1875 pr_err("failed to allocate memory for kernel client handle\n");
1876 return -ENOMEM;
1877 }
1878
Mona Hossaind44a3842012-10-15 09:41:35 -07001879 data = kzalloc(sizeof(*data), GFP_KERNEL);
1880 if (!data) {
1881 pr_err("kmalloc failed\n");
1882 if (ret == 0) {
1883 kfree(*handle);
1884 *handle = NULL;
1885 }
1886 return -ENOMEM;
1887 }
1888 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001889 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001890 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001891 data->client.sb_length = size;
1892 data->client.user_virt_sb_base = 0;
1893 data->client.ihandle = NULL;
1894
1895 init_waitqueue_head(&data->abort_wq);
1896 atomic_set(&data->ioctl_count, 0);
1897
1898 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1899 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1900 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1901 pr_err("Ion client could not retrieve the handle\n");
1902 kfree(data);
1903 kfree(*handle);
1904 *handle = NULL;
1905 return -EINVAL;
1906 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001907 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001908 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001909 if (qseecom.commonlib_loaded == false) {
1910 ret = qseecom_load_commonlib_image(data);
1911 if (ret == 0)
1912 qseecom.commonlib_loaded = true;
1913 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001914 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001915 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001916 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001917 ret = -EIO;
1918 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001919 }
1920
1921 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1922 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1923 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001924 if (ret < 0)
1925 goto err;
1926
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001927 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001928 if (ret > 0) {
1929 pr_warn("App id %d for [%s] app exists\n", ret,
1930 (char *)app_ireq.app_name);
1931 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1932 list_for_each_entry(entry,
1933 &qseecom.registered_app_list_head, list){
1934 if (entry->app_id == ret) {
1935 entry->ref_cnt++;
1936 found_app = true;
1937 break;
1938 }
1939 }
1940 spin_unlock_irqrestore(
1941 &qseecom.registered_app_list_lock, flags);
1942 if (!found_app)
1943 pr_warn("App_id %d [%s] was loaded but not registered\n",
1944 ret, (char *)app_ireq.app_name);
1945 } else {
1946 /* load the app and get the app_id */
1947 pr_debug("%s: Loading app for the first time'\n",
1948 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001949 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001950 if (ret < 0)
1951 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001952 data->client.app_id = ret;
1953 }
1954 if (!found_app) {
1955 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1956 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001957 pr_err("kmalloc for app entry failed\n");
1958 ret = -ENOMEM;
1959 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001960 }
1961 entry->app_id = ret;
1962 entry->ref_cnt = 1;
1963
1964 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1965 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1966 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1967 flags);
1968 }
1969
1970 /* Get the physical address of the ION BUF */
1971 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1972 /* Populate the structure for sending scm call to load image */
1973 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1974 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001975 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001976 data->client.sb_phys = pa;
1977 (*handle)->dev = (void *)data;
1978 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1979 (*handle)->sbuf_len = data->client.sb_length;
1980
1981 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1982 if (!kclient_entry) {
1983 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001984 ret = -ENOMEM;
1985 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001986 }
1987 kclient_entry->handle = *handle;
1988
1989 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1990 list_add_tail(&kclient_entry->list,
1991 &qseecom.registered_kclient_list_head);
1992 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1993
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001994 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001995 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001996
1997err:
1998 kfree(data);
1999 kfree(*handle);
2000 *handle = NULL;
2001 mutex_unlock(&app_access_lock);
2002 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002003}
2004EXPORT_SYMBOL(qseecom_start_app);
2005
2006int qseecom_shutdown_app(struct qseecom_handle **handle)
2007{
2008 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002009 struct qseecom_dev_handle *data;
2010
Mona Hossaind44a3842012-10-15 09:41:35 -07002011 struct qseecom_registered_kclient_list *kclient = NULL;
2012 unsigned long flags = 0;
2013 bool found_handle = false;
2014
Mona Hossain33824022013-02-25 09:32:33 -08002015 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002016 pr_err("Handle is not initialized\n");
2017 return -EINVAL;
2018 }
Mona Hossain33824022013-02-25 09:32:33 -08002019 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07002020 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2021 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2022 list) {
2023 if (kclient->handle == (*handle)) {
2024 list_del(&kclient->list);
2025 found_handle = true;
2026 break;
2027 }
2028 }
2029 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2030 if (!found_handle)
2031 pr_err("Unable to find the handle, exiting\n");
2032 else
2033 ret = qseecom_unload_app(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002034
2035 if (qseecom.support_bus_scaling) {
2036 mutex_lock(&qsee_bw_mutex);
2037 if (data->mode != INACTIVE) {
2038 qseecom_unregister_bus_bandwidth_needs(data);
2039 if (qseecom.cumulative_mode == INACTIVE) {
2040 ret = __qseecom_set_msm_bus_request(INACTIVE);
2041 if (ret)
2042 pr_err("Fail to scale down bus\n");
2043 }
2044 }
2045 mutex_unlock(&qsee_bw_mutex);
2046 } else {
2047 if (data->fast_load_enabled == true)
2048 qsee_disable_clock_vote(data, CLK_SFPB);
2049 if (data->perf_enabled == true)
2050 qsee_disable_clock_vote(data, CLK_DFAB);
2051 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002052 if (ret == 0) {
2053 kzfree(data);
2054 kzfree(*handle);
2055 kzfree(kclient);
2056 *handle = NULL;
2057 }
2058 return ret;
2059}
2060EXPORT_SYMBOL(qseecom_shutdown_app);
2061
2062int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2063 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2064{
2065 int ret = 0;
2066 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2067 struct qseecom_dev_handle *data;
2068
Mona Hossaind44a3842012-10-15 09:41:35 -07002069 if (handle == NULL) {
2070 pr_err("Handle is not initialized\n");
2071 return -EINVAL;
2072 }
2073 data = handle->dev;
2074
2075 req.cmd_req_len = sbuf_len;
2076 req.resp_len = rbuf_len;
2077 req.cmd_req_buf = send_buf;
2078 req.resp_buf = resp_buf;
2079
2080 mutex_lock(&app_access_lock);
2081 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002082 if (qseecom.support_bus_scaling)
2083 qseecom_scale_bus_bandwidth_timer(INACTIVE,
2084 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002085 ret = __qseecom_send_cmd(data, &req);
Zhen Kong06418b72014-02-05 17:36:23 -08002086 if (qseecom.support_bus_scaling) {
2087 mutex_lock(&qsee_bw_mutex);
2088 qseecom.bw_scale_down_timer.expires = jiffies +
2089 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
2090 add_timer(&(qseecom.bw_scale_down_timer));
2091 qseecom.timer_running = true;
2092 mutex_unlock(&qsee_bw_mutex);
2093 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002094
2095 atomic_dec(&data->ioctl_count);
2096 mutex_unlock(&app_access_lock);
2097
2098 if (ret)
2099 return ret;
2100
2101 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2102 req.resp_len, req.resp_buf);
2103 return ret;
2104}
2105EXPORT_SYMBOL(qseecom_send_command);
2106
Mona Hossain91a8fc92012-11-07 19:58:30 -08002107int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2108{
Mona Hossainfca6f422013-01-12 13:00:35 -08002109 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002110 if ((handle == NULL) || (handle->dev == NULL)) {
2111 pr_err("No valid kernel client\n");
2112 return -EINVAL;
2113 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002114 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002115 if (qseecom.support_bus_scaling) {
2116 mutex_lock(&qsee_bw_mutex);
2117 __qseecom_register_bus_bandwidth_needs(handle->dev,
2118 HIGH);
2119 mutex_unlock(&qsee_bw_mutex);
2120 if (ret)
2121 pr_err("Failed to scale bus (med) %d\n", ret);
2122 } else {
2123 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2124 if (ret)
2125 pr_err("Failed to vote for DFAB clock%d\n",
2126 ret);
2127 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2128 if (ret) {
2129 pr_err("Failed to vote for SFPB clock%d\n",
2130 ret);
2131 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2132 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002133 }
2134 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002135 if (!qseecom.support_bus_scaling) {
2136 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2137 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
2138 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002139 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002140 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002141}
2142EXPORT_SYMBOL(qseecom_set_bandwidth);
2143
Mona Hossain2892b6b2012-02-17 13:53:11 -08002144static int qseecom_send_resp(void)
2145{
2146 qseecom.send_resp_flag = 1;
2147 wake_up_interruptible(&qseecom.send_resp_wq);
2148 return 0;
2149}
2150
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002151
2152static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2153 void __user *argp)
2154{
2155 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002156 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002157 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002158
2159 if (copy_from_user(&resp, argp, sizeof(resp))) {
2160 pr_err("copy_from_user failed");
2161 return -EINVAL;
2162 }
Zhen Kongf4948192013-11-25 13:05:35 -08002163 this_lstnr = __qseecom_find_svc(data->listener.id);
2164 if (this_lstnr == NULL)
2165 return -EINVAL;
2166
2167 if (resp.resp_buf_ptr == NULL) {
2168 pr_err("Invalid resp_buf_ptr\n");
2169 return -EINVAL;
2170 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002171 /* validate offsets */
2172 for (i = 0; i < MAX_ION_FD; i++) {
2173 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2174 pr_err("Invalid offset %d = 0x%x\n",
2175 i, resp.ifd_data[i].cmd_buf_offset);
2176 return -EINVAL;
2177 }
2178 }
Zhen Kongf4948192013-11-25 13:05:35 -08002179
2180 if (((uint32_t)resp.resp_buf_ptr <
2181 this_lstnr->user_virt_sb_base)
2182 || ((uint32_t)resp.resp_buf_ptr >=
2183 (this_lstnr->user_virt_sb_base +
2184 this_lstnr->sb_length))) {
2185 pr_err("resp_buf_ptr address not within shared buffer\n");
2186 return -EINVAL;
2187 }
2188 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2189 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002190 __qseecom_update_cmd_buf(&resp, false, data, true);
2191 qseecom.send_resp_flag = 1;
2192 wake_up_interruptible(&qseecom.send_resp_wq);
2193 return 0;
2194}
2195
2196
Mona Hossain2892b6b2012-02-17 13:53:11 -08002197static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2198 void __user *argp)
2199{
2200 struct qseecom_qseos_version_req req;
2201
2202 if (copy_from_user(&req, argp, sizeof(req))) {
2203 pr_err("copy_from_user failed");
2204 return -EINVAL;
2205 }
2206 req.qseos_version = qseecom.qseos_version;
2207 if (copy_to_user(argp, &req, sizeof(req))) {
2208 pr_err("copy_to_user failed");
2209 return -EINVAL;
2210 }
2211 return 0;
2212}
2213
Mona Hossainc92629e2013-04-01 13:37:46 -07002214static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002215{
2216 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002217 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002218
Mona Hossainc92629e2013-04-01 13:37:46 -07002219 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002220 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002221 else
2222 qclk = &qseecom.ce_drv;
2223
2224 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002225
2226 if (qclk->clk_access_cnt == ULONG_MAX)
2227 goto err;
2228
Mona Hossainc92629e2013-04-01 13:37:46 -07002229 if (qclk->clk_access_cnt > 0) {
2230 qclk->clk_access_cnt++;
2231 mutex_unlock(&clk_access_lock);
2232 return rc;
2233 }
2234
Mona Hossain6311d572013-03-01 15:54:02 -08002235 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002236 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002237 if (rc) {
2238 pr_err("Unable to enable/prepare CE core clk\n");
2239 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002240 }
2241 /* Enable CE clk */
2242 rc = clk_prepare_enable(qclk->ce_clk);
2243 if (rc) {
2244 pr_err("Unable to enable/prepare CE iface clk\n");
2245 goto ce_clk_err;
2246 }
2247 /* Enable AXI clk */
2248 rc = clk_prepare_enable(qclk->ce_bus_clk);
2249 if (rc) {
2250 pr_err("Unable to enable/prepare CE bus clk\n");
2251 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002252 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002253 qclk->clk_access_cnt++;
2254 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002255 return 0;
2256
2257ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002258 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002259ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002260 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002261err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002262 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002263 return -EIO;
2264}
2265
Mona Hossainc92629e2013-04-01 13:37:46 -07002266static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002267{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002268 struct qseecom_clk *qclk;
2269
Mona Hossainc92629e2013-04-01 13:37:46 -07002270 if (ce == CLK_QSEE)
2271 qclk = &qseecom.qsee;
2272 else
2273 qclk = &qseecom.ce_drv;
2274
2275 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002276
2277 if (qclk->clk_access_cnt == 0) {
2278 mutex_unlock(&clk_access_lock);
2279 return;
2280 }
2281
Mona Hossainc92629e2013-04-01 13:37:46 -07002282 if (qclk->clk_access_cnt == 1) {
2283 if (qclk->ce_clk != NULL)
2284 clk_disable_unprepare(qclk->ce_clk);
2285 if (qclk->ce_core_clk != NULL)
2286 clk_disable_unprepare(qclk->ce_core_clk);
2287 if (qclk->ce_bus_clk != NULL)
2288 clk_disable_unprepare(qclk->ce_bus_clk);
2289 }
2290 qclk->clk_access_cnt--;
2291 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002292}
2293
Mona Hossain04d3fac2012-12-03 10:10:37 -08002294static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2295 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002296{
2297 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002298 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002299
Mona Hossain17a4faf2013-03-22 16:40:56 -07002300 qclk = &qseecom.qsee;
2301 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002302 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002303
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002304 switch (clk_type) {
2305 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002306 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002307 if (!qseecom.qsee_bw_count) {
2308 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002309 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002310 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002311 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002312 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002313 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002314 if (!ret) {
2315 ret =
2316 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002317 qseecom.qsee_perf_client, 1);
2318 if ((ret) &&
2319 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002320 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002321 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002322 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002323 if (ret)
2324 pr_err("DFAB Bandwidth req failed (%d)\n",
2325 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002326 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002327 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002328 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002329 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002330 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002331 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002332 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002333 }
2334 mutex_unlock(&qsee_bw_mutex);
2335 break;
2336 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002337 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002338 if (!qseecom.qsee_sfpb_bw_count) {
2339 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002340 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002341 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002342 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002343 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002344 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002345 if (!ret) {
2346 ret =
2347 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002348 qseecom.qsee_perf_client, 2);
2349 if ((ret) &&
2350 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002351 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002352 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002353 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002354
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002355 if (ret)
2356 pr_err("SFPB Bandwidth req failed (%d)\n",
2357 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002358 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002359 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002360 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002361 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002362 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002363 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002364 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002365 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002366 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002367 break;
2368 default:
2369 pr_err("Clock type not defined\n");
2370 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002371 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002372 return ret;
2373}
2374
Mona Hossain04d3fac2012-12-03 10:10:37 -08002375static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2376 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002377{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002378 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002379 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002380
Mona Hossain17a4faf2013-03-22 16:40:56 -07002381 qclk = &qseecom.qsee;
2382 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002383 return;
2384
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002385 switch (clk_type) {
2386 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002387 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002388 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002389 pr_err("Client error.Extra call to disable DFAB clk\n");
2390 mutex_unlock(&qsee_bw_mutex);
2391 return;
2392 }
2393
Mona Hossain17a4faf2013-03-22 16:40:56 -07002394 if (qseecom.qsee_bw_count == 1) {
2395 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002396 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002397 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002398 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002399 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002400 qseecom.qsee_perf_client, 0);
2401 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002402 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002403 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002404 if (ret)
2405 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002406 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002407 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002408 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002409 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002410 }
2411 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002412 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002413 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002414 }
2415 mutex_unlock(&qsee_bw_mutex);
2416 break;
2417 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002418 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002419 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002420 pr_err("Client error.Extra call to disable SFPB clk\n");
2421 mutex_unlock(&qsee_bw_mutex);
2422 return;
2423 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002424 if (qseecom.qsee_sfpb_bw_count == 1) {
2425 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002426 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002427 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002428 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002429 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002430 qseecom.qsee_perf_client, 0);
2431 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002432 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002433 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002434 if (ret)
2435 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002436 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002437 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002438 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002439 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002440 }
2441 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002442 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002443 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002444 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002445 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002446 break;
2447 default:
2448 pr_err("Clock type not defined\n");
2449 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002450 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002451
Mona Hossain2892b6b2012-02-17 13:53:11 -08002452}
2453
Mona Hossain5ab9d772012-04-11 21:00:40 -07002454static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2455 void __user *argp)
2456{
2457 struct ion_handle *ihandle; /* Ion handle */
2458 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002459 int ret;
2460 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002461 ion_phys_addr_t pa = 0;
2462 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002463 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002464 struct qseecom_load_app_ireq load_req;
2465 struct qseecom_command_scm_resp resp;
2466
2467 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002468 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002469 (void __user *)argp,
2470 sizeof(struct qseecom_load_img_req))) {
2471 pr_err("copy_from_user failed\n");
2472 return -EFAULT;
2473 }
2474
2475 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002476 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002477 load_img_req.ifd_data_fd);
2478 if (IS_ERR_OR_NULL(ihandle)) {
2479 pr_err("Ion client could not retrieve the handle\n");
2480 return -ENOMEM;
2481 }
2482
2483 /* Get the physical address of the ION BUF */
2484 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2485
2486 /* Populate the structure for sending scm call to load image */
2487 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2488 load_req.mdt_len = load_img_req.mdt_len;
2489 load_req.img_len = load_img_req.img_len;
2490 load_req.phy_addr = pa;
2491
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002492 /* SCM_CALL tied to Core0 */
2493 mask = CPU_MASK_CPU0;
2494 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2495 if (set_cpu_ret) {
2496 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2497 set_cpu_ret);
2498 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302499 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002500 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302501
Mona Hossain6311d572013-03-01 15:54:02 -08002502 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002503 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002504 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002505 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302506 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002507 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002508 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2509 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002510 /* SCM_CALL to load the external elf */
2511 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2512 sizeof(struct qseecom_load_app_ireq),
2513 &resp, sizeof(resp));
2514 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002515 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002516 ret);
2517 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302518 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002519 }
2520
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302521 switch (resp.result) {
2522 case QSEOS_RESULT_SUCCESS:
2523 break;
2524 case QSEOS_RESULT_INCOMPLETE:
2525 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002526 ret = __qseecom_process_incomplete_cmd(data, &resp);
2527 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302528 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2529 break;
2530 case QSEOS_RESULT_FAILURE:
2531 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2532 ret = -EFAULT;
2533 break;
2534 default:
2535 pr_err("scm_call response result %d not supported\n",
2536 resp.result);
2537 ret = -EFAULT;
2538 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002539 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002540
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302541exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002542 __qseecom_disable_clk_scale_down(data);
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302543exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002544 /* Restore the CPU mask */
2545 mask = CPU_MASK_ALL;
2546 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2547 if (set_cpu_ret) {
2548 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2549 set_cpu_ret);
2550 ret = -EFAULT;
2551 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302552exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002553 /* Deallocate the handle */
2554 if (!IS_ERR_OR_NULL(ihandle))
2555 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002556 return ret;
2557}
2558
2559static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2560{
2561 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002562 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002563 struct qseecom_command_scm_resp resp;
2564 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002565 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002566
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302567 /* unavailable client app */
2568 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2569
Mona Hossain5ab9d772012-04-11 21:00:40 -07002570 /* Populate the structure for sending scm call to unload image */
2571 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002572
2573 /* SCM_CALL tied to Core0 */
2574 mask = CPU_MASK_CPU0;
2575 ret = set_cpus_allowed_ptr(current, &mask);
2576 if (ret) {
2577 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2578 ret);
2579 return -EFAULT;
2580 }
2581
Mona Hossain5ab9d772012-04-11 21:00:40 -07002582 /* SCM_CALL to unload the external elf */
2583 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2584 sizeof(struct qseecom_unload_app_ireq),
2585 &resp, sizeof(resp));
2586 if (ret) {
2587 pr_err("scm_call to unload failed : ret %d\n",
2588 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002589 ret = -EFAULT;
2590 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002591 }
2592 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2593 ret = __qseecom_process_incomplete_cmd(data, &resp);
2594 if (ret)
2595 pr_err("process_incomplete_cmd fail err: %d\n",
2596 ret);
2597 } else {
2598 if (resp.result != QSEOS_RESULT_SUCCESS) {
2599 pr_err("scm_call to unload image failed resp.result =%d\n",
2600 resp.result);
2601 ret = -EFAULT;
2602 }
2603 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002604
2605qseecom_unload_external_elf_scm_err:
2606 /* Restore the CPU mask */
2607 mask = CPU_MASK_ALL;
2608 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2609 if (set_cpu_ret) {
2610 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2611 set_cpu_ret);
2612 ret = -EFAULT;
2613 }
2614
Mona Hossain5ab9d772012-04-11 21:00:40 -07002615 return ret;
2616}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002617
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002618static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2619 void __user *argp)
2620{
2621
2622 int32_t ret;
2623 struct qseecom_qseos_app_load_query query_req;
2624 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002625 struct qseecom_registered_app_list *entry = NULL;
2626 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002627
2628 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002629 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002630 (void __user *)argp,
2631 sizeof(struct qseecom_qseos_app_load_query))) {
2632 pr_err("copy_from_user failed\n");
2633 return -EFAULT;
2634 }
2635
2636 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002637 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002638 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2639
2640 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002641
2642 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002643 pr_err(" scm call to check if app is loaded failed");
2644 return ret; /* scm call failed */
2645 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002646 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002647 (char *)(req.app_name));
2648 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2649 list_for_each_entry(entry,
2650 &qseecom.registered_app_list_head, list){
2651 if (entry->app_id == ret) {
2652 entry->ref_cnt++;
2653 break;
2654 }
2655 }
2656 spin_unlock_irqrestore(
2657 &qseecom.registered_app_list_lock, flags);
2658 data->client.app_id = ret;
2659 query_req.app_id = ret;
2660
2661 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2662 pr_err("copy_to_user failed\n");
2663 return -EFAULT;
2664 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002665 return -EEXIST; /* app already loaded */
2666 } else {
2667 return 0; /* app not loaded */
2668 }
2669}
2670
Mona Hossain4cf78a92013-02-14 12:06:41 -08002671static int __qseecom_get_ce_pipe_info(
2672 enum qseecom_key_management_usage_type usage,
2673 uint32_t *pipe, uint32_t *ce_hw)
2674{
2675 int ret;
2676 switch (usage) {
2677 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2678 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2679 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2680 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2681 qseecom.ce_info.disk_encrypt_pipe,
2682 qseecom.ce_info.hlos_ce_hw_instance);
2683 ret = -EINVAL;
2684 } else {
2685 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2686 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2687 ret = 0;
2688 }
2689 break;
2690 default:
2691 ret = -EINVAL;
2692 break;
2693 }
2694 return ret;
2695}
2696
2697static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2698 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002699 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002700{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002701 struct qseecom_command_scm_resp resp;
2702 int ret;
2703
Zhen Kong9730ddf2013-12-17 16:49:43 -08002704 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2705 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002706 pr_err("Error:: unsupported usage %d\n", usage);
2707 return -EFAULT;
2708 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002709 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002710
2711 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002712 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002713 &resp, sizeof(resp));
2714 if (ret) {
2715 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002716 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002717 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002718 }
2719
2720 switch (resp.result) {
2721 case QSEOS_RESULT_SUCCESS:
2722 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002723 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002724 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002725 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002726 case QSEOS_RESULT_INCOMPLETE:
2727 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002728 if (ret) {
2729 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002730 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002731 ret = 0;
2732 } else {
2733 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2734 resp.result);
2735 }
2736 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002737 break;
2738 case QSEOS_RESULT_FAILURE:
2739 default:
2740 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2741 ret = -EINVAL;
2742 break;
2743 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002744 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002745 return ret;
2746}
2747
2748static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2749 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002750 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002751{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002752 struct qseecom_command_scm_resp resp;
2753 int ret;
2754
2755 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2756 pr_err("Error:: unsupported usage %d\n", usage);
2757 return -EFAULT;
2758 }
2759
Mona Hossainc92629e2013-04-01 13:37:46 -07002760 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002761
2762 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002763 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002764 &resp, sizeof(struct qseecom_command_scm_resp));
2765 if (ret) {
2766 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002767 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002768 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002769 }
2770
2771 switch (resp.result) {
2772 case QSEOS_RESULT_SUCCESS:
2773 break;
2774 case QSEOS_RESULT_INCOMPLETE:
2775 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002776 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002777 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2778 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002779 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2780 pr_debug("Max attempts to input password reached.\n");
2781 ret = -ERANGE;
2782 }
2783 }
2784 break;
2785 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2786 pr_debug("Max attempts to input password reached.\n");
2787 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002788 break;
2789 case QSEOS_RESULT_FAILURE:
2790 default:
2791 pr_err("Delete key scm call failed resp.result %d\n",
2792 resp.result);
2793 ret = -EINVAL;
2794 break;
2795 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002796 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002797 return ret;
2798}
2799
2800static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2801 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002802 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002803{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002804 struct qseecom_command_scm_resp resp;
2805 int ret;
2806
Zhen Kong9730ddf2013-12-17 16:49:43 -08002807 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2808 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002809 pr_err("Error:: unsupported usage %d\n", usage);
2810 return -EFAULT;
2811 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002812
Zhen Kongdb2bf742013-05-13 23:55:42 -07002813 __qseecom_enable_clk(CLK_QSEE);
2814 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002815 __qseecom_enable_clk(CLK_CE_DRV);
2816
Zhen Kong336636e2013-04-15 11:04:54 -07002817 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002818 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002819 &resp, sizeof(struct qseecom_command_scm_resp));
2820 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002821 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002822 __qseecom_disable_clk(CLK_QSEE);
2823 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2824 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002825 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07002826 }
2827
Mona Hossain4cf78a92013-02-14 12:06:41 -08002828 switch (resp.result) {
2829 case QSEOS_RESULT_SUCCESS:
2830 break;
2831 case QSEOS_RESULT_INCOMPLETE:
2832 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002833 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002834 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2835 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002836 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2837 pr_debug("Max attempts to input password reached.\n");
2838 ret = -ERANGE;
2839 }
2840 }
2841 break;
2842 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2843 pr_debug("Max attempts to input password reached.\n");
2844 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002845 break;
2846 case QSEOS_RESULT_FAILURE:
2847 default:
2848 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2849 ret = -EINVAL;
2850 break;
2851 }
2852
Zhen Kongdb2bf742013-05-13 23:55:42 -07002853 __qseecom_disable_clk(CLK_QSEE);
2854 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002855 __qseecom_disable_clk(CLK_CE_DRV);
2856
Mona Hossain4cf78a92013-02-14 12:06:41 -08002857 return ret;
2858}
2859
Zhen Kong9730ddf2013-12-17 16:49:43 -08002860static int __qseecom_update_current_key_user_info(
2861 struct qseecom_dev_handle *data,
2862 enum qseecom_key_management_usage_type usage,
2863 struct qseecom_key_userinfo_update_ireq *ireq)
2864{
2865 struct qseecom_command_scm_resp resp;
2866 int ret;
2867
2868 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2869 usage >= QSEOS_KM_USAGE_MAX) {
2870 pr_err("Error:: unsupported usage %d\n", usage);
2871 return -EFAULT;
2872 }
2873
2874 __qseecom_enable_clk(CLK_QSEE);
2875
2876 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
2877 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
2878 &resp, sizeof(struct qseecom_command_scm_resp));
2879 if (ret) {
2880 pr_err("scm call to update key userinfo failed : %d\n", ret);
2881 __qseecom_disable_clk(CLK_QSEE);
2882 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2883 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002884 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002885 }
2886
2887 switch (resp.result) {
2888 case QSEOS_RESULT_SUCCESS:
2889 break;
2890 case QSEOS_RESULT_INCOMPLETE:
2891 ret = __qseecom_process_incomplete_cmd(data, &resp);
2892 if (ret)
2893 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2894 resp.result);
2895 break;
2896 case QSEOS_RESULT_FAILURE:
2897 default:
2898 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2899 ret = -EINVAL;
2900 break;
2901 }
2902
2903 __qseecom_disable_clk(CLK_QSEE);
2904 return ret;
2905}
2906
Mona Hossain4cf78a92013-02-14 12:06:41 -08002907static int qseecom_create_key(struct qseecom_dev_handle *data,
2908 void __user *argp)
2909{
2910 uint32_t ce_hw = 0;
2911 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002912 int ret = 0;
2913 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002914 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002915 struct qseecom_key_generate_ireq generate_key_ireq;
2916 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002917
2918 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2919 if (ret) {
2920 pr_err("copy_from_user failed\n");
2921 return ret;
2922 }
2923
Zhen Kong9730ddf2013-12-17 16:49:43 -08002924 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2925 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002926 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2927 return -EFAULT;
2928 }
2929
2930 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2931 if (ret) {
2932 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2933 return -EINVAL;
2934 }
2935
Zhen Kong9730ddf2013-12-17 16:49:43 -08002936 generate_key_ireq.flags = flags;
2937 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
2938 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2939 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2940 memcpy((void *)generate_key_ireq.key_id,
2941 (void *)key_id_array[create_key_req.usage - 1],
2942 QSEECOM_KEY_ID_SIZE);
2943 memcpy((void *)generate_key_ireq.hash32,
2944 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
2945
Mona Hossain4cf78a92013-02-14 12:06:41 -08002946 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002947 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002948 if (ret) {
2949 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002950 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002951 }
2952
Zhen Kong9730ddf2013-12-17 16:49:43 -08002953 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
2954 set_key_ireq.ce = ce_hw;
2955 set_key_ireq.pipe = pipe;
2956 set_key_ireq.flags = flags;
2957
2958 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2959 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
2960 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
2961 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
2962 memcpy((void *)set_key_ireq.key_id,
2963 (void *)key_id_array[create_key_req.usage - 1],
2964 QSEECOM_KEY_ID_SIZE);
2965 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002966 QSEECOM_HASH_SIZE);
2967
2968 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002969 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002970 if (ret) {
2971 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2972 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08002973 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002974 }
2975
2976 return ret;
2977}
2978
2979static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2980 void __user *argp)
2981{
2982 uint32_t ce_hw = 0;
2983 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002984 int ret = 0;
2985 uint32_t flags = 0;
2986 int i;
2987 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002988 struct qseecom_key_delete_ireq delete_key_ireq;
2989 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002990
2991 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2992 if (ret) {
2993 pr_err("copy_from_user failed\n");
2994 return ret;
2995 }
2996
Zhen Kong9730ddf2013-12-17 16:49:43 -08002997 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2998 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002999 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3000 return -EFAULT;
3001 }
3002
3003 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3004 if (ret) {
3005 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3006 return -EINVAL;
3007 }
3008
Zhen Kong9730ddf2013-12-17 16:49:43 -08003009 delete_key_ireq.flags = flags;
3010 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3011 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3012 memcpy((void *)delete_key_ireq.key_id,
3013 (void *)key_id_array[wipe_key_req.usage - 1],
3014 QSEECOM_KEY_ID_SIZE);
3015 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3016
3017 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
3018 &delete_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003019 if (ret) {
3020 pr_err("Failed to delete key from ssd storage: %d\n", ret);
3021 return -EFAULT;
3022 }
3023
Zhen Kong9730ddf2013-12-17 16:49:43 -08003024 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3025 clear_key_ireq.ce = ce_hw;
3026 clear_key_ireq.pipe = pipe;
3027 clear_key_ireq.flags = flags;
3028 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003029 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kong9730ddf2013-12-17 16:49:43 -08003030 clear_key_ireq.key_id[i] = 0xff;
3031 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3032
Mona Hossain4cf78a92013-02-14 12:06:41 -08003033 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003034 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003035 if (ret) {
3036 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3037 pipe, ce_hw, ret);
3038 return -EFAULT;
3039 }
3040
3041 return ret;
3042}
3043
Zhen Kong9730ddf2013-12-17 16:49:43 -08003044static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3045 void __user *argp)
3046{
3047 int ret = 0;
3048 uint32_t flags = 0;
3049 struct qseecom_update_key_userinfo_req update_key_req;
3050 struct qseecom_key_userinfo_update_ireq ireq;
3051
3052 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3053 if (ret) {
3054 pr_err("copy_from_user failed\n");
3055 return ret;
3056 }
3057
3058 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3059 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3060 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3061 return -EFAULT;
3062 }
3063
3064 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3065 ireq.flags = flags;
3066 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3067 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3068 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
3069 memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
3070 QSEECOM_KEY_ID_SIZE);
3071 memcpy((void *)ireq.current_hash32,
3072 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3073 memcpy((void *)ireq.new_hash32,
3074 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3075
3076 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3077 &ireq);
3078 if (ret) {
3079 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003080 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003081 }
3082 return ret;
3083
3084}
3085
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003086static int qseecom_is_es_activated(void __user *argp)
3087{
3088 struct qseecom_is_es_activated_req req;
3089 int ret;
3090 int resp_buf;
3091
3092 if (qseecom.qsee_version < QSEE_VERSION_04) {
3093 pr_err("invalid qsee version");
3094 return -ENODEV;
3095 }
3096
3097 if (argp == NULL) {
3098 pr_err("arg is null");
3099 return -EINVAL;
3100 }
3101
3102 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3103 (void *) &resp_buf, sizeof(resp_buf));
3104 if (ret) {
3105 pr_err("scm_call failed");
3106 return ret;
3107 }
3108
3109 req.is_activated = resp_buf;
3110 ret = copy_to_user(argp, &req, sizeof(req));
3111 if (ret) {
3112 pr_err("copy_to_user failed");
3113 return ret;
3114 }
3115
3116 return 0;
3117}
3118
3119static int qseecom_save_partition_hash(void __user *argp)
3120{
3121 struct qseecom_save_partition_hash_req req;
3122 int ret;
3123
3124 if (qseecom.qsee_version < QSEE_VERSION_04) {
3125 pr_err("invalid qsee version ");
3126 return -ENODEV;
3127 }
3128
3129 if (argp == NULL) {
3130 pr_err("arg is null");
3131 return -EINVAL;
3132 }
3133
3134 ret = copy_from_user(&req, argp, sizeof(req));
3135 if (ret) {
3136 pr_err("copy_from_user failed");
3137 return ret;
3138 }
3139
3140 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3141 (void *) &req, sizeof(req), NULL, 0);
3142 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003143 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003144 return ret;
3145 }
3146
3147 return 0;
3148}
3149
Mona Hossain2892b6b2012-02-17 13:53:11 -08003150static long qseecom_ioctl(struct file *file, unsigned cmd,
3151 unsigned long arg)
3152{
3153 int ret = 0;
3154 struct qseecom_dev_handle *data = file->private_data;
3155 void __user *argp = (void __user *) arg;
3156
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303157 if (!data) {
3158 pr_err("Invalid/uninitialized device handle\n");
3159 return -EINVAL;
3160 }
3161
Mona Hossain2892b6b2012-02-17 13:53:11 -08003162 if (data->abort) {
3163 pr_err("Aborting qseecom driver\n");
3164 return -ENODEV;
3165 }
3166
3167 switch (cmd) {
3168 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003169 if (data->type != QSEECOM_GENERIC) {
3170 pr_err("reg lstnr req: invalid handle (%d)\n",
3171 data->type);
3172 ret = -EINVAL;
3173 break;
3174 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003175 pr_debug("ioctl register_listener_req()\n");
3176 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003177 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003178 ret = qseecom_register_listener(data, argp);
3179 atomic_dec(&data->ioctl_count);
3180 wake_up_all(&data->abort_wq);
3181 if (ret)
3182 pr_err("failed qseecom_register_listener: %d\n", ret);
3183 break;
3184 }
3185 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003186 if ((data->listener.id == 0) ||
3187 (data->type != QSEECOM_LISTENER_SERVICE)) {
3188 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3189 data->type, data->listener.id);
3190 ret = -EINVAL;
3191 break;
3192 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003193 pr_debug("ioctl unregister_listener_req()\n");
3194 atomic_inc(&data->ioctl_count);
3195 ret = qseecom_unregister_listener(data);
3196 atomic_dec(&data->ioctl_count);
3197 wake_up_all(&data->abort_wq);
3198 if (ret)
3199 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3200 break;
3201 }
3202 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003203 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003204 if ((data->client.app_id == 0) ||
3205 (data->type != QSEECOM_CLIENT_APP)) {
3206 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3207 data->type, data->client.app_id);
3208 ret = -EINVAL;
3209 break;
3210 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003211 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003212 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003213 if (qseecom.support_bus_scaling)
3214 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3215 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003216 atomic_inc(&data->ioctl_count);
3217 ret = qseecom_send_cmd(data, argp);
Zhen Kong06418b72014-02-05 17:36:23 -08003218 if (qseecom.support_bus_scaling) {
3219 mutex_lock(&qsee_bw_mutex);
3220 qseecom.bw_scale_down_timer.expires = jiffies +
3221 msecs_to_jiffies(
3222 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
3223 add_timer(&(qseecom.bw_scale_down_timer));
3224 qseecom.timer_running = true;
3225 mutex_unlock(&qsee_bw_mutex);
3226 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003227 atomic_dec(&data->ioctl_count);
3228 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003229 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003230 if (ret)
3231 pr_err("failed qseecom_send_cmd: %d\n", ret);
3232 break;
3233 }
3234 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003235 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003236 if ((data->client.app_id == 0) ||
3237 (data->type != QSEECOM_CLIENT_APP)) {
3238 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3239 data->type, data->client.app_id);
3240 ret = -EINVAL;
3241 break;
3242 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003243 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003244 mutex_lock(&app_access_lock);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003245 if (qseecom.support_bus_scaling)
3246 qseecom_scale_bus_bandwidth_timer(INACTIVE,
3247 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003248 atomic_inc(&data->ioctl_count);
3249 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kong06418b72014-02-05 17:36:23 -08003250 if (qseecom.support_bus_scaling) {
3251 mutex_lock(&qsee_bw_mutex);
3252 qseecom.bw_scale_down_timer.expires = jiffies +
3253 msecs_to_jiffies(
3254 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
3255 add_timer(&(qseecom.bw_scale_down_timer));
3256 qseecom.timer_running = true;
3257 mutex_unlock(&qsee_bw_mutex);
3258 } atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003259 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003260 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003261 if (ret)
3262 pr_err("failed qseecom_send_cmd: %d\n", ret);
3263 break;
3264 }
3265 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003266 if ((data->listener.id == 0) ||
3267 (data->type != QSEECOM_LISTENER_SERVICE)) {
3268 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3269 data->type, data->listener.id);
3270 ret = -EINVAL;
3271 break;
3272 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003273 atomic_inc(&data->ioctl_count);
3274 ret = qseecom_receive_req(data);
3275 atomic_dec(&data->ioctl_count);
3276 wake_up_all(&data->abort_wq);
3277 if (ret)
3278 pr_err("failed qseecom_receive_req: %d\n", ret);
3279 break;
3280 }
3281 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003282 if ((data->listener.id == 0) ||
3283 (data->type != QSEECOM_LISTENER_SERVICE)) {
3284 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3285 data->type, data->listener.id);
3286 ret = -EINVAL;
3287 break;
3288 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003289 atomic_inc(&data->ioctl_count);
3290 ret = qseecom_send_resp();
3291 atomic_dec(&data->ioctl_count);
3292 wake_up_all(&data->abort_wq);
3293 if (ret)
3294 pr_err("failed qseecom_send_resp: %d\n", ret);
3295 break;
3296 }
3297 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003298 if ((data->type != QSEECOM_CLIENT_APP) &&
3299 (data->type != QSEECOM_GENERIC) &&
3300 (data->type != QSEECOM_SECURE_SERVICE)) {
3301 pr_err("set mem param req: invalid handle (%d)\n",
3302 data->type);
3303 ret = -EINVAL;
3304 break;
3305 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003306 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003307 ret = qseecom_set_client_mem_param(data, argp);
3308 if (ret)
3309 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3310 ret);
3311 break;
3312 }
3313 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003314 if ((data->type != QSEECOM_GENERIC) &&
3315 (data->type != QSEECOM_CLIENT_APP)) {
3316 pr_err("load app req: invalid handle (%d)\n",
3317 data->type);
3318 ret = -EINVAL;
3319 break;
3320 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003321 data->type = QSEECOM_CLIENT_APP;
3322 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003323 mutex_lock(&app_access_lock);
3324 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003325 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3326 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003327 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003328 if (ret == 0)
3329 qseecom.commonlib_loaded = true;
3330 }
3331 }
3332 if (ret == 0)
3333 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003334 atomic_dec(&data->ioctl_count);
3335 mutex_unlock(&app_access_lock);
3336 if (ret)
3337 pr_err("failed load_app request: %d\n", ret);
3338 break;
3339 }
3340 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003341 if ((data->client.app_id == 0) ||
3342 (data->type != QSEECOM_CLIENT_APP)) {
3343 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3344 data->type, data->client.app_id);
3345 ret = -EINVAL;
3346 break;
3347 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003348 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003349 mutex_lock(&app_access_lock);
3350 atomic_inc(&data->ioctl_count);
3351 ret = qseecom_unload_app(data);
3352 atomic_dec(&data->ioctl_count);
3353 mutex_unlock(&app_access_lock);
3354 if (ret)
3355 pr_err("failed unload_app request: %d\n", ret);
3356 break;
3357 }
3358 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3359 atomic_inc(&data->ioctl_count);
3360 ret = qseecom_get_qseos_version(data, argp);
3361 if (ret)
3362 pr_err("qseecom_get_qseos_version: %d\n", ret);
3363 atomic_dec(&data->ioctl_count);
3364 break;
3365 }
3366 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003367 if ((data->type != QSEECOM_GENERIC) &&
3368 (data->type != QSEECOM_CLIENT_APP)) {
3369 pr_err("perf enable req: invalid handle (%d)\n",
3370 data->type);
3371 ret = -EINVAL;
3372 break;
3373 }
3374 if ((data->type == QSEECOM_CLIENT_APP) &&
3375 (data->client.app_id == 0)) {
3376 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3377 data->type, data->client.app_id);
3378 ret = -EINVAL;
3379 break;
3380 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003381 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003382 if (qseecom.support_bus_scaling) {
3383 mutex_lock(&qsee_bw_mutex);
3384 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3385 mutex_unlock(&qsee_bw_mutex);
3386 } else {
3387 ret = qsee_vote_for_clock(data, CLK_DFAB);
3388 if (ret)
3389 pr_err("Fail to vote for DFAB clock%d\n", ret);
3390 ret = qsee_vote_for_clock(data, CLK_SFPB);
3391 if (ret)
3392 pr_err("Fail to vote for SFPB clock%d\n", ret);
3393 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003394 atomic_dec(&data->ioctl_count);
3395 break;
3396 }
3397 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003398 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3399 (data->type != QSEECOM_CLIENT_APP)) {
3400 pr_err("perf disable req: invalid handle (%d)\n",
3401 data->type);
3402 ret = -EINVAL;
3403 break;
3404 }
3405 if ((data->type == QSEECOM_CLIENT_APP) &&
3406 (data->client.app_id == 0)) {
3407 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3408 data->type, data->client.app_id);
3409 ret = -EINVAL;
3410 break;
3411 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003412 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003413 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003414 qsee_disable_clock_vote(data, CLK_DFAB);
3415 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003416 }
3417 atomic_dec(&data->ioctl_count);
3418 break;
3419 }
3420
3421 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3422 if ((data->client.app_id == 0) ||
3423 (data->type != QSEECOM_CLIENT_APP)) {
3424 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3425 data->type, data->client.app_id);
3426 ret = -EINVAL;
3427 break;
3428 }
3429 atomic_inc(&data->ioctl_count);
3430 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003431 atomic_dec(&data->ioctl_count);
3432 break;
3433 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003434 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003435 if (data->type != QSEECOM_GENERIC) {
3436 pr_err("load ext elf req: invalid client handle (%d)\n",
3437 data->type);
3438 ret = -EINVAL;
3439 break;
3440 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003441 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003442 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003443 mutex_lock(&app_access_lock);
3444 atomic_inc(&data->ioctl_count);
3445 ret = qseecom_load_external_elf(data, argp);
3446 atomic_dec(&data->ioctl_count);
3447 mutex_unlock(&app_access_lock);
3448 if (ret)
3449 pr_err("failed load_external_elf request: %d\n", ret);
3450 break;
3451 }
3452 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003453 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3454 pr_err("unload ext elf req: invalid handle (%d)\n",
3455 data->type);
3456 ret = -EINVAL;
3457 break;
3458 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003459 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003460 mutex_lock(&app_access_lock);
3461 atomic_inc(&data->ioctl_count);
3462 ret = qseecom_unload_external_elf(data);
3463 atomic_dec(&data->ioctl_count);
3464 mutex_unlock(&app_access_lock);
3465 if (ret)
3466 pr_err("failed unload_app request: %d\n", ret);
3467 break;
3468 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003469 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003470 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003471 mutex_lock(&app_access_lock);
3472 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003473 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003474 ret = qseecom_query_app_loaded(data, argp);
3475 atomic_dec(&data->ioctl_count);
3476 mutex_unlock(&app_access_lock);
3477 break;
3478 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003479 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003480 if (data->type != QSEECOM_GENERIC) {
3481 pr_err("send cmd svc req: invalid handle (%d)\n",
3482 data->type);
3483 ret = -EINVAL;
3484 break;
3485 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003486 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003487 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003488 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003489 qseecom.qsee_version);
3490 return -EINVAL;
3491 }
3492 mutex_lock(&app_access_lock);
3493 atomic_inc(&data->ioctl_count);
3494 ret = qseecom_send_service_cmd(data, argp);
3495 atomic_dec(&data->ioctl_count);
3496 mutex_unlock(&app_access_lock);
3497 break;
3498 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003499 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003500 if (data->type != QSEECOM_GENERIC) {
3501 pr_err("create key req: invalid handle (%d)\n",
3502 data->type);
3503 ret = -EINVAL;
3504 break;
3505 }
Zhen Kong336636e2013-04-15 11:04:54 -07003506 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003507 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003508 qseecom.qsee_version);
3509 return -EINVAL;
3510 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003511 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003512 atomic_inc(&data->ioctl_count);
3513 ret = qseecom_create_key(data, argp);
3514 if (ret)
3515 pr_err("failed to create encryption key: %d\n", ret);
3516
3517 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003518 break;
3519 }
3520 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003521 if (data->type != QSEECOM_GENERIC) {
3522 pr_err("wipe key req: invalid handle (%d)\n",
3523 data->type);
3524 ret = -EINVAL;
3525 break;
3526 }
Zhen Kong336636e2013-04-15 11:04:54 -07003527 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003528 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003529 qseecom.qsee_version);
3530 return -EINVAL;
3531 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003532 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003533 atomic_inc(&data->ioctl_count);
3534 ret = qseecom_wipe_key(data, argp);
3535 if (ret)
3536 pr_err("failed to wipe encryption key: %d\n", ret);
3537 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003538 break;
3539 }
3540 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
3541 if (data->type != QSEECOM_GENERIC) {
3542 pr_err("update key req: invalid handle (%d)\n",
3543 data->type);
3544 ret = -EINVAL;
3545 break;
3546 }
3547 if (qseecom.qsee_version < QSEE_VERSION_05) {
3548 pr_err("Update Key feature unsupported in qsee ver %u\n",
3549 qseecom.qsee_version);
3550 return -EINVAL;
3551 }
3552 data->released = true;
3553 atomic_inc(&data->ioctl_count);
3554 ret = qseecom_update_key_user_info(data, argp);
3555 if (ret)
3556 pr_err("failed to update key user info: %d\n", ret);
3557 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003558 break;
3559 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003560 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003561 if (data->type != QSEECOM_GENERIC) {
3562 pr_err("save part hash req: invalid handle (%d)\n",
3563 data->type);
3564 ret = -EINVAL;
3565 break;
3566 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003567 data->released = true;
3568 mutex_lock(&app_access_lock);
3569 atomic_inc(&data->ioctl_count);
3570 ret = qseecom_save_partition_hash(argp);
3571 atomic_dec(&data->ioctl_count);
3572 mutex_unlock(&app_access_lock);
3573 break;
3574 }
3575 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003576 if (data->type != QSEECOM_GENERIC) {
3577 pr_err("ES activated req: invalid handle (%d)\n",
3578 data->type);
3579 ret = -EINVAL;
3580 break;
3581 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003582 data->released = true;
3583 mutex_lock(&app_access_lock);
3584 atomic_inc(&data->ioctl_count);
3585 ret = qseecom_is_es_activated(argp);
3586 atomic_dec(&data->ioctl_count);
3587 mutex_unlock(&app_access_lock);
3588 break;
3589 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003590 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003591 if ((data->listener.id == 0) ||
3592 (data->type != QSEECOM_LISTENER_SERVICE)) {
3593 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3594 data->type, data->listener.id);
3595 ret = -EINVAL;
3596 break;
3597 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003598 /* Only one client allowed here at a time */
3599 atomic_inc(&data->ioctl_count);
3600 ret = qseecom_send_modfd_resp(data, argp);
3601 atomic_dec(&data->ioctl_count);
3602 wake_up_all(&data->abort_wq);
3603 if (ret)
3604 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3605 break;
3606 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003607 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003608 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003609 return -EINVAL;
3610 }
3611 return ret;
3612}
3613
3614static int qseecom_open(struct inode *inode, struct file *file)
3615{
3616 int ret = 0;
3617 struct qseecom_dev_handle *data;
3618
3619 data = kzalloc(sizeof(*data), GFP_KERNEL);
3620 if (!data) {
3621 pr_err("kmalloc failed\n");
3622 return -ENOMEM;
3623 }
3624 file->private_data = data;
3625 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003626 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003627 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003628 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003629 init_waitqueue_head(&data->abort_wq);
3630 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003631
Mona Hossain2892b6b2012-02-17 13:53:11 -08003632 return ret;
3633}
3634
3635static int qseecom_release(struct inode *inode, struct file *file)
3636{
3637 struct qseecom_dev_handle *data = file->private_data;
3638 int ret = 0;
3639
3640 if (data->released == false) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003641 pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
3642 data->type, data->mode, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003643 switch (data->type) {
3644 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003645 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003646 break;
3647 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003648 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003649 break;
3650 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003651 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003652 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003653 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003654 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003655 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303656 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3657 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003658 default:
3659 pr_err("Unsupported clnt_handle_type %d",
3660 data->type);
3661 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003662 }
3663 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003664
Zhen Kong2edf90d2013-08-27 12:05:06 -07003665 if (qseecom.support_bus_scaling) {
3666 mutex_lock(&qsee_bw_mutex);
3667 if (data->mode != INACTIVE) {
3668 qseecom_unregister_bus_bandwidth_needs(data);
3669 if (qseecom.cumulative_mode == INACTIVE) {
3670 ret = __qseecom_set_msm_bus_request(INACTIVE);
3671 if (ret)
3672 pr_err("Fail to scale down bus\n");
3673 }
3674 }
3675 mutex_unlock(&qsee_bw_mutex);
3676 } else {
3677 if (data->fast_load_enabled == true)
3678 qsee_disable_clock_vote(data, CLK_SFPB);
3679 if (data->perf_enabled == true)
3680 qsee_disable_clock_vote(data, CLK_DFAB);
3681 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003682 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003683
Mona Hossain2892b6b2012-02-17 13:53:11 -08003684 return ret;
3685}
3686
Mona Hossain2892b6b2012-02-17 13:53:11 -08003687static const struct file_operations qseecom_fops = {
3688 .owner = THIS_MODULE,
3689 .unlocked_ioctl = qseecom_ioctl,
3690 .open = qseecom_open,
3691 .release = qseecom_release
3692};
3693
Mona Hossainc92629e2013-04-01 13:37:46 -07003694static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003695{
3696 int rc = 0;
3697 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003698 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003699 char *core_clk_src = NULL;
3700 char *core_clk = NULL;
3701 char *iface_clk = NULL;
3702 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003703
Mona Hossainc92629e2013-04-01 13:37:46 -07003704 switch (ce) {
3705 case CLK_QSEE: {
3706 core_clk_src = "core_clk_src";
3707 core_clk = "core_clk";
3708 iface_clk = "iface_clk";
3709 bus_clk = "bus_clk";
3710 qclk = &qseecom.qsee;
3711 qclk->instance = CLK_QSEE;
3712 break;
3713 };
3714 case CLK_CE_DRV: {
3715 core_clk_src = "ce_drv_core_clk_src";
3716 core_clk = "ce_drv_core_clk";
3717 iface_clk = "ce_drv_iface_clk";
3718 bus_clk = "ce_drv_bus_clk";
3719 qclk = &qseecom.ce_drv;
3720 qclk->instance = CLK_CE_DRV;
3721 break;
3722 };
3723 default:
3724 pr_err("Invalid ce hw instance: %d!\n", ce);
3725 return -EIO;
3726 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003727 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003728
Mona Hossainc92629e2013-04-01 13:37:46 -07003729 /* Get CE3 src core clk. */
3730 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003731 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003732 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003733 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003734 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003735 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003736 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003737 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003738 }
3739 } else {
3740 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003741 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003742 }
3743
3744 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003745 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003746 if (IS_ERR(qclk->ce_core_clk)) {
3747 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003748 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003749 if (qclk->ce_core_src_clk != NULL)
3750 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003751 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003752 }
3753
3754 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003755 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003756 if (IS_ERR(qclk->ce_clk)) {
3757 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003758 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003759 if (qclk->ce_core_src_clk != NULL)
3760 clk_put(qclk->ce_core_src_clk);
3761 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003762 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003763 }
3764
3765 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003766 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003767 if (IS_ERR(qclk->ce_bus_clk)) {
3768 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003769 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003770 if (qclk->ce_core_src_clk != NULL)
3771 clk_put(qclk->ce_core_src_clk);
3772 clk_put(qclk->ce_core_clk);
3773 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003774 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003775 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003776 return rc;
3777}
3778
Mona Hossainc92629e2013-04-01 13:37:46 -07003779static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003780{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003781 struct qseecom_clk *qclk;
3782
Mona Hossainc92629e2013-04-01 13:37:46 -07003783 if (ce == CLK_QSEE)
3784 qclk = &qseecom.qsee;
3785 else
3786 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003787
3788 if (qclk->ce_clk != NULL) {
3789 clk_put(qclk->ce_clk);
3790 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003791 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003792 if (qclk->ce_core_clk != NULL) {
3793 clk_put(qclk->ce_core_clk);
3794 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003795 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003796 if (qclk->ce_bus_clk != NULL) {
3797 clk_put(qclk->ce_bus_clk);
3798 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003799 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003800 if (qclk->ce_core_src_clk != NULL) {
3801 clk_put(qclk->ce_core_src_clk);
3802 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003803 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003804}
3805
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003806static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003807{
3808 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003809 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003810 struct device *class_dev;
3811 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003812 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003813 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3814
Mona Hossain17a4faf2013-03-22 16:40:56 -07003815 qseecom.qsee_bw_count = 0;
3816 qseecom.qsee_perf_client = 0;
3817 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003818
Mona Hossain17a4faf2013-03-22 16:40:56 -07003819 qseecom.qsee.ce_core_clk = NULL;
3820 qseecom.qsee.ce_clk = NULL;
3821 qseecom.qsee.ce_core_src_clk = NULL;
3822 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003823
Zhen Kong2edf90d2013-08-27 12:05:06 -07003824 qseecom.cumulative_mode = 0;
3825 qseecom.current_mode = INACTIVE;
3826 qseecom.support_bus_scaling = false;
3827
Mona Hossainc92629e2013-04-01 13:37:46 -07003828 qseecom.ce_drv.ce_core_clk = NULL;
3829 qseecom.ce_drv.ce_clk = NULL;
3830 qseecom.ce_drv.ce_core_src_clk = NULL;
3831 qseecom.ce_drv.ce_bus_clk = NULL;
3832
Mona Hossain2892b6b2012-02-17 13:53:11 -08003833 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3834 if (rc < 0) {
3835 pr_err("alloc_chrdev_region failed %d\n", rc);
3836 return rc;
3837 }
3838
3839 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3840 if (IS_ERR(driver_class)) {
3841 rc = -ENOMEM;
3842 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303843 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003844 }
3845
3846 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3847 QSEECOM_DEV);
3848 if (!class_dev) {
3849 pr_err("class_device_create failed %d\n", rc);
3850 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303851 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003852 }
3853
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303854 cdev_init(&qseecom.cdev, &qseecom_fops);
3855 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003856
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303857 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003858 if (rc < 0) {
3859 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303860 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003861 }
3862
3863 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3864 spin_lock_init(&qseecom.registered_listener_list_lock);
3865 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3866 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003867 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3868 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003869 init_waitqueue_head(&qseecom.send_resp_wq);
3870 qseecom.send_resp_flag = 0;
3871
3872 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3873 &qsee_not_legacy, sizeof(qsee_not_legacy));
3874 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003875 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303876 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003877 }
Mona Hossain05c73562012-10-29 17:49:01 -07003878 if (qsee_not_legacy) {
3879 uint32_t feature = 10;
3880
3881 qseecom.qsee_version = QSEEE_VERSION_00;
3882 rc = scm_call(6, 3, &feature, sizeof(feature),
3883 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3884 if (rc) {
3885 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303886 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003887 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003888 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003889 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003890 pr_err("QSEE legacy version is not supported:");
3891 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3892 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303893 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003894 }
Mona Hossain05c73562012-10-29 17:49:01 -07003895 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003896 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003897 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003898 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003899 if (qseecom.ion_clnt == NULL) {
3900 pr_err("Ion client cannot be created\n");
3901 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303902 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003903 }
3904
3905 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003906 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05303907 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003908 qseecom.support_bus_scaling =
3909 of_property_read_bool((&pdev->dev)->of_node,
3910 "qcom,support-bus-scaling");
3911 pr_warn("support_bus_scaling=0x%x",
3912 qseecom.support_bus_scaling);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003913 if (of_property_read_u32((&pdev->dev)->of_node,
3914 "qcom,disk-encrypt-pipe-pair",
3915 &qseecom.ce_info.disk_encrypt_pipe)) {
3916 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3917 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3918 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303919 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003920 } else {
3921 pr_warn("bam_pipe_pair=0x%x",
3922 qseecom.ce_info.disk_encrypt_pipe);
3923 }
3924
3925 if (of_property_read_u32((&pdev->dev)->of_node,
3926 "qcom,qsee-ce-hw-instance",
3927 &qseecom.ce_info.qsee_ce_hw_instance)) {
3928 pr_err("Fail to get qsee ce hw instance information.\n");
3929 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3930 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303931 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003932 } else {
3933 pr_warn("qsee-ce-hw-instance=0x%x",
3934 qseecom.ce_info.qsee_ce_hw_instance);
3935 }
3936
3937 if (of_property_read_u32((&pdev->dev)->of_node,
3938 "qcom,hlos-ce-hw-instance",
3939 &qseecom.ce_info.hlos_ce_hw_instance)) {
3940 pr_err("Fail to get hlos ce hw instance information.\n");
3941 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3942 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303943 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003944 } else {
3945 pr_warn("hlos-ce-hw-instance=0x%x",
3946 qseecom.ce_info.hlos_ce_hw_instance);
3947 }
3948
Mona Hossainc92629e2013-04-01 13:37:46 -07003949 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3950 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3951
3952 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003953 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303954 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003955
Mona Hossainc92629e2013-04-01 13:37:46 -07003956 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3957 ret = __qseecom_init_clk(CLK_CE_DRV);
3958 if (ret) {
3959 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303960 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003961 }
3962 } else {
3963 struct qseecom_clk *qclk;
3964
3965 qclk = &qseecom.qsee;
3966 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3967 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3968 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3969 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3970 }
3971
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003972 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3973 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003974 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3975 struct resource *resource = NULL;
3976 struct qsee_apps_region_info_ireq req;
3977 struct qseecom_command_scm_resp resp;
3978
3979 resource = platform_get_resource_byname(pdev,
3980 IORESOURCE_MEM, "secapp-region");
3981 if (resource) {
3982 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3983 req.addr = resource->start;
3984 req.size = resource_size(resource);
3985 pr_warn("secure app region addr=0x%x size=0x%x",
3986 req.addr, req.size);
3987 } else {
3988 pr_err("Fail to get secure app region info\n");
3989 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303990 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003991 }
3992 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3993 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003994 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3995 pr_err("send secapp reg fail %d resp.res %d\n",
3996 rc, resp.result);
3997 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303998 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003999 }
4000 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004001 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004002 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4003 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004004 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004005 if (qseecom.support_bus_scaling) {
4006 init_timer(&(qseecom.bw_scale_down_timer));
4007 INIT_WORK(&qseecom.bw_inactive_req_ws,
4008 qseecom_bw_inactive_req_work);
4009 qseecom.bw_scale_down_timer.function =
4010 qseecom_scale_bus_bandwidth_timer_callback;
4011 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004012 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004013 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004014 qseecom_platform_support);
4015
Mona Hossain17a4faf2013-03-22 16:40:56 -07004016 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004017 pr_err("Unable to register bus client\n");
4018 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304019
4020exit_destroy_ion_client:
4021 ion_client_destroy(qseecom.ion_clnt);
4022exit_del_cdev:
4023 cdev_del(&qseecom.cdev);
4024exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004025 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304026exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004027 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304028exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004029 unregister_chrdev_region(qseecom_device_no, 1);
4030 return rc;
4031}
4032
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004033static int __devinit qseecom_remove(struct platform_device *pdev)
4034{
Mona Hossaind44a3842012-10-15 09:41:35 -07004035 struct qseecom_registered_kclient_list *kclient = NULL;
4036 unsigned long flags = 0;
4037 int ret = 0;
4038
Mona Hossaind44a3842012-10-15 09:41:35 -07004039 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304040
Mona Hossaind44a3842012-10-15 09:41:35 -07004041 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304042 list) {
4043 if (!kclient)
4044 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07004045
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304046 /* Break the loop if client handle is NULL */
4047 if (!kclient->handle)
4048 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004049
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304050 if (list_empty(&kclient->list))
4051 goto exit_free_kc_handle;
4052
4053 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07004054 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304055 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004056 kzfree(kclient->handle->dev);
4057 kzfree(kclient->handle);
4058 kzfree(kclient);
4059 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004060 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304061
4062exit_free_kc_handle:
4063 kzfree(kclient->handle);
4064exit_free_kclient:
4065 kzfree(kclient);
4066exit_irqrestore:
4067 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4068
4069 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004070 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004071
Mona Hossain17a4faf2013-03-22 16:40:56 -07004072 if (qseecom.qsee_perf_client)
4073 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4074 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304075 if (pdev->dev.platform_data != NULL)
4076 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4077
Zhen Kong2edf90d2013-08-27 12:05:06 -07004078 if (qseecom.support_bus_scaling) {
4079 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4080 del_timer_sync(&qseecom.bw_scale_down_timer);
4081 }
4082
Mona Hossaind39e33b2012-11-05 13:36:40 -08004083 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004084 if (pdev->dev.of_node) {
4085 __qseecom_deinit_clk(CLK_QSEE);
4086 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
4087 __qseecom_deinit_clk(CLK_CE_DRV);
4088 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304089
4090 ion_client_destroy(qseecom.ion_clnt);
4091
4092 cdev_del(&qseecom.cdev);
4093
4094 device_destroy(driver_class, qseecom_device_no);
4095
4096 class_destroy(driver_class);
4097
4098 unregister_chrdev_region(qseecom_device_no, 1);
4099
Mona Hossaind44a3842012-10-15 09:41:35 -07004100 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304101}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004102
Zhen Konga0944b82013-11-06 17:02:00 -08004103static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4104{
4105 int ret = 0;
4106 struct qseecom_clk *qclk;
4107 qclk = &qseecom.qsee;
4108
4109 if (qseecom.cumulative_mode != INACTIVE) {
4110 ret = __qseecom_set_msm_bus_request(INACTIVE);
4111 if (ret)
4112 pr_err("Fail to scale down bus\n");
4113 }
4114 mutex_lock(&clk_access_lock);
4115 if (qclk->clk_access_cnt) {
4116 if (qclk->ce_clk != NULL)
4117 clk_disable_unprepare(qclk->ce_clk);
4118 if (qclk->ce_core_clk != NULL)
4119 clk_disable_unprepare(qclk->ce_core_clk);
4120 if (qclk->ce_bus_clk != NULL)
4121 clk_disable_unprepare(qclk->ce_bus_clk);
4122 }
4123 mutex_unlock(&clk_access_lock);
4124 return 0;
4125}
4126
4127static int qseecom_resume(struct platform_device *pdev)
4128{
4129 int mode = 0;
4130 int ret = 0;
4131 struct qseecom_clk *qclk;
4132 qclk = &qseecom.qsee;
4133
4134 if (qseecom.cumulative_mode >= HIGH)
4135 mode = HIGH;
4136 else
4137 mode = qseecom.cumulative_mode;
4138
4139 if (qseecom.cumulative_mode != INACTIVE) {
4140 ret = __qseecom_set_msm_bus_request(mode);
4141 if (ret)
4142 pr_err("Fail to scale down bus\n");
4143 }
4144
4145 mutex_lock(&clk_access_lock);
4146 if (qclk->clk_access_cnt) {
4147
4148 ret = clk_prepare_enable(qclk->ce_core_clk);
4149 if (ret) {
4150 pr_err("Unable to enable/prepare CE core clk\n");
4151 qclk->clk_access_cnt = 0;
4152 goto err;
4153 }
4154
4155 ret = clk_prepare_enable(qclk->ce_clk);
4156 if (ret) {
4157 pr_err("Unable to enable/prepare CE iface clk\n");
4158 qclk->clk_access_cnt = 0;
4159 goto ce_clk_err;
4160 }
4161
4162 ret = clk_prepare_enable(qclk->ce_bus_clk);
4163 if (ret) {
4164 pr_err("Unable to enable/prepare CE bus clk\n");
4165 qclk->clk_access_cnt = 0;
4166 goto ce_bus_clk_err;
4167 }
4168 }
4169 mutex_unlock(&clk_access_lock);
4170 return 0;
4171
4172ce_bus_clk_err:
4173 clk_disable_unprepare(qclk->ce_clk);
4174ce_clk_err:
4175 clk_disable_unprepare(qclk->ce_core_clk);
4176err:
4177 mutex_unlock(&clk_access_lock);
4178 return -EIO;
4179}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004180static struct of_device_id qseecom_match[] = {
4181 {
4182 .compatible = "qcom,qseecom",
4183 },
4184 {}
4185};
4186
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004187static struct platform_driver qseecom_plat_driver = {
4188 .probe = qseecom_probe,
4189 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004190 .suspend = qseecom_suspend,
4191 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004192 .driver = {
4193 .name = "qseecom",
4194 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004195 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004196 },
4197};
4198
4199static int __devinit qseecom_init(void)
4200{
4201 return platform_driver_register(&qseecom_plat_driver);
4202}
4203
4204static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004205{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304206 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004207}
4208
4209MODULE_LICENSE("GPL v2");
4210MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4211
4212module_init(qseecom_init);
4213module_exit(qseecom_exit);