blob: 4f99365a6e0d5951d9c227089ec8f2040f5edf3b [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 Kong581df352017-04-28 16:13:57 +08003 * Copyright (c) 2012-2017, 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
Zhen Konge3674c62017-05-02 13:39:41 +080048#define U32_MAX ((u32)~0U)
49
Mona Hossain2892b6b2012-02-17 13:53:11 -080050#define QSEECOM_DEV "qseecom"
Mona Hossain2892b6b2012-02-17 13:53:11 -080051#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070052#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080053#define QSEE_VERSION_01 0x401000
54#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080055#define QSEE_VERSION_03 0x403000
Amir Samuelovd1fc7412013-03-10 16:56:13 +020056#define QSEE_VERSION_04 0x404000
Zhen Kong336636e2013-04-15 11:04:54 -070057#define QSEE_VERSION_05 0x405000
58
Mona Hossain5b76a622012-11-15 20:09:08 -080059
Mona Hossain05c73562012-10-29 17:49:01 -070060
61#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080062
Mona Hossaind39e33b2012-11-05 13:36:40 -080063#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080064
Mona Hossain13dd8922013-01-03 06:11:09 -080065#define QSEECOM_MAX_SG_ENTRY 512
Zhen Kongba69dfe2014-02-28 15:19:53 -080066#define QSEECOM_INVALID_KEY_ID 0xff
Mona Hossainf1f2ed62012-11-15 19:51:33 -080067
Amir Samuelovd1fc7412013-03-10 16:56:13 +020068/* Save partition image hash for authentication check */
69#define SCM_SAVE_PARTITION_HASH_ID 0x01
70
71/* Check if enterprise security is activate */
72#define SCM_IS_ACTIVATED_ID 0x02
73
Zhen Kong7812dc12013-07-09 17:12:55 -070074#define RPMB_SERVICE 0x2000
75
Zhen Kong2edf90d2013-08-27 12:05:06 -070076#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
77#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
78
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070079enum qseecom_clk_definitions {
80 CLK_DFAB = 0,
81 CLK_SFPB,
82};
83
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080084enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053085 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080086 QSEECOM_LISTENER_SERVICE,
87 QSEECOM_SECURE_SERVICE,
88 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053089 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080090};
91
Mona Hossainc92629e2013-04-01 13:37:46 -070092enum qseecom_ce_hw_instance {
93 CLK_QSEE = 0,
94 CLK_CE_DRV,
95};
96
Mona Hossain2892b6b2012-02-17 13:53:11 -080097static struct class *driver_class;
98static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -080099
Mona Hossain2892b6b2012-02-17 13:53:11 -0800100static DEFINE_MUTEX(qsee_bw_mutex);
101static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -0700102static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800103
Mona Hossain2892b6b2012-02-17 13:53:11 -0800104struct qseecom_registered_listener_list {
105 struct list_head list;
106 struct qseecom_register_listener_req svc;
Zhen Kongf4948192013-11-25 13:05:35 -0800107 uint32_t user_virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800108 u8 *sb_virt;
109 s32 sb_phys;
110 size_t sb_length;
111 struct ion_handle *ihandle; /* Retrieve phy addr */
112
113 wait_queue_head_t rcv_req_wq;
114 int rcv_req_flag;
115};
116
117struct qseecom_registered_app_list {
118 struct list_head list;
119 u32 app_id;
120 u32 ref_cnt;
William Clarkc7a043d2014-05-23 15:08:52 -0700121 char app_name[MAX_APP_NAME_SIZE];
Mona Hossain2892b6b2012-02-17 13:53:11 -0800122};
123
Mona Hossaind44a3842012-10-15 09:41:35 -0700124struct qseecom_registered_kclient_list {
125 struct list_head list;
126 struct qseecom_handle *handle;
127};
128
Mona Hossain4cf78a92013-02-14 12:06:41 -0800129struct ce_hw_usage_info {
130 uint32_t qsee_ce_hw_instance;
131 uint32_t hlos_ce_hw_instance;
132 uint32_t disk_encrypt_pipe;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800133 uint32_t file_encrypt_pipe;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800134};
135
Mona Hossain17a4faf2013-03-22 16:40:56 -0700136struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700137 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700138 struct clk *ce_core_clk;
139 struct clk *ce_clk;
140 struct clk *ce_core_src_clk;
141 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700142 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700143};
144
Mona Hossain2892b6b2012-02-17 13:53:11 -0800145struct qseecom_control {
146 struct ion_client *ion_clnt; /* Ion client */
147 struct list_head registered_listener_list_head;
148 spinlock_t registered_listener_list_lock;
149
150 struct list_head registered_app_list_head;
151 spinlock_t registered_app_list_lock;
152
Mona Hossaind44a3842012-10-15 09:41:35 -0700153 struct list_head registered_kclient_list_head;
154 spinlock_t registered_kclient_list_lock;
155
Mona Hossain2892b6b2012-02-17 13:53:11 -0800156 wait_queue_head_t send_resp_wq;
157 int send_resp_flag;
158
159 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700160 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700161 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700162 bool commonlib_loaded;
Zhen Kongc46b5842013-12-12 13:09:16 +0530163 struct ion_handle *cmnlib_ion_handle;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800164 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700165
166 int qsee_bw_count;
167 int qsee_sfpb_bw_count;
168
169 uint32_t qsee_perf_client;
170 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700171 struct qseecom_clk ce_drv;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700172
173 bool support_bus_scaling;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800174 bool support_fde;
175 bool support_pfe;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700176 uint32_t cumulative_mode;
177 enum qseecom_bandwidth_request_mode current_mode;
178 struct timer_list bw_scale_down_timer;
179 struct work_struct bw_inactive_req_ws;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800180 struct cdev cdev;
181 bool timer_running;
Zhen Kong56d62642015-03-10 16:29:53 -0700182 bool appsbl_qseecom_support;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800183};
184
185struct qseecom_client_handle {
186 u32 app_id;
187 u8 *sb_virt;
188 s32 sb_phys;
189 uint32_t user_virt_sb_base;
190 size_t sb_length;
191 struct ion_handle *ihandle; /* Retrieve phy addr */
William Clarkc7a043d2014-05-23 15:08:52 -0700192 char app_name[MAX_APP_NAME_SIZE];
Mona Hossain2892b6b2012-02-17 13:53:11 -0800193};
194
195struct qseecom_listener_handle {
196 u32 id;
197};
198
199static struct qseecom_control qseecom;
200
201struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800202 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800203 union {
204 struct qseecom_client_handle client;
205 struct qseecom_listener_handle listener;
206 };
207 bool released;
208 int abort;
209 wait_queue_head_t abort_wq;
210 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700211 bool perf_enabled;
212 bool fast_load_enabled;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700213 enum qseecom_bandwidth_request_mode mode;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800214};
215
Mona Hossain4cf78a92013-02-14 12:06:41 -0800216enum qseecom_set_clear_key_flag {
217 QSEECOM_CLEAR_CE_KEY_CMD = 0,
218 QSEECOM_SET_CE_KEY_CMD,
219};
220
221struct qseecom_set_key_parameter {
222 uint32_t ce_hw;
223 uint32_t pipe;
224 uint32_t flags;
225 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
226 unsigned char hash32[QSEECOM_HASH_SIZE];
227 enum qseecom_set_clear_key_flag set_clear_key_flag;
228};
229
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800230struct qseecom_sg_entry {
231 uint32_t phys_addr;
232 uint32_t len;
233};
234
Zhen Kongba69dfe2014-02-28 15:19:53 -0800235struct qseecom_key_id_usage_desc {
236 uint8_t desc[QSEECOM_KEY_ID_SIZE];
237};
238
239static struct qseecom_key_id_usage_desc key_id_array[] = {
240 {
241 .desc = "Undefined Usage Index",
242 },
243
244 {
245 .desc = "Full Disk Encryption",
246 },
247
248 {
249 .desc = "Per File Encryption",
250 },
Zhen Kong9730ddf2013-12-17 16:49:43 -0800251};
252
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700253/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800254static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
255static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700256static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
257static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700258
Mona Hossain2892b6b2012-02-17 13:53:11 -0800259static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800260 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800261{
262 struct qseecom_registered_listener_list *ptr;
263 int unique = 1;
264 unsigned long flags;
265
266 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
267 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800268 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800269 pr_err("Service id: %u is already registered\n",
270 ptr->svc.listener_id);
271 unique = 0;
272 break;
273 }
274 }
275 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
276 return unique;
277}
278
279static struct qseecom_registered_listener_list *__qseecom_find_svc(
280 int32_t listener_id)
281{
282 struct qseecom_registered_listener_list *entry = NULL;
283 unsigned long flags;
284
285 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
286 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
287 {
288 if (entry->svc.listener_id == listener_id)
289 break;
290 }
291 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530292
293 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
294 pr_err("Service id: %u is not found\n", listener_id);
295 return NULL;
296 }
297
Mona Hossain2892b6b2012-02-17 13:53:11 -0800298 return entry;
299}
300
301static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
302 struct qseecom_dev_handle *handle,
303 struct qseecom_register_listener_req *listener)
304{
305 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800306 struct qseecom_register_listener_ireq req;
307 struct qseecom_command_scm_resp resp;
308 ion_phys_addr_t pa;
309
310 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800311 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
312 listener->ifd_data_fd);
Hariprasad Dhalinarasimha1401bc02014-02-18 13:46:37 -0800313 if (IS_ERR_OR_NULL(svc->ihandle)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800314 pr_err("Ion client could not retrieve the handle\n");
315 return -ENOMEM;
316 }
317
318 /* Get the physical address of the ION BUF */
319 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
Zhen Kong05ed4462014-01-28 18:21:30 -0800320 if (ret) {
321 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
322 ret);
323 return ret;
324 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800325 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700326 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800327 svc->sb_phys = pa;
328
Mona Hossaind4613de2013-05-15 16:49:29 -0700329 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
330 req.listener_id = svc->svc.listener_id;
331 req.sb_len = svc->sb_length;
332 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800333
Mona Hossaind4613de2013-05-15 16:49:29 -0700334 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800335
Mona Hossaind4613de2013-05-15 16:49:29 -0700336 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800337 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700338 if (ret) {
339 pr_err("qseecom_scm_call failed with err: %d\n", ret);
340 return -EINVAL;
341 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800342
Mona Hossaind4613de2013-05-15 16:49:29 -0700343 if (resp.result != QSEOS_RESULT_SUCCESS) {
344 pr_err("Error SB registration req: resp.result = %d\n",
345 resp.result);
346 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800347 }
348 return 0;
349}
350
351static int qseecom_register_listener(struct qseecom_dev_handle *data,
352 void __user *argp)
353{
354 int ret = 0;
355 unsigned long flags;
356 struct qseecom_register_listener_req rcvd_lstnr;
357 struct qseecom_registered_listener_list *new_entry;
358
359 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
360 if (ret) {
361 pr_err("copy_from_user failed\n");
362 return ret;
363 }
Zhen Kongf4948192013-11-25 13:05:35 -0800364 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
365 rcvd_lstnr.sb_size))
366 return -EFAULT;
367
Mona Hossain0af10ab2012-02-28 18:26:41 -0800368 data->listener.id = 0;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800369 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800370 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800371 data->released = true;
372 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800373 }
374
375 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
376 if (!new_entry) {
377 pr_err("kmalloc failed\n");
378 return -ENOMEM;
379 }
380 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
381 new_entry->rcv_req_flag = 0;
382
383 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
384 new_entry->sb_length = rcvd_lstnr.sb_size;
Zhen Kongf4948192013-11-25 13:05:35 -0800385 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800386 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
387 pr_err("qseecom_set_sb_memoryfailed\n");
388 kzfree(new_entry);
389 return -ENOMEM;
390 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800391
Mona Hossain2892b6b2012-02-17 13:53:11 -0800392 init_waitqueue_head(&new_entry->rcv_req_wq);
393
394 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
395 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
396 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800397
Zhen Kongd7c6fe62019-09-20 13:49:41 -0700398 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800399 return ret;
400}
401
402static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
403{
404 int ret = 0;
405 unsigned long flags;
406 uint32_t unmap_mem = 0;
407 struct qseecom_register_listener_ireq req;
408 struct qseecom_registered_listener_list *ptr_svc = NULL;
409 struct qseecom_command_scm_resp resp;
410 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
411
Zhen Kongd7c6fe62019-09-20 13:49:41 -0700412 if (data->released) {
413 pr_err("Don't unregister lsnr %d\n", data->listener.id);
414 return -EINVAL;
415 }
416
Mona Hossaind4613de2013-05-15 16:49:29 -0700417 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
418 req.listener_id = data->listener.id;
419 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800420
Mona Hossaind4613de2013-05-15 16:49:29 -0700421 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800422 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700423 if (ret) {
424 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
425 ret, data->listener.id);
426 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800427 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700428
429 if (resp.result != QSEOS_RESULT_SUCCESS) {
430 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
431 resp.result, data->listener.id);
432 return -EPERM;
433 }
434
Mona Hossain2892b6b2012-02-17 13:53:11 -0800435 data->abort = 1;
436 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
437 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
438 list) {
439 if (ptr_svc->svc.listener_id == data->listener.id) {
440 wake_up_all(&ptr_svc->rcv_req_wq);
441 break;
442 }
443 }
444 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
445
446 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700447 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800448 atomic_read(&data->ioctl_count) <= 1)) {
449 pr_err("Interrupted from abort\n");
450 ret = -ERESTARTSYS;
451 break;
452 }
453 }
454
455 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
456 list_for_each_entry(ptr_svc,
457 &qseecom.registered_listener_list_head,
458 list)
459 {
460 if (ptr_svc->svc.listener_id == data->listener.id) {
461 if (ptr_svc->sb_virt) {
462 unmap_mem = 1;
463 ihandle = ptr_svc->ihandle;
464 }
465 list_del(&ptr_svc->list);
466 kzfree(ptr_svc);
467 break;
468 }
469 }
470 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
471
472 /* Unmap the memory */
473 if (unmap_mem) {
474 if (!IS_ERR_OR_NULL(ihandle)) {
475 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
476 ion_free(qseecom.ion_clnt, ihandle);
477 }
478 }
479 data->released = true;
480 return ret;
481}
482
Zhen Kong2edf90d2013-08-27 12:05:06 -0700483static int __qseecom_set_msm_bus_request(uint32_t mode)
484{
485 int ret = 0;
486 struct qseecom_clk *qclk;
487
488 qclk = &qseecom.qsee;
489 if (qclk->ce_core_src_clk != NULL) {
490 if (mode == INACTIVE) {
491 __qseecom_disable_clk(CLK_QSEE);
492 } else {
493 ret = __qseecom_enable_clk(CLK_QSEE);
494 if (ret)
495 pr_err("CLK enabling failed (%d) MODE (%d)\n",
496 ret, mode);
497 }
498 }
499
500 if ((!ret) && (qseecom.current_mode != mode)) {
501 ret = msm_bus_scale_client_update_request(
502 qseecom.qsee_perf_client, mode);
503 if (ret) {
504 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
505 ret, mode);
506 if (qclk->ce_core_src_clk != NULL) {
507 if (mode == INACTIVE)
508 __qseecom_enable_clk(CLK_QSEE);
509 else
510 __qseecom_disable_clk(CLK_QSEE);
511 }
512 }
513 qseecom.current_mode = mode;
514 }
515 return ret;
516}
517
518static void qseecom_bw_inactive_req_work(struct work_struct *work)
519{
520 mutex_lock(&app_access_lock);
521 mutex_lock(&qsee_bw_mutex);
522 __qseecom_set_msm_bus_request(INACTIVE);
523 pr_debug("current_mode = %d, cumulative_mode = %d\n",
524 qseecom.current_mode, qseecom.cumulative_mode);
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800525 qseecom.timer_running = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700526 mutex_unlock(&qsee_bw_mutex);
527 mutex_unlock(&app_access_lock);
528 return;
529}
530
531static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
532{
533 schedule_work(&qseecom.bw_inactive_req_ws);
534 return;
535}
536
Zhen Kongca4c2d52014-03-12 13:22:46 -0700537static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800538{
539 struct qseecom_clk *qclk;
Zhen Kongca4c2d52014-03-12 13:22:46 -0700540 int ret = 0;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800541 mutex_lock(&clk_access_lock);
542 if (ce == CLK_QSEE)
543 qclk = &qseecom.qsee;
544 else
545 qclk = &qseecom.ce_drv;
546
Zhen Kongca4c2d52014-03-12 13:22:46 -0700547 if (qclk->clk_access_cnt > 2) {
548 pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
549 ret = -EINVAL;
550 goto err_dec_ref_cnt;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800551 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700552 if (qclk->clk_access_cnt == 2)
553 qclk->clk_access_cnt--;
554
555err_dec_ref_cnt:
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800556 mutex_unlock(&clk_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -0700557 return ret;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800558}
559
560
Zhen Kongaf950192014-02-05 17:36:23 -0800561static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700562{
563 int32_t ret = 0;
564 int32_t request_mode = INACTIVE;
565
566 mutex_lock(&qsee_bw_mutex);
567 if (mode == 0) {
568 if (qseecom.cumulative_mode > MEDIUM)
569 request_mode = HIGH;
570 else
571 request_mode = qseecom.cumulative_mode;
572 } else {
573 request_mode = mode;
574 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700575
Zhen Kongca4c2d52014-03-12 13:22:46 -0700576 ret = __qseecom_set_msm_bus_request(request_mode);
577 if (ret) {
578 pr_err("set msm bus request failed (%d),request_mode (%d)\n",
579 ret, request_mode);
580 goto err_scale_timer;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800581 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700582
583 if (qseecom.timer_running) {
584 ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
585 if (ret) {
586 pr_err("Failed to decrease clk ref count.\n");
587 goto err_scale_timer;
588 }
589 del_timer_sync(&(qseecom.bw_scale_down_timer));
590 qseecom.timer_running = false;
591 }
592err_scale_timer:
Zhen Kong2edf90d2013-08-27 12:05:06 -0700593 mutex_unlock(&qsee_bw_mutex);
594 return ret;
595}
596
597
598static int qseecom_unregister_bus_bandwidth_needs(
599 struct qseecom_dev_handle *data)
600{
601 int32_t ret = 0;
602
603 qseecom.cumulative_mode -= data->mode;
604 data->mode = INACTIVE;
605
606 return ret;
607}
608
609static int __qseecom_register_bus_bandwidth_needs(
610 struct qseecom_dev_handle *data, uint32_t request_mode)
611{
612 int32_t ret = 0;
613
614 if (data->mode == INACTIVE) {
615 qseecom.cumulative_mode += request_mode;
616 data->mode = request_mode;
617 } else {
618 if (data->mode != request_mode) {
619 qseecom.cumulative_mode -= data->mode;
620 qseecom.cumulative_mode += request_mode;
621 data->mode = request_mode;
622 }
623 }
624 return ret;
625}
626
Zhen Kongd08301c2014-10-08 17:02:54 -0700627static int qseecom_perf_enable(struct qseecom_dev_handle *data)
628{
629 int ret = 0;
630 ret = qsee_vote_for_clock(data, CLK_DFAB);
631 if (ret) {
632 pr_err("Failed to vote for DFAB clock with err %d\n", ret);
633 goto perf_enable_exit;
634 }
635 ret = qsee_vote_for_clock(data, CLK_SFPB);
636 if (ret) {
637 qsee_disable_clock_vote(data, CLK_DFAB);
638 pr_err("Failed to vote for SFPB clock with err %d\n", ret);
639 goto perf_enable_exit;
640 }
641
642perf_enable_exit:
643 return ret;
644}
645
Zhen Kong2edf90d2013-08-27 12:05:06 -0700646static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
647 void __user *argp)
648{
649 int32_t ret = 0;
650 int32_t req_mode;
651
652 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
653 if (ret) {
654 pr_err("copy_from_user failed\n");
655 return ret;
656 }
657 if (req_mode > HIGH) {
658 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
Mona Hossain268c3122014-11-03 17:05:48 -0800659 return -EINVAL;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700660 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700661
Zhen Kongd08301c2014-10-08 17:02:54 -0700662 /*
663 * Register bus bandwidth needs if bus scaling feature is enabled;
664 * otherwise, qseecom enable/disable clocks for the client directly.
665 */
666 if (qseecom.support_bus_scaling) {
667 mutex_lock(&qsee_bw_mutex);
668 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
669 mutex_unlock(&qsee_bw_mutex);
670 } else {
671 pr_debug("Bus scaling feature is NOT enabled\n");
672 pr_debug("request bandwidth mode %d for the client\n",
673 req_mode);
674 if (req_mode != INACTIVE) {
675 ret = qseecom_perf_enable(data);
676 if (ret)
677 pr_err("Failed to vote for clock with err %d\n",
678 ret);
679 } else {
680 qsee_disable_clock_vote(data, CLK_DFAB);
681 qsee_disable_clock_vote(data, CLK_SFPB);
682 }
683 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700684 return ret;
685}
686
Zhen Kongaf950192014-02-05 17:36:23 -0800687static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
688{
689 mutex_lock(&qsee_bw_mutex);
690 qseecom.bw_scale_down_timer.expires = jiffies +
691 msecs_to_jiffies(duration);
Zhen Konge5b434e2014-04-17 16:47:06 -0700692 mod_timer(&(qseecom.bw_scale_down_timer),
693 qseecom.bw_scale_down_timer.expires);
Zhen Kongaf950192014-02-05 17:36:23 -0800694 qseecom.timer_running = true;
695 mutex_unlock(&qsee_bw_mutex);
696}
697
Zhen Kong2edf90d2013-08-27 12:05:06 -0700698static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
699{
700 if (!qseecom.support_bus_scaling)
701 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -0800702 else
703 __qseecom_add_bw_scale_down_timer(
704 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700705 return;
706}
707
708static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
709{
710 int ret = 0;
711 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -0700712 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
713 if (ret)
714 pr_err("Failed to set bw MEDIUM.\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700715 } else {
716 ret = qsee_vote_for_clock(data, CLK_SFPB);
717 if (ret)
718 pr_err("Fail vote for clk SFPB ret %d\n", ret);
719 }
720 return ret;
721}
722
Mona Hossain2892b6b2012-02-17 13:53:11 -0800723static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
724 void __user *argp)
725{
726 ion_phys_addr_t pa;
727 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800728 struct qseecom_set_sb_mem_param_req req;
729 uint32_t len;
730
731 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700732 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800733 return -EFAULT;
734
Mona Hossaina1124de2013-10-01 13:41:09 -0700735 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
736 (req.sb_len == 0)) {
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +0530737 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%pK)\n",
738 req.ifd_data_fd, req.sb_len, (void *)req.virt_sb_base);
Mona Hossaina1124de2013-10-01 13:41:09 -0700739 return -EFAULT;
740 }
Zhen Kongf4948192013-11-25 13:05:35 -0800741 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
742 req.sb_len))
743 return -EFAULT;
744
Mona Hossain2892b6b2012-02-17 13:53:11 -0800745 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800746 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
747 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800748 if (IS_ERR_OR_NULL(data->client.ihandle)) {
749 pr_err("Ion client could not retrieve the handle\n");
750 return -ENOMEM;
751 }
752 /* Get the physical address of the ION BUF */
753 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800754 if (ret) {
755
756 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
757 ret);
758 return ret;
759 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800760 /* Populate the structure for sending scm call to load image */
761 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700762 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800763 data->client.sb_phys = pa;
764 data->client.sb_length = req.sb_len;
765 data->client.user_virt_sb_base = req.virt_sb_base;
766 return 0;
767}
768
Mona Hossain2892b6b2012-02-17 13:53:11 -0800769static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
770{
771 int ret;
772 ret = (qseecom.send_resp_flag != 0);
773 return ret || data->abort;
774}
775
776static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
777 struct qseecom_command_scm_resp *resp)
778{
779 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800780 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800781 uint32_t lstnr;
782 unsigned long flags;
783 struct qseecom_client_listener_data_irsp send_data_rsp;
784 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700785 sigset_t new_sigset;
786 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800787
Mona Hossain2892b6b2012-02-17 13:53:11 -0800788 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
789 lstnr = resp->data;
790 /*
791 * Wake up blocking lsitener service with the lstnr id
792 */
793 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
794 flags);
795 list_for_each_entry(ptr_svc,
796 &qseecom.registered_listener_list_head, list) {
797 if (ptr_svc->svc.listener_id == lstnr) {
798 ptr_svc->rcv_req_flag = 1;
799 wake_up_interruptible(&ptr_svc->rcv_req_wq);
800 break;
801 }
802 }
803 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
804 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700805
806 if (ptr_svc == NULL) {
807 pr_err("Listener Svc %d does not exist\n", lstnr);
808 return -EINVAL;
809 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800810 if (ptr_svc->svc.listener_id != lstnr) {
811 pr_warning("Service requested for does on exist\n");
812 return -ERESTARTSYS;
813 }
814 pr_debug("waking up rcv_req_wq and "
815 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800816
Mona Hossain91da2c52013-03-29 17:28:31 -0700817 /* initialize the new signal mask with all signals*/
818 sigfillset(&new_sigset);
819 /* block all signals */
820 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
821
822 do {
823 if (!wait_event_freezable(qseecom.send_resp_wq,
824 __qseecom_listener_has_sent_rsp(data)))
825 break;
826 } while (1);
827
828 /* restore signal mask */
829 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
830 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700831 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
832 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700833 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800834 send_data_rsp.status = QSEOS_RESULT_FAILURE;
835 } else {
836 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800837 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800838
Mona Hossain2892b6b2012-02-17 13:53:11 -0800839 qseecom.send_resp_flag = 0;
840 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
841 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700842 if (ptr_svc)
843 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
844 ptr_svc->sb_virt, ptr_svc->sb_length,
845 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700846
847 if (lstnr == RPMB_SERVICE)
848 __qseecom_enable_clk(CLK_QSEE);
849
Mona Hossain2892b6b2012-02-17 13:53:11 -0800850 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
851 (const void *)&send_data_rsp,
852 sizeof(send_data_rsp), resp,
853 sizeof(*resp));
854 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700855 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800856 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700857 if (lstnr == RPMB_SERVICE)
858 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800859 return ret;
860 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800861 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
862 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
863 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
864 resp->result, data->client.app_id, lstnr);
865 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700866 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700867 if (lstnr == RPMB_SERVICE)
868 __qseecom_disable_clk(CLK_QSEE);
869
Mona Hossain2892b6b2012-02-17 13:53:11 -0800870 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800871 if (rc)
872 return rc;
873
Mona Hossain2892b6b2012-02-17 13:53:11 -0800874 return ret;
875}
876
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700877static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
878{
879 int32_t ret;
880 struct qseecom_command_scm_resp resp;
881
882 /* SCM_CALL to check if app_id for the mentioned app exists */
883 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
884 sizeof(struct qseecom_check_app_ireq),
885 &resp, sizeof(resp));
886 if (ret) {
887 pr_err("scm_call to check if app is already loaded failed\n");
888 return -EINVAL;
889 }
890
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700891 if (resp.result == QSEOS_RESULT_FAILURE) {
892 return 0;
893 } else {
894 switch (resp.resp_type) {
895 /*qsee returned listener type response */
896 case QSEOS_LISTENER_ID:
897 pr_err("resp type is of listener type instead of app");
898 return -EINVAL;
899 break;
900 case QSEOS_APP_ID:
901 return resp.data;
902 default:
903 pr_err("invalid resp type (%d) from qsee",
904 resp.resp_type);
905 return -ENODEV;
906 break;
907 }
908 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700909}
910
Mona Hossain2892b6b2012-02-17 13:53:11 -0800911static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
912{
913 struct qseecom_registered_app_list *entry = NULL;
914 unsigned long flags = 0;
915 u32 app_id = 0;
916 struct ion_handle *ihandle; /* Ion handle */
917 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700918 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800919 ion_phys_addr_t pa = 0;
920 uint32_t len;
921 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800922 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700923 struct qseecom_load_app_ireq load_req;
Mallikarjuna Reddy Amireddyd3d8eae2016-11-22 17:24:46 +0530924 bool first_time = false;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700925
Mona Hossain2892b6b2012-02-17 13:53:11 -0800926 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700927 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800928 (void __user *)argp,
929 sizeof(struct qseecom_load_img_req))) {
930 pr_err("copy_from_user failed\n");
931 return -EFAULT;
932 }
Zhen Kong4bead3c2014-04-14 15:07:13 -0700933
934 if (qseecom.support_bus_scaling) {
935 mutex_lock(&qsee_bw_mutex);
936 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
937 mutex_unlock(&qsee_bw_mutex);
938 if (ret)
939 return ret;
940 }
941
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700942 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700943 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700944 if (ret)
Zhen Kong4bead3c2014-04-14 15:07:13 -0700945 goto enable_clk_err;
946
Mona Hossain436b75f2012-11-20 17:10:40 -0800947 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700948 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -0700949 strlcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800950
Mona Hossain436b75f2012-11-20 17:10:40 -0800951 ret = __qseecom_check_app_exists(req);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700952 if (ret < 0)
953 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800954
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530955 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800956 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700957 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800958 (char *)(req.app_name));
959 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
960 list_for_each_entry(entry,
961 &qseecom.registered_app_list_head, list){
962 if (entry->app_id == app_id) {
963 entry->ref_cnt++;
964 break;
965 }
966 }
967 spin_unlock_irqrestore(
968 &qseecom.registered_app_list_lock, flags);
Zhen Kong3a5eaac2014-06-12 12:16:12 -0700969 ret = 0;
Mona Hossain436b75f2012-11-20 17:10:40 -0800970 } else {
Mallikarjuna Reddy Amireddyd3d8eae2016-11-22 17:24:46 +0530971 first_time = true;
Mona Hossain436b75f2012-11-20 17:10:40 -0800972 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700973 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800974 /* Get the handle of the shared fd */
975 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800976 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800977 if (IS_ERR_OR_NULL(ihandle)) {
978 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -0700979 ret = -ENOMEM;
980 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800981 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800982
Mona Hossain436b75f2012-11-20 17:10:40 -0800983 /* Get the physical address of the ION BUF */
984 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800985 if (ret) {
986 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
987 ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700988 goto loadapp_err;
Zhen Kong05ed4462014-01-28 18:21:30 -0800989 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800990
Mona Hossain436b75f2012-11-20 17:10:40 -0800991 /* Populate the structure for sending scm call to load image */
William Clarkba7f03c2015-03-09 12:07:49 -0700992 strlcpy(load_req.app_name, load_img_req.img_name,
Mona Hossain436b75f2012-11-20 17:10:40 -0800993 MAX_APP_NAME_SIZE);
994 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
995 load_req.mdt_len = load_img_req.mdt_len;
996 load_req.img_len = load_img_req.img_len;
997 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700998 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
999 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001000
Mona Hossain436b75f2012-11-20 17:10:40 -08001001 /* SCM_CALL to load the app and get the app_id back */
1002 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001003 sizeof(struct qseecom_load_app_ireq),
1004 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001005 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -08001006 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001007 if (!IS_ERR_OR_NULL(ihandle))
1008 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001009 ret = -EINVAL;
1010 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001011 }
1012
1013 if (resp.result == QSEOS_RESULT_FAILURE) {
1014 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001015 if (!IS_ERR_OR_NULL(ihandle))
1016 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001017 ret = -EFAULT;
1018 goto loadapp_err;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001019 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001020
Mona Hossain436b75f2012-11-20 17:10:40 -08001021 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1022 ret = __qseecom_process_incomplete_cmd(data, &resp);
1023 if (ret) {
1024 pr_err("process_incomplete_cmd failed err: %d\n",
1025 ret);
1026 if (!IS_ERR_OR_NULL(ihandle))
1027 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001028 ret = -EFAULT;
1029 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001030 }
1031 }
1032
1033 if (resp.result != QSEOS_RESULT_SUCCESS) {
1034 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001035 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -08001036 if (!IS_ERR_OR_NULL(ihandle))
1037 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001038 ret = -EFAULT;
1039 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001040 }
1041
1042 app_id = resp.data;
1043
1044 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1045 if (!entry) {
1046 pr_err("kmalloc failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001047 ret = -ENOMEM;
1048 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001049 }
1050 entry->app_id = app_id;
1051 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07001052 strlcpy(entry->app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001053 MAX_APP_NAME_SIZE);
Mona Hossain436b75f2012-11-20 17:10:40 -08001054 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001055 if (!IS_ERR_OR_NULL(ihandle))
1056 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001057
Mona Hossain436b75f2012-11-20 17:10:40 -08001058 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1059 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1060 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1061 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001062
Mona Hossain436b75f2012-11-20 17:10:40 -08001063 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -07001064 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -08001065 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001066 data->client.app_id = app_id;
William Clarkba7f03c2015-03-09 12:07:49 -07001067 strlcpy(data->client.app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001068 MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001069 load_img_req.app_id = app_id;
1070 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
1071 pr_err("copy_to_user failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001072 ret = -EFAULT;
Mallikarjuna Reddy Amireddyd3d8eae2016-11-22 17:24:46 +05301073 if (first_time == true) {
1074 spin_lock_irqsave(
1075 &qseecom.registered_app_list_lock, flags);
1076 list_del(&entry->list);
1077 spin_unlock_irqrestore(
1078 &qseecom.registered_app_list_lock, flags);
1079 kzfree(entry);
1080 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001081 }
Zhen Kong4bead3c2014-04-14 15:07:13 -07001082
1083loadapp_err:
Zhen Kong2edf90d2013-08-27 12:05:06 -07001084 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001085enable_clk_err:
1086 if (qseecom.support_bus_scaling) {
1087 mutex_lock(&qsee_bw_mutex);
1088 qseecom_unregister_bus_bandwidth_needs(data);
1089 mutex_unlock(&qsee_bw_mutex);
1090 }
1091 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001092}
1093
1094static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
1095{
1096 wake_up_all(&qseecom.send_resp_wq);
1097 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001098 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001099 atomic_read(&data->ioctl_count) <= 1)) {
1100 pr_err("Interrupted from abort\n");
1101 return -ERESTARTSYS;
1102 break;
1103 }
1104 }
1105 /* Set unload app */
1106 return 1;
1107}
1108
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001109static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
1110{
1111 int ret = 0;
1112 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
1113 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
1114 ion_free(qseecom.ion_clnt, data->client.ihandle);
1115 data->client.ihandle = NULL;
1116 }
1117 return ret;
1118}
1119
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001120static int qseecom_unload_app(struct qseecom_dev_handle *data,
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001121 bool app_crash)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001122{
1123 unsigned long flags;
William Clarkc7a043d2014-05-23 15:08:52 -07001124 unsigned long flags1;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001125 int ret = 0;
1126 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001127 struct qseecom_registered_app_list *ptr_app = NULL;
Mona Hossain340dba82012-08-07 19:54:46 -07001128 bool unload = false;
1129 bool found_app = false;
William Clarkc7a043d2014-05-23 15:08:52 -07001130 bool found_dead_app = false;
1131
1132 if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
Zhen Kong763307c2014-09-12 12:58:13 -07001133 pr_debug("Do not unload keymaster app from tz\n");
1134 goto unload_exit;
William Clarkc7a043d2014-05-23 15:08:52 -07001135 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001136
Mona Hossaind4613de2013-05-15 16:49:29 -07001137 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001138 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1139 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001140 list) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001141 if (ptr_app->app_id == data->client.app_id) {
William Clarkc7a043d2014-05-23 15:08:52 -07001142 if (!memcmp((void *)ptr_app->app_name,
1143 (void *)data->client.app_name,
1144 strlen(data->client.app_name))) {
1145 found_app = true;
1146 if (app_crash || ptr_app->ref_cnt == 1)
1147 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001148 break;
1149 } else {
William Clarkc7a043d2014-05-23 15:08:52 -07001150 found_dead_app = true;
1151 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001152 }
1153 }
1154 }
1155 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1156 flags);
William Clarkc7a043d2014-05-23 15:08:52 -07001157 if (found_app == false && found_dead_app == false) {
1158 pr_err("Cannot find app with id = %d (%s)\n",
1159 data->client.app_id,
1160 (char *)data->client.app_name);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001161 return -EINVAL;
1162 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001163 }
1164
William Clarkc7a043d2014-05-23 15:08:52 -07001165 if (found_dead_app) {
1166 pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
1167 (char *)data->client.app_name);
1168 __qseecom_cleanup_app(data);
1169 }
1170
Mona Hossaind4613de2013-05-15 16:49:29 -07001171 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001172 struct qseecom_unload_app_ireq req;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001173 /* Populate the structure for sending scm call to load image */
1174 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1175 req.app_id = data->client.app_id;
1176
1177 /* SCM_CALL to unload the app */
1178 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1179 sizeof(struct qseecom_unload_app_ireq),
1180 &resp, sizeof(resp));
1181 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001182 pr_err("scm_call to unload app (id = %d) failed\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001183 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001184 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001185 } else {
1186 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001187 }
William Clarkc7a043d2014-05-23 15:08:52 -07001188 if (resp.result == QSEOS_RESULT_FAILURE) {
1189 pr_err("app (%d) unload_failed!!\n",
1190 data->client.app_id);
1191 return -EFAULT;
1192 }
1193 if (resp.result == QSEOS_RESULT_SUCCESS)
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301194 pr_debug("App (%d) is unloaded!!\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001195 data->client.app_id);
1196 __qseecom_cleanup_app(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001197 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1198 ret = __qseecom_process_incomplete_cmd(data, &resp);
1199 if (ret) {
1200 pr_err("process_incomplete_cmd fail err: %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001201 ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001202 return ret;
1203 }
1204 }
1205 }
William Clarkc7a043d2014-05-23 15:08:52 -07001206
1207 if (found_app) {
1208 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
1209 if (app_crash) {
1210 ptr_app->ref_cnt = 0;
1211 pr_debug("app_crash: ref_count = 0\n");
1212 } else {
1213 if (ptr_app->ref_cnt == 1) {
1214 ptr_app->ref_cnt = 0;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301215 pr_debug("ref_count set to 0\n");
William Clarkc7a043d2014-05-23 15:08:52 -07001216 } else {
1217 ptr_app->ref_cnt--;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301218 pr_debug("Can't unload app(%d) inuse\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001219 ptr_app->app_id);
1220 }
1221 }
1222 if (unload) {
1223 list_del(&ptr_app->list);
1224 kzfree(ptr_app);
1225 }
1226 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1227 flags1);
1228 }
Zhen Kong763307c2014-09-12 12:58:13 -07001229unload_exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001230 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001231 data->released = true;
1232 return ret;
1233}
1234
1235static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1236 uint32_t virt)
1237{
1238 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1239}
1240
Zhen Kongf4948192013-11-25 13:05:35 -08001241static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1242 uint32_t virt)
1243{
1244 return (uint32_t)data->client.sb_virt +
1245 (virt - data->client.user_virt_sb_base);
1246}
1247
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001248int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1249 struct qseecom_send_svc_cmd_req *req_ptr,
1250 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1251{
1252 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001253 void *req_buf = NULL;
1254
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001255 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
Jeron Susan19547b82016-11-03 10:02:25 +08001256 pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001257 req_ptr, send_svc_ireq_ptr);
1258 return -EINVAL;
1259 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001260
Zhen Kong581df352017-04-28 16:13:57 +08001261
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001262 /* Clients need to ensure req_buf is at base offset of shared buffer */
1263 if ((uint32_t)req_ptr->cmd_req_buf !=
1264 data_ptr->client.user_virt_sb_base) {
1265 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001266 return -EINVAL;
1267 }
1268
Zhen Kong581df352017-04-28 16:13:57 +08001269 if (data_ptr->client.sb_length <
1270 sizeof(struct qseecom_rpmb_provision_key)) {
1271 pr_err("shared buffer is too small to hold key type\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001272 return -EINVAL;
1273 }
1274
1275 req_buf = data_ptr->client.sb_virt;
1276
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001277 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1278 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001279 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001280 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1281 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1282 (uint32_t)req_ptr->resp_buf));
1283 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1284
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001285 return ret;
1286}
1287
Zhen Kong581df352017-04-28 16:13:57 +08001288static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
1289 struct qseecom_send_svc_cmd_req *req)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001290{
Zhen Kong581df352017-04-28 16:13:57 +08001291 if (!req || !req->resp_buf || !req->cmd_req_buf) {
1292 pr_err("req or cmd buffer or response buffer is null\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001293 return -EINVAL;
1294 }
1295
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001296 if (data->client.sb_virt == NULL) {
1297 pr_err("sb_virt null\n");
1298 return -EINVAL;
1299 }
1300
1301 if (data->client.user_virt_sb_base == 0) {
1302 pr_err("user_virt_sb_base is null\n");
1303 return -EINVAL;
1304 }
1305
1306 if (data->client.sb_length == 0) {
1307 pr_err("sb_length is 0\n");
1308 return -EINVAL;
1309 }
1310
Zhen Kong581df352017-04-28 16:13:57 +08001311 if (((uintptr_t)req->cmd_req_buf <
1312 data->client.user_virt_sb_base) ||
1313 ((uintptr_t)req->cmd_req_buf >=
1314 (data->client.user_virt_sb_base + data->client.sb_length))) {
1315 pr_err("cmd buffer address not within shared bufffer\n");
1316 return -EINVAL;
1317 }
1318 if (((uintptr_t)req->resp_buf <
1319 data->client.user_virt_sb_base) ||
1320 ((uintptr_t)req->resp_buf >=
1321 (data->client.user_virt_sb_base + data->client.sb_length))) {
1322 pr_err("response buffer address not within shared bufffer\n");
1323 return -EINVAL;
1324 }
1325 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
1326 (req->cmd_req_len > data->client.sb_length) ||
1327 (req->resp_len > data->client.sb_length)) {
1328 pr_err("cmd buf length or response buf length not valid\n");
1329 return -EINVAL;
1330 }
1331 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1332 pr_err("Integer overflow detected in req_len & rsp_len\n");
1333 return -EINVAL;
1334 }
1335
1336 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1337 pr_debug("Not enough memory to fit cmd_buf.\n");
1338 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1339 (req->cmd_req_len + req->resp_len),
1340 data->client.sb_length);
1341 return -ENOMEM;
1342 }
1343 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1344 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1345 return -EINVAL;
1346 }
1347 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1348 pr_err("Integer overflow in resp_len & resp_buf\n");
1349 return -EINVAL;
1350 }
1351 if (data->client.user_virt_sb_base >
1352 (ULONG_MAX - data->client.sb_length)) {
1353 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1354 return -EINVAL;
1355 }
1356 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1357 ((uintptr_t)data->client.user_virt_sb_base +
1358 data->client.sb_length)) ||
1359 (((uintptr_t)req->resp_buf + req->resp_len) >
1360 ((uintptr_t)data->client.user_virt_sb_base +
1361 data->client.sb_length))) {
1362 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1363 return -EINVAL;
1364 }
1365 return 0;
1366}
1367
1368static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1369 void __user *argp)
1370{
1371 int ret = 0;
1372 struct qseecom_client_send_service_ireq send_svc_ireq;
1373 struct qseecom_command_scm_resp resp;
1374 struct qseecom_send_svc_cmd_req req;
1375
1376 /*struct qseecom_command_scm_resp resp;*/
1377
1378 if (copy_from_user(&req,
1379 (void __user *)argp,
1380 sizeof(req))) {
1381 pr_err("copy_from_user failed\n");
1382 return -EFAULT;
1383 }
1384
1385 if (__validate_send_service_cmd_inputs(data, &req))
1386 return -EINVAL;
1387
Zhen Kong2edf90d2013-08-27 12:05:06 -07001388 data->type = QSEECOM_SECURE_SERVICE;
1389
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001390 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001391 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1392 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001393 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1394 &send_svc_ireq))
1395 return -EINVAL;
1396 break;
1397 default:
1398 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1399 return -EINVAL;
1400 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301401
Zhen Kong2edf90d2013-08-27 12:05:06 -07001402 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001403 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001404 if (ret) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001405 pr_err("Fail to set bw HIGH\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -07001406 return ret;
1407 }
1408 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07001409 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001410 if (ret) {
Zhen Kongd08301c2014-10-08 17:02:54 -07001411 pr_err("Failed to vote for clocks with err %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001412 goto exit;
1413 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301414 }
1415
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001416 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1417 data->client.sb_virt, data->client.sb_length,
1418 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001419 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1420 sizeof(send_svc_ireq),
1421 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001422 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1423 data->client.sb_virt, data->client.sb_length,
1424 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001425 if (ret) {
1426 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001427 if (!qseecom.support_bus_scaling) {
1428 qsee_disable_clock_vote(data, CLK_DFAB);
1429 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -08001430 } else {
1431 __qseecom_add_bw_scale_down_timer(
1432 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001433 }
1434 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001435 }
1436
1437 switch (resp.result) {
1438 case QSEOS_RESULT_SUCCESS:
1439 break;
1440 case QSEOS_RESULT_INCOMPLETE:
1441 pr_err("qseos_result_incomplete\n");
1442 ret = __qseecom_process_incomplete_cmd(data, &resp);
1443 if (ret) {
1444 pr_err("process_incomplete_cmd fail: err: %d\n",
1445 ret);
1446 }
1447 break;
1448 case QSEOS_RESULT_FAILURE:
1449 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1450 break;
1451 default:
1452 pr_err("Response result %d not supported\n",
1453 resp.result);
1454 ret = -EINVAL;
1455 break;
1456 }
Zhen Kongaf950192014-02-05 17:36:23 -08001457 if (!qseecom.support_bus_scaling) {
1458 qsee_disable_clock_vote(data, CLK_DFAB);
1459 qsee_disable_clock_vote(data, CLK_SFPB);
1460 } else {
1461 __qseecom_add_bw_scale_down_timer(
1462 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1463 }
1464
Zhen Kong2edf90d2013-08-27 12:05:06 -07001465exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001466 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001467}
1468
Mona Hossain268c3122014-11-03 17:05:48 -08001469static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
1470 struct qseecom_send_cmd_req *req)
1471{
1472 if (!data || !data->client.ihandle) {
1473 pr_err("Client or client handle is not initialized\n");
1474 return -EINVAL;
1475 }
1476 if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
1477 (req->cmd_req_buf == NULL)) {
1478 pr_err("cmd buffer or response buffer is null\n");
1479 return -EINVAL;
1480 }
1481 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1482 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1483 data->client.sb_length))) {
1484 pr_err("cmd buffer address not within shared bufffer\n");
1485 return -EINVAL;
1486 }
1487 if (((uintptr_t)req->resp_buf <
1488 data->client.user_virt_sb_base) ||
1489 ((uintptr_t)req->resp_buf >=
1490 (data->client.user_virt_sb_base + data->client.sb_length))) {
1491 pr_err("response buffer address not within shared bufffer\n");
1492 return -EINVAL;
1493 }
1494 if ((req->cmd_req_len == 0) ||
1495 (req->cmd_req_len > data->client.sb_length) ||
1496 (req->resp_len > data->client.sb_length)) {
1497 pr_err("cmd buf length or response buf length not valid\n");
1498 return -EINVAL;
1499 }
1500 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1501 pr_err("Integer overflow detected in req_len & rsp_len\n");
1502 return -EINVAL;
1503 }
1504
1505 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1506 pr_debug("Not enough memory to fit cmd_buf.\n");
1507 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1508 (req->cmd_req_len + req->resp_len),
1509 data->client.sb_length);
1510 return -ENOMEM;
1511 }
1512 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1513 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1514 return -EINVAL;
1515 }
1516 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1517 pr_err("Integer overflow in resp_len & resp_buf\n");
1518 return -EINVAL;
1519 }
1520 if (data->client.user_virt_sb_base >
1521 (ULONG_MAX - data->client.sb_length)) {
1522 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1523 return -EINVAL;
1524 }
1525 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1526 ((uintptr_t)data->client.user_virt_sb_base +
1527 data->client.sb_length)) ||
1528 (((uintptr_t)req->resp_buf + req->resp_len) >
1529 ((uintptr_t)data->client.user_virt_sb_base +
1530 data->client.sb_length))) {
1531 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1532 return -EINVAL;
1533 }
1534 return 0;
1535}
1536
Mona Hossain2892b6b2012-02-17 13:53:11 -08001537static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1538 struct qseecom_send_cmd_req *req)
1539{
1540 int ret = 0;
1541 u32 reqd_len_sb_in = 0;
1542 struct qseecom_client_send_data_ireq send_data_req;
1543 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001544 unsigned long flags;
1545 struct qseecom_registered_app_list *ptr_app;
1546 bool found_app = false;
William Clark3f378a42014-07-03 15:32:13 -07001547 int name_len = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001548
Mona Hossain2892b6b2012-02-17 13:53:11 -08001549 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
William Clarkc7a043d2014-05-23 15:08:52 -07001550 /* find app_id & img_name from list */
1551 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1552 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
1553 list) {
William Clark3f378a42014-07-03 15:32:13 -07001554 name_len = min(strlen(data->client.app_name),
1555 strlen(ptr_app->app_name));
William Clarkc7a043d2014-05-23 15:08:52 -07001556 if ((ptr_app->app_id == data->client.app_id) &&
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001557 (!memcmp(ptr_app->app_name,
1558 data->client.app_name, name_len))) {
William Clarkc7a043d2014-05-23 15:08:52 -07001559 found_app = true;
1560 break;
1561 }
1562 }
1563 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
1564
1565 if (!found_app) {
1566 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
1567 (char *)data->client.app_name);
1568 return -EINVAL;
1569 }
1570
Mona Hossain2892b6b2012-02-17 13:53:11 -08001571 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1572 send_data_req.app_id = data->client.app_id;
1573 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1574 (uint32_t)req->cmd_req_buf));
1575 send_data_req.req_len = req->cmd_req_len;
1576 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1577 (uint32_t)req->resp_buf));
1578 send_data_req.rsp_len = req->resp_len;
1579
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001580 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1581 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001582 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001583 ION_IOC_CLEAN_INV_CACHES);
1584
Mona Hossain2892b6b2012-02-17 13:53:11 -08001585 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1586 sizeof(send_data_req),
1587 &resp, sizeof(resp));
1588 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001589 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1590 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001591 return ret;
1592 }
1593
1594 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1595 ret = __qseecom_process_incomplete_cmd(data, &resp);
1596 if (ret) {
1597 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1598 return ret;
1599 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001600 } else {
1601 if (resp.result != QSEOS_RESULT_SUCCESS) {
1602 pr_err("Response result %d not supported\n",
1603 resp.result);
1604 ret = -EINVAL;
1605 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001606 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001607 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1608 data->client.sb_virt, data->client.sb_length,
1609 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001610 return ret;
1611}
1612
Mona Hossain2892b6b2012-02-17 13:53:11 -08001613static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1614{
1615 int ret = 0;
1616 struct qseecom_send_cmd_req req;
1617
1618 ret = copy_from_user(&req, argp, sizeof(req));
1619 if (ret) {
1620 pr_err("copy_from_user failed\n");
1621 return ret;
1622 }
Mona Hossain268c3122014-11-03 17:05:48 -08001623
1624 if (__validate_send_cmd_inputs(data, &req))
1625 return -EINVAL;
1626
Mona Hossaind4613de2013-05-15 16:49:29 -07001627 ret = __qseecom_send_cmd(data, &req);
1628
Mona Hossain2892b6b2012-02-17 13:53:11 -08001629 if (ret)
1630 return ret;
1631
Mona Hossain2892b6b2012-02-17 13:53:11 -08001632 return ret;
1633}
1634
Mona Hossain268c3122014-11-03 17:05:48 -08001635int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
Mona Hossainb9470692014-10-09 12:00:03 -07001636 struct qseecom_send_modfd_listener_resp *lstnr_resp,
1637 struct qseecom_dev_handle *data, bool listener_svc,
1638 int i) {
Mona Hossainb9470692014-10-09 12:00:03 -07001639
1640 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001641 if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
1642 (cmd_req->ifd_data[i].cmd_buf_offset >
1643 cmd_req->cmd_req_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001644 pr_err("Invalid offset 0x%x\n",
1645 cmd_req->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001646 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001647 }
1648 } else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001649 if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
1650 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1651 lstnr_resp->resp_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001652 pr_err("Invalid offset 0x%x\n",
1653 lstnr_resp->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001654 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001655 }
1656 }
Mona Hossain268c3122014-11-03 17:05:48 -08001657 return 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001658}
1659
Mona Hossain268c3122014-11-03 17:05:48 -08001660#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001661static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1662 struct qseecom_dev_handle *data,
1663 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001664{
1665 struct ion_handle *ihandle;
1666 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001667 int ret = 0;
1668 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001669 uint32_t len = 0;
1670 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001671 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1672 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1673 struct qseecom_registered_listener_list *this_lstnr = NULL;
1674
1675 if (msg == NULL) {
1676 pr_err("Invalid address\n");
1677 return -EINVAL;
1678 }
1679 if (listener_svc) {
1680 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1681 this_lstnr = __qseecom_find_svc(data->listener.id);
1682 if (IS_ERR_OR_NULL(this_lstnr)) {
1683 pr_err("Invalid listener ID\n");
1684 return -ENOMEM;
1685 }
1686 } else {
1687 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1688 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001689
1690 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001691 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001692 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001693 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001694 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001695 if (IS_ERR_OR_NULL(ihandle)) {
1696 pr_err("Ion client can't retrieve the handle\n");
1697 return -ENOMEM;
1698 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001699 field = (char *) cmd_req->cmd_req_buf +
1700 cmd_req->ifd_data[i].cmd_buf_offset;
1701 } else if ((listener_svc) &&
1702 (lstnr_resp->ifd_data[i].fd > 0)) {
1703 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1704 lstnr_resp->ifd_data[i].fd);
1705 if (IS_ERR_OR_NULL(ihandle)) {
1706 pr_err("Ion client can't retrieve the handle\n");
1707 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001708 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001709 field = lstnr_resp->resp_buf_ptr +
1710 lstnr_resp->ifd_data[i].cmd_buf_offset;
1711 } else {
1712 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001713 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001714 /* Populate the cmd data structure with the phys_addr */
1715 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1716 if (sg_ptr == NULL) {
1717 pr_err("IOn client could not retrieve sg table\n");
1718 goto err;
1719 }
1720 if (sg_ptr->nents == 0) {
1721 pr_err("Num of scattered entries is 0\n");
1722 goto err;
1723 }
1724 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1725 pr_err("Num of scattered entries");
1726 pr_err(" (%d) is greater than max supported %d\n",
1727 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1728 goto err;
1729 }
1730 sg = sg_ptr->sgl;
1731 if (sg_ptr->nents == 1) {
1732 uint32_t *update;
1733 update = (uint32_t *) field;
Mona Hossainb9470692014-10-09 12:00:03 -07001734
Mona Hossain268c3122014-11-03 17:05:48 -08001735 if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
Mona Hossainb9470692014-10-09 12:00:03 -07001736 listener_svc, i))
1737 goto err;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001738 if (cleanup)
1739 *update = 0;
1740 else
1741 *update = (uint32_t)sg_dma_address(
1742 sg_ptr->sgl);
1743 len += (uint32_t)sg->length;
1744 } else {
1745 struct qseecom_sg_entry *update;
1746 int j = 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001747
1748 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001749 if ((cmd_req->cmd_req_len <
1750 SG_ENTRY_SZ * sg_ptr->nents) ||
1751 (cmd_req->ifd_data[i].cmd_buf_offset >
1752 (cmd_req->cmd_req_len -
1753 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001754 pr_err("Invalid offset = 0x%x\n",
1755 cmd_req->ifd_data[i].
1756 cmd_buf_offset);
1757 goto err;
1758 }
1759 } else if ((listener_svc) &&
1760 (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001761 if ((lstnr_resp->resp_len <
1762 SG_ENTRY_SZ * sg_ptr->nents) ||
1763 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1764 (lstnr_resp->resp_len -
1765 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001766 pr_err("Invalid offset = 0x%x\n",
1767 lstnr_resp->ifd_data[i].
1768 cmd_buf_offset);
1769 goto err;
1770 }
1771 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001772 update = (struct qseecom_sg_entry *) field;
1773 for (j = 0; j < sg_ptr->nents; j++) {
1774 if (cleanup) {
1775 update->phys_addr = 0;
1776 update->len = 0;
1777 } else {
1778 update->phys_addr = (uint32_t)
1779 sg_dma_address(sg);
1780 update->len = sg->length;
1781 }
1782 len += sg->length;
1783 update++;
1784 sg = sg_next(sg);
1785 }
1786 }
1787 if (cleanup)
1788 msm_ion_do_cache_op(qseecom.ion_clnt,
1789 ihandle, NULL, len,
1790 ION_IOC_INV_CACHES);
1791 else
1792 msm_ion_do_cache_op(qseecom.ion_clnt,
1793 ihandle, NULL, len,
1794 ION_IOC_CLEAN_INV_CACHES);
1795 /* Deallocate the handle */
1796 if (!IS_ERR_OR_NULL(ihandle))
1797 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001798 }
1799 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001800err:
1801 if (!IS_ERR_OR_NULL(ihandle))
1802 ion_free(qseecom.ion_clnt, ihandle);
1803 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001804}
1805
1806static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1807 void __user *argp)
1808{
1809 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001810 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001811 struct qseecom_send_modfd_cmd_req req;
1812 struct qseecom_send_cmd_req send_cmd_req;
1813
1814 ret = copy_from_user(&req, argp, sizeof(req));
1815 if (ret) {
1816 pr_err("copy_from_user failed\n");
1817 return ret;
1818 }
Zhen Kongf4948192013-11-25 13:05:35 -08001819
jeronf5cf7042016-07-26 16:13:50 +08001820 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1821 pr_err("cmd buffer or response buffer is null\n");
1822 return -EINVAL;
1823 }
1824 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1825 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1826 data->client.sb_length))) {
1827 pr_err("cmd buffer address not within shared bufffer\n");
1828 return -EINVAL;
1829 }
1830
1831 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1832 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1833 data->client.sb_length))){
1834 pr_err("response buffer address not within shared bufffer\n");
1835 return -EINVAL;
1836 }
Teow Wan Yee1a428fd2016-07-27 14:01:01 +08001837
1838 if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
1839 req.resp_len > data->client.sb_length) {
1840 pr_err("cmd or response buffer length not valid\n");
1841 return -EINVAL;
1842 }
1843
Mona Hossain2892b6b2012-02-17 13:53:11 -08001844 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1845 send_cmd_req.cmd_req_len = req.cmd_req_len;
1846 send_cmd_req.resp_buf = req.resp_buf;
1847 send_cmd_req.resp_len = req.resp_len;
1848
Mona Hossain268c3122014-11-03 17:05:48 -08001849 if (__validate_send_cmd_inputs(data, &send_cmd_req))
1850 return -EINVAL;
1851
Mona Hossaindddf4442013-10-01 14:08:20 -07001852 /* validate offsets */
1853 for (i = 0; i < MAX_ION_FD; i++) {
1854 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1855 pr_err("Invalid offset %d = 0x%x\n",
1856 i, req.ifd_data[i].cmd_buf_offset);
1857 return -EINVAL;
1858 }
1859 }
Zhen Kongf4948192013-11-25 13:05:35 -08001860 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1861 (uint32_t)req.cmd_req_buf);
1862 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1863 (uint32_t)req.resp_buf);
1864
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001865 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001866 if (ret)
1867 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001868 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001869 if (ret)
1870 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001871 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001872 if (ret)
1873 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001874
Mona Hossain2892b6b2012-02-17 13:53:11 -08001875 return ret;
1876}
1877
1878static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1879 struct qseecom_registered_listener_list *svc)
1880{
1881 int ret;
1882 ret = (svc->rcv_req_flag != 0);
1883 return ret || data->abort;
1884}
1885
1886static int qseecom_receive_req(struct qseecom_dev_handle *data)
1887{
1888 int ret = 0;
1889 struct qseecom_registered_listener_list *this_lstnr;
1890
1891 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301892 if (!this_lstnr) {
1893 pr_err("Invalid listener ID\n");
1894 return -ENODATA;
1895 }
1896
Mona Hossain2892b6b2012-02-17 13:53:11 -08001897 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001898 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001899 __qseecom_listener_has_rcvd_req(data,
1900 this_lstnr))) {
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05301901 pr_debug("Interrupted: exiting Listener Service = %d\n",
Mona Hossain17a4faf2013-03-22 16:40:56 -07001902 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001903 /* woken up for different reason */
1904 return -ERESTARTSYS;
1905 }
1906
1907 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001908 pr_err("Aborting Listener Service = %d\n",
1909 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001910 return -ENODEV;
1911 }
1912 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001913 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001914 }
1915 return ret;
1916}
1917
Mona Hossaind44a3842012-10-15 09:41:35 -07001918static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1919{
1920 struct elf32_hdr *ehdr;
1921
1922 if (fw_entry->size < sizeof(*ehdr)) {
1923 pr_err("%s: Not big enough to be an elf header\n",
1924 qseecom.pdev->init_name);
1925 return false;
1926 }
1927 ehdr = (struct elf32_hdr *)fw_entry->data;
1928 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1929 pr_err("%s: Not an elf header\n",
1930 qseecom.pdev->init_name);
1931 return false;
1932 }
1933
1934 if (ehdr->e_phnum == 0) {
1935 pr_err("%s: No loadable segments\n",
1936 qseecom.pdev->init_name);
1937 return false;
1938 }
1939 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1940 sizeof(struct elf32_hdr) > fw_entry->size) {
1941 pr_err("%s: Program headers not within mdt\n",
1942 qseecom.pdev->init_name);
1943 return false;
1944 }
1945 return true;
1946}
1947
Zhen Konge3674c62017-05-02 13:39:41 +08001948static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size)
Mona Hossaind44a3842012-10-15 09:41:35 -07001949{
1950 int ret = -1;
1951 int i = 0, rc = 0;
1952 const struct firmware *fw_entry = NULL;
1953 struct elf32_phdr *phdr;
1954 char fw_name[MAX_APP_NAME_SIZE];
1955 struct elf32_hdr *ehdr;
1956 int num_images = 0;
1957
1958 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1959 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1960 if (rc) {
1961 pr_err("error with request_firmware\n");
1962 ret = -EIO;
1963 goto err;
1964 }
1965 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1966 ret = -EIO;
1967 goto err;
1968 }
1969 *fw_size = fw_entry->size;
1970 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1971 ehdr = (struct elf32_hdr *)fw_entry->data;
1972 num_images = ehdr->e_phnum;
1973 release_firmware(fw_entry);
Zhen Konge3674c62017-05-02 13:39:41 +08001974 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001975 for (i = 0; i < num_images; i++, phdr++) {
1976 memset(fw_name, 0, sizeof(fw_name));
1977 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1978 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1979 if (ret)
1980 goto err;
Zhen Konge3674c62017-05-02 13:39:41 +08001981 if (*fw_size > U32_MAX - fw_entry->size) {
1982 pr_err("QSEE %s app file size overflow\n", appname);
1983 ret = -EINVAL;
1984 goto err;
1985 }
Mona Hossaind44a3842012-10-15 09:41:35 -07001986 *fw_size += fw_entry->size;
1987 release_firmware(fw_entry);
Zhen Konge3674c62017-05-02 13:39:41 +08001988 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001989 }
1990 return ret;
1991err:
1992 if (fw_entry)
1993 release_firmware(fw_entry);
1994 *fw_size = 0;
1995 return ret;
1996}
1997
Zhen Konge3674c62017-05-02 13:39:41 +08001998static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
1999 uint32_t fw_size,
2000 struct qseecom_load_app_ireq *load_req)
Mona Hossaind44a3842012-10-15 09:41:35 -07002001{
2002 int ret = -1;
2003 int i = 0, rc = 0;
2004 const struct firmware *fw_entry = NULL;
2005 char fw_name[MAX_APP_NAME_SIZE];
2006 u8 *img_data_ptr = img_data;
2007 struct elf32_hdr *ehdr;
2008 int num_images = 0;
2009
2010 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
2011 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2012 if (rc) {
2013 ret = -EIO;
2014 goto err;
2015 }
2016 load_req->img_len = fw_entry->size;
Zhen Konge3674c62017-05-02 13:39:41 +08002017 if (load_req->img_len > fw_size) {
2018 pr_err("app %s size %zu is larger than buf size %u\n",
2019 appname, fw_entry->size, fw_size);
2020 ret = -EINVAL;
2021 goto err;
2022 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002023 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2024 img_data_ptr = img_data_ptr + fw_entry->size;
2025 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
2026 ehdr = (struct elf32_hdr *)fw_entry->data;
2027 num_images = ehdr->e_phnum;
2028 release_firmware(fw_entry);
Zhen Konge3674c62017-05-02 13:39:41 +08002029 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002030 for (i = 0; i < num_images; i++) {
2031 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
2032 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2033 if (ret) {
2034 pr_err("Failed to locate blob %s\n", fw_name);
2035 goto err;
2036 }
Zhen Konge3674c62017-05-02 13:39:41 +08002037 if ((fw_entry->size > U32_MAX - load_req->img_len) ||
2038 (fw_entry->size + load_req->img_len > fw_size)) {
2039 pr_err("Invalid file size for %s\n", fw_name);
2040 ret = -EINVAL;
2041 goto err;
2042 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002043 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2044 img_data_ptr = img_data_ptr + fw_entry->size;
2045 load_req->img_len += fw_entry->size;
2046 release_firmware(fw_entry);
Zhen Konge3674c62017-05-02 13:39:41 +08002047 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002048 }
2049 load_req->phy_addr = virt_to_phys(img_data);
2050 return ret;
2051err:
2052 release_firmware(fw_entry);
2053 return ret;
2054}
2055
2056static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
2057{
2058 int ret = -1;
2059 uint32_t fw_size = 0;
2060 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2061 struct qseecom_command_scm_resp resp;
2062 u8 *img_data = NULL;
2063
2064 if (__qseecom_get_fw_size(appname, &fw_size))
2065 return -EIO;
2066
2067 img_data = kzalloc(fw_size, GFP_KERNEL);
2068 if (!img_data) {
2069 pr_err("Failied to allocate memory for copying image data\n");
2070 return -ENOMEM;
2071 }
Zhen Konge3674c62017-05-02 13:39:41 +08002072 ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
Mona Hossaind44a3842012-10-15 09:41:35 -07002073 if (ret) {
2074 kzfree(img_data);
2075 return -EIO;
2076 }
2077
2078 /* Populate the remaining parameters */
2079 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002080 strlcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002081
2082 if (qseecom.support_bus_scaling) {
2083 mutex_lock(&qsee_bw_mutex);
2084 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2085 mutex_unlock(&qsee_bw_mutex);
2086 if (ret) {
2087 kzfree(img_data);
2088 return ret;
2089 }
2090 }
2091
Zhen Kong2edf90d2013-08-27 12:05:06 -07002092 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08002093 if (ret) {
Zhen Kong4bead3c2014-04-14 15:07:13 -07002094 ret = -EIO;
2095 goto loadfw_err;
Mona Hossain60f9fb02012-11-05 13:51:50 -08002096 }
2097
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002098 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07002099 /* SCM_CALL to load the image */
2100 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2101 sizeof(struct qseecom_load_app_ireq),
2102 &resp, sizeof(resp));
Mona Hossaind44a3842012-10-15 09:41:35 -07002103 if (ret) {
2104 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002105 ret = -EIO;
2106 goto loadfw_err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002107 }
2108
2109 switch (resp.result) {
2110 case QSEOS_RESULT_SUCCESS:
2111 ret = resp.data;
2112 break;
2113 case QSEOS_RESULT_INCOMPLETE:
2114 ret = __qseecom_process_incomplete_cmd(data, &resp);
2115 if (ret)
2116 pr_err("process_incomplete_cmd FAILED\n");
2117 else
2118 ret = resp.data;
2119 break;
2120 case QSEOS_RESULT_FAILURE:
2121 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
2122 break;
2123 default:
2124 pr_err("scm call return unknown response %d\n", resp.result);
2125 ret = -EINVAL;
2126 break;
2127 }
Mona Hossain60f9fb02012-11-05 13:51:50 -08002128
Zhen Kong4bead3c2014-04-14 15:07:13 -07002129loadfw_err:
William Clarkd83bdcb2014-07-17 14:40:41 -07002130 kzfree(img_data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002131 __qseecom_disable_clk_scale_down(data);
2132 if (qseecom.support_bus_scaling) {
2133 mutex_lock(&qsee_bw_mutex);
2134 qseecom_unregister_bus_bandwidth_needs(data);
2135 mutex_unlock(&qsee_bw_mutex);
2136 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002137 return ret;
2138}
2139
Mona Hossain9498f5e2013-01-23 18:08:45 -08002140static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07002141{
Zhen Kongc46b5842013-12-12 13:09:16 +05302142 int ret = 0;
Zhen Kongfd64c982013-12-19 16:35:43 -08002143 int len = 0;
Mona Hossain05c73562012-10-29 17:49:01 -07002144 uint32_t fw_size = 0;
2145 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2146 struct qseecom_command_scm_resp resp;
2147 u8 *img_data = NULL;
Zhen Kongfd64c982013-12-19 16:35:43 -08002148 ion_phys_addr_t pa;
Mona Hossain05c73562012-10-29 17:49:01 -07002149
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08002150 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07002151 return -EIO;
2152
Zhen Kongc46b5842013-12-12 13:09:16 +05302153 qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
2154 SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2155 if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002156 pr_err("ION alloc failed\n");
Mona Hossain05c73562012-10-29 17:49:01 -07002157 return -ENOMEM;
2158 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302159
2160 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
2161 qseecom.cmnlib_ion_handle);
2162 if (IS_ERR_OR_NULL(img_data)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002163 pr_err("ION memory mapping for cmnlib failed\n");
Zhen Kongc46b5842013-12-12 13:09:16 +05302164 ret = -ENOMEM;
2165 goto exit_ion_free;
2166 }
Zhen Konge3674c62017-05-02 13:39:41 +08002167 ret = __qseecom_get_fw_data("cmnlib", img_data, fw_size, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07002168 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302169 ret = -EIO;
2170 goto exit_ion_unmap_kernel;
Mona Hossain05c73562012-10-29 17:49:01 -07002171 }
Zhen Kongfd64c982013-12-19 16:35:43 -08002172 /* Get the physical address of the ION BUF */
2173 ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
2174 &pa, &len);
2175 load_req.phy_addr = (s32)pa;
2176 if (ret) {
2177 pr_err("physical memory retrieval failure\n");
2178 ret = -EIO;
2179 goto exit_ion_unmap_kernel;
2180 }
Mona Hossain05c73562012-10-29 17:49:01 -07002181 /* Populate the remaining parameters */
2182 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002183
2184 if (qseecom.support_bus_scaling) {
2185 mutex_lock(&qsee_bw_mutex);
2186 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2187 mutex_unlock(&qsee_bw_mutex);
2188 if (ret) {
2189 ret = -EIO;
2190 goto exit_ion_unmap_kernel;
2191 }
2192 }
2193
Mona Hossain6311d572013-03-01 15:54:02 -08002194 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002195 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002196 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302197 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002198 goto exit_unregister_bus_bw_need;
Mona Hossain6311d572013-03-01 15:54:02 -08002199 }
2200
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002201 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07002202 /* SCM_CALL to load the image */
2203 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2204 sizeof(struct qseecom_load_lib_image_ireq),
2205 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07002206 if (ret) {
2207 pr_err("scm_call to load failed : ret %d\n", ret);
2208 ret = -EIO;
Zhen Kongc46b5842013-12-12 13:09:16 +05302209 goto exit_disable_clk_vote;
Mona Hossain05c73562012-10-29 17:49:01 -07002210 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302211
2212 switch (resp.result) {
2213 case QSEOS_RESULT_SUCCESS:
2214 break;
2215 case QSEOS_RESULT_FAILURE:
2216 pr_err("scm call failed w/response result%d\n", resp.result);
2217 ret = -EINVAL;
2218 goto exit_disable_clk_vote;
2219 case QSEOS_RESULT_INCOMPLETE:
2220 ret = __qseecom_process_incomplete_cmd(data, &resp);
2221 if (ret) {
2222 pr_err("process_incomplete_cmd failed err: %d\n", ret);
2223 goto exit_disable_clk_vote;
2224 }
2225 break;
2226 default:
2227 pr_err("scm call return unknown response %d\n", resp.result);
2228 ret = -EINVAL;
2229 goto exit_disable_clk_vote;
2230 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07002231 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002232 if (qseecom.support_bus_scaling) {
2233 mutex_lock(&qsee_bw_mutex);
2234 qseecom_unregister_bus_bandwidth_needs(data);
2235 mutex_unlock(&qsee_bw_mutex);
2236 }
Mona Hossain05c73562012-10-29 17:49:01 -07002237 return ret;
Zhen Kongc46b5842013-12-12 13:09:16 +05302238
2239exit_disable_clk_vote:
2240 __qseecom_disable_clk_scale_down(data);
2241
Zhen Kong4bead3c2014-04-14 15:07:13 -07002242exit_unregister_bus_bw_need:
2243 if (qseecom.support_bus_scaling) {
2244 mutex_lock(&qsee_bw_mutex);
2245 qseecom_unregister_bus_bandwidth_needs(data);
2246 mutex_unlock(&qsee_bw_mutex);
2247 }
2248
Zhen Kongc46b5842013-12-12 13:09:16 +05302249exit_ion_unmap_kernel:
2250 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2251
2252exit_ion_free:
2253 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2254 qseecom.cmnlib_ion_handle = NULL;
2255 return ret;
Mona Hossain05c73562012-10-29 17:49:01 -07002256}
2257
2258static int qseecom_unload_commonlib_image(void)
2259{
2260 int ret = -EINVAL;
2261 struct qseecom_unload_lib_image_ireq unload_req = {0};
2262 struct qseecom_command_scm_resp resp;
2263
2264 /* Populate the remaining parameters */
2265 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
2266 /* SCM_CALL to load the image */
2267 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
2268 sizeof(struct qseecom_unload_lib_image_ireq),
2269 &resp, sizeof(resp));
2270 if (ret) {
2271 pr_err("scm_call to unload lib failed : ret %d\n", ret);
2272 ret = -EIO;
2273 } else {
2274 switch (resp.result) {
2275 case QSEOS_RESULT_SUCCESS:
2276 break;
2277 case QSEOS_RESULT_FAILURE:
2278 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
2279 break;
2280 default:
2281 pr_err("scm call return unknown response %d\n",
2282 resp.result);
2283 ret = -EINVAL;
2284 break;
2285 }
2286 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302287
2288 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2289 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2290 qseecom.cmnlib_ion_handle = NULL;
2291
Mona Hossain05c73562012-10-29 17:49:01 -07002292 return ret;
2293}
2294
Mona Hossaind44a3842012-10-15 09:41:35 -07002295int qseecom_start_app(struct qseecom_handle **handle,
2296 char *app_name, uint32_t size)
2297{
Mona Hossain05c73562012-10-29 17:49:01 -07002298 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002299 unsigned long flags = 0;
2300 struct qseecom_dev_handle *data = NULL;
2301 struct qseecom_check_app_ireq app_ireq;
2302 struct qseecom_registered_app_list *entry = NULL;
2303 struct qseecom_registered_kclient_list *kclient_entry = NULL;
2304 bool found_app = false;
2305 uint32_t len;
2306 ion_phys_addr_t pa;
2307
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002308 if (!app_name || strlen(app_name) >= MAX_APP_NAME_SIZE) {
2309 pr_err("The app_name (%s) is not valid\n", app_name);
2310 return -EINVAL;
2311 }
2312
Mona Hossain823f9882012-11-23 14:42:20 -08002313 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
2314 if (!(*handle)) {
2315 pr_err("failed to allocate memory for kernel client handle\n");
2316 return -ENOMEM;
2317 }
2318
Mona Hossaind44a3842012-10-15 09:41:35 -07002319 data = kzalloc(sizeof(*data), GFP_KERNEL);
2320 if (!data) {
2321 pr_err("kmalloc failed\n");
2322 if (ret == 0) {
2323 kfree(*handle);
2324 *handle = NULL;
2325 }
2326 return -ENOMEM;
2327 }
2328 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002329 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07002330 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002331 data->client.sb_length = size;
2332 data->client.user_virt_sb_base = 0;
2333 data->client.ihandle = NULL;
2334
2335 init_waitqueue_head(&data->abort_wq);
2336 atomic_set(&data->ioctl_count, 0);
2337
2338 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
2339 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2340 if (IS_ERR_OR_NULL(data->client.ihandle)) {
2341 pr_err("Ion client could not retrieve the handle\n");
2342 kfree(data);
2343 kfree(*handle);
2344 *handle = NULL;
2345 return -EINVAL;
2346 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002347 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002348 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002349 if (qseecom.commonlib_loaded == false) {
2350 ret = qseecom_load_commonlib_image(data);
2351 if (ret == 0)
2352 qseecom.commonlib_loaded = true;
2353 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002354 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002355 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002356 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002357 ret = -EIO;
2358 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08002359 }
2360
2361 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002362 strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002363 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002364 if (ret < 0)
2365 goto err;
2366
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07002367 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002368 if (ret > 0) {
2369 pr_warn("App id %d for [%s] app exists\n", ret,
2370 (char *)app_ireq.app_name);
2371 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2372 list_for_each_entry(entry,
2373 &qseecom.registered_app_list_head, list){
2374 if (entry->app_id == ret) {
2375 entry->ref_cnt++;
2376 found_app = true;
2377 break;
2378 }
2379 }
2380 spin_unlock_irqrestore(
2381 &qseecom.registered_app_list_lock, flags);
2382 if (!found_app)
2383 pr_warn("App_id %d [%s] was loaded but not registered\n",
2384 ret, (char *)app_ireq.app_name);
2385 } else {
2386 /* load the app and get the app_id */
2387 pr_debug("%s: Loading app for the first time'\n",
2388 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07002389 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002390 if (ret < 0)
2391 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002392 data->client.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07002393 strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002394 }
2395 if (!found_app) {
2396 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2397 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002398 pr_err("kmalloc for app entry failed\n");
2399 ret = -ENOMEM;
2400 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002401 }
2402 entry->app_id = ret;
2403 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07002404 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002405
2406 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2407 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2408 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2409 flags);
2410 }
2411
2412 /* Get the physical address of the ION BUF */
2413 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002414 if (ret) {
2415 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2416 ret);
2417 goto err;
2418 }
2419
Mona Hossaind44a3842012-10-15 09:41:35 -07002420 /* Populate the structure for sending scm call to load image */
2421 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
2422 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08002423 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07002424 data->client.sb_phys = pa;
2425 (*handle)->dev = (void *)data;
2426 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
2427 (*handle)->sbuf_len = data->client.sb_length;
2428
2429 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
2430 if (!kclient_entry) {
2431 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002432 ret = -ENOMEM;
2433 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002434 }
2435 kclient_entry->handle = *handle;
2436
2437 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2438 list_add_tail(&kclient_entry->list,
2439 &qseecom.registered_kclient_list_head);
2440 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2441
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002442 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002443 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002444
2445err:
2446 kfree(data);
2447 kfree(*handle);
2448 *handle = NULL;
2449 mutex_unlock(&app_access_lock);
2450 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002451}
2452EXPORT_SYMBOL(qseecom_start_app);
2453
2454int qseecom_shutdown_app(struct qseecom_handle **handle)
2455{
2456 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002457 struct qseecom_dev_handle *data;
2458
Mona Hossaind44a3842012-10-15 09:41:35 -07002459 struct qseecom_registered_kclient_list *kclient = NULL;
2460 unsigned long flags = 0;
2461 bool found_handle = false;
2462
Mona Hossain33824022013-02-25 09:32:33 -08002463 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002464 pr_err("Handle is not initialized\n");
2465 return -EINVAL;
2466 }
Mona Hossain33824022013-02-25 09:32:33 -08002467 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002468 mutex_lock(&app_access_lock);
2469 atomic_inc(&data->ioctl_count);
2470
Mona Hossaind44a3842012-10-15 09:41:35 -07002471 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2472 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2473 list) {
2474 if (kclient->handle == (*handle)) {
2475 list_del(&kclient->list);
2476 found_handle = true;
2477 break;
2478 }
2479 }
2480 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2481 if (!found_handle)
2482 pr_err("Unable to find the handle, exiting\n");
2483 else
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07002484 ret = qseecom_unload_app(data, false);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002485
2486 if (qseecom.support_bus_scaling) {
2487 mutex_lock(&qsee_bw_mutex);
2488 if (data->mode != INACTIVE) {
2489 qseecom_unregister_bus_bandwidth_needs(data);
2490 if (qseecom.cumulative_mode == INACTIVE) {
2491 ret = __qseecom_set_msm_bus_request(INACTIVE);
2492 if (ret)
2493 pr_err("Fail to scale down bus\n");
2494 }
2495 }
2496 mutex_unlock(&qsee_bw_mutex);
2497 } else {
2498 if (data->fast_load_enabled == true)
2499 qsee_disable_clock_vote(data, CLK_SFPB);
2500 if (data->perf_enabled == true)
2501 qsee_disable_clock_vote(data, CLK_DFAB);
2502 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002503
2504 atomic_dec(&data->ioctl_count);
2505 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002506 if (ret == 0) {
2507 kzfree(data);
2508 kzfree(*handle);
2509 kzfree(kclient);
2510 *handle = NULL;
2511 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002512
Mona Hossaind44a3842012-10-15 09:41:35 -07002513 return ret;
2514}
2515EXPORT_SYMBOL(qseecom_shutdown_app);
2516
2517int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2518 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2519{
2520 int ret = 0;
2521 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2522 struct qseecom_dev_handle *data;
Zhen Kongd08301c2014-10-08 17:02:54 -07002523 bool perf_enabled = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002524
Mona Hossaind44a3842012-10-15 09:41:35 -07002525 if (handle == NULL) {
2526 pr_err("Handle is not initialized\n");
2527 return -EINVAL;
2528 }
2529 data = handle->dev;
2530
2531 req.cmd_req_len = sbuf_len;
2532 req.resp_len = rbuf_len;
2533 req.cmd_req_buf = send_buf;
2534 req.resp_buf = resp_buf;
2535
Mona Hossain268c3122014-11-03 17:05:48 -08002536 if (__validate_send_cmd_inputs(data, &req))
2537 return -EINVAL;
2538
Mona Hossaind44a3842012-10-15 09:41:35 -07002539 mutex_lock(&app_access_lock);
2540 atomic_inc(&data->ioctl_count);
Zhen Kongca4c2d52014-03-12 13:22:46 -07002541 if (qseecom.support_bus_scaling) {
2542 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
2543 if (ret) {
2544 pr_err("Failed to set bw.\n");
2545 atomic_dec(&data->ioctl_count);
2546 mutex_unlock(&app_access_lock);
2547 return ret;
2548 }
2549 }
Zhen Kong1e15c272014-09-18 12:33:07 -07002550 /*
2551 * On targets where crypto clock is handled by HLOS,
2552 * if clk_access_cnt is zero and perf_enabled is false,
2553 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07002554 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07002555 */
2556 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07002557 pr_debug("ce clock is not enabled!\n");
2558 ret = qseecom_perf_enable(data);
2559 if (ret) {
2560 pr_err("Failed to vote for clock with err %d\n",
2561 ret);
2562 atomic_dec(&data->ioctl_count);
2563 mutex_unlock(&app_access_lock);
2564 return -EINVAL;
2565 }
2566 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07002567 }
2568
Mona Hossaind44a3842012-10-15 09:41:35 -07002569 ret = __qseecom_send_cmd(data, &req);
Zhen Kongaf950192014-02-05 17:36:23 -08002570 if (qseecom.support_bus_scaling)
2571 __qseecom_add_bw_scale_down_timer(
2572 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002573
Zhen Kongd08301c2014-10-08 17:02:54 -07002574 if (perf_enabled) {
2575 qsee_disable_clock_vote(data, CLK_DFAB);
2576 qsee_disable_clock_vote(data, CLK_SFPB);
2577 }
2578
Mona Hossaind44a3842012-10-15 09:41:35 -07002579 atomic_dec(&data->ioctl_count);
2580 mutex_unlock(&app_access_lock);
2581
2582 if (ret)
2583 return ret;
2584
Jeron Susan19547b82016-11-03 10:02:25 +08002585 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%pK\n",
Mona Hossaind44a3842012-10-15 09:41:35 -07002586 req.resp_len, req.resp_buf);
2587 return ret;
2588}
2589EXPORT_SYMBOL(qseecom_send_command);
2590
Mona Hossain91a8fc92012-11-07 19:58:30 -08002591int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2592{
Mona Hossainfca6f422013-01-12 13:00:35 -08002593 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002594 if ((handle == NULL) || (handle->dev == NULL)) {
2595 pr_err("No valid kernel client\n");
2596 return -EINVAL;
2597 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002598 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002599 if (qseecom.support_bus_scaling) {
2600 mutex_lock(&qsee_bw_mutex);
2601 __qseecom_register_bus_bandwidth_needs(handle->dev,
2602 HIGH);
2603 mutex_unlock(&qsee_bw_mutex);
2604 if (ret)
2605 pr_err("Failed to scale bus (med) %d\n", ret);
2606 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07002607 ret = qseecom_perf_enable(handle->dev);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002608 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07002609 pr_err("Failed to vote for clock with err %d\n",
2610 ret);
Mona Hossainfca6f422013-01-12 13:00:35 -08002611 }
2612 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002613 if (!qseecom.support_bus_scaling) {
2614 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2615 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07002616 } else {
2617 mutex_lock(&qsee_bw_mutex);
2618 qseecom_unregister_bus_bandwidth_needs(handle->dev);
2619 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002620 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002621 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002622 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002623}
2624EXPORT_SYMBOL(qseecom_set_bandwidth);
2625
Mona Hossain2892b6b2012-02-17 13:53:11 -08002626static int qseecom_send_resp(void)
2627{
2628 qseecom.send_resp_flag = 1;
2629 wake_up_interruptible(&qseecom.send_resp_wq);
2630 return 0;
2631}
2632
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002633
Zhen Kongcdf2c7e2016-07-18 13:20:18 -07002634static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
2635 struct qseecom_send_modfd_listener_resp *resp,
2636 struct qseecom_registered_listener_list *this_lstnr)
2637{
2638 int i;
2639
2640 if (!data || !resp || !this_lstnr) {
2641 pr_err("listener handle or resp msg is null\n");
2642 return -EINVAL;
2643 }
2644
2645 if (resp->resp_buf_ptr == NULL) {
2646 pr_err("resp buffer is null\n");
2647 return -EINVAL;
2648 }
2649 /* validate resp buf length */
2650 if ((resp->resp_len == 0) ||
2651 (resp->resp_len > this_lstnr->sb_length)) {
2652 pr_err("resp buf length %d not valid\n", resp->resp_len);
2653 return -EINVAL;
2654 }
2655
2656 if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
2657 pr_err("Integer overflow in resp_len & resp_buf\n");
2658 return -EINVAL;
2659 }
2660 if ((uintptr_t)this_lstnr->user_virt_sb_base >
2661 (ULONG_MAX - this_lstnr->sb_length)) {
2662 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
2663 return -EINVAL;
2664 }
2665 /* validate resp buf */
2666 if (((uintptr_t)resp->resp_buf_ptr <
2667 (uintptr_t)this_lstnr->user_virt_sb_base) ||
2668 ((uintptr_t)resp->resp_buf_ptr >=
2669 ((uintptr_t)this_lstnr->user_virt_sb_base +
2670 this_lstnr->sb_length)) ||
2671 (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
2672 ((uintptr_t)this_lstnr->user_virt_sb_base +
2673 this_lstnr->sb_length))) {
2674 pr_err("resp buf is out of shared buffer region\n");
2675 return -EINVAL;
2676 }
2677
2678 /* validate offsets */
2679 for (i = 0; i < MAX_ION_FD; i++) {
2680 if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
2681 pr_err("Invalid offset %d = 0x%x\n",
2682 i, resp->ifd_data[i].cmd_buf_offset);
2683 return -EINVAL;
2684 }
2685 }
2686
2687 return 0;
2688}
2689
2690static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2691 void __user *argp, bool is_64bit_addr)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002692{
2693 struct qseecom_send_modfd_listener_resp resp;
Zhen Kongf4948192013-11-25 13:05:35 -08002694 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002695
2696 if (copy_from_user(&resp, argp, sizeof(resp))) {
2697 pr_err("copy_from_user failed");
2698 return -EINVAL;
2699 }
Zhen Kongcdf2c7e2016-07-18 13:20:18 -07002700
Zhen Kongf4948192013-11-25 13:05:35 -08002701 this_lstnr = __qseecom_find_svc(data->listener.id);
2702 if (this_lstnr == NULL)
2703 return -EINVAL;
2704
Zhen Kongcdf2c7e2016-07-18 13:20:18 -07002705 if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
Zhen Kongf4948192013-11-25 13:05:35 -08002706 return -EINVAL;
Zhen Kongf4948192013-11-25 13:05:35 -08002707
Zhen Kongf4948192013-11-25 13:05:35 -08002708 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2709 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002710 __qseecom_update_cmd_buf(&resp, false, data, true);
2711 qseecom.send_resp_flag = 1;
2712 wake_up_interruptible(&qseecom.send_resp_wq);
2713 return 0;
2714}
2715
Zhen Kongcdf2c7e2016-07-18 13:20:18 -07002716static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2717 void __user *argp)
2718{
2719 return __qseecom_send_modfd_resp(data, argp, false);
2720}
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002721
Mona Hossain2892b6b2012-02-17 13:53:11 -08002722static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2723 void __user *argp)
2724{
2725 struct qseecom_qseos_version_req req;
2726
2727 if (copy_from_user(&req, argp, sizeof(req))) {
2728 pr_err("copy_from_user failed");
2729 return -EINVAL;
2730 }
2731 req.qseos_version = qseecom.qseos_version;
2732 if (copy_to_user(argp, &req, sizeof(req))) {
2733 pr_err("copy_to_user failed");
2734 return -EINVAL;
2735 }
2736 return 0;
2737}
2738
Mona Hossainc92629e2013-04-01 13:37:46 -07002739static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002740{
2741 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002742 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002743
Mona Hossainc92629e2013-04-01 13:37:46 -07002744 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002745 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002746 else
2747 qclk = &qseecom.ce_drv;
2748
2749 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002750
2751 if (qclk->clk_access_cnt == ULONG_MAX)
2752 goto err;
2753
Mona Hossainc92629e2013-04-01 13:37:46 -07002754 if (qclk->clk_access_cnt > 0) {
2755 qclk->clk_access_cnt++;
2756 mutex_unlock(&clk_access_lock);
2757 return rc;
2758 }
2759
Mona Hossain6311d572013-03-01 15:54:02 -08002760 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002761 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002762 if (rc) {
2763 pr_err("Unable to enable/prepare CE core clk\n");
2764 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002765 }
2766 /* Enable CE clk */
2767 rc = clk_prepare_enable(qclk->ce_clk);
2768 if (rc) {
2769 pr_err("Unable to enable/prepare CE iface clk\n");
2770 goto ce_clk_err;
2771 }
2772 /* Enable AXI clk */
2773 rc = clk_prepare_enable(qclk->ce_bus_clk);
2774 if (rc) {
2775 pr_err("Unable to enable/prepare CE bus clk\n");
2776 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002777 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002778 qclk->clk_access_cnt++;
2779 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002780 return 0;
2781
2782ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002783 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002784ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002785 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002786err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002787 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002788 return -EIO;
2789}
2790
Mona Hossainc92629e2013-04-01 13:37:46 -07002791static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002792{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002793 struct qseecom_clk *qclk;
2794
Mona Hossainc92629e2013-04-01 13:37:46 -07002795 if (ce == CLK_QSEE)
2796 qclk = &qseecom.qsee;
2797 else
2798 qclk = &qseecom.ce_drv;
2799
2800 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002801
2802 if (qclk->clk_access_cnt == 0) {
2803 mutex_unlock(&clk_access_lock);
2804 return;
2805 }
2806
Mona Hossainc92629e2013-04-01 13:37:46 -07002807 if (qclk->clk_access_cnt == 1) {
2808 if (qclk->ce_clk != NULL)
2809 clk_disable_unprepare(qclk->ce_clk);
2810 if (qclk->ce_core_clk != NULL)
2811 clk_disable_unprepare(qclk->ce_core_clk);
2812 if (qclk->ce_bus_clk != NULL)
2813 clk_disable_unprepare(qclk->ce_bus_clk);
2814 }
2815 qclk->clk_access_cnt--;
2816 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002817}
2818
Mona Hossain04d3fac2012-12-03 10:10:37 -08002819static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2820 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002821{
2822 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002823 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002824
Mona Hossain17a4faf2013-03-22 16:40:56 -07002825 qclk = &qseecom.qsee;
2826 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002827 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002828
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002829 switch (clk_type) {
2830 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002831 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002832 if (!qseecom.qsee_bw_count) {
2833 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002834 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002835 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002836 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002837 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002838 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002839 if (!ret) {
2840 ret =
2841 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002842 qseecom.qsee_perf_client, 1);
2843 if ((ret) &&
2844 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002845 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002846 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002847 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002848 if (ret)
2849 pr_err("DFAB Bandwidth req failed (%d)\n",
2850 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002851 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002852 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002853 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002854 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002855 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002856 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002857 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002858 }
2859 mutex_unlock(&qsee_bw_mutex);
2860 break;
2861 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002862 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002863 if (!qseecom.qsee_sfpb_bw_count) {
2864 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002865 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002866 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002867 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002868 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002869 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002870 if (!ret) {
2871 ret =
2872 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002873 qseecom.qsee_perf_client, 2);
2874 if ((ret) &&
2875 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002876 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002877 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002878 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002879
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002880 if (ret)
2881 pr_err("SFPB Bandwidth req failed (%d)\n",
2882 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002883 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002884 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002885 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002886 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002887 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002888 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002889 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002890 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002891 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002892 break;
2893 default:
2894 pr_err("Clock type not defined\n");
2895 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002896 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002897 return ret;
2898}
2899
Mona Hossain04d3fac2012-12-03 10:10:37 -08002900static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2901 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002902{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002903 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002904 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002905
Mona Hossain17a4faf2013-03-22 16:40:56 -07002906 qclk = &qseecom.qsee;
2907 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002908 return;
2909
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002910 switch (clk_type) {
2911 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002912 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002913 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002914 pr_err("Client error.Extra call to disable DFAB clk\n");
2915 mutex_unlock(&qsee_bw_mutex);
2916 return;
2917 }
2918
Mona Hossain17a4faf2013-03-22 16:40:56 -07002919 if (qseecom.qsee_bw_count == 1) {
2920 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002921 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002922 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002923 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002924 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002925 qseecom.qsee_perf_client, 0);
2926 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002927 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002928 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002929 if (ret)
2930 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002931 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002932 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002933 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002934 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002935 }
2936 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002937 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002938 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002939 }
2940 mutex_unlock(&qsee_bw_mutex);
2941 break;
2942 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002943 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002944 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002945 pr_err("Client error.Extra call to disable SFPB clk\n");
2946 mutex_unlock(&qsee_bw_mutex);
2947 return;
2948 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002949 if (qseecom.qsee_sfpb_bw_count == 1) {
2950 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002951 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002952 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002953 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002954 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002955 qseecom.qsee_perf_client, 0);
2956 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002957 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002958 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002959 if (ret)
2960 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002961 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002962 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002963 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002964 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002965 }
2966 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002967 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002968 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002969 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002970 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002971 break;
2972 default:
2973 pr_err("Clock type not defined\n");
2974 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002975 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002976
Mona Hossain2892b6b2012-02-17 13:53:11 -08002977}
2978
Mona Hossain5ab9d772012-04-11 21:00:40 -07002979static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2980 void __user *argp)
2981{
2982 struct ion_handle *ihandle; /* Ion handle */
2983 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002984 int ret;
2985 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002986 ion_phys_addr_t pa = 0;
2987 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002988 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002989 struct qseecom_load_app_ireq load_req;
2990 struct qseecom_command_scm_resp resp;
2991
2992 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002993 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002994 (void __user *)argp,
2995 sizeof(struct qseecom_load_img_req))) {
2996 pr_err("copy_from_user failed\n");
2997 return -EFAULT;
2998 }
2999
3000 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08003001 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07003002 load_img_req.ifd_data_fd);
3003 if (IS_ERR_OR_NULL(ihandle)) {
3004 pr_err("Ion client could not retrieve the handle\n");
3005 return -ENOMEM;
3006 }
3007
3008 /* Get the physical address of the ION BUF */
3009 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08003010 if (ret) {
3011 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
3012 ret);
3013 return ret;
3014 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003015 /* Populate the structure for sending scm call to load image */
3016 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
3017 load_req.mdt_len = load_img_req.mdt_len;
3018 load_req.img_len = load_img_req.img_len;
3019 load_req.phy_addr = pa;
3020
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003021 /* SCM_CALL tied to Core0 */
3022 mask = CPU_MASK_CPU0;
3023 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3024 if (set_cpu_ret) {
3025 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3026 set_cpu_ret);
3027 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303028 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003029 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303030
Zhen Kong4bead3c2014-04-14 15:07:13 -07003031 if (qseecom.support_bus_scaling) {
3032 mutex_lock(&qsee_bw_mutex);
3033 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
3034 mutex_unlock(&qsee_bw_mutex);
3035 if (ret) {
3036 ret = -EIO;
3037 goto exit_cpu_restore;
3038 }
3039 }
3040
Mona Hossain6311d572013-03-01 15:54:02 -08003041 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07003042 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08003043 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08003044 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07003045 goto exit_register_bus_bandwidth_needs;
Mona Hossain6311d572013-03-01 15:54:02 -08003046 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003047 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
3048 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003049 /* SCM_CALL to load the external elf */
3050 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
3051 sizeof(struct qseecom_load_app_ireq),
3052 &resp, sizeof(resp));
3053 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003054 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07003055 ret);
3056 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303057 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003058 }
3059
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303060 switch (resp.result) {
3061 case QSEOS_RESULT_SUCCESS:
3062 break;
3063 case QSEOS_RESULT_INCOMPLETE:
3064 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003065 ret = __qseecom_process_incomplete_cmd(data, &resp);
3066 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303067 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
3068 break;
3069 case QSEOS_RESULT_FAILURE:
3070 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
3071 ret = -EFAULT;
3072 break;
3073 default:
3074 pr_err("scm_call response result %d not supported\n",
3075 resp.result);
3076 ret = -EFAULT;
3077 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003078 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003079
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303080exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07003081 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07003082
3083exit_register_bus_bandwidth_needs:
3084 if (qseecom.support_bus_scaling) {
3085 mutex_lock(&qsee_bw_mutex);
3086 ret = qseecom_unregister_bus_bandwidth_needs(data);
3087 mutex_unlock(&qsee_bw_mutex);
3088 }
3089
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303090exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003091 /* Restore the CPU mask */
3092 mask = CPU_MASK_ALL;
3093 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3094 if (set_cpu_ret) {
3095 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3096 set_cpu_ret);
3097 ret = -EFAULT;
3098 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303099exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07003100 /* Deallocate the handle */
3101 if (!IS_ERR_OR_NULL(ihandle))
3102 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003103 return ret;
3104}
3105
3106static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
3107{
3108 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003109 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003110 struct qseecom_command_scm_resp resp;
3111 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003112 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003113
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303114 /* unavailable client app */
3115 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
3116
Mona Hossain5ab9d772012-04-11 21:00:40 -07003117 /* Populate the structure for sending scm call to unload image */
3118 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003119
3120 /* SCM_CALL tied to Core0 */
3121 mask = CPU_MASK_CPU0;
3122 ret = set_cpus_allowed_ptr(current, &mask);
3123 if (ret) {
3124 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3125 ret);
3126 return -EFAULT;
3127 }
3128
Mona Hossain5ab9d772012-04-11 21:00:40 -07003129 /* SCM_CALL to unload the external elf */
3130 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
3131 sizeof(struct qseecom_unload_app_ireq),
3132 &resp, sizeof(resp));
3133 if (ret) {
3134 pr_err("scm_call to unload failed : ret %d\n",
3135 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003136 ret = -EFAULT;
3137 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003138 }
3139 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
3140 ret = __qseecom_process_incomplete_cmd(data, &resp);
3141 if (ret)
3142 pr_err("process_incomplete_cmd fail err: %d\n",
3143 ret);
3144 } else {
3145 if (resp.result != QSEOS_RESULT_SUCCESS) {
3146 pr_err("scm_call to unload image failed resp.result =%d\n",
3147 resp.result);
3148 ret = -EFAULT;
3149 }
3150 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003151
3152qseecom_unload_external_elf_scm_err:
3153 /* Restore the CPU mask */
3154 mask = CPU_MASK_ALL;
3155 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3156 if (set_cpu_ret) {
3157 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3158 set_cpu_ret);
3159 ret = -EFAULT;
3160 }
3161
Mona Hossain5ab9d772012-04-11 21:00:40 -07003162 return ret;
3163}
Mona Hossain2892b6b2012-02-17 13:53:11 -08003164
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003165static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
3166 void __user *argp)
3167{
3168
3169 int32_t ret;
3170 struct qseecom_qseos_app_load_query query_req;
3171 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003172 struct qseecom_registered_app_list *entry = NULL;
3173 unsigned long flags = 0;
Zhen Kong59155a72015-05-20 13:50:04 -07003174 bool found_app = false;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003175
3176 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07003177 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003178 (void __user *)argp,
3179 sizeof(struct qseecom_qseos_app_load_query))) {
3180 pr_err("copy_from_user failed\n");
3181 return -EFAULT;
3182 }
3183
3184 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07003185 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -07003186 strlcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003187
3188 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003189
3190 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003191 pr_err(" scm call to check if app is loaded failed");
3192 return ret; /* scm call failed */
3193 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07003194 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003195 (char *)(req.app_name));
3196 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
3197 list_for_each_entry(entry,
3198 &qseecom.registered_app_list_head, list){
3199 if (entry->app_id == ret) {
3200 entry->ref_cnt++;
Zhen Kong59155a72015-05-20 13:50:04 -07003201 found_app = true;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003202 break;
3203 }
3204 }
3205 spin_unlock_irqrestore(
3206 &qseecom.registered_app_list_lock, flags);
3207 data->client.app_id = ret;
3208 query_req.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07003209 strlcpy(data->client.app_name, query_req.app_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07003210 MAX_APP_NAME_SIZE);
Zhen Kong59155a72015-05-20 13:50:04 -07003211 /*
3212 * If app was loaded by appsbl or kernel client before
3213 * and was not registered, regiser this app now.
3214 */
3215 if (!found_app) {
3216 pr_debug("Register app %d [%s] which was loaded before\n",
3217 ret, (char *)query_req.app_name);
3218 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
3219 if (!entry) {
3220 pr_err("kmalloc for app entry failed\n");
3221 return -ENOMEM;
3222 }
3223 entry->app_id = ret;
3224 entry->ref_cnt = 1;
3225 strlcpy(entry->app_name, data->client.app_name,
3226 MAX_APP_NAME_SIZE);
3227 spin_lock_irqsave(&qseecom.registered_app_list_lock,
3228 flags);
3229 list_add_tail(&entry->list,
3230 &qseecom.registered_app_list_head);
3231 spin_unlock_irqrestore(
3232 &qseecom.registered_app_list_lock, flags);
3233 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003234 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
3235 pr_err("copy_to_user failed\n");
3236 return -EFAULT;
3237 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003238 return -EEXIST; /* app already loaded */
3239 } else {
3240 return 0; /* app not loaded */
3241 }
3242}
3243
Mona Hossain4cf78a92013-02-14 12:06:41 -08003244static int __qseecom_get_ce_pipe_info(
3245 enum qseecom_key_management_usage_type usage,
3246 uint32_t *pipe, uint32_t *ce_hw)
3247{
3248 int ret;
3249 switch (usage) {
3250 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003251 if (qseecom.support_fde) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003252 *pipe = qseecom.ce_info.disk_encrypt_pipe;
3253 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3254 ret = 0;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003255
3256 } else {
3257 pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
3258 qseecom.ce_info.disk_encrypt_pipe,
3259 qseecom.ce_info.hlos_ce_hw_instance);
3260 ret = -EINVAL;
3261 }
3262 break;
3263 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
3264 if (qseecom.support_pfe) {
3265 *pipe = qseecom.ce_info.file_encrypt_pipe;
3266 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3267 ret = 0;
3268 } else {
3269 pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
3270 qseecom.ce_info.file_encrypt_pipe,
3271 qseecom.ce_info.hlos_ce_hw_instance);
3272 ret = -EINVAL;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003273 }
3274 break;
3275 default:
3276 ret = -EINVAL;
3277 break;
3278 }
3279 return ret;
3280}
3281
3282static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
3283 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003284 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003285{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003286 struct qseecom_command_scm_resp resp;
3287 int ret;
3288
Zhen Kong9730ddf2013-12-17 16:49:43 -08003289 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3290 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003291 pr_err("Error:: unsupported usage %d\n", usage);
3292 return -EFAULT;
3293 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003294 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003295
3296 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003297 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003298 &resp, sizeof(resp));
3299 if (ret) {
3300 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003301 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003302 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003303 }
3304
3305 switch (resp.result) {
3306 case QSEOS_RESULT_SUCCESS:
3307 break;
Zhen Kong336636e2013-04-15 11:04:54 -07003308 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongba69dfe2014-02-28 15:19:53 -08003309 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07003310 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003311 case QSEOS_RESULT_INCOMPLETE:
3312 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07003313 if (ret) {
3314 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongba69dfe2014-02-28 15:19:53 -08003315 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07003316 ret = 0;
3317 } else {
3318 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3319 resp.result);
3320 }
3321 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003322 break;
3323 case QSEOS_RESULT_FAILURE:
3324 default:
3325 pr_err("gen key scm call failed resp.result %d\n", resp.result);
3326 ret = -EINVAL;
3327 break;
3328 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003329 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003330 return ret;
3331}
3332
3333static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
3334 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003335 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003336{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003337 struct qseecom_command_scm_resp resp;
3338 int ret;
3339
Amir Samuelov48a1e7d2014-06-23 11:49:05 +03003340 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3341 usage >= QSEOS_KM_USAGE_MAX) {
3342 pr_err("Error:: unsupported usage %d\n", usage);
3343 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003344 }
3345
Mona Hossainc92629e2013-04-01 13:37:46 -07003346 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003347
3348 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003349 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003350 &resp, sizeof(struct qseecom_command_scm_resp));
3351 if (ret) {
3352 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003353 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003354 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003355 }
3356
3357 switch (resp.result) {
3358 case QSEOS_RESULT_SUCCESS:
3359 break;
3360 case QSEOS_RESULT_INCOMPLETE:
3361 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003362 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003363 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3364 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003365 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3366 pr_debug("Max attempts to input password reached.\n");
3367 ret = -ERANGE;
3368 }
3369 }
3370 break;
3371 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3372 pr_debug("Max attempts to input password reached.\n");
3373 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003374 break;
3375 case QSEOS_RESULT_FAILURE:
3376 default:
3377 pr_err("Delete key scm call failed resp.result %d\n",
3378 resp.result);
3379 ret = -EINVAL;
3380 break;
3381 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003382 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003383 return ret;
3384}
3385
3386static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
3387 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003388 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003389{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003390 struct qseecom_command_scm_resp resp;
3391 int ret;
3392
Zhen Kong9730ddf2013-12-17 16:49:43 -08003393 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3394 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003395 pr_err("Error:: unsupported usage %d\n", usage);
3396 return -EFAULT;
3397 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003398
Zhen Kongdb2bf742013-05-13 23:55:42 -07003399 __qseecom_enable_clk(CLK_QSEE);
3400 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003401 __qseecom_enable_clk(CLK_CE_DRV);
3402
Zhen Kong336636e2013-04-15 11:04:54 -07003403 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003404 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003405 &resp, sizeof(struct qseecom_command_scm_resp));
3406 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003407 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07003408 __qseecom_disable_clk(CLK_QSEE);
3409 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3410 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08003411 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07003412 }
3413
Mona Hossain4cf78a92013-02-14 12:06:41 -08003414 switch (resp.result) {
3415 case QSEOS_RESULT_SUCCESS:
3416 break;
3417 case QSEOS_RESULT_INCOMPLETE:
3418 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003419 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003420 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3421 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003422 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3423 pr_debug("Max attempts to input password reached.\n");
3424 ret = -ERANGE;
3425 }
3426 }
3427 break;
3428 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3429 pr_debug("Max attempts to input password reached.\n");
3430 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003431 break;
3432 case QSEOS_RESULT_FAILURE:
3433 default:
3434 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3435 ret = -EINVAL;
3436 break;
3437 }
3438
Zhen Kongdb2bf742013-05-13 23:55:42 -07003439 __qseecom_disable_clk(CLK_QSEE);
3440 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003441 __qseecom_disable_clk(CLK_CE_DRV);
3442
Mona Hossain4cf78a92013-02-14 12:06:41 -08003443 return ret;
3444}
3445
Zhen Kong9730ddf2013-12-17 16:49:43 -08003446static int __qseecom_update_current_key_user_info(
3447 struct qseecom_dev_handle *data,
3448 enum qseecom_key_management_usage_type usage,
3449 struct qseecom_key_userinfo_update_ireq *ireq)
3450{
3451 struct qseecom_command_scm_resp resp;
3452 int ret;
3453
3454 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3455 usage >= QSEOS_KM_USAGE_MAX) {
3456 pr_err("Error:: unsupported usage %d\n", usage);
3457 return -EFAULT;
3458 }
3459
3460 __qseecom_enable_clk(CLK_QSEE);
3461
3462 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
3463 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
3464 &resp, sizeof(struct qseecom_command_scm_resp));
3465 if (ret) {
3466 pr_err("scm call to update key userinfo failed : %d\n", ret);
3467 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003468 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003469 }
3470
3471 switch (resp.result) {
3472 case QSEOS_RESULT_SUCCESS:
3473 break;
3474 case QSEOS_RESULT_INCOMPLETE:
3475 ret = __qseecom_process_incomplete_cmd(data, &resp);
3476 if (ret)
3477 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3478 resp.result);
3479 break;
3480 case QSEOS_RESULT_FAILURE:
3481 default:
3482 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3483 ret = -EINVAL;
3484 break;
3485 }
3486
3487 __qseecom_disable_clk(CLK_QSEE);
3488 return ret;
3489}
3490
Mona Hossain4cf78a92013-02-14 12:06:41 -08003491static int qseecom_create_key(struct qseecom_dev_handle *data,
3492 void __user *argp)
3493{
3494 uint32_t ce_hw = 0;
3495 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003496 int ret = 0;
3497 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003498 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003499 struct qseecom_key_generate_ireq generate_key_ireq;
3500 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003501
3502 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
3503 if (ret) {
3504 pr_err("copy_from_user failed\n");
3505 return ret;
3506 }
3507
Zhen Kong9730ddf2013-12-17 16:49:43 -08003508 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3509 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003510 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
3511 return -EFAULT;
3512 }
3513
3514 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
3515 if (ret) {
3516 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3517 return -EINVAL;
3518 }
3519
Zhen Kong9730ddf2013-12-17 16:49:43 -08003520 generate_key_ireq.flags = flags;
3521 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
3522 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3523 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3524 memcpy((void *)generate_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003525 (void *)key_id_array[create_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003526 QSEECOM_KEY_ID_SIZE);
3527 memcpy((void *)generate_key_ireq.hash32,
3528 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
3529
Mona Hossain4cf78a92013-02-14 12:06:41 -08003530 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003531 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003532 if (ret) {
3533 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003534 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003535 }
3536
Zhen Kong9730ddf2013-12-17 16:49:43 -08003537 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3538 set_key_ireq.ce = ce_hw;
3539 set_key_ireq.pipe = pipe;
3540 set_key_ireq.flags = flags;
3541
3542 /* set both PIPE_ENC and PIPE_ENC_XTS*/
3543 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
3544 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3545 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3546 memcpy((void *)set_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003547 (void *)key_id_array[create_key_req.usage].desc,
3548 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003549 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08003550 QSEECOM_HASH_SIZE);
3551
3552 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003553 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003554 if (ret) {
3555 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
3556 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003557 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003558 }
3559
3560 return ret;
3561}
3562
3563static int qseecom_wipe_key(struct qseecom_dev_handle *data,
3564 void __user *argp)
3565{
3566 uint32_t ce_hw = 0;
3567 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003568 int ret = 0;
3569 uint32_t flags = 0;
3570 int i;
3571 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003572 struct qseecom_key_delete_ireq delete_key_ireq;
3573 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003574
3575 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
3576 if (ret) {
3577 pr_err("copy_from_user failed\n");
3578 return ret;
3579 }
3580
Zhen Kong9730ddf2013-12-17 16:49:43 -08003581 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3582 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003583 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3584 return -EFAULT;
3585 }
3586
3587 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3588 if (ret) {
3589 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3590 return -EINVAL;
3591 }
3592
Zhen Kongba69dfe2014-02-28 15:19:53 -08003593 if (wipe_key_req.wipe_key_flag) {
3594 delete_key_ireq.flags = flags;
3595 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3596 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3597 memcpy((void *)delete_key_ireq.key_id,
3598 (void *)key_id_array[wipe_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003599 QSEECOM_KEY_ID_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003600 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003601
Zhen Kongba69dfe2014-02-28 15:19:53 -08003602 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003603 &delete_key_ireq);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003604 if (ret) {
3605 pr_err("Failed to delete key from ssd storage: %d\n",
3606 ret);
3607 return -EFAULT;
3608 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003609 }
3610
Zhen Kong9730ddf2013-12-17 16:49:43 -08003611 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3612 clear_key_ireq.ce = ce_hw;
3613 clear_key_ireq.pipe = pipe;
3614 clear_key_ireq.flags = flags;
3615 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003616 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kongba69dfe2014-02-28 15:19:53 -08003617 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003618 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3619
Mona Hossain4cf78a92013-02-14 12:06:41 -08003620 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003621 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003622 if (ret) {
3623 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3624 pipe, ce_hw, ret);
3625 return -EFAULT;
3626 }
3627
3628 return ret;
3629}
3630
Zhen Kong9730ddf2013-12-17 16:49:43 -08003631static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3632 void __user *argp)
3633{
3634 int ret = 0;
3635 uint32_t flags = 0;
3636 struct qseecom_update_key_userinfo_req update_key_req;
3637 struct qseecom_key_userinfo_update_ireq ireq;
3638
3639 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3640 if (ret) {
3641 pr_err("copy_from_user failed\n");
3642 return ret;
3643 }
3644
3645 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3646 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3647 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3648 return -EFAULT;
3649 }
3650
3651 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3652 ireq.flags = flags;
3653 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3654 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3655 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003656 memcpy((void *)ireq.key_id,
3657 (void *)key_id_array[update_key_req.usage].desc,
3658 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003659 memcpy((void *)ireq.current_hash32,
3660 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3661 memcpy((void *)ireq.new_hash32,
3662 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3663
3664 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3665 &ireq);
3666 if (ret) {
3667 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003668 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003669 }
3670 return ret;
3671
3672}
3673
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003674static int qseecom_is_es_activated(void __user *argp)
3675{
3676 struct qseecom_is_es_activated_req req;
3677 int ret;
3678 int resp_buf;
3679
3680 if (qseecom.qsee_version < QSEE_VERSION_04) {
3681 pr_err("invalid qsee version");
3682 return -ENODEV;
3683 }
3684
3685 if (argp == NULL) {
3686 pr_err("arg is null");
3687 return -EINVAL;
3688 }
3689
3690 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3691 (void *) &resp_buf, sizeof(resp_buf));
3692 if (ret) {
3693 pr_err("scm_call failed");
3694 return ret;
3695 }
3696
3697 req.is_activated = resp_buf;
3698 ret = copy_to_user(argp, &req, sizeof(req));
3699 if (ret) {
3700 pr_err("copy_to_user failed");
3701 return ret;
3702 }
3703
3704 return 0;
3705}
3706
3707static int qseecom_save_partition_hash(void __user *argp)
3708{
3709 struct qseecom_save_partition_hash_req req;
3710 int ret;
3711
3712 if (qseecom.qsee_version < QSEE_VERSION_04) {
3713 pr_err("invalid qsee version ");
3714 return -ENODEV;
3715 }
3716
3717 if (argp == NULL) {
3718 pr_err("arg is null");
3719 return -EINVAL;
3720 }
3721
3722 ret = copy_from_user(&req, argp, sizeof(req));
3723 if (ret) {
3724 pr_err("copy_from_user failed");
3725 return ret;
3726 }
3727
3728 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3729 (void *) &req, sizeof(req), NULL, 0);
3730 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003731 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003732 return ret;
3733 }
3734
3735 return 0;
3736}
3737
Mona Hossain2892b6b2012-02-17 13:53:11 -08003738static long qseecom_ioctl(struct file *file, unsigned cmd,
3739 unsigned long arg)
3740{
3741 int ret = 0;
3742 struct qseecom_dev_handle *data = file->private_data;
3743 void __user *argp = (void __user *) arg;
Zhen Kongd08301c2014-10-08 17:02:54 -07003744 bool perf_enabled = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003745
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303746 if (!data) {
3747 pr_err("Invalid/uninitialized device handle\n");
3748 return -EINVAL;
3749 }
3750
Mona Hossain2892b6b2012-02-17 13:53:11 -08003751 if (data->abort) {
3752 pr_err("Aborting qseecom driver\n");
3753 return -ENODEV;
3754 }
3755
3756 switch (cmd) {
3757 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003758 if (data->type != QSEECOM_GENERIC) {
3759 pr_err("reg lstnr req: invalid handle (%d)\n",
3760 data->type);
3761 ret = -EINVAL;
3762 break;
3763 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003764 pr_debug("ioctl register_listener_req()\n");
3765 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003766 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003767 ret = qseecom_register_listener(data, argp);
3768 atomic_dec(&data->ioctl_count);
3769 wake_up_all(&data->abort_wq);
3770 if (ret)
3771 pr_err("failed qseecom_register_listener: %d\n", ret);
3772 break;
3773 }
3774 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003775 if ((data->listener.id == 0) ||
3776 (data->type != QSEECOM_LISTENER_SERVICE)) {
3777 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3778 data->type, data->listener.id);
3779 ret = -EINVAL;
3780 break;
3781 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003782 pr_debug("ioctl unregister_listener_req()\n");
3783 atomic_inc(&data->ioctl_count);
3784 ret = qseecom_unregister_listener(data);
3785 atomic_dec(&data->ioctl_count);
3786 wake_up_all(&data->abort_wq);
3787 if (ret)
3788 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3789 break;
3790 }
3791 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003792 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003793 if ((data->client.app_id == 0) ||
3794 (data->type != QSEECOM_CLIENT_APP)) {
3795 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3796 data->type, data->client.app_id);
3797 ret = -EINVAL;
3798 break;
3799 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003800 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003801 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003802 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003803 /* register bus bw in case the client doesn't do it */
3804 if (!data->mode) {
3805 mutex_lock(&qsee_bw_mutex);
3806 __qseecom_register_bus_bandwidth_needs(
3807 data, HIGH);
3808 mutex_unlock(&qsee_bw_mutex);
3809 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003810 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3811 if (ret) {
3812 pr_err("Failed to set bw.\n");
3813 ret = -EINVAL;
3814 mutex_unlock(&app_access_lock);
3815 break;
3816 }
3817 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003818 /*
3819 * On targets where crypto clock is handled by HLOS,
3820 * if clk_access_cnt is zero and perf_enabled is false,
3821 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003822 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003823 */
3824 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003825 pr_debug("ce clock is not enabled!\n");
3826 ret = qseecom_perf_enable(data);
3827 if (ret) {
3828 pr_err("Failed to vote for clock with err %d\n",
3829 ret);
3830 mutex_unlock(&app_access_lock);
3831 ret = -EINVAL;
3832 break;
3833 }
3834 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003835 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003836 atomic_inc(&data->ioctl_count);
3837 ret = qseecom_send_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003838 if (qseecom.support_bus_scaling)
3839 __qseecom_add_bw_scale_down_timer(
3840 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003841 if (perf_enabled) {
3842 qsee_disable_clock_vote(data, CLK_DFAB);
3843 qsee_disable_clock_vote(data, CLK_SFPB);
3844 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003845 atomic_dec(&data->ioctl_count);
3846 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003847 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003848 if (ret)
3849 pr_err("failed qseecom_send_cmd: %d\n", ret);
3850 break;
3851 }
3852 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003853 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003854 if ((data->client.app_id == 0) ||
3855 (data->type != QSEECOM_CLIENT_APP)) {
3856 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3857 data->type, data->client.app_id);
3858 ret = -EINVAL;
3859 break;
3860 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003861 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003862 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003863 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003864 if (!data->mode) {
3865 mutex_lock(&qsee_bw_mutex);
3866 __qseecom_register_bus_bandwidth_needs(
3867 data, HIGH);
3868 mutex_unlock(&qsee_bw_mutex);
3869 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003870 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3871 if (ret) {
3872 pr_err("Failed to set bw.\n");
3873 mutex_unlock(&app_access_lock);
3874 ret = -EINVAL;
3875 break;
3876 }
3877 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003878 /*
3879 * On targets where crypto clock is handled by HLOS,
3880 * if clk_access_cnt is zero and perf_enabled is false,
3881 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003882 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003883 */
3884 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003885 pr_debug("ce clock is not enabled!\n");
3886 ret = qseecom_perf_enable(data);
3887 if (ret) {
3888 pr_err("Failed to vote for clock with err %d\n",
3889 ret);
3890 mutex_unlock(&app_access_lock);
3891 ret = -EINVAL;
3892 break;
3893 }
3894 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003895 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003896 atomic_inc(&data->ioctl_count);
3897 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003898 if (qseecom.support_bus_scaling)
3899 __qseecom_add_bw_scale_down_timer(
3900 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003901 if (perf_enabled) {
3902 qsee_disable_clock_vote(data, CLK_DFAB);
3903 qsee_disable_clock_vote(data, CLK_SFPB);
3904 }
Zhen Konge8a02082014-03-11 17:36:50 -07003905 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003906 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003907 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003908 if (ret)
3909 pr_err("failed qseecom_send_cmd: %d\n", ret);
3910 break;
3911 }
3912 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003913 if ((data->listener.id == 0) ||
3914 (data->type != QSEECOM_LISTENER_SERVICE)) {
3915 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3916 data->type, data->listener.id);
3917 ret = -EINVAL;
3918 break;
3919 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003920 atomic_inc(&data->ioctl_count);
3921 ret = qseecom_receive_req(data);
3922 atomic_dec(&data->ioctl_count);
3923 wake_up_all(&data->abort_wq);
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05303924 if (ret && (ret != -ERESTARTSYS))
Mona Hossain2892b6b2012-02-17 13:53:11 -08003925 pr_err("failed qseecom_receive_req: %d\n", ret);
3926 break;
3927 }
3928 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003929 if ((data->listener.id == 0) ||
3930 (data->type != QSEECOM_LISTENER_SERVICE)) {
3931 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3932 data->type, data->listener.id);
3933 ret = -EINVAL;
3934 break;
3935 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003936 atomic_inc(&data->ioctl_count);
3937 ret = qseecom_send_resp();
3938 atomic_dec(&data->ioctl_count);
3939 wake_up_all(&data->abort_wq);
3940 if (ret)
3941 pr_err("failed qseecom_send_resp: %d\n", ret);
3942 break;
3943 }
3944 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003945 if ((data->type != QSEECOM_CLIENT_APP) &&
3946 (data->type != QSEECOM_GENERIC) &&
3947 (data->type != QSEECOM_SECURE_SERVICE)) {
3948 pr_err("set mem param req: invalid handle (%d)\n",
3949 data->type);
3950 ret = -EINVAL;
3951 break;
3952 }
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05303953 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%pK\n", data);
Zhen Kong96f5c012017-05-23 10:21:20 +08003954 mutex_lock(&app_access_lock);
3955 atomic_inc(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003956 ret = qseecom_set_client_mem_param(data, argp);
Zhen Kong96f5c012017-05-23 10:21:20 +08003957 atomic_dec(&data->ioctl_count);
3958 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003959 if (ret)
3960 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3961 ret);
3962 break;
3963 }
3964 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003965 if ((data->type != QSEECOM_GENERIC) &&
3966 (data->type != QSEECOM_CLIENT_APP)) {
3967 pr_err("load app req: invalid handle (%d)\n",
3968 data->type);
3969 ret = -EINVAL;
3970 break;
3971 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003972 data->type = QSEECOM_CLIENT_APP;
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05303973 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%pK\n", data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003974 mutex_lock(&app_access_lock);
3975 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003976 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3977 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003978 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003979 if (ret == 0)
3980 qseecom.commonlib_loaded = true;
3981 }
3982 }
3983 if (ret == 0)
3984 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003985 atomic_dec(&data->ioctl_count);
3986 mutex_unlock(&app_access_lock);
3987 if (ret)
3988 pr_err("failed load_app request: %d\n", ret);
3989 break;
3990 }
3991 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003992 if ((data->client.app_id == 0) ||
3993 (data->type != QSEECOM_CLIENT_APP)) {
3994 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3995 data->type, data->client.app_id);
3996 ret = -EINVAL;
3997 break;
3998 }
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05303999 pr_debug("UNLOAD_APP: qseecom_addr = 0x%pK\n", data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004000 mutex_lock(&app_access_lock);
4001 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004002 ret = qseecom_unload_app(data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004003 atomic_dec(&data->ioctl_count);
4004 mutex_unlock(&app_access_lock);
4005 if (ret)
4006 pr_err("failed unload_app request: %d\n", ret);
4007 break;
4008 }
4009 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
4010 atomic_inc(&data->ioctl_count);
4011 ret = qseecom_get_qseos_version(data, argp);
4012 if (ret)
4013 pr_err("qseecom_get_qseos_version: %d\n", ret);
4014 atomic_dec(&data->ioctl_count);
4015 break;
4016 }
4017 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004018 if ((data->type != QSEECOM_GENERIC) &&
4019 (data->type != QSEECOM_CLIENT_APP)) {
4020 pr_err("perf enable req: invalid handle (%d)\n",
4021 data->type);
4022 ret = -EINVAL;
4023 break;
4024 }
4025 if ((data->type == QSEECOM_CLIENT_APP) &&
4026 (data->client.app_id == 0)) {
4027 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
4028 data->type, data->client.app_id);
4029 ret = -EINVAL;
4030 break;
4031 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004032 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004033 if (qseecom.support_bus_scaling) {
4034 mutex_lock(&qsee_bw_mutex);
4035 __qseecom_register_bus_bandwidth_needs(data, HIGH);
4036 mutex_unlock(&qsee_bw_mutex);
4037 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07004038 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004039 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07004040 pr_err("Fail to vote for clocks %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004041 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004042 atomic_dec(&data->ioctl_count);
4043 break;
4044 }
4045 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004046 if ((data->type != QSEECOM_SECURE_SERVICE) &&
4047 (data->type != QSEECOM_CLIENT_APP)) {
4048 pr_err("perf disable req: invalid handle (%d)\n",
4049 data->type);
4050 ret = -EINVAL;
4051 break;
4052 }
4053 if ((data->type == QSEECOM_CLIENT_APP) &&
4054 (data->client.app_id == 0)) {
4055 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
4056 data->type, data->client.app_id);
4057 ret = -EINVAL;
4058 break;
4059 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004060 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004061 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004062 qsee_disable_clock_vote(data, CLK_DFAB);
4063 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07004064 } else {
4065 mutex_lock(&qsee_bw_mutex);
4066 qseecom_unregister_bus_bandwidth_needs(data);
4067 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004068 }
4069 atomic_dec(&data->ioctl_count);
4070 break;
4071 }
4072
4073 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
4074 if ((data->client.app_id == 0) ||
4075 (data->type != QSEECOM_CLIENT_APP)) {
4076 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
4077 data->type, data->client.app_id);
4078 ret = -EINVAL;
4079 break;
4080 }
4081 atomic_inc(&data->ioctl_count);
4082 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004083 atomic_dec(&data->ioctl_count);
4084 break;
4085 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004086 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004087 if (data->type != QSEECOM_GENERIC) {
4088 pr_err("load ext elf req: invalid client handle (%d)\n",
4089 data->type);
4090 ret = -EINVAL;
4091 break;
4092 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004093 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004094 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004095 mutex_lock(&app_access_lock);
4096 atomic_inc(&data->ioctl_count);
4097 ret = qseecom_load_external_elf(data, argp);
4098 atomic_dec(&data->ioctl_count);
4099 mutex_unlock(&app_access_lock);
4100 if (ret)
4101 pr_err("failed load_external_elf request: %d\n", ret);
4102 break;
4103 }
4104 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004105 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
4106 pr_err("unload ext elf req: invalid handle (%d)\n",
4107 data->type);
4108 ret = -EINVAL;
4109 break;
4110 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004111 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004112 mutex_lock(&app_access_lock);
4113 atomic_inc(&data->ioctl_count);
4114 ret = qseecom_unload_external_elf(data);
4115 atomic_dec(&data->ioctl_count);
4116 mutex_unlock(&app_access_lock);
4117 if (ret)
4118 pr_err("failed unload_app request: %d\n", ret);
4119 break;
4120 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004121 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004122 data->type = QSEECOM_CLIENT_APP;
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05304123 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%pK\n", data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004124 mutex_lock(&app_access_lock);
4125 atomic_inc(&data->ioctl_count);
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05304126 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%pK\n", data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004127 ret = qseecom_query_app_loaded(data, argp);
4128 atomic_dec(&data->ioctl_count);
4129 mutex_unlock(&app_access_lock);
4130 break;
4131 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004132 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004133 if (data->type != QSEECOM_GENERIC) {
4134 pr_err("send cmd svc req: invalid handle (%d)\n",
4135 data->type);
4136 ret = -EINVAL;
4137 break;
4138 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004139 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004140 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004141 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004142 qseecom.qsee_version);
4143 return -EINVAL;
4144 }
4145 mutex_lock(&app_access_lock);
4146 atomic_inc(&data->ioctl_count);
4147 ret = qseecom_send_service_cmd(data, argp);
4148 atomic_dec(&data->ioctl_count);
4149 mutex_unlock(&app_access_lock);
4150 break;
4151 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004152 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004153 if (!(qseecom.support_pfe || qseecom.support_fde))
4154 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004155 if (data->type != QSEECOM_GENERIC) {
4156 pr_err("create key req: invalid handle (%d)\n",
4157 data->type);
4158 ret = -EINVAL;
4159 break;
4160 }
Zhen Kong336636e2013-04-15 11:04:54 -07004161 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004162 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004163 qseecom.qsee_version);
4164 return -EINVAL;
4165 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004166 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004167 atomic_inc(&data->ioctl_count);
4168 ret = qseecom_create_key(data, argp);
4169 if (ret)
4170 pr_err("failed to create encryption key: %d\n", ret);
4171
4172 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004173 break;
4174 }
4175 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004176 if (!(qseecom.support_pfe || qseecom.support_fde))
4177 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004178 if (data->type != QSEECOM_GENERIC) {
4179 pr_err("wipe key req: invalid handle (%d)\n",
4180 data->type);
4181 ret = -EINVAL;
4182 break;
4183 }
Zhen Kong336636e2013-04-15 11:04:54 -07004184 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004185 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004186 qseecom.qsee_version);
4187 return -EINVAL;
4188 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004189 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004190 atomic_inc(&data->ioctl_count);
4191 ret = qseecom_wipe_key(data, argp);
4192 if (ret)
4193 pr_err("failed to wipe encryption key: %d\n", ret);
4194 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08004195 break;
4196 }
4197 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004198 if (!(qseecom.support_pfe || qseecom.support_fde))
4199 pr_err("Features requiring key init not supported\n");
Zhen Kong9730ddf2013-12-17 16:49:43 -08004200 if (data->type != QSEECOM_GENERIC) {
4201 pr_err("update key req: invalid handle (%d)\n",
4202 data->type);
4203 ret = -EINVAL;
4204 break;
4205 }
4206 if (qseecom.qsee_version < QSEE_VERSION_05) {
4207 pr_err("Update Key feature unsupported in qsee ver %u\n",
4208 qseecom.qsee_version);
4209 return -EINVAL;
4210 }
4211 data->released = true;
4212 atomic_inc(&data->ioctl_count);
4213 ret = qseecom_update_key_user_info(data, argp);
4214 if (ret)
4215 pr_err("failed to update key user info: %d\n", ret);
4216 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004217 break;
4218 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004219 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004220 if (data->type != QSEECOM_GENERIC) {
4221 pr_err("save part hash req: invalid handle (%d)\n",
4222 data->type);
4223 ret = -EINVAL;
4224 break;
4225 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004226 data->released = true;
4227 mutex_lock(&app_access_lock);
4228 atomic_inc(&data->ioctl_count);
4229 ret = qseecom_save_partition_hash(argp);
4230 atomic_dec(&data->ioctl_count);
4231 mutex_unlock(&app_access_lock);
4232 break;
4233 }
4234 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004235 if (data->type != QSEECOM_GENERIC) {
4236 pr_err("ES activated req: invalid handle (%d)\n",
4237 data->type);
4238 ret = -EINVAL;
4239 break;
4240 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004241 data->released = true;
4242 mutex_lock(&app_access_lock);
4243 atomic_inc(&data->ioctl_count);
4244 ret = qseecom_is_es_activated(argp);
4245 atomic_dec(&data->ioctl_count);
4246 mutex_unlock(&app_access_lock);
4247 break;
4248 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004249 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004250 if ((data->listener.id == 0) ||
4251 (data->type != QSEECOM_LISTENER_SERVICE)) {
4252 pr_err("receive req: invalid handle (%d), lid(%d)\n",
4253 data->type, data->listener.id);
4254 ret = -EINVAL;
4255 break;
4256 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004257 /* Only one client allowed here at a time */
4258 atomic_inc(&data->ioctl_count);
4259 ret = qseecom_send_modfd_resp(data, argp);
4260 atomic_dec(&data->ioctl_count);
4261 wake_up_all(&data->abort_wq);
4262 if (ret)
4263 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
4264 break;
4265 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004266 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07004267 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004268 return -EINVAL;
4269 }
4270 return ret;
4271}
4272
4273static int qseecom_open(struct inode *inode, struct file *file)
4274{
4275 int ret = 0;
4276 struct qseecom_dev_handle *data;
4277
4278 data = kzalloc(sizeof(*data), GFP_KERNEL);
4279 if (!data) {
4280 pr_err("kmalloc failed\n");
4281 return -ENOMEM;
4282 }
4283 file->private_data = data;
4284 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004285 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004286 data->released = false;
William Clarkc7a043d2014-05-23 15:08:52 -07004287 memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004288 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004289 init_waitqueue_head(&data->abort_wq);
4290 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07004291
Mona Hossain2892b6b2012-02-17 13:53:11 -08004292 return ret;
4293}
4294
4295static int qseecom_release(struct inode *inode, struct file *file)
4296{
4297 struct qseecom_dev_handle *data = file->private_data;
4298 int ret = 0;
4299
4300 if (data->released == false) {
Mallikarjuna Reddy Amireddy3b78a672016-07-25 18:14:39 +05304301 pr_debug("data: released = false, type = %d, data = 0x%pK\n",
4302 data->type, data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004303 switch (data->type) {
4304 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004305 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004306 break;
4307 case QSEECOM_CLIENT_APP:
Zhen Kong9bfacc52015-06-09 14:49:36 -07004308 mutex_lock(&app_access_lock);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004309 ret = qseecom_unload_app(data, true);
Zhen Kong9bfacc52015-06-09 14:49:36 -07004310 mutex_unlock(&app_access_lock);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004311 break;
4312 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07004313 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004314 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004315 if (ret)
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07004316 pr_err("Ion Unmap failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004317 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05304318 case QSEECOM_UNAVAILABLE_CLIENT_APP:
4319 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004320 default:
4321 pr_err("Unsupported clnt_handle_type %d",
4322 data->type);
4323 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004324 }
4325 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004326
Zhen Kong2edf90d2013-08-27 12:05:06 -07004327 if (qseecom.support_bus_scaling) {
4328 mutex_lock(&qsee_bw_mutex);
4329 if (data->mode != INACTIVE) {
4330 qseecom_unregister_bus_bandwidth_needs(data);
4331 if (qseecom.cumulative_mode == INACTIVE) {
4332 ret = __qseecom_set_msm_bus_request(INACTIVE);
4333 if (ret)
4334 pr_err("Fail to scale down bus\n");
4335 }
4336 }
4337 mutex_unlock(&qsee_bw_mutex);
4338 } else {
4339 if (data->fast_load_enabled == true)
4340 qsee_disable_clock_vote(data, CLK_SFPB);
4341 if (data->perf_enabled == true)
4342 qsee_disable_clock_vote(data, CLK_DFAB);
4343 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004344 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08004345
Mona Hossain2892b6b2012-02-17 13:53:11 -08004346 return ret;
4347}
4348
Mona Hossain2892b6b2012-02-17 13:53:11 -08004349static const struct file_operations qseecom_fops = {
4350 .owner = THIS_MODULE,
4351 .unlocked_ioctl = qseecom_ioctl,
4352 .open = qseecom_open,
4353 .release = qseecom_release
4354};
4355
Mona Hossainc92629e2013-04-01 13:37:46 -07004356static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004357{
4358 int rc = 0;
4359 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004360 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07004361 char *core_clk_src = NULL;
4362 char *core_clk = NULL;
4363 char *iface_clk = NULL;
4364 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004365
Mona Hossainc92629e2013-04-01 13:37:46 -07004366 switch (ce) {
4367 case CLK_QSEE: {
4368 core_clk_src = "core_clk_src";
4369 core_clk = "core_clk";
4370 iface_clk = "iface_clk";
4371 bus_clk = "bus_clk";
4372 qclk = &qseecom.qsee;
4373 qclk->instance = CLK_QSEE;
4374 break;
4375 };
4376 case CLK_CE_DRV: {
4377 core_clk_src = "ce_drv_core_clk_src";
4378 core_clk = "ce_drv_core_clk";
4379 iface_clk = "ce_drv_iface_clk";
4380 bus_clk = "ce_drv_bus_clk";
4381 qclk = &qseecom.ce_drv;
4382 qclk->instance = CLK_CE_DRV;
4383 break;
4384 };
4385 default:
4386 pr_err("Invalid ce hw instance: %d!\n", ce);
4387 return -EIO;
4388 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004389 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004390
Mona Hossainc92629e2013-04-01 13:37:46 -07004391 /* Get CE3 src core clk. */
4392 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004393 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08004394 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07004395 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004396 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07004397 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004398 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08004399 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004400 }
4401 } else {
4402 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004403 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004404 }
4405
4406 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004407 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004408 if (IS_ERR(qclk->ce_core_clk)) {
4409 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004410 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004411 if (qclk->ce_core_src_clk != NULL)
4412 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004413 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004414 }
4415
4416 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004417 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004418 if (IS_ERR(qclk->ce_clk)) {
4419 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004420 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004421 if (qclk->ce_core_src_clk != NULL)
4422 clk_put(qclk->ce_core_src_clk);
4423 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004424 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004425 }
4426
4427 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004428 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004429 if (IS_ERR(qclk->ce_bus_clk)) {
4430 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004431 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004432 if (qclk->ce_core_src_clk != NULL)
4433 clk_put(qclk->ce_core_src_clk);
4434 clk_put(qclk->ce_core_clk);
4435 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004436 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004437 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004438 return rc;
4439}
4440
Mona Hossainc92629e2013-04-01 13:37:46 -07004441static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004442{
Mona Hossain17a4faf2013-03-22 16:40:56 -07004443 struct qseecom_clk *qclk;
4444
Mona Hossainc92629e2013-04-01 13:37:46 -07004445 if (ce == CLK_QSEE)
4446 qclk = &qseecom.qsee;
4447 else
4448 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004449
4450 if (qclk->ce_clk != NULL) {
4451 clk_put(qclk->ce_clk);
4452 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004453 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004454 if (qclk->ce_core_clk != NULL) {
4455 clk_put(qclk->ce_core_clk);
4456 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004457 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004458 if (qclk->ce_bus_clk != NULL) {
4459 clk_put(qclk->ce_bus_clk);
4460 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004461 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004462 if (qclk->ce_core_src_clk != NULL) {
4463 clk_put(qclk->ce_core_src_clk);
4464 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004465 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004466}
4467
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004468static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004469{
4470 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004471 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004472 struct device *class_dev;
4473 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07004474 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004475 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
4476
Mona Hossain17a4faf2013-03-22 16:40:56 -07004477 qseecom.qsee_bw_count = 0;
4478 qseecom.qsee_perf_client = 0;
4479 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004480
Mona Hossain17a4faf2013-03-22 16:40:56 -07004481 qseecom.qsee.ce_core_clk = NULL;
4482 qseecom.qsee.ce_clk = NULL;
4483 qseecom.qsee.ce_core_src_clk = NULL;
4484 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07004485
Zhen Kong2edf90d2013-08-27 12:05:06 -07004486 qseecom.cumulative_mode = 0;
4487 qseecom.current_mode = INACTIVE;
4488 qseecom.support_bus_scaling = false;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004489 qseecom.support_fde = false;
4490 qseecom.support_pfe = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004491
Mona Hossainc92629e2013-04-01 13:37:46 -07004492 qseecom.ce_drv.ce_core_clk = NULL;
4493 qseecom.ce_drv.ce_clk = NULL;
4494 qseecom.ce_drv.ce_core_src_clk = NULL;
4495 qseecom.ce_drv.ce_bus_clk = NULL;
4496
Mona Hossain2892b6b2012-02-17 13:53:11 -08004497 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
4498 if (rc < 0) {
4499 pr_err("alloc_chrdev_region failed %d\n", rc);
4500 return rc;
4501 }
4502
4503 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
4504 if (IS_ERR(driver_class)) {
4505 rc = -ENOMEM;
4506 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304507 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004508 }
4509
4510 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
4511 QSEECOM_DEV);
4512 if (!class_dev) {
4513 pr_err("class_device_create failed %d\n", rc);
4514 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304515 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004516 }
4517
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304518 cdev_init(&qseecom.cdev, &qseecom_fops);
4519 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004520
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304521 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004522 if (rc < 0) {
4523 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304524 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004525 }
4526
4527 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
4528 spin_lock_init(&qseecom.registered_listener_list_lock);
4529 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
4530 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07004531 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
4532 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004533 init_waitqueue_head(&qseecom.send_resp_wq);
4534 qseecom.send_resp_flag = 0;
4535
4536 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
4537 &qsee_not_legacy, sizeof(qsee_not_legacy));
4538 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07004539 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304540 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004541 }
Mona Hossain05c73562012-10-29 17:49:01 -07004542 if (qsee_not_legacy) {
4543 uint32_t feature = 10;
4544
4545 qseecom.qsee_version = QSEEE_VERSION_00;
4546 rc = scm_call(6, 3, &feature, sizeof(feature),
4547 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
4548 if (rc) {
4549 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304550 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07004551 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004552 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07004553 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07004554 pr_err("QSEE legacy version is not supported:");
4555 pr_err("Support for TZ1.3 and earlier is deprecated\n");
4556 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304557 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004558 }
Mona Hossain05c73562012-10-29 17:49:01 -07004559 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004560 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004561 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07004562 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08004563 if (qseecom.ion_clnt == NULL) {
4564 pr_err("Ion client cannot be created\n");
4565 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304566 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004567 }
4568
4569 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004570 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05304571 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004572 qseecom.support_bus_scaling =
4573 of_property_read_bool((&pdev->dev)->of_node,
4574 "qcom,support-bus-scaling");
4575 pr_warn("support_bus_scaling=0x%x",
4576 qseecom.support_bus_scaling);
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004577 qseecom.support_fde =
4578 of_property_read_bool((&pdev->dev)->of_node,
4579 "qcom,support-fde");
4580 if (qseecom.support_fde) {
4581 if (of_property_read_u32((&pdev->dev)->of_node,
Mona Hossain4cf78a92013-02-14 12:06:41 -08004582 "qcom,disk-encrypt-pipe-pair",
4583 &qseecom.ce_info.disk_encrypt_pipe)) {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004584 pr_err("Fail to get FDE pipe information.\n");
4585 rc = -EINVAL;
4586 goto exit_destroy_ion_client;
4587 } else {
4588 pr_warn("disk-encrypt-pipe-pair=0x%x",
4589 qseecom.ce_info.disk_encrypt_pipe);
4590 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004591 } else {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004592 pr_warn("Device does not support FDE");
4593 qseecom.ce_info.disk_encrypt_pipe = 0xff;
4594 }
4595 qseecom.support_pfe =
4596 of_property_read_bool((&pdev->dev)->of_node,
4597 "qcom,support-pfe");
4598 if (qseecom.support_pfe) {
4599 if (of_property_read_u32((&pdev->dev)->of_node,
4600 "qcom,file-encrypt-pipe-pair",
4601 &qseecom.ce_info.disk_encrypt_pipe)) {
4602 pr_err("Fail to get PFE pipe information.\n");
4603 rc = -EINVAL;
4604 goto exit_destroy_ion_client;
4605 } else {
4606 pr_warn("file-encrypt-pipe-pair=0x%x",
4607 qseecom.ce_info.file_encrypt_pipe);
4608 }
4609 } else {
4610 pr_warn("Device does not support PFE");
4611 qseecom.ce_info.file_encrypt_pipe = 0xff;
4612 }
4613 if (qseecom.support_pfe || qseecom.support_fde) {
4614 if (of_property_read_u32((&pdev->dev)->of_node,
4615 "qcom,hlos-ce-hw-instance",
4616 &qseecom.ce_info.hlos_ce_hw_instance)) {
4617 pr_err("Fail: get hlos ce hw instanc info\n");
4618 rc = -EINVAL;
4619 goto exit_destroy_ion_client;
4620 } else {
4621 pr_warn("hlos-ce-hw-instance=0x%x",
4622 qseecom.ce_info.hlos_ce_hw_instance);
4623 }
4624 } else {
4625 pr_warn("Device does not support PFE/FDE");
4626 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004627 }
4628
4629 if (of_property_read_u32((&pdev->dev)->of_node,
4630 "qcom,qsee-ce-hw-instance",
4631 &qseecom.ce_info.qsee_ce_hw_instance)) {
4632 pr_err("Fail to get qsee ce hw instance information.\n");
Mona Hossain4cf78a92013-02-14 12:06:41 -08004633 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304634 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004635 } else {
4636 pr_warn("qsee-ce-hw-instance=0x%x",
4637 qseecom.ce_info.qsee_ce_hw_instance);
4638 }
4639
Zhen Kong56d62642015-03-10 16:29:53 -07004640 qseecom.appsbl_qseecom_support =
4641 of_property_read_bool((&pdev->dev)->of_node,
4642 "qcom,appsbl-qseecom-support");
4643 pr_info("qseecom.appsbl_qseecom_support = 0x%x",
4644 qseecom.appsbl_qseecom_support);
4645
Mona Hossainc92629e2013-04-01 13:37:46 -07004646 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
4647 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
4648
4649 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004650 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304651 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08004652
Zhen Konga10dcab2014-03-19 10:32:27 -07004653 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4654 (qseecom.support_pfe || qseecom.support_fde)) {
Mona Hossainc92629e2013-04-01 13:37:46 -07004655 ret = __qseecom_init_clk(CLK_CE_DRV);
4656 if (ret) {
4657 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304658 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07004659 }
4660 } else {
4661 struct qseecom_clk *qclk;
4662
4663 qclk = &qseecom.qsee;
4664 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
4665 qseecom.ce_drv.ce_clk = qclk->ce_clk;
4666 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
4667 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
4668 }
4669
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004670 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4671 msm_bus_cl_get_pdata(pdev);
Zhen Kong56d62642015-03-10 16:29:53 -07004672 if (qseecom.qsee_version >= (QSEE_VERSION_02) &&
4673 !qseecom.appsbl_qseecom_support) {
Mona Hossain5b76a622012-11-15 20:09:08 -08004674 struct resource *resource = NULL;
4675 struct qsee_apps_region_info_ireq req;
4676 struct qseecom_command_scm_resp resp;
4677
4678 resource = platform_get_resource_byname(pdev,
4679 IORESOURCE_MEM, "secapp-region");
4680 if (resource) {
4681 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
4682 req.addr = resource->start;
4683 req.size = resource_size(resource);
4684 pr_warn("secure app region addr=0x%x size=0x%x",
4685 req.addr, req.size);
4686 } else {
4687 pr_err("Fail to get secure app region info\n");
4688 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304689 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004690 }
4691 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
4692 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07004693 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
4694 pr_err("send secapp reg fail %d resp.res %d\n",
4695 rc, resp.result);
4696 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304697 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004698 }
4699 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004700 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004701 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4702 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004703 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004704 if (qseecom.support_bus_scaling) {
4705 init_timer(&(qseecom.bw_scale_down_timer));
4706 INIT_WORK(&qseecom.bw_inactive_req_ws,
4707 qseecom_bw_inactive_req_work);
4708 qseecom.bw_scale_down_timer.function =
4709 qseecom_scale_bus_bandwidth_timer_callback;
4710 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004711 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004712 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004713 qseecom_platform_support);
4714
Mona Hossain17a4faf2013-03-22 16:40:56 -07004715 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004716 pr_err("Unable to register bus client\n");
4717 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304718
4719exit_destroy_ion_client:
4720 ion_client_destroy(qseecom.ion_clnt);
4721exit_del_cdev:
4722 cdev_del(&qseecom.cdev);
4723exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004724 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304725exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004726 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304727exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004728 unregister_chrdev_region(qseecom_device_no, 1);
4729 return rc;
4730}
4731
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004732static int __devinit qseecom_remove(struct platform_device *pdev)
4733{
Mona Hossaind44a3842012-10-15 09:41:35 -07004734 struct qseecom_registered_kclient_list *kclient = NULL;
4735 unsigned long flags = 0;
4736 int ret = 0;
4737
Mona Hossaind44a3842012-10-15 09:41:35 -07004738 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304739
Mona Hossaind44a3842012-10-15 09:41:35 -07004740 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304741 list) {
4742 if (!kclient)
4743 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07004744
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304745 /* Break the loop if client handle is NULL */
4746 if (!kclient->handle)
4747 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004748
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304749 if (list_empty(&kclient->list))
4750 goto exit_free_kc_handle;
4751
4752 list_del(&kclient->list);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004753 ret = qseecom_unload_app(kclient->handle->dev, false);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304754 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004755 kzfree(kclient->handle->dev);
4756 kzfree(kclient->handle);
4757 kzfree(kclient);
4758 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004759 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304760
4761exit_free_kc_handle:
4762 kzfree(kclient->handle);
4763exit_free_kclient:
4764 kzfree(kclient);
4765exit_irqrestore:
4766 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4767
4768 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004769 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004770
Mona Hossain17a4faf2013-03-22 16:40:56 -07004771 if (qseecom.qsee_perf_client)
4772 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4773 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304774 if (pdev->dev.platform_data != NULL)
4775 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4776
Zhen Kong2edf90d2013-08-27 12:05:06 -07004777 if (qseecom.support_bus_scaling) {
4778 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4779 del_timer_sync(&qseecom.bw_scale_down_timer);
4780 }
4781
Mona Hossaind39e33b2012-11-05 13:36:40 -08004782 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004783 if (pdev->dev.of_node) {
4784 __qseecom_deinit_clk(CLK_QSEE);
Zhen Konga10dcab2014-03-19 10:32:27 -07004785 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4786 (qseecom.support_pfe || qseecom.support_fde))
Mona Hossainc92629e2013-04-01 13:37:46 -07004787 __qseecom_deinit_clk(CLK_CE_DRV);
4788 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304789
4790 ion_client_destroy(qseecom.ion_clnt);
4791
4792 cdev_del(&qseecom.cdev);
4793
4794 device_destroy(driver_class, qseecom_device_no);
4795
4796 class_destroy(driver_class);
4797
4798 unregister_chrdev_region(qseecom_device_no, 1);
4799
Mona Hossaind44a3842012-10-15 09:41:35 -07004800 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304801}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004802
Zhen Konga0944b82013-11-06 17:02:00 -08004803static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4804{
4805 int ret = 0;
4806 struct qseecom_clk *qclk;
4807 qclk = &qseecom.qsee;
4808
Zhen Konge5b434e2014-04-17 16:47:06 -07004809 mutex_lock(&qsee_bw_mutex);
4810 mutex_lock(&clk_access_lock);
4811
Zhen Kong60f4f702014-10-15 17:57:17 -07004812 if (qseecom.current_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004813 ret = msm_bus_scale_client_update_request(
4814 qseecom.qsee_perf_client, INACTIVE);
Zhen Konga0944b82013-11-06 17:02:00 -08004815 if (ret)
4816 pr_err("Fail to scale down bus\n");
Zhen Konge5b434e2014-04-17 16:47:06 -07004817 else
4818 qseecom.current_mode = INACTIVE;
Zhen Konga0944b82013-11-06 17:02:00 -08004819 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004820
Zhen Konga0944b82013-11-06 17:02:00 -08004821 if (qclk->clk_access_cnt) {
4822 if (qclk->ce_clk != NULL)
4823 clk_disable_unprepare(qclk->ce_clk);
4824 if (qclk->ce_core_clk != NULL)
4825 clk_disable_unprepare(qclk->ce_core_clk);
4826 if (qclk->ce_bus_clk != NULL)
4827 clk_disable_unprepare(qclk->ce_bus_clk);
4828 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004829
4830 del_timer_sync(&(qseecom.bw_scale_down_timer));
4831 qseecom.timer_running = false;
4832
Zhen Konga0944b82013-11-06 17:02:00 -08004833 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004834 mutex_unlock(&qsee_bw_mutex);
4835
Zhen Konga0944b82013-11-06 17:02:00 -08004836 return 0;
4837}
4838
4839static int qseecom_resume(struct platform_device *pdev)
4840{
4841 int mode = 0;
4842 int ret = 0;
4843 struct qseecom_clk *qclk;
4844 qclk = &qseecom.qsee;
4845
Zhen Konge5b434e2014-04-17 16:47:06 -07004846 mutex_lock(&qsee_bw_mutex);
4847 mutex_lock(&clk_access_lock);
Zhen Konga0944b82013-11-06 17:02:00 -08004848 if (qseecom.cumulative_mode >= HIGH)
4849 mode = HIGH;
4850 else
4851 mode = qseecom.cumulative_mode;
4852
4853 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004854 ret = msm_bus_scale_client_update_request(
Zhen Kong98b0e512014-04-04 10:12:24 -07004855 qseecom.qsee_perf_client, mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004856 if (ret)
Zhen Kong98b0e512014-04-04 10:12:24 -07004857 pr_err("Fail to scale up bus to %d\n", mode);
Zhen Konge5b434e2014-04-17 16:47:06 -07004858 else
4859 qseecom.current_mode = mode;
Zhen Konga0944b82013-11-06 17:02:00 -08004860 }
4861
Zhen Konga0944b82013-11-06 17:02:00 -08004862 if (qclk->clk_access_cnt) {
4863
4864 ret = clk_prepare_enable(qclk->ce_core_clk);
4865 if (ret) {
4866 pr_err("Unable to enable/prepare CE core clk\n");
4867 qclk->clk_access_cnt = 0;
4868 goto err;
4869 }
4870
4871 ret = clk_prepare_enable(qclk->ce_clk);
4872 if (ret) {
4873 pr_err("Unable to enable/prepare CE iface clk\n");
4874 qclk->clk_access_cnt = 0;
4875 goto ce_clk_err;
4876 }
4877
4878 ret = clk_prepare_enable(qclk->ce_bus_clk);
4879 if (ret) {
4880 pr_err("Unable to enable/prepare CE bus clk\n");
4881 qclk->clk_access_cnt = 0;
4882 goto ce_bus_clk_err;
4883 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004884 }
4885
4886 if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004887 qseecom.bw_scale_down_timer.expires = jiffies +
4888 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge5b434e2014-04-17 16:47:06 -07004889 mod_timer(&(qseecom.bw_scale_down_timer),
4890 qseecom.bw_scale_down_timer.expires);
Zhen Kongca4c2d52014-03-12 13:22:46 -07004891 qseecom.timer_running = true;
Zhen Konga0944b82013-11-06 17:02:00 -08004892 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004893
Zhen Konga0944b82013-11-06 17:02:00 -08004894 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004895 mutex_unlock(&qsee_bw_mutex);
4896
4897
Zhen Konga0944b82013-11-06 17:02:00 -08004898 return 0;
4899
4900ce_bus_clk_err:
4901 clk_disable_unprepare(qclk->ce_clk);
4902ce_clk_err:
4903 clk_disable_unprepare(qclk->ce_core_clk);
4904err:
4905 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004906 mutex_unlock(&qsee_bw_mutex);
Zhen Konga0944b82013-11-06 17:02:00 -08004907 return -EIO;
4908}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004909static struct of_device_id qseecom_match[] = {
4910 {
4911 .compatible = "qcom,qseecom",
4912 },
4913 {}
4914};
4915
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004916static struct platform_driver qseecom_plat_driver = {
4917 .probe = qseecom_probe,
4918 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004919 .suspend = qseecom_suspend,
4920 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004921 .driver = {
4922 .name = "qseecom",
4923 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004924 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004925 },
4926};
4927
4928static int __devinit qseecom_init(void)
4929{
4930 return platform_driver_register(&qseecom_plat_driver);
4931}
4932
4933static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004934{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304935 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004936}
4937
4938MODULE_LICENSE("GPL v2");
4939MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4940
4941module_init(qseecom_init);
4942module_exit(qseecom_exit);