blob: 950c80b8c59a240e11dc68bb90c2c477bfbd3fe0 [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
Zhen Kong82e296d2016-10-20 17:34:20 -070079#define U32_MAX ((u32)~0U)
80
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070081enum qseecom_clk_definitions {
82 CLK_DFAB = 0,
83 CLK_SFPB,
84};
85
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080086enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053087 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080088 QSEECOM_LISTENER_SERVICE,
89 QSEECOM_SECURE_SERVICE,
90 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053091 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080092};
93
Mona Hossainc92629e2013-04-01 13:37:46 -070094enum qseecom_ce_hw_instance {
95 CLK_QSEE = 0,
96 CLK_CE_DRV,
97};
98
Mona Hossain2892b6b2012-02-17 13:53:11 -080099static struct class *driver_class;
100static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800101
Mona Hossain2892b6b2012-02-17 13:53:11 -0800102static DEFINE_MUTEX(qsee_bw_mutex);
103static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -0700104static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800105
Mona Hossain2892b6b2012-02-17 13:53:11 -0800106struct qseecom_registered_listener_list {
107 struct list_head list;
108 struct qseecom_register_listener_req svc;
Zhen Kongf4948192013-11-25 13:05:35 -0800109 uint32_t user_virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800110 u8 *sb_virt;
111 s32 sb_phys;
112 size_t sb_length;
113 struct ion_handle *ihandle; /* Retrieve phy addr */
114
115 wait_queue_head_t rcv_req_wq;
116 int rcv_req_flag;
117};
118
119struct qseecom_registered_app_list {
120 struct list_head list;
121 u32 app_id;
122 u32 ref_cnt;
William Clarkc7a043d2014-05-23 15:08:52 -0700123 char app_name[MAX_APP_NAME_SIZE];
Mona Hossain2892b6b2012-02-17 13:53:11 -0800124};
125
Mona Hossaind44a3842012-10-15 09:41:35 -0700126struct qseecom_registered_kclient_list {
127 struct list_head list;
128 struct qseecom_handle *handle;
129};
130
Mona Hossain4cf78a92013-02-14 12:06:41 -0800131struct ce_hw_usage_info {
132 uint32_t qsee_ce_hw_instance;
133 uint32_t hlos_ce_hw_instance;
134 uint32_t disk_encrypt_pipe;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800135 uint32_t file_encrypt_pipe;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800136};
137
Mona Hossain17a4faf2013-03-22 16:40:56 -0700138struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700139 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700140 struct clk *ce_core_clk;
141 struct clk *ce_clk;
142 struct clk *ce_core_src_clk;
143 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700144 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700145};
146
Mona Hossain2892b6b2012-02-17 13:53:11 -0800147struct qseecom_control {
148 struct ion_client *ion_clnt; /* Ion client */
149 struct list_head registered_listener_list_head;
150 spinlock_t registered_listener_list_lock;
151
152 struct list_head registered_app_list_head;
153 spinlock_t registered_app_list_lock;
154
Mona Hossaind44a3842012-10-15 09:41:35 -0700155 struct list_head registered_kclient_list_head;
156 spinlock_t registered_kclient_list_lock;
157
Mona Hossain2892b6b2012-02-17 13:53:11 -0800158 wait_queue_head_t send_resp_wq;
159 int send_resp_flag;
160
161 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700162 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700163 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700164 bool commonlib_loaded;
Zhen Kongc46b5842013-12-12 13:09:16 +0530165 struct ion_handle *cmnlib_ion_handle;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800166 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700167
168 int qsee_bw_count;
169 int qsee_sfpb_bw_count;
170
171 uint32_t qsee_perf_client;
172 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700173 struct qseecom_clk ce_drv;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700174
175 bool support_bus_scaling;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800176 bool support_fde;
177 bool support_pfe;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700178 uint32_t cumulative_mode;
179 enum qseecom_bandwidth_request_mode current_mode;
180 struct timer_list bw_scale_down_timer;
181 struct work_struct bw_inactive_req_ws;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800182 struct cdev cdev;
183 bool timer_running;
Zhen Kong56d62642015-03-10 16:29:53 -0700184 bool appsbl_qseecom_support;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800185};
186
187struct qseecom_client_handle {
188 u32 app_id;
189 u8 *sb_virt;
190 s32 sb_phys;
191 uint32_t user_virt_sb_base;
192 size_t sb_length;
193 struct ion_handle *ihandle; /* Retrieve phy addr */
William Clarkc7a043d2014-05-23 15:08:52 -0700194 char app_name[MAX_APP_NAME_SIZE];
Mona Hossain2892b6b2012-02-17 13:53:11 -0800195};
196
197struct qseecom_listener_handle {
198 u32 id;
199};
200
201static struct qseecom_control qseecom;
202
203struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800204 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800205 union {
206 struct qseecom_client_handle client;
207 struct qseecom_listener_handle listener;
208 };
209 bool released;
210 int abort;
211 wait_queue_head_t abort_wq;
212 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700213 bool perf_enabled;
214 bool fast_load_enabled;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700215 enum qseecom_bandwidth_request_mode mode;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800216};
217
Mona Hossain4cf78a92013-02-14 12:06:41 -0800218enum qseecom_set_clear_key_flag {
219 QSEECOM_CLEAR_CE_KEY_CMD = 0,
220 QSEECOM_SET_CE_KEY_CMD,
221};
222
223struct qseecom_set_key_parameter {
224 uint32_t ce_hw;
225 uint32_t pipe;
226 uint32_t flags;
227 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
228 unsigned char hash32[QSEECOM_HASH_SIZE];
229 enum qseecom_set_clear_key_flag set_clear_key_flag;
230};
231
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800232struct qseecom_sg_entry {
233 uint32_t phys_addr;
234 uint32_t len;
235};
236
Zhen Kongba69dfe2014-02-28 15:19:53 -0800237struct qseecom_key_id_usage_desc {
238 uint8_t desc[QSEECOM_KEY_ID_SIZE];
239};
240
241static struct qseecom_key_id_usage_desc key_id_array[] = {
242 {
243 .desc = "Undefined Usage Index",
244 },
245
246 {
247 .desc = "Full Disk Encryption",
248 },
249
250 {
251 .desc = "Per File Encryption",
252 },
Zhen Kong9730ddf2013-12-17 16:49:43 -0800253};
254
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700255/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800256static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
257static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700258static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
259static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700260
Mona Hossain2892b6b2012-02-17 13:53:11 -0800261static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800262 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800263{
264 struct qseecom_registered_listener_list *ptr;
265 int unique = 1;
266 unsigned long flags;
267
268 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
269 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800270 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800271 pr_err("Service id: %u is already registered\n",
272 ptr->svc.listener_id);
273 unique = 0;
274 break;
275 }
276 }
277 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
278 return unique;
279}
280
281static struct qseecom_registered_listener_list *__qseecom_find_svc(
282 int32_t listener_id)
283{
284 struct qseecom_registered_listener_list *entry = NULL;
285 unsigned long flags;
286
287 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
288 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
289 {
290 if (entry->svc.listener_id == listener_id)
291 break;
292 }
293 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530294
295 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
296 pr_err("Service id: %u is not found\n", listener_id);
297 return NULL;
298 }
299
Mona Hossain2892b6b2012-02-17 13:53:11 -0800300 return entry;
301}
302
303static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
304 struct qseecom_dev_handle *handle,
305 struct qseecom_register_listener_req *listener)
306{
307 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800308 struct qseecom_register_listener_ireq req;
309 struct qseecom_command_scm_resp resp;
310 ion_phys_addr_t pa;
311
312 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800313 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
314 listener->ifd_data_fd);
Hariprasad Dhalinarasimha1401bc02014-02-18 13:46:37 -0800315 if (IS_ERR_OR_NULL(svc->ihandle)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800316 pr_err("Ion client could not retrieve the handle\n");
317 return -ENOMEM;
318 }
319
320 /* Get the physical address of the ION BUF */
321 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
Zhen Kong05ed4462014-01-28 18:21:30 -0800322 if (ret) {
323 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
324 ret);
325 return ret;
326 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800327 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700328 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800329 svc->sb_phys = pa;
330
Mona Hossaind4613de2013-05-15 16:49:29 -0700331 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
332 req.listener_id = svc->svc.listener_id;
333 req.sb_len = svc->sb_length;
334 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800335
Mona Hossaind4613de2013-05-15 16:49:29 -0700336 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800337
Mona Hossaind4613de2013-05-15 16:49:29 -0700338 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800339 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700340 if (ret) {
341 pr_err("qseecom_scm_call failed with err: %d\n", ret);
342 return -EINVAL;
343 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800344
Mona Hossaind4613de2013-05-15 16:49:29 -0700345 if (resp.result != QSEOS_RESULT_SUCCESS) {
346 pr_err("Error SB registration req: resp.result = %d\n",
347 resp.result);
348 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800349 }
350 return 0;
351}
352
353static int qseecom_register_listener(struct qseecom_dev_handle *data,
354 void __user *argp)
355{
356 int ret = 0;
357 unsigned long flags;
358 struct qseecom_register_listener_req rcvd_lstnr;
359 struct qseecom_registered_listener_list *new_entry;
360
361 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
362 if (ret) {
363 pr_err("copy_from_user failed\n");
364 return ret;
365 }
Zhen Kongf4948192013-11-25 13:05:35 -0800366 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
367 rcvd_lstnr.sb_size))
368 return -EFAULT;
369
Mona Hossain0af10ab2012-02-28 18:26:41 -0800370 data->listener.id = 0;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800371 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800372 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800373 data->released = true;
374 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800375 }
376
377 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
378 if (!new_entry) {
379 pr_err("kmalloc failed\n");
380 return -ENOMEM;
381 }
382 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
383 new_entry->rcv_req_flag = 0;
384
385 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
386 new_entry->sb_length = rcvd_lstnr.sb_size;
Zhen Kongf4948192013-11-25 13:05:35 -0800387 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800388 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
389 pr_err("qseecom_set_sb_memoryfailed\n");
390 kzfree(new_entry);
391 return -ENOMEM;
392 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800393
Mona Hossain2892b6b2012-02-17 13:53:11 -0800394 init_waitqueue_head(&new_entry->rcv_req_wq);
395
396 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
397 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
398 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800399
Zhen Kong5eb9faa2019-09-20 13:49:41 -0700400 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800401 return ret;
402}
403
404static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
405{
406 int ret = 0;
407 unsigned long flags;
408 uint32_t unmap_mem = 0;
409 struct qseecom_register_listener_ireq req;
410 struct qseecom_registered_listener_list *ptr_svc = NULL;
411 struct qseecom_command_scm_resp resp;
412 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
413
Zhen Kong5eb9faa2019-09-20 13:49:41 -0700414 if (data->released) {
415 pr_err("Don't unregister lsnr %d\n", data->listener.id);
416 return -EINVAL;
417 }
418
Mona Hossaind4613de2013-05-15 16:49:29 -0700419 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
420 req.listener_id = data->listener.id;
421 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800422
Mona Hossaind4613de2013-05-15 16:49:29 -0700423 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800424 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700425 if (ret) {
426 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
427 ret, data->listener.id);
428 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800429 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700430
431 if (resp.result != QSEOS_RESULT_SUCCESS) {
432 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
433 resp.result, data->listener.id);
434 return -EPERM;
435 }
436
Mona Hossain2892b6b2012-02-17 13:53:11 -0800437 data->abort = 1;
438 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
439 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
440 list) {
441 if (ptr_svc->svc.listener_id == data->listener.id) {
442 wake_up_all(&ptr_svc->rcv_req_wq);
443 break;
444 }
445 }
446 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
447
448 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700449 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800450 atomic_read(&data->ioctl_count) <= 1)) {
451 pr_err("Interrupted from abort\n");
452 ret = -ERESTARTSYS;
453 break;
454 }
455 }
456
457 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
458 list_for_each_entry(ptr_svc,
459 &qseecom.registered_listener_list_head,
460 list)
461 {
462 if (ptr_svc->svc.listener_id == data->listener.id) {
463 if (ptr_svc->sb_virt) {
464 unmap_mem = 1;
465 ihandle = ptr_svc->ihandle;
466 }
467 list_del(&ptr_svc->list);
468 kzfree(ptr_svc);
469 break;
470 }
471 }
472 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
473
474 /* Unmap the memory */
475 if (unmap_mem) {
476 if (!IS_ERR_OR_NULL(ihandle)) {
477 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
478 ion_free(qseecom.ion_clnt, ihandle);
479 }
480 }
481 data->released = true;
482 return ret;
483}
484
Zhen Kong2edf90d2013-08-27 12:05:06 -0700485static int __qseecom_set_msm_bus_request(uint32_t mode)
486{
487 int ret = 0;
488 struct qseecom_clk *qclk;
489
490 qclk = &qseecom.qsee;
491 if (qclk->ce_core_src_clk != NULL) {
492 if (mode == INACTIVE) {
493 __qseecom_disable_clk(CLK_QSEE);
494 } else {
495 ret = __qseecom_enable_clk(CLK_QSEE);
496 if (ret)
497 pr_err("CLK enabling failed (%d) MODE (%d)\n",
498 ret, mode);
499 }
500 }
501
502 if ((!ret) && (qseecom.current_mode != mode)) {
503 ret = msm_bus_scale_client_update_request(
504 qseecom.qsee_perf_client, mode);
505 if (ret) {
506 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
507 ret, mode);
508 if (qclk->ce_core_src_clk != NULL) {
509 if (mode == INACTIVE)
510 __qseecom_enable_clk(CLK_QSEE);
511 else
512 __qseecom_disable_clk(CLK_QSEE);
513 }
514 }
515 qseecom.current_mode = mode;
516 }
517 return ret;
518}
519
520static void qseecom_bw_inactive_req_work(struct work_struct *work)
521{
522 mutex_lock(&app_access_lock);
523 mutex_lock(&qsee_bw_mutex);
524 __qseecom_set_msm_bus_request(INACTIVE);
525 pr_debug("current_mode = %d, cumulative_mode = %d\n",
526 qseecom.current_mode, qseecom.cumulative_mode);
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800527 qseecom.timer_running = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700528 mutex_unlock(&qsee_bw_mutex);
529 mutex_unlock(&app_access_lock);
530 return;
531}
532
533static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
534{
535 schedule_work(&qseecom.bw_inactive_req_ws);
536 return;
537}
538
Zhen Kongca4c2d52014-03-12 13:22:46 -0700539static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800540{
541 struct qseecom_clk *qclk;
Zhen Kongca4c2d52014-03-12 13:22:46 -0700542 int ret = 0;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800543 mutex_lock(&clk_access_lock);
544 if (ce == CLK_QSEE)
545 qclk = &qseecom.qsee;
546 else
547 qclk = &qseecom.ce_drv;
548
Zhen Kongca4c2d52014-03-12 13:22:46 -0700549 if (qclk->clk_access_cnt > 2) {
550 pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
551 ret = -EINVAL;
552 goto err_dec_ref_cnt;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800553 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700554 if (qclk->clk_access_cnt == 2)
555 qclk->clk_access_cnt--;
556
557err_dec_ref_cnt:
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800558 mutex_unlock(&clk_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -0700559 return ret;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800560}
561
562
Zhen Kongaf950192014-02-05 17:36:23 -0800563static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700564{
565 int32_t ret = 0;
566 int32_t request_mode = INACTIVE;
567
568 mutex_lock(&qsee_bw_mutex);
569 if (mode == 0) {
570 if (qseecom.cumulative_mode > MEDIUM)
571 request_mode = HIGH;
572 else
573 request_mode = qseecom.cumulative_mode;
574 } else {
575 request_mode = mode;
576 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700577
Zhen Kongca4c2d52014-03-12 13:22:46 -0700578 ret = __qseecom_set_msm_bus_request(request_mode);
579 if (ret) {
580 pr_err("set msm bus request failed (%d),request_mode (%d)\n",
581 ret, request_mode);
582 goto err_scale_timer;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800583 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700584
585 if (qseecom.timer_running) {
586 ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
587 if (ret) {
588 pr_err("Failed to decrease clk ref count.\n");
589 goto err_scale_timer;
590 }
591 del_timer_sync(&(qseecom.bw_scale_down_timer));
592 qseecom.timer_running = false;
593 }
594err_scale_timer:
Zhen Kong2edf90d2013-08-27 12:05:06 -0700595 mutex_unlock(&qsee_bw_mutex);
596 return ret;
597}
598
599
600static int qseecom_unregister_bus_bandwidth_needs(
601 struct qseecom_dev_handle *data)
602{
603 int32_t ret = 0;
604
605 qseecom.cumulative_mode -= data->mode;
606 data->mode = INACTIVE;
607
608 return ret;
609}
610
611static int __qseecom_register_bus_bandwidth_needs(
612 struct qseecom_dev_handle *data, uint32_t request_mode)
613{
614 int32_t ret = 0;
615
616 if (data->mode == INACTIVE) {
617 qseecom.cumulative_mode += request_mode;
618 data->mode = request_mode;
619 } else {
620 if (data->mode != request_mode) {
621 qseecom.cumulative_mode -= data->mode;
622 qseecom.cumulative_mode += request_mode;
623 data->mode = request_mode;
624 }
625 }
626 return ret;
627}
628
Zhen Kongd08301c2014-10-08 17:02:54 -0700629static int qseecom_perf_enable(struct qseecom_dev_handle *data)
630{
631 int ret = 0;
632 ret = qsee_vote_for_clock(data, CLK_DFAB);
633 if (ret) {
634 pr_err("Failed to vote for DFAB clock with err %d\n", ret);
635 goto perf_enable_exit;
636 }
637 ret = qsee_vote_for_clock(data, CLK_SFPB);
638 if (ret) {
639 qsee_disable_clock_vote(data, CLK_DFAB);
640 pr_err("Failed to vote for SFPB clock with err %d\n", ret);
641 goto perf_enable_exit;
642 }
643
644perf_enable_exit:
645 return ret;
646}
647
Zhen Kong2edf90d2013-08-27 12:05:06 -0700648static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
649 void __user *argp)
650{
651 int32_t ret = 0;
652 int32_t req_mode;
653
654 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
655 if (ret) {
656 pr_err("copy_from_user failed\n");
657 return ret;
658 }
659 if (req_mode > HIGH) {
660 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
Mona Hossain268c3122014-11-03 17:05:48 -0800661 return -EINVAL;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700662 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700663
Zhen Kongd08301c2014-10-08 17:02:54 -0700664 /*
665 * Register bus bandwidth needs if bus scaling feature is enabled;
666 * otherwise, qseecom enable/disable clocks for the client directly.
667 */
668 if (qseecom.support_bus_scaling) {
669 mutex_lock(&qsee_bw_mutex);
670 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
671 mutex_unlock(&qsee_bw_mutex);
672 } else {
673 pr_debug("Bus scaling feature is NOT enabled\n");
674 pr_debug("request bandwidth mode %d for the client\n",
675 req_mode);
676 if (req_mode != INACTIVE) {
677 ret = qseecom_perf_enable(data);
678 if (ret)
679 pr_err("Failed to vote for clock with err %d\n",
680 ret);
681 } else {
682 qsee_disable_clock_vote(data, CLK_DFAB);
683 qsee_disable_clock_vote(data, CLK_SFPB);
684 }
685 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700686 return ret;
687}
688
Zhen Kongaf950192014-02-05 17:36:23 -0800689static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
690{
691 mutex_lock(&qsee_bw_mutex);
692 qseecom.bw_scale_down_timer.expires = jiffies +
693 msecs_to_jiffies(duration);
Zhen Konge5b434e2014-04-17 16:47:06 -0700694 mod_timer(&(qseecom.bw_scale_down_timer),
695 qseecom.bw_scale_down_timer.expires);
Zhen Kongaf950192014-02-05 17:36:23 -0800696 qseecom.timer_running = true;
697 mutex_unlock(&qsee_bw_mutex);
698}
699
Zhen Kong2edf90d2013-08-27 12:05:06 -0700700static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
701{
702 if (!qseecom.support_bus_scaling)
703 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -0800704 else
705 __qseecom_add_bw_scale_down_timer(
706 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700707 return;
708}
709
710static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
711{
712 int ret = 0;
713 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -0700714 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
715 if (ret)
716 pr_err("Failed to set bw MEDIUM.\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700717 } else {
718 ret = qsee_vote_for_clock(data, CLK_SFPB);
719 if (ret)
720 pr_err("Fail vote for clk SFPB ret %d\n", ret);
721 }
722 return ret;
723}
724
Mona Hossain2892b6b2012-02-17 13:53:11 -0800725static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
726 void __user *argp)
727{
728 ion_phys_addr_t pa;
729 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800730 struct qseecom_set_sb_mem_param_req req;
731 uint32_t len;
732
733 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700734 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800735 return -EFAULT;
736
Mona Hossaina1124de2013-10-01 13:41:09 -0700737 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
738 (req.sb_len == 0)) {
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +0530739 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%pK)\n",
740 req.ifd_data_fd, req.sb_len, (void *)req.virt_sb_base);
Mona Hossaina1124de2013-10-01 13:41:09 -0700741 return -EFAULT;
742 }
Zhen Kongf4948192013-11-25 13:05:35 -0800743 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
744 req.sb_len))
745 return -EFAULT;
746
Mona Hossain2892b6b2012-02-17 13:53:11 -0800747 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800748 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
749 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800750 if (IS_ERR_OR_NULL(data->client.ihandle)) {
751 pr_err("Ion client could not retrieve the handle\n");
752 return -ENOMEM;
753 }
754 /* Get the physical address of the ION BUF */
755 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800756 if (ret) {
757
758 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
759 ret);
760 return ret;
761 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800762 /* Populate the structure for sending scm call to load image */
763 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700764 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800765 data->client.sb_phys = pa;
766 data->client.sb_length = req.sb_len;
767 data->client.user_virt_sb_base = req.virt_sb_base;
768 return 0;
769}
770
Mona Hossain2892b6b2012-02-17 13:53:11 -0800771static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
772{
773 int ret;
774 ret = (qseecom.send_resp_flag != 0);
775 return ret || data->abort;
776}
777
778static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
779 struct qseecom_command_scm_resp *resp)
780{
781 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800782 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800783 uint32_t lstnr;
784 unsigned long flags;
785 struct qseecom_client_listener_data_irsp send_data_rsp;
786 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700787 sigset_t new_sigset;
788 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800789
Mona Hossain2892b6b2012-02-17 13:53:11 -0800790 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
791 lstnr = resp->data;
792 /*
793 * Wake up blocking lsitener service with the lstnr id
794 */
795 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
796 flags);
797 list_for_each_entry(ptr_svc,
798 &qseecom.registered_listener_list_head, list) {
799 if (ptr_svc->svc.listener_id == lstnr) {
800 ptr_svc->rcv_req_flag = 1;
801 wake_up_interruptible(&ptr_svc->rcv_req_wq);
802 break;
803 }
804 }
805 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
806 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700807
808 if (ptr_svc == NULL) {
809 pr_err("Listener Svc %d does not exist\n", lstnr);
810 return -EINVAL;
811 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800812 if (ptr_svc->svc.listener_id != lstnr) {
813 pr_warning("Service requested for does on exist\n");
814 return -ERESTARTSYS;
815 }
816 pr_debug("waking up rcv_req_wq and "
817 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800818
Mona Hossain91da2c52013-03-29 17:28:31 -0700819 /* initialize the new signal mask with all signals*/
820 sigfillset(&new_sigset);
821 /* block all signals */
822 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
823
824 do {
825 if (!wait_event_freezable(qseecom.send_resp_wq,
826 __qseecom_listener_has_sent_rsp(data)))
827 break;
828 } while (1);
829
830 /* restore signal mask */
831 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
832 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700833 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
834 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700835 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800836 send_data_rsp.status = QSEOS_RESULT_FAILURE;
837 } else {
838 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800839 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800840
Mona Hossain2892b6b2012-02-17 13:53:11 -0800841 qseecom.send_resp_flag = 0;
842 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
843 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700844 if (ptr_svc)
845 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
846 ptr_svc->sb_virt, ptr_svc->sb_length,
847 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700848
849 if (lstnr == RPMB_SERVICE)
850 __qseecom_enable_clk(CLK_QSEE);
851
Mona Hossain2892b6b2012-02-17 13:53:11 -0800852 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
853 (const void *)&send_data_rsp,
854 sizeof(send_data_rsp), resp,
855 sizeof(*resp));
856 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700857 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800858 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700859 if (lstnr == RPMB_SERVICE)
860 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800861 return ret;
862 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800863 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
864 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
865 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
866 resp->result, data->client.app_id, lstnr);
867 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700868 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700869 if (lstnr == RPMB_SERVICE)
870 __qseecom_disable_clk(CLK_QSEE);
871
Mona Hossain2892b6b2012-02-17 13:53:11 -0800872 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800873 if (rc)
874 return rc;
875
Mona Hossain2892b6b2012-02-17 13:53:11 -0800876 return ret;
877}
878
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700879static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
880{
881 int32_t ret;
882 struct qseecom_command_scm_resp resp;
883
884 /* SCM_CALL to check if app_id for the mentioned app exists */
885 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
886 sizeof(struct qseecom_check_app_ireq),
887 &resp, sizeof(resp));
888 if (ret) {
889 pr_err("scm_call to check if app is already loaded failed\n");
890 return -EINVAL;
891 }
892
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700893 if (resp.result == QSEOS_RESULT_FAILURE) {
894 return 0;
895 } else {
896 switch (resp.resp_type) {
897 /*qsee returned listener type response */
898 case QSEOS_LISTENER_ID:
899 pr_err("resp type is of listener type instead of app");
900 return -EINVAL;
901 break;
902 case QSEOS_APP_ID:
903 return resp.data;
904 default:
905 pr_err("invalid resp type (%d) from qsee",
906 resp.resp_type);
907 return -ENODEV;
908 break;
909 }
910 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700911}
912
Mona Hossain2892b6b2012-02-17 13:53:11 -0800913static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
914{
915 struct qseecom_registered_app_list *entry = NULL;
916 unsigned long flags = 0;
917 u32 app_id = 0;
918 struct ion_handle *ihandle; /* Ion handle */
919 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700920 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800921 ion_phys_addr_t pa = 0;
922 uint32_t len;
923 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800924 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700925 struct qseecom_load_app_ireq load_req;
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +0800926 bool first_time = false;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700927
Mona Hossain2892b6b2012-02-17 13:53:11 -0800928 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700929 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800930 (void __user *)argp,
931 sizeof(struct qseecom_load_img_req))) {
932 pr_err("copy_from_user failed\n");
933 return -EFAULT;
934 }
Zhen Kong4bead3c2014-04-14 15:07:13 -0700935
936 if (qseecom.support_bus_scaling) {
937 mutex_lock(&qsee_bw_mutex);
938 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
939 mutex_unlock(&qsee_bw_mutex);
940 if (ret)
941 return ret;
942 }
943
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700944 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700945 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700946 if (ret)
Zhen Kong4bead3c2014-04-14 15:07:13 -0700947 goto enable_clk_err;
948
Mona Hossain436b75f2012-11-20 17:10:40 -0800949 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700950 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -0700951 strlcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800952
Mona Hossain436b75f2012-11-20 17:10:40 -0800953 ret = __qseecom_check_app_exists(req);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700954 if (ret < 0)
955 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800956
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530957 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800958 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700959 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800960 (char *)(req.app_name));
961 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
962 list_for_each_entry(entry,
963 &qseecom.registered_app_list_head, list){
964 if (entry->app_id == app_id) {
965 entry->ref_cnt++;
966 break;
967 }
968 }
969 spin_unlock_irqrestore(
970 &qseecom.registered_app_list_lock, flags);
Zhen Kong3a5eaac2014-06-12 12:16:12 -0700971 ret = 0;
Mona Hossain436b75f2012-11-20 17:10:40 -0800972 } else {
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +0800973 first_time = true;
Mona Hossain436b75f2012-11-20 17:10:40 -0800974 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700975 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800976 /* Get the handle of the shared fd */
977 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800978 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800979 if (IS_ERR_OR_NULL(ihandle)) {
980 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -0700981 ret = -ENOMEM;
982 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800983 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800984
Mona Hossain436b75f2012-11-20 17:10:40 -0800985 /* Get the physical address of the ION BUF */
986 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800987 if (ret) {
988 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
989 ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700990 goto loadapp_err;
Zhen Kong05ed4462014-01-28 18:21:30 -0800991 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800992
Mona Hossain436b75f2012-11-20 17:10:40 -0800993 /* Populate the structure for sending scm call to load image */
William Clarkba7f03c2015-03-09 12:07:49 -0700994 strlcpy(load_req.app_name, load_img_req.img_name,
Mona Hossain436b75f2012-11-20 17:10:40 -0800995 MAX_APP_NAME_SIZE);
996 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
997 load_req.mdt_len = load_img_req.mdt_len;
998 load_req.img_len = load_img_req.img_len;
999 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001000 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
1001 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001002
Mona Hossain436b75f2012-11-20 17:10:40 -08001003 /* SCM_CALL to load the app and get the app_id back */
1004 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001005 sizeof(struct qseecom_load_app_ireq),
1006 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001007 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -08001008 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001009 if (!IS_ERR_OR_NULL(ihandle))
1010 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001011 ret = -EINVAL;
1012 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001013 }
1014
1015 if (resp.result == QSEOS_RESULT_FAILURE) {
1016 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001017 if (!IS_ERR_OR_NULL(ihandle))
1018 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001019 ret = -EFAULT;
1020 goto loadapp_err;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001021 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001022
Mona Hossain436b75f2012-11-20 17:10:40 -08001023 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1024 ret = __qseecom_process_incomplete_cmd(data, &resp);
1025 if (ret) {
1026 pr_err("process_incomplete_cmd failed err: %d\n",
1027 ret);
1028 if (!IS_ERR_OR_NULL(ihandle))
1029 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001030 ret = -EFAULT;
1031 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001032 }
1033 }
1034
1035 if (resp.result != QSEOS_RESULT_SUCCESS) {
1036 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001037 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -08001038 if (!IS_ERR_OR_NULL(ihandle))
1039 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001040 ret = -EFAULT;
1041 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001042 }
1043
1044 app_id = resp.data;
1045
1046 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1047 if (!entry) {
1048 pr_err("kmalloc failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001049 ret = -ENOMEM;
1050 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001051 }
1052 entry->app_id = app_id;
1053 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07001054 strlcpy(entry->app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001055 MAX_APP_NAME_SIZE);
Mona Hossain436b75f2012-11-20 17:10:40 -08001056 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001057 if (!IS_ERR_OR_NULL(ihandle))
1058 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001059
Mona Hossain436b75f2012-11-20 17:10:40 -08001060 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1061 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1062 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1063 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001064
Mona Hossain436b75f2012-11-20 17:10:40 -08001065 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -07001066 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -08001067 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001068 data->client.app_id = app_id;
William Clarkba7f03c2015-03-09 12:07:49 -07001069 strlcpy(data->client.app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001070 MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001071 load_img_req.app_id = app_id;
1072 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
1073 pr_err("copy_to_user failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001074 ret = -EFAULT;
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +08001075 if (first_time == true) {
1076 spin_lock_irqsave(
1077 &qseecom.registered_app_list_lock, flags);
1078 list_del(&entry->list);
1079 spin_unlock_irqrestore(
1080 &qseecom.registered_app_list_lock, flags);
1081 kzfree(entry);
1082 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001083 }
Zhen Kong4bead3c2014-04-14 15:07:13 -07001084
1085loadapp_err:
Zhen Kong2edf90d2013-08-27 12:05:06 -07001086 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001087enable_clk_err:
1088 if (qseecom.support_bus_scaling) {
1089 mutex_lock(&qsee_bw_mutex);
1090 qseecom_unregister_bus_bandwidth_needs(data);
1091 mutex_unlock(&qsee_bw_mutex);
1092 }
1093 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001094}
1095
1096static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
1097{
1098 wake_up_all(&qseecom.send_resp_wq);
1099 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001100 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001101 atomic_read(&data->ioctl_count) <= 1)) {
1102 pr_err("Interrupted from abort\n");
1103 return -ERESTARTSYS;
1104 break;
1105 }
1106 }
1107 /* Set unload app */
1108 return 1;
1109}
1110
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001111static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
1112{
1113 int ret = 0;
1114 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
1115 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
1116 ion_free(qseecom.ion_clnt, data->client.ihandle);
jitendrathakareaaa7e1c2019-09-12 19:46:48 +05301117 memset((void *)&data->client,
1118 0, sizeof(struct qseecom_client_handle));
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001119 }
1120 return ret;
1121}
1122
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001123static int qseecom_unload_app(struct qseecom_dev_handle *data,
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001124 bool app_crash)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001125{
1126 unsigned long flags;
William Clarkc7a043d2014-05-23 15:08:52 -07001127 unsigned long flags1;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001128 int ret = 0;
1129 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001130 struct qseecom_registered_app_list *ptr_app = NULL;
Mona Hossain340dba82012-08-07 19:54:46 -07001131 bool unload = false;
1132 bool found_app = false;
William Clarkc7a043d2014-05-23 15:08:52 -07001133 bool found_dead_app = false;
1134
1135 if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
Zhen Kong763307c2014-09-12 12:58:13 -07001136 pr_debug("Do not unload keymaster app from tz\n");
1137 goto unload_exit;
William Clarkc7a043d2014-05-23 15:08:52 -07001138 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001139
Mona Hossaind4613de2013-05-15 16:49:29 -07001140 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001141 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1142 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001143 list) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001144 if (ptr_app->app_id == data->client.app_id) {
William Clarkc7a043d2014-05-23 15:08:52 -07001145 if (!memcmp((void *)ptr_app->app_name,
1146 (void *)data->client.app_name,
1147 strlen(data->client.app_name))) {
1148 found_app = true;
1149 if (app_crash || ptr_app->ref_cnt == 1)
1150 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001151 break;
1152 } else {
William Clarkc7a043d2014-05-23 15:08:52 -07001153 found_dead_app = true;
1154 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001155 }
1156 }
1157 }
1158 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1159 flags);
William Clarkc7a043d2014-05-23 15:08:52 -07001160 if (found_app == false && found_dead_app == false) {
1161 pr_err("Cannot find app with id = %d (%s)\n",
1162 data->client.app_id,
1163 (char *)data->client.app_name);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001164 return -EINVAL;
1165 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001166 }
1167
William Clarkc7a043d2014-05-23 15:08:52 -07001168 if (found_dead_app) {
1169 pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
1170 (char *)data->client.app_name);
1171 __qseecom_cleanup_app(data);
1172 }
1173
Mona Hossaind4613de2013-05-15 16:49:29 -07001174 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001175 struct qseecom_unload_app_ireq req;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001176 /* Populate the structure for sending scm call to load image */
1177 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1178 req.app_id = data->client.app_id;
1179
1180 /* SCM_CALL to unload the app */
1181 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1182 sizeof(struct qseecom_unload_app_ireq),
1183 &resp, sizeof(resp));
1184 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001185 pr_err("scm_call to unload app (id = %d) failed\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001186 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001187 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001188 } else {
1189 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001190 }
William Clarkc7a043d2014-05-23 15:08:52 -07001191 if (resp.result == QSEOS_RESULT_FAILURE) {
1192 pr_err("app (%d) unload_failed!!\n",
1193 data->client.app_id);
1194 return -EFAULT;
1195 }
1196 if (resp.result == QSEOS_RESULT_SUCCESS)
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301197 pr_debug("App (%d) is unloaded!!\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001198 data->client.app_id);
1199 __qseecom_cleanup_app(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001200 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1201 ret = __qseecom_process_incomplete_cmd(data, &resp);
1202 if (ret) {
1203 pr_err("process_incomplete_cmd fail err: %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001204 ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001205 return ret;
1206 }
1207 }
1208 }
William Clarkc7a043d2014-05-23 15:08:52 -07001209
1210 if (found_app) {
1211 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
1212 if (app_crash) {
1213 ptr_app->ref_cnt = 0;
1214 pr_debug("app_crash: ref_count = 0\n");
1215 } else {
1216 if (ptr_app->ref_cnt == 1) {
1217 ptr_app->ref_cnt = 0;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301218 pr_debug("ref_count set to 0\n");
William Clarkc7a043d2014-05-23 15:08:52 -07001219 } else {
1220 ptr_app->ref_cnt--;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301221 pr_debug("Can't unload app(%d) inuse\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001222 ptr_app->app_id);
1223 }
1224 }
1225 if (unload) {
1226 list_del(&ptr_app->list);
1227 kzfree(ptr_app);
1228 }
1229 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1230 flags1);
1231 }
Zhen Kong763307c2014-09-12 12:58:13 -07001232unload_exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001233 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001234 data->released = true;
1235 return ret;
1236}
1237
1238static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1239 uint32_t virt)
1240{
1241 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1242}
1243
Zhen Kongf4948192013-11-25 13:05:35 -08001244static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1245 uint32_t virt)
1246{
1247 return (uint32_t)data->client.sb_virt +
1248 (virt - data->client.user_virt_sb_base);
1249}
1250
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001251int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1252 struct qseecom_send_svc_cmd_req *req_ptr,
1253 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1254{
1255 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001256 void *req_buf = NULL;
1257
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001258 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
Jeron Susan84186d42016-11-03 10:02:25 +08001259 pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001260 req_ptr, send_svc_ireq_ptr);
1261 return -EINVAL;
1262 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001263
Zhen Kong581df352017-04-28 16:13:57 +08001264
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001265 /* Clients need to ensure req_buf is at base offset of shared buffer */
1266 if ((uint32_t)req_ptr->cmd_req_buf !=
1267 data_ptr->client.user_virt_sb_base) {
1268 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001269 return -EINVAL;
1270 }
1271
Zhen Kong581df352017-04-28 16:13:57 +08001272 if (data_ptr->client.sb_length <
1273 sizeof(struct qseecom_rpmb_provision_key)) {
1274 pr_err("shared buffer is too small to hold key type\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001275 return -EINVAL;
1276 }
1277
1278 req_buf = data_ptr->client.sb_virt;
1279
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001280 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1281 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001282 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001283 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1284 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1285 (uint32_t)req_ptr->resp_buf));
1286 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1287
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001288 return ret;
1289}
1290
Zhen Kong581df352017-04-28 16:13:57 +08001291static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
1292 struct qseecom_send_svc_cmd_req *req)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001293{
Zhen Kong581df352017-04-28 16:13:57 +08001294 if (!req || !req->resp_buf || !req->cmd_req_buf) {
1295 pr_err("req or cmd buffer or response buffer is null\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001296 return -EINVAL;
1297 }
1298
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001299 if (data->client.sb_virt == NULL) {
1300 pr_err("sb_virt null\n");
1301 return -EINVAL;
1302 }
1303
1304 if (data->client.user_virt_sb_base == 0) {
1305 pr_err("user_virt_sb_base is null\n");
1306 return -EINVAL;
1307 }
1308
1309 if (data->client.sb_length == 0) {
1310 pr_err("sb_length is 0\n");
1311 return -EINVAL;
1312 }
1313
Zhen Kong581df352017-04-28 16:13:57 +08001314 if (((uintptr_t)req->cmd_req_buf <
1315 data->client.user_virt_sb_base) ||
1316 ((uintptr_t)req->cmd_req_buf >=
1317 (data->client.user_virt_sb_base + data->client.sb_length))) {
1318 pr_err("cmd buffer address not within shared bufffer\n");
1319 return -EINVAL;
1320 }
1321 if (((uintptr_t)req->resp_buf <
1322 data->client.user_virt_sb_base) ||
1323 ((uintptr_t)req->resp_buf >=
1324 (data->client.user_virt_sb_base + data->client.sb_length))) {
1325 pr_err("response buffer address not within shared bufffer\n");
1326 return -EINVAL;
1327 }
1328 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
1329 (req->cmd_req_len > data->client.sb_length) ||
1330 (req->resp_len > data->client.sb_length)) {
1331 pr_err("cmd buf length or response buf length not valid\n");
1332 return -EINVAL;
1333 }
1334 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1335 pr_err("Integer overflow detected in req_len & rsp_len\n");
1336 return -EINVAL;
1337 }
1338
1339 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1340 pr_debug("Not enough memory to fit cmd_buf.\n");
1341 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1342 (req->cmd_req_len + req->resp_len),
1343 data->client.sb_length);
1344 return -ENOMEM;
1345 }
1346 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1347 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1348 return -EINVAL;
1349 }
1350 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1351 pr_err("Integer overflow in resp_len & resp_buf\n");
1352 return -EINVAL;
1353 }
1354 if (data->client.user_virt_sb_base >
1355 (ULONG_MAX - data->client.sb_length)) {
1356 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1357 return -EINVAL;
1358 }
1359 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1360 ((uintptr_t)data->client.user_virt_sb_base +
1361 data->client.sb_length)) ||
1362 (((uintptr_t)req->resp_buf + req->resp_len) >
1363 ((uintptr_t)data->client.user_virt_sb_base +
1364 data->client.sb_length))) {
1365 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1366 return -EINVAL;
1367 }
1368 return 0;
1369}
1370
1371static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1372 void __user *argp)
1373{
1374 int ret = 0;
1375 struct qseecom_client_send_service_ireq send_svc_ireq;
1376 struct qseecom_command_scm_resp resp;
1377 struct qseecom_send_svc_cmd_req req;
1378
1379 /*struct qseecom_command_scm_resp resp;*/
1380
1381 if (copy_from_user(&req,
1382 (void __user *)argp,
1383 sizeof(req))) {
1384 pr_err("copy_from_user failed\n");
1385 return -EFAULT;
1386 }
1387
1388 if (__validate_send_service_cmd_inputs(data, &req))
1389 return -EINVAL;
1390
Zhen Kong2edf90d2013-08-27 12:05:06 -07001391 data->type = QSEECOM_SECURE_SERVICE;
1392
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001393 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001394 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1395 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001396 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1397 &send_svc_ireq))
1398 return -EINVAL;
1399 break;
1400 default:
1401 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1402 return -EINVAL;
1403 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301404
Zhen Kong2edf90d2013-08-27 12:05:06 -07001405 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001406 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001407 if (ret) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001408 pr_err("Fail to set bw HIGH\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -07001409 return ret;
1410 }
1411 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07001412 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001413 if (ret) {
Zhen Kongd08301c2014-10-08 17:02:54 -07001414 pr_err("Failed to vote for clocks with err %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001415 goto exit;
1416 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301417 }
1418
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001419 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1420 data->client.sb_virt, data->client.sb_length,
1421 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001422 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1423 sizeof(send_svc_ireq),
1424 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001425 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1426 data->client.sb_virt, data->client.sb_length,
1427 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001428 if (ret) {
1429 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001430 if (!qseecom.support_bus_scaling) {
1431 qsee_disable_clock_vote(data, CLK_DFAB);
1432 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -08001433 } else {
1434 __qseecom_add_bw_scale_down_timer(
1435 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001436 }
1437 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001438 }
1439
1440 switch (resp.result) {
1441 case QSEOS_RESULT_SUCCESS:
1442 break;
1443 case QSEOS_RESULT_INCOMPLETE:
1444 pr_err("qseos_result_incomplete\n");
1445 ret = __qseecom_process_incomplete_cmd(data, &resp);
1446 if (ret) {
1447 pr_err("process_incomplete_cmd fail: err: %d\n",
1448 ret);
1449 }
1450 break;
1451 case QSEOS_RESULT_FAILURE:
1452 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1453 break;
1454 default:
1455 pr_err("Response result %d not supported\n",
1456 resp.result);
1457 ret = -EINVAL;
1458 break;
1459 }
Zhen Kongaf950192014-02-05 17:36:23 -08001460 if (!qseecom.support_bus_scaling) {
1461 qsee_disable_clock_vote(data, CLK_DFAB);
1462 qsee_disable_clock_vote(data, CLK_SFPB);
1463 } else {
1464 __qseecom_add_bw_scale_down_timer(
1465 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1466 }
1467
Zhen Kong2edf90d2013-08-27 12:05:06 -07001468exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001469 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001470}
1471
Mona Hossain268c3122014-11-03 17:05:48 -08001472static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
1473 struct qseecom_send_cmd_req *req)
1474{
1475 if (!data || !data->client.ihandle) {
1476 pr_err("Client or client handle is not initialized\n");
1477 return -EINVAL;
1478 }
1479 if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
1480 (req->cmd_req_buf == NULL)) {
1481 pr_err("cmd buffer or response buffer is null\n");
1482 return -EINVAL;
1483 }
1484 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1485 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1486 data->client.sb_length))) {
1487 pr_err("cmd buffer address not within shared bufffer\n");
1488 return -EINVAL;
1489 }
1490 if (((uintptr_t)req->resp_buf <
1491 data->client.user_virt_sb_base) ||
1492 ((uintptr_t)req->resp_buf >=
1493 (data->client.user_virt_sb_base + data->client.sb_length))) {
1494 pr_err("response buffer address not within shared bufffer\n");
1495 return -EINVAL;
1496 }
1497 if ((req->cmd_req_len == 0) ||
1498 (req->cmd_req_len > data->client.sb_length) ||
1499 (req->resp_len > data->client.sb_length)) {
1500 pr_err("cmd buf length or response buf length not valid\n");
1501 return -EINVAL;
1502 }
1503 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1504 pr_err("Integer overflow detected in req_len & rsp_len\n");
1505 return -EINVAL;
1506 }
1507
1508 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1509 pr_debug("Not enough memory to fit cmd_buf.\n");
1510 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1511 (req->cmd_req_len + req->resp_len),
1512 data->client.sb_length);
1513 return -ENOMEM;
1514 }
1515 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1516 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1517 return -EINVAL;
1518 }
1519 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1520 pr_err("Integer overflow in resp_len & resp_buf\n");
1521 return -EINVAL;
1522 }
1523 if (data->client.user_virt_sb_base >
1524 (ULONG_MAX - data->client.sb_length)) {
1525 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1526 return -EINVAL;
1527 }
1528 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1529 ((uintptr_t)data->client.user_virt_sb_base +
1530 data->client.sb_length)) ||
1531 (((uintptr_t)req->resp_buf + req->resp_len) >
1532 ((uintptr_t)data->client.user_virt_sb_base +
1533 data->client.sb_length))) {
1534 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1535 return -EINVAL;
1536 }
1537 return 0;
1538}
1539
Mona Hossain2892b6b2012-02-17 13:53:11 -08001540static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1541 struct qseecom_send_cmd_req *req)
1542{
1543 int ret = 0;
1544 u32 reqd_len_sb_in = 0;
1545 struct qseecom_client_send_data_ireq send_data_req;
1546 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001547 unsigned long flags;
1548 struct qseecom_registered_app_list *ptr_app;
1549 bool found_app = false;
William Clark3f378a42014-07-03 15:32:13 -07001550 int name_len = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001551
Mona Hossain2892b6b2012-02-17 13:53:11 -08001552 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
William Clarkc7a043d2014-05-23 15:08:52 -07001553 /* find app_id & img_name from list */
1554 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1555 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
1556 list) {
William Clark3f378a42014-07-03 15:32:13 -07001557 name_len = min(strlen(data->client.app_name),
1558 strlen(ptr_app->app_name));
William Clarkc7a043d2014-05-23 15:08:52 -07001559 if ((ptr_app->app_id == data->client.app_id) &&
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001560 (!memcmp(ptr_app->app_name,
1561 data->client.app_name, name_len))) {
William Clarkc7a043d2014-05-23 15:08:52 -07001562 found_app = true;
1563 break;
1564 }
1565 }
1566 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
1567
1568 if (!found_app) {
1569 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
1570 (char *)data->client.app_name);
1571 return -EINVAL;
1572 }
1573
Mona Hossain2892b6b2012-02-17 13:53:11 -08001574 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1575 send_data_req.app_id = data->client.app_id;
1576 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1577 (uint32_t)req->cmd_req_buf));
1578 send_data_req.req_len = req->cmd_req_len;
1579 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1580 (uint32_t)req->resp_buf));
1581 send_data_req.rsp_len = req->resp_len;
1582
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001583 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1584 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001585 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001586 ION_IOC_CLEAN_INV_CACHES);
1587
Mona Hossain2892b6b2012-02-17 13:53:11 -08001588 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1589 sizeof(send_data_req),
1590 &resp, sizeof(resp));
1591 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001592 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1593 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001594 return ret;
1595 }
1596
1597 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1598 ret = __qseecom_process_incomplete_cmd(data, &resp);
1599 if (ret) {
1600 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1601 return ret;
1602 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001603 } else {
1604 if (resp.result != QSEOS_RESULT_SUCCESS) {
1605 pr_err("Response result %d not supported\n",
1606 resp.result);
1607 ret = -EINVAL;
1608 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001609 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001610 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1611 data->client.sb_virt, data->client.sb_length,
1612 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001613 return ret;
1614}
1615
Mona Hossain2892b6b2012-02-17 13:53:11 -08001616static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1617{
1618 int ret = 0;
1619 struct qseecom_send_cmd_req req;
1620
1621 ret = copy_from_user(&req, argp, sizeof(req));
1622 if (ret) {
1623 pr_err("copy_from_user failed\n");
1624 return ret;
1625 }
Mona Hossain268c3122014-11-03 17:05:48 -08001626
1627 if (__validate_send_cmd_inputs(data, &req))
1628 return -EINVAL;
1629
Mona Hossaind4613de2013-05-15 16:49:29 -07001630 ret = __qseecom_send_cmd(data, &req);
1631
Mona Hossain2892b6b2012-02-17 13:53:11 -08001632 if (ret)
1633 return ret;
1634
Mona Hossain2892b6b2012-02-17 13:53:11 -08001635 return ret;
1636}
1637
Mona Hossain268c3122014-11-03 17:05:48 -08001638int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
Mona Hossainb9470692014-10-09 12:00:03 -07001639 struct qseecom_send_modfd_listener_resp *lstnr_resp,
1640 struct qseecom_dev_handle *data, bool listener_svc,
1641 int i) {
Mona Hossainb9470692014-10-09 12:00:03 -07001642
1643 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001644 if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
1645 (cmd_req->ifd_data[i].cmd_buf_offset >
1646 cmd_req->cmd_req_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001647 pr_err("Invalid offset 0x%x\n",
1648 cmd_req->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001649 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001650 }
1651 } else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001652 if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
1653 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1654 lstnr_resp->resp_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001655 pr_err("Invalid offset 0x%x\n",
1656 lstnr_resp->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001657 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001658 }
1659 }
Mona Hossain268c3122014-11-03 17:05:48 -08001660 return 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001661}
1662
Mona Hossain268c3122014-11-03 17:05:48 -08001663#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001664static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1665 struct qseecom_dev_handle *data,
1666 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001667{
1668 struct ion_handle *ihandle;
1669 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001670 int ret = 0;
1671 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001672 uint32_t len = 0;
1673 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001674 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1675 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1676 struct qseecom_registered_listener_list *this_lstnr = NULL;
1677
1678 if (msg == NULL) {
1679 pr_err("Invalid address\n");
1680 return -EINVAL;
1681 }
1682 if (listener_svc) {
1683 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1684 this_lstnr = __qseecom_find_svc(data->listener.id);
1685 if (IS_ERR_OR_NULL(this_lstnr)) {
1686 pr_err("Invalid listener ID\n");
1687 return -ENOMEM;
1688 }
1689 } else {
1690 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1691 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001692
1693 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001694 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001695 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001696 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001697 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001698 if (IS_ERR_OR_NULL(ihandle)) {
1699 pr_err("Ion client can't retrieve the handle\n");
1700 return -ENOMEM;
1701 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001702 field = (char *) cmd_req->cmd_req_buf +
1703 cmd_req->ifd_data[i].cmd_buf_offset;
1704 } else if ((listener_svc) &&
1705 (lstnr_resp->ifd_data[i].fd > 0)) {
1706 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1707 lstnr_resp->ifd_data[i].fd);
1708 if (IS_ERR_OR_NULL(ihandle)) {
1709 pr_err("Ion client can't retrieve the handle\n");
1710 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001711 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001712 field = lstnr_resp->resp_buf_ptr +
1713 lstnr_resp->ifd_data[i].cmd_buf_offset;
1714 } else {
1715 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001716 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001717 /* Populate the cmd data structure with the phys_addr */
1718 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1719 if (sg_ptr == NULL) {
1720 pr_err("IOn client could not retrieve sg table\n");
1721 goto err;
1722 }
1723 if (sg_ptr->nents == 0) {
1724 pr_err("Num of scattered entries is 0\n");
1725 goto err;
1726 }
1727 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1728 pr_err("Num of scattered entries");
1729 pr_err(" (%d) is greater than max supported %d\n",
1730 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1731 goto err;
1732 }
1733 sg = sg_ptr->sgl;
1734 if (sg_ptr->nents == 1) {
1735 uint32_t *update;
1736 update = (uint32_t *) field;
Mona Hossainb9470692014-10-09 12:00:03 -07001737
Mona Hossain268c3122014-11-03 17:05:48 -08001738 if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
Mona Hossainb9470692014-10-09 12:00:03 -07001739 listener_svc, i))
1740 goto err;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001741 if (cleanup)
1742 *update = 0;
1743 else
1744 *update = (uint32_t)sg_dma_address(
1745 sg_ptr->sgl);
1746 len += (uint32_t)sg->length;
1747 } else {
1748 struct qseecom_sg_entry *update;
1749 int j = 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001750
1751 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001752 if ((cmd_req->cmd_req_len <
1753 SG_ENTRY_SZ * sg_ptr->nents) ||
1754 (cmd_req->ifd_data[i].cmd_buf_offset >
1755 (cmd_req->cmd_req_len -
1756 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001757 pr_err("Invalid offset = 0x%x\n",
1758 cmd_req->ifd_data[i].
1759 cmd_buf_offset);
1760 goto err;
1761 }
1762 } else if ((listener_svc) &&
1763 (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001764 if ((lstnr_resp->resp_len <
1765 SG_ENTRY_SZ * sg_ptr->nents) ||
1766 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1767 (lstnr_resp->resp_len -
1768 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001769 pr_err("Invalid offset = 0x%x\n",
1770 lstnr_resp->ifd_data[i].
1771 cmd_buf_offset);
1772 goto err;
1773 }
1774 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001775 update = (struct qseecom_sg_entry *) field;
1776 for (j = 0; j < sg_ptr->nents; j++) {
1777 if (cleanup) {
1778 update->phys_addr = 0;
1779 update->len = 0;
1780 } else {
1781 update->phys_addr = (uint32_t)
1782 sg_dma_address(sg);
1783 update->len = sg->length;
1784 }
1785 len += sg->length;
1786 update++;
1787 sg = sg_next(sg);
1788 }
1789 }
1790 if (cleanup)
1791 msm_ion_do_cache_op(qseecom.ion_clnt,
1792 ihandle, NULL, len,
1793 ION_IOC_INV_CACHES);
1794 else
1795 msm_ion_do_cache_op(qseecom.ion_clnt,
1796 ihandle, NULL, len,
1797 ION_IOC_CLEAN_INV_CACHES);
1798 /* Deallocate the handle */
1799 if (!IS_ERR_OR_NULL(ihandle))
1800 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001801 }
1802 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001803err:
1804 if (!IS_ERR_OR_NULL(ihandle))
1805 ion_free(qseecom.ion_clnt, ihandle);
1806 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001807}
1808
1809static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1810 void __user *argp)
1811{
1812 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001813 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001814 struct qseecom_send_modfd_cmd_req req;
1815 struct qseecom_send_cmd_req send_cmd_req;
1816
1817 ret = copy_from_user(&req, argp, sizeof(req));
1818 if (ret) {
1819 pr_err("copy_from_user failed\n");
1820 return ret;
1821 }
Zhen Kongf4948192013-11-25 13:05:35 -08001822
jeronf5cf7042016-07-26 16:13:50 +08001823 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1824 pr_err("cmd buffer or response buffer is null\n");
1825 return -EINVAL;
1826 }
1827 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1828 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1829 data->client.sb_length))) {
1830 pr_err("cmd buffer address not within shared bufffer\n");
1831 return -EINVAL;
1832 }
1833
1834 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1835 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1836 data->client.sb_length))){
1837 pr_err("response buffer address not within shared bufffer\n");
1838 return -EINVAL;
1839 }
Teow Wan Yee1a428fd2016-07-27 14:01:01 +08001840
1841 if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
1842 req.resp_len > data->client.sb_length) {
1843 pr_err("cmd or response buffer length not valid\n");
1844 return -EINVAL;
1845 }
1846
Mona Hossain2892b6b2012-02-17 13:53:11 -08001847 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1848 send_cmd_req.cmd_req_len = req.cmd_req_len;
1849 send_cmd_req.resp_buf = req.resp_buf;
1850 send_cmd_req.resp_len = req.resp_len;
1851
Mona Hossain268c3122014-11-03 17:05:48 -08001852 if (__validate_send_cmd_inputs(data, &send_cmd_req))
1853 return -EINVAL;
1854
Mona Hossaindddf4442013-10-01 14:08:20 -07001855 /* validate offsets */
1856 for (i = 0; i < MAX_ION_FD; i++) {
1857 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1858 pr_err("Invalid offset %d = 0x%x\n",
1859 i, req.ifd_data[i].cmd_buf_offset);
1860 return -EINVAL;
1861 }
1862 }
Zhen Kongf4948192013-11-25 13:05:35 -08001863 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1864 (uint32_t)req.cmd_req_buf);
1865 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1866 (uint32_t)req.resp_buf);
1867
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001868 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001869 if (ret)
1870 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001871 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001872 if (ret)
1873 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001874 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001875 if (ret)
1876 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001877
Mona Hossain2892b6b2012-02-17 13:53:11 -08001878 return ret;
1879}
1880
1881static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1882 struct qseecom_registered_listener_list *svc)
1883{
1884 int ret;
1885 ret = (svc->rcv_req_flag != 0);
1886 return ret || data->abort;
1887}
1888
1889static int qseecom_receive_req(struct qseecom_dev_handle *data)
1890{
1891 int ret = 0;
1892 struct qseecom_registered_listener_list *this_lstnr;
1893
1894 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301895 if (!this_lstnr) {
1896 pr_err("Invalid listener ID\n");
1897 return -ENODATA;
1898 }
1899
Mona Hossain2892b6b2012-02-17 13:53:11 -08001900 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001901 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001902 __qseecom_listener_has_rcvd_req(data,
1903 this_lstnr))) {
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05301904 pr_debug("Interrupted: exiting Listener Service = %d\n",
Mona Hossain17a4faf2013-03-22 16:40:56 -07001905 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001906 /* woken up for different reason */
1907 return -ERESTARTSYS;
1908 }
1909
1910 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001911 pr_err("Aborting Listener Service = %d\n",
1912 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001913 return -ENODEV;
1914 }
1915 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001916 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001917 }
1918 return ret;
1919}
1920
Mona Hossaind44a3842012-10-15 09:41:35 -07001921static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1922{
1923 struct elf32_hdr *ehdr;
1924
1925 if (fw_entry->size < sizeof(*ehdr)) {
1926 pr_err("%s: Not big enough to be an elf header\n",
1927 qseecom.pdev->init_name);
1928 return false;
1929 }
1930 ehdr = (struct elf32_hdr *)fw_entry->data;
1931 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1932 pr_err("%s: Not an elf header\n",
1933 qseecom.pdev->init_name);
1934 return false;
1935 }
1936
1937 if (ehdr->e_phnum == 0) {
1938 pr_err("%s: No loadable segments\n",
1939 qseecom.pdev->init_name);
1940 return false;
1941 }
1942 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1943 sizeof(struct elf32_hdr) > fw_entry->size) {
1944 pr_err("%s: Program headers not within mdt\n",
1945 qseecom.pdev->init_name);
1946 return false;
1947 }
1948 return true;
1949}
1950
Zhen Kong82e296d2016-10-20 17:34:20 -07001951static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size)
Mona Hossaind44a3842012-10-15 09:41:35 -07001952{
1953 int ret = -1;
1954 int i = 0, rc = 0;
1955 const struct firmware *fw_entry = NULL;
1956 struct elf32_phdr *phdr;
1957 char fw_name[MAX_APP_NAME_SIZE];
1958 struct elf32_hdr *ehdr;
1959 int num_images = 0;
1960
1961 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1962 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1963 if (rc) {
1964 pr_err("error with request_firmware\n");
1965 ret = -EIO;
1966 goto err;
1967 }
1968 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1969 ret = -EIO;
1970 goto err;
1971 }
1972 *fw_size = fw_entry->size;
1973 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1974 ehdr = (struct elf32_hdr *)fw_entry->data;
1975 num_images = ehdr->e_phnum;
1976 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07001977 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001978 for (i = 0; i < num_images; i++, phdr++) {
1979 memset(fw_name, 0, sizeof(fw_name));
1980 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1981 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1982 if (ret)
1983 goto err;
Zhen Kong82e296d2016-10-20 17:34:20 -07001984 if (*fw_size > U32_MAX - fw_entry->size) {
1985 pr_err("QSEE %s app file size overflow\n", appname);
1986 ret = -EINVAL;
1987 goto err;
1988 }
Mona Hossaind44a3842012-10-15 09:41:35 -07001989 *fw_size += fw_entry->size;
1990 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07001991 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001992 }
1993 return ret;
1994err:
1995 if (fw_entry)
1996 release_firmware(fw_entry);
1997 *fw_size = 0;
1998 return ret;
1999}
2000
Zhen Kong82e296d2016-10-20 17:34:20 -07002001static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
2002 uint32_t fw_size,
2003 struct qseecom_load_app_ireq *load_req)
Mona Hossaind44a3842012-10-15 09:41:35 -07002004{
2005 int ret = -1;
2006 int i = 0, rc = 0;
2007 const struct firmware *fw_entry = NULL;
2008 char fw_name[MAX_APP_NAME_SIZE];
2009 u8 *img_data_ptr = img_data;
2010 struct elf32_hdr *ehdr;
2011 int num_images = 0;
2012
2013 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
2014 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2015 if (rc) {
2016 ret = -EIO;
2017 goto err;
2018 }
2019 load_req->img_len = fw_entry->size;
Zhen Kong82e296d2016-10-20 17:34:20 -07002020 if (load_req->img_len > fw_size) {
2021 pr_err("app %s size %zu is larger than buf size %u\n",
2022 appname, fw_entry->size, fw_size);
2023 ret = -EINVAL;
2024 goto err;
2025 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002026 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2027 img_data_ptr = img_data_ptr + fw_entry->size;
2028 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
2029 ehdr = (struct elf32_hdr *)fw_entry->data;
2030 num_images = ehdr->e_phnum;
2031 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07002032 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002033 for (i = 0; i < num_images; i++) {
2034 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
2035 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2036 if (ret) {
2037 pr_err("Failed to locate blob %s\n", fw_name);
2038 goto err;
2039 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002040 if ((fw_entry->size > U32_MAX - load_req->img_len) ||
2041 (fw_entry->size + load_req->img_len > fw_size)) {
2042 pr_err("Invalid file size for %s\n", fw_name);
2043 ret = -EINVAL;
2044 goto err;
2045 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002046 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2047 img_data_ptr = img_data_ptr + fw_entry->size;
2048 load_req->img_len += fw_entry->size;
2049 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07002050 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002051 }
2052 load_req->phy_addr = virt_to_phys(img_data);
2053 return ret;
2054err:
2055 release_firmware(fw_entry);
2056 return ret;
2057}
2058
2059static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
2060{
2061 int ret = -1;
2062 uint32_t fw_size = 0;
2063 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2064 struct qseecom_command_scm_resp resp;
2065 u8 *img_data = NULL;
2066
2067 if (__qseecom_get_fw_size(appname, &fw_size))
2068 return -EIO;
2069
2070 img_data = kzalloc(fw_size, GFP_KERNEL);
2071 if (!img_data) {
2072 pr_err("Failied to allocate memory for copying image data\n");
2073 return -ENOMEM;
2074 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002075 ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
Mona Hossaind44a3842012-10-15 09:41:35 -07002076 if (ret) {
2077 kzfree(img_data);
2078 return -EIO;
2079 }
2080
2081 /* Populate the remaining parameters */
2082 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002083 strlcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002084
2085 if (qseecom.support_bus_scaling) {
2086 mutex_lock(&qsee_bw_mutex);
2087 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2088 mutex_unlock(&qsee_bw_mutex);
2089 if (ret) {
2090 kzfree(img_data);
2091 return ret;
2092 }
2093 }
2094
Zhen Kong2edf90d2013-08-27 12:05:06 -07002095 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08002096 if (ret) {
Zhen Kong4bead3c2014-04-14 15:07:13 -07002097 ret = -EIO;
2098 goto loadfw_err;
Mona Hossain60f9fb02012-11-05 13:51:50 -08002099 }
2100
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002101 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07002102 /* SCM_CALL to load the image */
2103 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2104 sizeof(struct qseecom_load_app_ireq),
2105 &resp, sizeof(resp));
Mona Hossaind44a3842012-10-15 09:41:35 -07002106 if (ret) {
2107 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002108 ret = -EIO;
2109 goto loadfw_err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002110 }
2111
2112 switch (resp.result) {
2113 case QSEOS_RESULT_SUCCESS:
2114 ret = resp.data;
2115 break;
2116 case QSEOS_RESULT_INCOMPLETE:
2117 ret = __qseecom_process_incomplete_cmd(data, &resp);
2118 if (ret)
2119 pr_err("process_incomplete_cmd FAILED\n");
2120 else
2121 ret = resp.data;
2122 break;
2123 case QSEOS_RESULT_FAILURE:
2124 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
2125 break;
2126 default:
2127 pr_err("scm call return unknown response %d\n", resp.result);
2128 ret = -EINVAL;
2129 break;
2130 }
Mona Hossain60f9fb02012-11-05 13:51:50 -08002131
Zhen Kong4bead3c2014-04-14 15:07:13 -07002132loadfw_err:
William Clarkd83bdcb2014-07-17 14:40:41 -07002133 kzfree(img_data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002134 __qseecom_disable_clk_scale_down(data);
2135 if (qseecom.support_bus_scaling) {
2136 mutex_lock(&qsee_bw_mutex);
2137 qseecom_unregister_bus_bandwidth_needs(data);
2138 mutex_unlock(&qsee_bw_mutex);
2139 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002140 return ret;
2141}
2142
Mona Hossain9498f5e2013-01-23 18:08:45 -08002143static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07002144{
Zhen Kongc46b5842013-12-12 13:09:16 +05302145 int ret = 0;
Zhen Kongfd64c982013-12-19 16:35:43 -08002146 int len = 0;
Mona Hossain05c73562012-10-29 17:49:01 -07002147 uint32_t fw_size = 0;
2148 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2149 struct qseecom_command_scm_resp resp;
2150 u8 *img_data = NULL;
Zhen Kongfd64c982013-12-19 16:35:43 -08002151 ion_phys_addr_t pa;
Mona Hossain05c73562012-10-29 17:49:01 -07002152
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08002153 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07002154 return -EIO;
2155
Zhen Kongc46b5842013-12-12 13:09:16 +05302156 qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
2157 SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2158 if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002159 pr_err("ION alloc failed\n");
Mona Hossain05c73562012-10-29 17:49:01 -07002160 return -ENOMEM;
2161 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302162
2163 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
2164 qseecom.cmnlib_ion_handle);
2165 if (IS_ERR_OR_NULL(img_data)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002166 pr_err("ION memory mapping for cmnlib failed\n");
Zhen Kongc46b5842013-12-12 13:09:16 +05302167 ret = -ENOMEM;
2168 goto exit_ion_free;
2169 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002170 ret = __qseecom_get_fw_data("cmnlib", img_data, fw_size, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07002171 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302172 ret = -EIO;
2173 goto exit_ion_unmap_kernel;
Mona Hossain05c73562012-10-29 17:49:01 -07002174 }
Zhen Kongfd64c982013-12-19 16:35:43 -08002175 /* Get the physical address of the ION BUF */
2176 ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
2177 &pa, &len);
2178 load_req.phy_addr = (s32)pa;
2179 if (ret) {
2180 pr_err("physical memory retrieval failure\n");
2181 ret = -EIO;
2182 goto exit_ion_unmap_kernel;
2183 }
Mona Hossain05c73562012-10-29 17:49:01 -07002184 /* Populate the remaining parameters */
2185 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002186
2187 if (qseecom.support_bus_scaling) {
2188 mutex_lock(&qsee_bw_mutex);
2189 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2190 mutex_unlock(&qsee_bw_mutex);
2191 if (ret) {
2192 ret = -EIO;
2193 goto exit_ion_unmap_kernel;
2194 }
2195 }
2196
Mona Hossain6311d572013-03-01 15:54:02 -08002197 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002198 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002199 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302200 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002201 goto exit_unregister_bus_bw_need;
Mona Hossain6311d572013-03-01 15:54:02 -08002202 }
2203
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002204 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07002205 /* SCM_CALL to load the image */
2206 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2207 sizeof(struct qseecom_load_lib_image_ireq),
2208 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07002209 if (ret) {
2210 pr_err("scm_call to load failed : ret %d\n", ret);
2211 ret = -EIO;
Zhen Kongc46b5842013-12-12 13:09:16 +05302212 goto exit_disable_clk_vote;
Mona Hossain05c73562012-10-29 17:49:01 -07002213 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302214
2215 switch (resp.result) {
2216 case QSEOS_RESULT_SUCCESS:
2217 break;
2218 case QSEOS_RESULT_FAILURE:
2219 pr_err("scm call failed w/response result%d\n", resp.result);
2220 ret = -EINVAL;
2221 goto exit_disable_clk_vote;
2222 case QSEOS_RESULT_INCOMPLETE:
2223 ret = __qseecom_process_incomplete_cmd(data, &resp);
2224 if (ret) {
2225 pr_err("process_incomplete_cmd failed err: %d\n", ret);
2226 goto exit_disable_clk_vote;
2227 }
2228 break;
2229 default:
2230 pr_err("scm call return unknown response %d\n", resp.result);
2231 ret = -EINVAL;
2232 goto exit_disable_clk_vote;
2233 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07002234 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002235 if (qseecom.support_bus_scaling) {
2236 mutex_lock(&qsee_bw_mutex);
2237 qseecom_unregister_bus_bandwidth_needs(data);
2238 mutex_unlock(&qsee_bw_mutex);
2239 }
Mona Hossain05c73562012-10-29 17:49:01 -07002240 return ret;
Zhen Kongc46b5842013-12-12 13:09:16 +05302241
2242exit_disable_clk_vote:
2243 __qseecom_disable_clk_scale_down(data);
2244
Zhen Kong4bead3c2014-04-14 15:07:13 -07002245exit_unregister_bus_bw_need:
2246 if (qseecom.support_bus_scaling) {
2247 mutex_lock(&qsee_bw_mutex);
2248 qseecom_unregister_bus_bandwidth_needs(data);
2249 mutex_unlock(&qsee_bw_mutex);
2250 }
2251
Zhen Kongc46b5842013-12-12 13:09:16 +05302252exit_ion_unmap_kernel:
2253 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2254
2255exit_ion_free:
2256 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2257 qseecom.cmnlib_ion_handle = NULL;
2258 return ret;
Mona Hossain05c73562012-10-29 17:49:01 -07002259}
2260
2261static int qseecom_unload_commonlib_image(void)
2262{
2263 int ret = -EINVAL;
2264 struct qseecom_unload_lib_image_ireq unload_req = {0};
2265 struct qseecom_command_scm_resp resp;
2266
2267 /* Populate the remaining parameters */
2268 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
2269 /* SCM_CALL to load the image */
2270 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
2271 sizeof(struct qseecom_unload_lib_image_ireq),
2272 &resp, sizeof(resp));
2273 if (ret) {
2274 pr_err("scm_call to unload lib failed : ret %d\n", ret);
2275 ret = -EIO;
2276 } else {
2277 switch (resp.result) {
2278 case QSEOS_RESULT_SUCCESS:
2279 break;
2280 case QSEOS_RESULT_FAILURE:
2281 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
2282 break;
2283 default:
2284 pr_err("scm call return unknown response %d\n",
2285 resp.result);
2286 ret = -EINVAL;
2287 break;
2288 }
2289 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302290
2291 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2292 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2293 qseecom.cmnlib_ion_handle = NULL;
2294
Mona Hossain05c73562012-10-29 17:49:01 -07002295 return ret;
2296}
2297
Mona Hossaind44a3842012-10-15 09:41:35 -07002298int qseecom_start_app(struct qseecom_handle **handle,
2299 char *app_name, uint32_t size)
2300{
Mona Hossain05c73562012-10-29 17:49:01 -07002301 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002302 unsigned long flags = 0;
2303 struct qseecom_dev_handle *data = NULL;
2304 struct qseecom_check_app_ireq app_ireq;
2305 struct qseecom_registered_app_list *entry = NULL;
2306 struct qseecom_registered_kclient_list *kclient_entry = NULL;
2307 bool found_app = false;
2308 uint32_t len;
2309 ion_phys_addr_t pa;
2310
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002311 if (!app_name || strlen(app_name) >= MAX_APP_NAME_SIZE) {
2312 pr_err("The app_name (%s) is not valid\n", app_name);
2313 return -EINVAL;
2314 }
2315
Mona Hossain823f9882012-11-23 14:42:20 -08002316 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
2317 if (!(*handle)) {
2318 pr_err("failed to allocate memory for kernel client handle\n");
2319 return -ENOMEM;
2320 }
2321
Mona Hossaind44a3842012-10-15 09:41:35 -07002322 data = kzalloc(sizeof(*data), GFP_KERNEL);
2323 if (!data) {
2324 pr_err("kmalloc failed\n");
2325 if (ret == 0) {
2326 kfree(*handle);
2327 *handle = NULL;
2328 }
2329 return -ENOMEM;
2330 }
2331 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002332 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07002333 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002334 data->client.sb_length = size;
2335 data->client.user_virt_sb_base = 0;
2336 data->client.ihandle = NULL;
2337
2338 init_waitqueue_head(&data->abort_wq);
2339 atomic_set(&data->ioctl_count, 0);
2340
2341 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
2342 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2343 if (IS_ERR_OR_NULL(data->client.ihandle)) {
2344 pr_err("Ion client could not retrieve the handle\n");
2345 kfree(data);
2346 kfree(*handle);
2347 *handle = NULL;
2348 return -EINVAL;
2349 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002350 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002351 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002352 if (qseecom.commonlib_loaded == false) {
2353 ret = qseecom_load_commonlib_image(data);
2354 if (ret == 0)
2355 qseecom.commonlib_loaded = true;
2356 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002357 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002358 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002359 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002360 ret = -EIO;
2361 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08002362 }
2363
2364 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002365 strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002366 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002367 if (ret < 0)
2368 goto err;
2369
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07002370 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002371 if (ret > 0) {
2372 pr_warn("App id %d for [%s] app exists\n", ret,
2373 (char *)app_ireq.app_name);
2374 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2375 list_for_each_entry(entry,
2376 &qseecom.registered_app_list_head, list){
2377 if (entry->app_id == ret) {
2378 entry->ref_cnt++;
2379 found_app = true;
2380 break;
2381 }
2382 }
2383 spin_unlock_irqrestore(
2384 &qseecom.registered_app_list_lock, flags);
2385 if (!found_app)
2386 pr_warn("App_id %d [%s] was loaded but not registered\n",
2387 ret, (char *)app_ireq.app_name);
2388 } else {
2389 /* load the app and get the app_id */
2390 pr_debug("%s: Loading app for the first time'\n",
2391 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07002392 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002393 if (ret < 0)
2394 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002395 data->client.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07002396 strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002397 }
2398 if (!found_app) {
2399 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2400 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002401 pr_err("kmalloc for app entry failed\n");
2402 ret = -ENOMEM;
2403 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002404 }
2405 entry->app_id = ret;
2406 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07002407 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002408
2409 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2410 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2411 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2412 flags);
2413 }
2414
2415 /* Get the physical address of the ION BUF */
2416 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002417 if (ret) {
2418 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2419 ret);
2420 goto err;
2421 }
2422
Mona Hossaind44a3842012-10-15 09:41:35 -07002423 /* Populate the structure for sending scm call to load image */
2424 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
2425 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08002426 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07002427 data->client.sb_phys = pa;
2428 (*handle)->dev = (void *)data;
2429 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
2430 (*handle)->sbuf_len = data->client.sb_length;
2431
2432 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
2433 if (!kclient_entry) {
2434 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002435 ret = -ENOMEM;
2436 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002437 }
2438 kclient_entry->handle = *handle;
2439
2440 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2441 list_add_tail(&kclient_entry->list,
2442 &qseecom.registered_kclient_list_head);
2443 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2444
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002445 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002446 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002447
2448err:
2449 kfree(data);
2450 kfree(*handle);
2451 *handle = NULL;
2452 mutex_unlock(&app_access_lock);
2453 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002454}
2455EXPORT_SYMBOL(qseecom_start_app);
2456
2457int qseecom_shutdown_app(struct qseecom_handle **handle)
2458{
2459 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002460 struct qseecom_dev_handle *data;
2461
Mona Hossaind44a3842012-10-15 09:41:35 -07002462 struct qseecom_registered_kclient_list *kclient = NULL;
2463 unsigned long flags = 0;
2464 bool found_handle = false;
2465
Mona Hossain33824022013-02-25 09:32:33 -08002466 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002467 pr_err("Handle is not initialized\n");
2468 return -EINVAL;
2469 }
Mona Hossain33824022013-02-25 09:32:33 -08002470 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002471 mutex_lock(&app_access_lock);
2472 atomic_inc(&data->ioctl_count);
2473
Mona Hossaind44a3842012-10-15 09:41:35 -07002474 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2475 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2476 list) {
2477 if (kclient->handle == (*handle)) {
2478 list_del(&kclient->list);
2479 found_handle = true;
2480 break;
2481 }
2482 }
2483 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2484 if (!found_handle)
2485 pr_err("Unable to find the handle, exiting\n");
2486 else
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07002487 ret = qseecom_unload_app(data, false);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002488
2489 if (qseecom.support_bus_scaling) {
2490 mutex_lock(&qsee_bw_mutex);
2491 if (data->mode != INACTIVE) {
2492 qseecom_unregister_bus_bandwidth_needs(data);
2493 if (qseecom.cumulative_mode == INACTIVE) {
2494 ret = __qseecom_set_msm_bus_request(INACTIVE);
2495 if (ret)
2496 pr_err("Fail to scale down bus\n");
2497 }
2498 }
2499 mutex_unlock(&qsee_bw_mutex);
2500 } else {
2501 if (data->fast_load_enabled == true)
2502 qsee_disable_clock_vote(data, CLK_SFPB);
2503 if (data->perf_enabled == true)
2504 qsee_disable_clock_vote(data, CLK_DFAB);
2505 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002506
2507 atomic_dec(&data->ioctl_count);
2508 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002509 if (ret == 0) {
2510 kzfree(data);
2511 kzfree(*handle);
2512 kzfree(kclient);
2513 *handle = NULL;
2514 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002515
Mona Hossaind44a3842012-10-15 09:41:35 -07002516 return ret;
2517}
2518EXPORT_SYMBOL(qseecom_shutdown_app);
2519
2520int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2521 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2522{
2523 int ret = 0;
2524 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2525 struct qseecom_dev_handle *data;
Zhen Kongd08301c2014-10-08 17:02:54 -07002526 bool perf_enabled = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002527
Mona Hossaind44a3842012-10-15 09:41:35 -07002528 if (handle == NULL) {
2529 pr_err("Handle is not initialized\n");
2530 return -EINVAL;
2531 }
2532 data = handle->dev;
2533
2534 req.cmd_req_len = sbuf_len;
2535 req.resp_len = rbuf_len;
2536 req.cmd_req_buf = send_buf;
2537 req.resp_buf = resp_buf;
2538
Mona Hossain268c3122014-11-03 17:05:48 -08002539 if (__validate_send_cmd_inputs(data, &req))
2540 return -EINVAL;
2541
Mona Hossaind44a3842012-10-15 09:41:35 -07002542 mutex_lock(&app_access_lock);
2543 atomic_inc(&data->ioctl_count);
Zhen Kongca4c2d52014-03-12 13:22:46 -07002544 if (qseecom.support_bus_scaling) {
2545 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
2546 if (ret) {
2547 pr_err("Failed to set bw.\n");
2548 atomic_dec(&data->ioctl_count);
2549 mutex_unlock(&app_access_lock);
2550 return ret;
2551 }
2552 }
Zhen Kong1e15c272014-09-18 12:33:07 -07002553 /*
2554 * On targets where crypto clock is handled by HLOS,
2555 * if clk_access_cnt is zero and perf_enabled is false,
2556 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07002557 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07002558 */
2559 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07002560 pr_debug("ce clock is not enabled!\n");
2561 ret = qseecom_perf_enable(data);
2562 if (ret) {
2563 pr_err("Failed to vote for clock with err %d\n",
2564 ret);
2565 atomic_dec(&data->ioctl_count);
2566 mutex_unlock(&app_access_lock);
2567 return -EINVAL;
2568 }
2569 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07002570 }
2571
Mona Hossaind44a3842012-10-15 09:41:35 -07002572 ret = __qseecom_send_cmd(data, &req);
Zhen Kongaf950192014-02-05 17:36:23 -08002573 if (qseecom.support_bus_scaling)
2574 __qseecom_add_bw_scale_down_timer(
2575 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002576
Zhen Kongd08301c2014-10-08 17:02:54 -07002577 if (perf_enabled) {
2578 qsee_disable_clock_vote(data, CLK_DFAB);
2579 qsee_disable_clock_vote(data, CLK_SFPB);
2580 }
2581
Mona Hossaind44a3842012-10-15 09:41:35 -07002582 atomic_dec(&data->ioctl_count);
2583 mutex_unlock(&app_access_lock);
2584
2585 if (ret)
2586 return ret;
2587
Jeron Susan84186d42016-11-03 10:02:25 +08002588 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%pK\n",
Mona Hossaind44a3842012-10-15 09:41:35 -07002589 req.resp_len, req.resp_buf);
2590 return ret;
2591}
2592EXPORT_SYMBOL(qseecom_send_command);
2593
Mona Hossain91a8fc92012-11-07 19:58:30 -08002594int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2595{
Mona Hossainfca6f422013-01-12 13:00:35 -08002596 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002597 if ((handle == NULL) || (handle->dev == NULL)) {
2598 pr_err("No valid kernel client\n");
2599 return -EINVAL;
2600 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002601 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002602 if (qseecom.support_bus_scaling) {
2603 mutex_lock(&qsee_bw_mutex);
2604 __qseecom_register_bus_bandwidth_needs(handle->dev,
2605 HIGH);
2606 mutex_unlock(&qsee_bw_mutex);
2607 if (ret)
2608 pr_err("Failed to scale bus (med) %d\n", ret);
2609 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07002610 ret = qseecom_perf_enable(handle->dev);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002611 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07002612 pr_err("Failed to vote for clock with err %d\n",
2613 ret);
Mona Hossainfca6f422013-01-12 13:00:35 -08002614 }
2615 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002616 if (!qseecom.support_bus_scaling) {
2617 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2618 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07002619 } else {
2620 mutex_lock(&qsee_bw_mutex);
2621 qseecom_unregister_bus_bandwidth_needs(handle->dev);
2622 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002623 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002624 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002625 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002626}
2627EXPORT_SYMBOL(qseecom_set_bandwidth);
2628
Mona Hossain2892b6b2012-02-17 13:53:11 -08002629static int qseecom_send_resp(void)
2630{
2631 qseecom.send_resp_flag = 1;
2632 wake_up_interruptible(&qseecom.send_resp_wq);
2633 return 0;
2634}
2635
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002636
Zhen Kong66e478b2016-07-18 13:20:18 -07002637static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
2638 struct qseecom_send_modfd_listener_resp *resp,
2639 struct qseecom_registered_listener_list *this_lstnr)
2640{
2641 int i;
2642
2643 if (!data || !resp || !this_lstnr) {
2644 pr_err("listener handle or resp msg is null\n");
2645 return -EINVAL;
2646 }
2647
2648 if (resp->resp_buf_ptr == NULL) {
2649 pr_err("resp buffer is null\n");
2650 return -EINVAL;
2651 }
2652 /* validate resp buf length */
2653 if ((resp->resp_len == 0) ||
2654 (resp->resp_len > this_lstnr->sb_length)) {
2655 pr_err("resp buf length %d not valid\n", resp->resp_len);
2656 return -EINVAL;
2657 }
2658
2659 if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
2660 pr_err("Integer overflow in resp_len & resp_buf\n");
2661 return -EINVAL;
2662 }
2663 if ((uintptr_t)this_lstnr->user_virt_sb_base >
2664 (ULONG_MAX - this_lstnr->sb_length)) {
2665 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
2666 return -EINVAL;
2667 }
2668 /* validate resp buf */
2669 if (((uintptr_t)resp->resp_buf_ptr <
2670 (uintptr_t)this_lstnr->user_virt_sb_base) ||
2671 ((uintptr_t)resp->resp_buf_ptr >=
2672 ((uintptr_t)this_lstnr->user_virt_sb_base +
2673 this_lstnr->sb_length)) ||
2674 (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
2675 ((uintptr_t)this_lstnr->user_virt_sb_base +
2676 this_lstnr->sb_length))) {
2677 pr_err("resp buf is out of shared buffer region\n");
2678 return -EINVAL;
2679 }
2680
2681 /* validate offsets */
2682 for (i = 0; i < MAX_ION_FD; i++) {
2683 if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
2684 pr_err("Invalid offset %d = 0x%x\n",
2685 i, resp->ifd_data[i].cmd_buf_offset);
2686 return -EINVAL;
2687 }
2688 }
2689
2690 return 0;
2691}
2692
2693static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2694 void __user *argp, bool is_64bit_addr)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002695{
2696 struct qseecom_send_modfd_listener_resp resp;
Zhen Kongf4948192013-11-25 13:05:35 -08002697 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002698
2699 if (copy_from_user(&resp, argp, sizeof(resp))) {
2700 pr_err("copy_from_user failed");
2701 return -EINVAL;
2702 }
Zhen Kong66e478b2016-07-18 13:20:18 -07002703
Zhen Kongf4948192013-11-25 13:05:35 -08002704 this_lstnr = __qseecom_find_svc(data->listener.id);
2705 if (this_lstnr == NULL)
2706 return -EINVAL;
2707
Zhen Kong66e478b2016-07-18 13:20:18 -07002708 if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
Zhen Kongf4948192013-11-25 13:05:35 -08002709 return -EINVAL;
Zhen Kongf4948192013-11-25 13:05:35 -08002710
Zhen Kongf4948192013-11-25 13:05:35 -08002711 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2712 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002713 __qseecom_update_cmd_buf(&resp, false, data, true);
2714 qseecom.send_resp_flag = 1;
2715 wake_up_interruptible(&qseecom.send_resp_wq);
2716 return 0;
2717}
2718
Zhen Kong66e478b2016-07-18 13:20:18 -07002719static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2720 void __user *argp)
2721{
2722 return __qseecom_send_modfd_resp(data, argp, false);
2723}
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002724
Mona Hossain2892b6b2012-02-17 13:53:11 -08002725static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2726 void __user *argp)
2727{
2728 struct qseecom_qseos_version_req req;
2729
2730 if (copy_from_user(&req, argp, sizeof(req))) {
2731 pr_err("copy_from_user failed");
2732 return -EINVAL;
2733 }
2734 req.qseos_version = qseecom.qseos_version;
2735 if (copy_to_user(argp, &req, sizeof(req))) {
2736 pr_err("copy_to_user failed");
2737 return -EINVAL;
2738 }
2739 return 0;
2740}
2741
Mona Hossainc92629e2013-04-01 13:37:46 -07002742static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002743{
2744 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002745 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002746
Mona Hossainc92629e2013-04-01 13:37:46 -07002747 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002748 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002749 else
2750 qclk = &qseecom.ce_drv;
2751
2752 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002753
2754 if (qclk->clk_access_cnt == ULONG_MAX)
2755 goto err;
2756
Mona Hossainc92629e2013-04-01 13:37:46 -07002757 if (qclk->clk_access_cnt > 0) {
2758 qclk->clk_access_cnt++;
2759 mutex_unlock(&clk_access_lock);
2760 return rc;
2761 }
2762
Mona Hossain6311d572013-03-01 15:54:02 -08002763 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002764 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002765 if (rc) {
2766 pr_err("Unable to enable/prepare CE core clk\n");
2767 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002768 }
2769 /* Enable CE clk */
2770 rc = clk_prepare_enable(qclk->ce_clk);
2771 if (rc) {
2772 pr_err("Unable to enable/prepare CE iface clk\n");
2773 goto ce_clk_err;
2774 }
2775 /* Enable AXI clk */
2776 rc = clk_prepare_enable(qclk->ce_bus_clk);
2777 if (rc) {
2778 pr_err("Unable to enable/prepare CE bus clk\n");
2779 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002780 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002781 qclk->clk_access_cnt++;
2782 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002783 return 0;
2784
2785ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002786 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002787ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002788 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002789err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002790 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002791 return -EIO;
2792}
2793
Mona Hossainc92629e2013-04-01 13:37:46 -07002794static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002795{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002796 struct qseecom_clk *qclk;
2797
Mona Hossainc92629e2013-04-01 13:37:46 -07002798 if (ce == CLK_QSEE)
2799 qclk = &qseecom.qsee;
2800 else
2801 qclk = &qseecom.ce_drv;
2802
2803 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002804
2805 if (qclk->clk_access_cnt == 0) {
2806 mutex_unlock(&clk_access_lock);
2807 return;
2808 }
2809
Mona Hossainc92629e2013-04-01 13:37:46 -07002810 if (qclk->clk_access_cnt == 1) {
2811 if (qclk->ce_clk != NULL)
2812 clk_disable_unprepare(qclk->ce_clk);
2813 if (qclk->ce_core_clk != NULL)
2814 clk_disable_unprepare(qclk->ce_core_clk);
2815 if (qclk->ce_bus_clk != NULL)
2816 clk_disable_unprepare(qclk->ce_bus_clk);
2817 }
2818 qclk->clk_access_cnt--;
2819 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002820}
2821
Mona Hossain04d3fac2012-12-03 10:10:37 -08002822static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2823 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002824{
2825 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002826 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002827
Mona Hossain17a4faf2013-03-22 16:40:56 -07002828 qclk = &qseecom.qsee;
2829 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002830 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002831
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002832 switch (clk_type) {
2833 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002834 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002835 if (!qseecom.qsee_bw_count) {
2836 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002837 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002838 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002839 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002840 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002841 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002842 if (!ret) {
2843 ret =
2844 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002845 qseecom.qsee_perf_client, 1);
2846 if ((ret) &&
2847 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002848 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002849 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002850 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002851 if (ret)
2852 pr_err("DFAB Bandwidth req failed (%d)\n",
2853 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002854 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002855 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002856 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002857 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002858 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002859 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002860 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002861 }
2862 mutex_unlock(&qsee_bw_mutex);
2863 break;
2864 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002865 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002866 if (!qseecom.qsee_sfpb_bw_count) {
2867 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002868 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002869 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002870 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002871 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002872 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002873 if (!ret) {
2874 ret =
2875 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002876 qseecom.qsee_perf_client, 2);
2877 if ((ret) &&
2878 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002879 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002880 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002881 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002882
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002883 if (ret)
2884 pr_err("SFPB Bandwidth req failed (%d)\n",
2885 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002886 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002887 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002888 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002889 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002890 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002891 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002892 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002893 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002894 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002895 break;
2896 default:
2897 pr_err("Clock type not defined\n");
2898 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002899 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002900 return ret;
2901}
2902
Mona Hossain04d3fac2012-12-03 10:10:37 -08002903static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2904 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002905{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002906 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002907 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002908
Mona Hossain17a4faf2013-03-22 16:40:56 -07002909 qclk = &qseecom.qsee;
2910 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002911 return;
2912
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002913 switch (clk_type) {
2914 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002915 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002916 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002917 pr_err("Client error.Extra call to disable DFAB clk\n");
2918 mutex_unlock(&qsee_bw_mutex);
2919 return;
2920 }
2921
Mona Hossain17a4faf2013-03-22 16:40:56 -07002922 if (qseecom.qsee_bw_count == 1) {
2923 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002924 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002925 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002926 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002927 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002928 qseecom.qsee_perf_client, 0);
2929 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002930 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002931 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002932 if (ret)
2933 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002934 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002935 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002936 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002937 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002938 }
2939 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002940 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002941 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002942 }
2943 mutex_unlock(&qsee_bw_mutex);
2944 break;
2945 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002946 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002947 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002948 pr_err("Client error.Extra call to disable SFPB clk\n");
2949 mutex_unlock(&qsee_bw_mutex);
2950 return;
2951 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002952 if (qseecom.qsee_sfpb_bw_count == 1) {
2953 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002954 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002955 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002956 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002957 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002958 qseecom.qsee_perf_client, 0);
2959 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002960 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002961 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002962 if (ret)
2963 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002964 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002965 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002966 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002967 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002968 }
2969 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002970 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002971 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002972 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002973 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002974 break;
2975 default:
2976 pr_err("Clock type not defined\n");
2977 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002978 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002979
Mona Hossain2892b6b2012-02-17 13:53:11 -08002980}
2981
Mona Hossain5ab9d772012-04-11 21:00:40 -07002982static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2983 void __user *argp)
2984{
2985 struct ion_handle *ihandle; /* Ion handle */
2986 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002987 int ret;
2988 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002989 ion_phys_addr_t pa = 0;
2990 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002991 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002992 struct qseecom_load_app_ireq load_req;
2993 struct qseecom_command_scm_resp resp;
2994
2995 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002996 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002997 (void __user *)argp,
2998 sizeof(struct qseecom_load_img_req))) {
2999 pr_err("copy_from_user failed\n");
3000 return -EFAULT;
3001 }
3002
3003 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08003004 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07003005 load_img_req.ifd_data_fd);
3006 if (IS_ERR_OR_NULL(ihandle)) {
3007 pr_err("Ion client could not retrieve the handle\n");
3008 return -ENOMEM;
3009 }
3010
3011 /* Get the physical address of the ION BUF */
3012 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08003013 if (ret) {
3014 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
3015 ret);
3016 return ret;
3017 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003018 /* Populate the structure for sending scm call to load image */
3019 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
3020 load_req.mdt_len = load_img_req.mdt_len;
3021 load_req.img_len = load_img_req.img_len;
3022 load_req.phy_addr = pa;
3023
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003024 /* SCM_CALL tied to Core0 */
3025 mask = CPU_MASK_CPU0;
3026 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3027 if (set_cpu_ret) {
3028 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3029 set_cpu_ret);
3030 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303031 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003032 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303033
Zhen Kong4bead3c2014-04-14 15:07:13 -07003034 if (qseecom.support_bus_scaling) {
3035 mutex_lock(&qsee_bw_mutex);
3036 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
3037 mutex_unlock(&qsee_bw_mutex);
3038 if (ret) {
3039 ret = -EIO;
3040 goto exit_cpu_restore;
3041 }
3042 }
3043
Mona Hossain6311d572013-03-01 15:54:02 -08003044 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07003045 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08003046 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08003047 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07003048 goto exit_register_bus_bandwidth_needs;
Mona Hossain6311d572013-03-01 15:54:02 -08003049 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003050 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
3051 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003052 /* SCM_CALL to load the external elf */
3053 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
3054 sizeof(struct qseecom_load_app_ireq),
3055 &resp, sizeof(resp));
3056 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003057 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07003058 ret);
3059 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303060 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003061 }
3062
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303063 switch (resp.result) {
3064 case QSEOS_RESULT_SUCCESS:
3065 break;
3066 case QSEOS_RESULT_INCOMPLETE:
3067 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003068 ret = __qseecom_process_incomplete_cmd(data, &resp);
3069 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303070 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
3071 break;
3072 case QSEOS_RESULT_FAILURE:
3073 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
3074 ret = -EFAULT;
3075 break;
3076 default:
3077 pr_err("scm_call response result %d not supported\n",
3078 resp.result);
3079 ret = -EFAULT;
3080 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003081 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003082
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303083exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07003084 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07003085
3086exit_register_bus_bandwidth_needs:
3087 if (qseecom.support_bus_scaling) {
3088 mutex_lock(&qsee_bw_mutex);
3089 ret = qseecom_unregister_bus_bandwidth_needs(data);
3090 mutex_unlock(&qsee_bw_mutex);
3091 }
3092
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303093exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003094 /* Restore the CPU mask */
3095 mask = CPU_MASK_ALL;
3096 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3097 if (set_cpu_ret) {
3098 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3099 set_cpu_ret);
3100 ret = -EFAULT;
3101 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303102exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07003103 /* Deallocate the handle */
3104 if (!IS_ERR_OR_NULL(ihandle))
3105 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003106 return ret;
3107}
3108
3109static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
3110{
3111 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003112 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003113 struct qseecom_command_scm_resp resp;
3114 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003115 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003116
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303117 /* unavailable client app */
3118 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
3119
Mona Hossain5ab9d772012-04-11 21:00:40 -07003120 /* Populate the structure for sending scm call to unload image */
3121 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003122
3123 /* SCM_CALL tied to Core0 */
3124 mask = CPU_MASK_CPU0;
3125 ret = set_cpus_allowed_ptr(current, &mask);
3126 if (ret) {
3127 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3128 ret);
3129 return -EFAULT;
3130 }
3131
Mona Hossain5ab9d772012-04-11 21:00:40 -07003132 /* SCM_CALL to unload the external elf */
3133 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
3134 sizeof(struct qseecom_unload_app_ireq),
3135 &resp, sizeof(resp));
3136 if (ret) {
3137 pr_err("scm_call to unload failed : ret %d\n",
3138 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003139 ret = -EFAULT;
3140 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003141 }
3142 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
3143 ret = __qseecom_process_incomplete_cmd(data, &resp);
3144 if (ret)
3145 pr_err("process_incomplete_cmd fail err: %d\n",
3146 ret);
3147 } else {
3148 if (resp.result != QSEOS_RESULT_SUCCESS) {
3149 pr_err("scm_call to unload image failed resp.result =%d\n",
3150 resp.result);
3151 ret = -EFAULT;
3152 }
3153 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003154
3155qseecom_unload_external_elf_scm_err:
3156 /* Restore the CPU mask */
3157 mask = CPU_MASK_ALL;
3158 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3159 if (set_cpu_ret) {
3160 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3161 set_cpu_ret);
3162 ret = -EFAULT;
3163 }
3164
Mona Hossain5ab9d772012-04-11 21:00:40 -07003165 return ret;
3166}
Mona Hossain2892b6b2012-02-17 13:53:11 -08003167
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003168static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
3169 void __user *argp)
3170{
3171
3172 int32_t ret;
3173 struct qseecom_qseos_app_load_query query_req;
3174 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003175 struct qseecom_registered_app_list *entry = NULL;
3176 unsigned long flags = 0;
Zhen Kong59155a72015-05-20 13:50:04 -07003177 bool found_app = false;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003178
3179 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07003180 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003181 (void __user *)argp,
3182 sizeof(struct qseecom_qseos_app_load_query))) {
3183 pr_err("copy_from_user failed\n");
3184 return -EFAULT;
3185 }
3186
3187 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07003188 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -07003189 strlcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003190
3191 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003192
3193 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003194 pr_err(" scm call to check if app is loaded failed");
3195 return ret; /* scm call failed */
3196 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07003197 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003198 (char *)(req.app_name));
3199 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
3200 list_for_each_entry(entry,
3201 &qseecom.registered_app_list_head, list){
3202 if (entry->app_id == ret) {
3203 entry->ref_cnt++;
Zhen Kong59155a72015-05-20 13:50:04 -07003204 found_app = true;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003205 break;
3206 }
3207 }
3208 spin_unlock_irqrestore(
3209 &qseecom.registered_app_list_lock, flags);
3210 data->client.app_id = ret;
3211 query_req.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07003212 strlcpy(data->client.app_name, query_req.app_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07003213 MAX_APP_NAME_SIZE);
Zhen Kong59155a72015-05-20 13:50:04 -07003214 /*
3215 * If app was loaded by appsbl or kernel client before
3216 * and was not registered, regiser this app now.
3217 */
3218 if (!found_app) {
3219 pr_debug("Register app %d [%s] which was loaded before\n",
3220 ret, (char *)query_req.app_name);
3221 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
3222 if (!entry) {
3223 pr_err("kmalloc for app entry failed\n");
3224 return -ENOMEM;
3225 }
3226 entry->app_id = ret;
3227 entry->ref_cnt = 1;
3228 strlcpy(entry->app_name, data->client.app_name,
3229 MAX_APP_NAME_SIZE);
3230 spin_lock_irqsave(&qseecom.registered_app_list_lock,
3231 flags);
3232 list_add_tail(&entry->list,
3233 &qseecom.registered_app_list_head);
3234 spin_unlock_irqrestore(
3235 &qseecom.registered_app_list_lock, flags);
3236 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003237 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
3238 pr_err("copy_to_user failed\n");
3239 return -EFAULT;
3240 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003241 return -EEXIST; /* app already loaded */
3242 } else {
3243 return 0; /* app not loaded */
3244 }
3245}
3246
Mona Hossain4cf78a92013-02-14 12:06:41 -08003247static int __qseecom_get_ce_pipe_info(
3248 enum qseecom_key_management_usage_type usage,
3249 uint32_t *pipe, uint32_t *ce_hw)
3250{
3251 int ret;
3252 switch (usage) {
3253 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003254 if (qseecom.support_fde) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003255 *pipe = qseecom.ce_info.disk_encrypt_pipe;
3256 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3257 ret = 0;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003258
3259 } else {
3260 pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
3261 qseecom.ce_info.disk_encrypt_pipe,
3262 qseecom.ce_info.hlos_ce_hw_instance);
3263 ret = -EINVAL;
3264 }
3265 break;
3266 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
3267 if (qseecom.support_pfe) {
3268 *pipe = qseecom.ce_info.file_encrypt_pipe;
3269 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3270 ret = 0;
3271 } else {
3272 pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
3273 qseecom.ce_info.file_encrypt_pipe,
3274 qseecom.ce_info.hlos_ce_hw_instance);
3275 ret = -EINVAL;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003276 }
3277 break;
3278 default:
3279 ret = -EINVAL;
3280 break;
3281 }
3282 return ret;
3283}
3284
3285static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
3286 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003287 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003288{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003289 struct qseecom_command_scm_resp resp;
3290 int ret;
3291
Zhen Kong9730ddf2013-12-17 16:49:43 -08003292 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3293 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003294 pr_err("Error:: unsupported usage %d\n", usage);
3295 return -EFAULT;
3296 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003297 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003298
3299 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003300 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003301 &resp, sizeof(resp));
3302 if (ret) {
3303 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003304 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003305 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003306 }
3307
3308 switch (resp.result) {
3309 case QSEOS_RESULT_SUCCESS:
3310 break;
Zhen Kong336636e2013-04-15 11:04:54 -07003311 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongba69dfe2014-02-28 15:19:53 -08003312 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07003313 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003314 case QSEOS_RESULT_INCOMPLETE:
3315 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07003316 if (ret) {
3317 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongba69dfe2014-02-28 15:19:53 -08003318 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07003319 ret = 0;
3320 } else {
3321 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3322 resp.result);
3323 }
3324 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003325 break;
3326 case QSEOS_RESULT_FAILURE:
3327 default:
3328 pr_err("gen key scm call failed resp.result %d\n", resp.result);
3329 ret = -EINVAL;
3330 break;
3331 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003332 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003333 return ret;
3334}
3335
3336static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
3337 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003338 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003339{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003340 struct qseecom_command_scm_resp resp;
3341 int ret;
3342
Amir Samuelov48a1e7d2014-06-23 11:49:05 +03003343 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3344 usage >= QSEOS_KM_USAGE_MAX) {
3345 pr_err("Error:: unsupported usage %d\n", usage);
3346 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003347 }
3348
Mona Hossainc92629e2013-04-01 13:37:46 -07003349 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003350
3351 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003352 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003353 &resp, sizeof(struct qseecom_command_scm_resp));
3354 if (ret) {
3355 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003356 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003357 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003358 }
3359
3360 switch (resp.result) {
3361 case QSEOS_RESULT_SUCCESS:
3362 break;
3363 case QSEOS_RESULT_INCOMPLETE:
3364 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003365 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003366 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3367 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003368 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3369 pr_debug("Max attempts to input password reached.\n");
3370 ret = -ERANGE;
3371 }
3372 }
3373 break;
3374 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3375 pr_debug("Max attempts to input password reached.\n");
3376 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003377 break;
3378 case QSEOS_RESULT_FAILURE:
3379 default:
3380 pr_err("Delete key scm call failed resp.result %d\n",
3381 resp.result);
3382 ret = -EINVAL;
3383 break;
3384 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003385 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003386 return ret;
3387}
3388
3389static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
3390 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003391 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003392{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003393 struct qseecom_command_scm_resp resp;
3394 int ret;
3395
Zhen Kong9730ddf2013-12-17 16:49:43 -08003396 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3397 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003398 pr_err("Error:: unsupported usage %d\n", usage);
3399 return -EFAULT;
3400 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003401
Zhen Kongdb2bf742013-05-13 23:55:42 -07003402 __qseecom_enable_clk(CLK_QSEE);
3403 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003404 __qseecom_enable_clk(CLK_CE_DRV);
3405
Zhen Kong336636e2013-04-15 11:04:54 -07003406 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003407 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003408 &resp, sizeof(struct qseecom_command_scm_resp));
3409 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003410 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07003411 __qseecom_disable_clk(CLK_QSEE);
3412 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3413 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08003414 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07003415 }
3416
Mona Hossain4cf78a92013-02-14 12:06:41 -08003417 switch (resp.result) {
3418 case QSEOS_RESULT_SUCCESS:
3419 break;
3420 case QSEOS_RESULT_INCOMPLETE:
3421 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003422 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003423 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3424 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003425 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3426 pr_debug("Max attempts to input password reached.\n");
3427 ret = -ERANGE;
3428 }
3429 }
3430 break;
3431 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3432 pr_debug("Max attempts to input password reached.\n");
3433 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003434 break;
3435 case QSEOS_RESULT_FAILURE:
3436 default:
3437 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3438 ret = -EINVAL;
3439 break;
3440 }
3441
Zhen Kongdb2bf742013-05-13 23:55:42 -07003442 __qseecom_disable_clk(CLK_QSEE);
3443 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003444 __qseecom_disable_clk(CLK_CE_DRV);
3445
Mona Hossain4cf78a92013-02-14 12:06:41 -08003446 return ret;
3447}
3448
Zhen Kong9730ddf2013-12-17 16:49:43 -08003449static int __qseecom_update_current_key_user_info(
3450 struct qseecom_dev_handle *data,
3451 enum qseecom_key_management_usage_type usage,
3452 struct qseecom_key_userinfo_update_ireq *ireq)
3453{
3454 struct qseecom_command_scm_resp resp;
3455 int ret;
3456
3457 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3458 usage >= QSEOS_KM_USAGE_MAX) {
3459 pr_err("Error:: unsupported usage %d\n", usage);
3460 return -EFAULT;
3461 }
3462
3463 __qseecom_enable_clk(CLK_QSEE);
3464
3465 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
3466 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
3467 &resp, sizeof(struct qseecom_command_scm_resp));
3468 if (ret) {
3469 pr_err("scm call to update key userinfo failed : %d\n", ret);
3470 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003471 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003472 }
3473
3474 switch (resp.result) {
3475 case QSEOS_RESULT_SUCCESS:
3476 break;
3477 case QSEOS_RESULT_INCOMPLETE:
3478 ret = __qseecom_process_incomplete_cmd(data, &resp);
3479 if (ret)
3480 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3481 resp.result);
3482 break;
3483 case QSEOS_RESULT_FAILURE:
3484 default:
3485 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3486 ret = -EINVAL;
3487 break;
3488 }
3489
3490 __qseecom_disable_clk(CLK_QSEE);
3491 return ret;
3492}
3493
Mona Hossain4cf78a92013-02-14 12:06:41 -08003494static int qseecom_create_key(struct qseecom_dev_handle *data,
3495 void __user *argp)
3496{
3497 uint32_t ce_hw = 0;
3498 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003499 int ret = 0;
3500 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003501 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003502 struct qseecom_key_generate_ireq generate_key_ireq;
3503 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003504
3505 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
3506 if (ret) {
3507 pr_err("copy_from_user failed\n");
3508 return ret;
3509 }
3510
Zhen Kong9730ddf2013-12-17 16:49:43 -08003511 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3512 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003513 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
3514 return -EFAULT;
3515 }
3516
3517 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
3518 if (ret) {
3519 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3520 return -EINVAL;
3521 }
3522
Zhen Kong9730ddf2013-12-17 16:49:43 -08003523 generate_key_ireq.flags = flags;
3524 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
3525 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3526 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3527 memcpy((void *)generate_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003528 (void *)key_id_array[create_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003529 QSEECOM_KEY_ID_SIZE);
3530 memcpy((void *)generate_key_ireq.hash32,
3531 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
3532
Mona Hossain4cf78a92013-02-14 12:06:41 -08003533 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003534 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003535 if (ret) {
3536 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003537 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003538 }
3539
Zhen Kong9730ddf2013-12-17 16:49:43 -08003540 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3541 set_key_ireq.ce = ce_hw;
3542 set_key_ireq.pipe = pipe;
3543 set_key_ireq.flags = flags;
3544
3545 /* set both PIPE_ENC and PIPE_ENC_XTS*/
3546 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
3547 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3548 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3549 memcpy((void *)set_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003550 (void *)key_id_array[create_key_req.usage].desc,
3551 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003552 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08003553 QSEECOM_HASH_SIZE);
3554
3555 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003556 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003557 if (ret) {
3558 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
3559 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003560 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003561 }
3562
3563 return ret;
3564}
3565
3566static int qseecom_wipe_key(struct qseecom_dev_handle *data,
3567 void __user *argp)
3568{
3569 uint32_t ce_hw = 0;
3570 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003571 int ret = 0;
3572 uint32_t flags = 0;
3573 int i;
3574 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003575 struct qseecom_key_delete_ireq delete_key_ireq;
3576 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003577
3578 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
3579 if (ret) {
3580 pr_err("copy_from_user failed\n");
3581 return ret;
3582 }
3583
Zhen Kong9730ddf2013-12-17 16:49:43 -08003584 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3585 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003586 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3587 return -EFAULT;
3588 }
3589
3590 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3591 if (ret) {
3592 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3593 return -EINVAL;
3594 }
3595
Zhen Kongba69dfe2014-02-28 15:19:53 -08003596 if (wipe_key_req.wipe_key_flag) {
3597 delete_key_ireq.flags = flags;
3598 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3599 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3600 memcpy((void *)delete_key_ireq.key_id,
3601 (void *)key_id_array[wipe_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003602 QSEECOM_KEY_ID_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003603 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003604
Zhen Kongba69dfe2014-02-28 15:19:53 -08003605 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003606 &delete_key_ireq);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003607 if (ret) {
3608 pr_err("Failed to delete key from ssd storage: %d\n",
3609 ret);
3610 return -EFAULT;
3611 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003612 }
3613
Zhen Kong9730ddf2013-12-17 16:49:43 -08003614 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3615 clear_key_ireq.ce = ce_hw;
3616 clear_key_ireq.pipe = pipe;
3617 clear_key_ireq.flags = flags;
3618 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003619 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kongba69dfe2014-02-28 15:19:53 -08003620 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003621 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3622
Mona Hossain4cf78a92013-02-14 12:06:41 -08003623 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003624 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003625 if (ret) {
3626 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3627 pipe, ce_hw, ret);
3628 return -EFAULT;
3629 }
3630
3631 return ret;
3632}
3633
Zhen Kong9730ddf2013-12-17 16:49:43 -08003634static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3635 void __user *argp)
3636{
3637 int ret = 0;
3638 uint32_t flags = 0;
3639 struct qseecom_update_key_userinfo_req update_key_req;
3640 struct qseecom_key_userinfo_update_ireq ireq;
3641
3642 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3643 if (ret) {
3644 pr_err("copy_from_user failed\n");
3645 return ret;
3646 }
3647
3648 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3649 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3650 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3651 return -EFAULT;
3652 }
3653
3654 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3655 ireq.flags = flags;
3656 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3657 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3658 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003659 memcpy((void *)ireq.key_id,
3660 (void *)key_id_array[update_key_req.usage].desc,
3661 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003662 memcpy((void *)ireq.current_hash32,
3663 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3664 memcpy((void *)ireq.new_hash32,
3665 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3666
3667 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3668 &ireq);
3669 if (ret) {
3670 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003671 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003672 }
3673 return ret;
3674
3675}
3676
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003677static int qseecom_is_es_activated(void __user *argp)
3678{
3679 struct qseecom_is_es_activated_req req;
3680 int ret;
3681 int resp_buf;
3682
3683 if (qseecom.qsee_version < QSEE_VERSION_04) {
3684 pr_err("invalid qsee version");
3685 return -ENODEV;
3686 }
3687
3688 if (argp == NULL) {
3689 pr_err("arg is null");
3690 return -EINVAL;
3691 }
3692
3693 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3694 (void *) &resp_buf, sizeof(resp_buf));
3695 if (ret) {
3696 pr_err("scm_call failed");
3697 return ret;
3698 }
3699
3700 req.is_activated = resp_buf;
3701 ret = copy_to_user(argp, &req, sizeof(req));
3702 if (ret) {
3703 pr_err("copy_to_user failed");
3704 return ret;
3705 }
3706
3707 return 0;
3708}
3709
3710static int qseecom_save_partition_hash(void __user *argp)
3711{
3712 struct qseecom_save_partition_hash_req req;
3713 int ret;
3714
3715 if (qseecom.qsee_version < QSEE_VERSION_04) {
3716 pr_err("invalid qsee version ");
3717 return -ENODEV;
3718 }
3719
3720 if (argp == NULL) {
3721 pr_err("arg is null");
3722 return -EINVAL;
3723 }
3724
3725 ret = copy_from_user(&req, argp, sizeof(req));
3726 if (ret) {
3727 pr_err("copy_from_user failed");
3728 return ret;
3729 }
3730
3731 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3732 (void *) &req, sizeof(req), NULL, 0);
3733 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003734 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003735 return ret;
3736 }
3737
3738 return 0;
3739}
3740
Mona Hossain2892b6b2012-02-17 13:53:11 -08003741static long qseecom_ioctl(struct file *file, unsigned cmd,
3742 unsigned long arg)
3743{
3744 int ret = 0;
3745 struct qseecom_dev_handle *data = file->private_data;
3746 void __user *argp = (void __user *) arg;
Zhen Kongd08301c2014-10-08 17:02:54 -07003747 bool perf_enabled = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003748
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303749 if (!data) {
3750 pr_err("Invalid/uninitialized device handle\n");
3751 return -EINVAL;
3752 }
3753
Mona Hossain2892b6b2012-02-17 13:53:11 -08003754 if (data->abort) {
3755 pr_err("Aborting qseecom driver\n");
3756 return -ENODEV;
3757 }
3758
3759 switch (cmd) {
3760 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003761 if (data->type != QSEECOM_GENERIC) {
3762 pr_err("reg lstnr req: invalid handle (%d)\n",
3763 data->type);
3764 ret = -EINVAL;
3765 break;
3766 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003767 pr_debug("ioctl register_listener_req()\n");
3768 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003769 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003770 ret = qseecom_register_listener(data, argp);
3771 atomic_dec(&data->ioctl_count);
3772 wake_up_all(&data->abort_wq);
3773 if (ret)
3774 pr_err("failed qseecom_register_listener: %d\n", ret);
3775 break;
3776 }
3777 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003778 if ((data->listener.id == 0) ||
3779 (data->type != QSEECOM_LISTENER_SERVICE)) {
3780 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3781 data->type, data->listener.id);
3782 ret = -EINVAL;
3783 break;
3784 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003785 pr_debug("ioctl unregister_listener_req()\n");
3786 atomic_inc(&data->ioctl_count);
3787 ret = qseecom_unregister_listener(data);
3788 atomic_dec(&data->ioctl_count);
3789 wake_up_all(&data->abort_wq);
3790 if (ret)
3791 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3792 break;
3793 }
3794 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003795 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003796 if ((data->client.app_id == 0) ||
3797 (data->type != QSEECOM_CLIENT_APP)) {
3798 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3799 data->type, data->client.app_id);
3800 ret = -EINVAL;
3801 break;
3802 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003803 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003804 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003805 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003806 /* register bus bw in case the client doesn't do it */
3807 if (!data->mode) {
3808 mutex_lock(&qsee_bw_mutex);
3809 __qseecom_register_bus_bandwidth_needs(
3810 data, HIGH);
3811 mutex_unlock(&qsee_bw_mutex);
3812 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003813 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3814 if (ret) {
3815 pr_err("Failed to set bw.\n");
3816 ret = -EINVAL;
3817 mutex_unlock(&app_access_lock);
3818 break;
3819 }
3820 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003821 /*
3822 * On targets where crypto clock is handled by HLOS,
3823 * if clk_access_cnt is zero and perf_enabled is false,
3824 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003825 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003826 */
3827 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003828 pr_debug("ce clock is not enabled!\n");
3829 ret = qseecom_perf_enable(data);
3830 if (ret) {
3831 pr_err("Failed to vote for clock with err %d\n",
3832 ret);
3833 mutex_unlock(&app_access_lock);
3834 ret = -EINVAL;
3835 break;
3836 }
3837 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003838 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003839 atomic_inc(&data->ioctl_count);
3840 ret = qseecom_send_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003841 if (qseecom.support_bus_scaling)
3842 __qseecom_add_bw_scale_down_timer(
3843 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003844 if (perf_enabled) {
3845 qsee_disable_clock_vote(data, CLK_DFAB);
3846 qsee_disable_clock_vote(data, CLK_SFPB);
3847 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003848 atomic_dec(&data->ioctl_count);
3849 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003850 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003851 if (ret)
3852 pr_err("failed qseecom_send_cmd: %d\n", ret);
3853 break;
3854 }
3855 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003856 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003857 if ((data->client.app_id == 0) ||
3858 (data->type != QSEECOM_CLIENT_APP)) {
3859 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3860 data->type, data->client.app_id);
3861 ret = -EINVAL;
3862 break;
3863 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003864 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003865 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003866 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003867 if (!data->mode) {
3868 mutex_lock(&qsee_bw_mutex);
3869 __qseecom_register_bus_bandwidth_needs(
3870 data, HIGH);
3871 mutex_unlock(&qsee_bw_mutex);
3872 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003873 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3874 if (ret) {
3875 pr_err("Failed to set bw.\n");
3876 mutex_unlock(&app_access_lock);
3877 ret = -EINVAL;
3878 break;
3879 }
3880 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003881 /*
3882 * On targets where crypto clock is handled by HLOS,
3883 * if clk_access_cnt is zero and perf_enabled is false,
3884 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003885 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003886 */
3887 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003888 pr_debug("ce clock is not enabled!\n");
3889 ret = qseecom_perf_enable(data);
3890 if (ret) {
3891 pr_err("Failed to vote for clock with err %d\n",
3892 ret);
3893 mutex_unlock(&app_access_lock);
3894 ret = -EINVAL;
3895 break;
3896 }
3897 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003898 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003899 atomic_inc(&data->ioctl_count);
3900 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003901 if (qseecom.support_bus_scaling)
3902 __qseecom_add_bw_scale_down_timer(
3903 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003904 if (perf_enabled) {
3905 qsee_disable_clock_vote(data, CLK_DFAB);
3906 qsee_disable_clock_vote(data, CLK_SFPB);
3907 }
Zhen Konge8a02082014-03-11 17:36:50 -07003908 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003909 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003910 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003911 if (ret)
3912 pr_err("failed qseecom_send_cmd: %d\n", ret);
3913 break;
3914 }
3915 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003916 if ((data->listener.id == 0) ||
3917 (data->type != QSEECOM_LISTENER_SERVICE)) {
3918 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3919 data->type, data->listener.id);
3920 ret = -EINVAL;
3921 break;
3922 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003923 atomic_inc(&data->ioctl_count);
3924 ret = qseecom_receive_req(data);
3925 atomic_dec(&data->ioctl_count);
3926 wake_up_all(&data->abort_wq);
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05303927 if (ret && (ret != -ERESTARTSYS))
Mona Hossain2892b6b2012-02-17 13:53:11 -08003928 pr_err("failed qseecom_receive_req: %d\n", ret);
3929 break;
3930 }
3931 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003932 if ((data->listener.id == 0) ||
3933 (data->type != QSEECOM_LISTENER_SERVICE)) {
3934 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3935 data->type, data->listener.id);
3936 ret = -EINVAL;
3937 break;
3938 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003939 atomic_inc(&data->ioctl_count);
3940 ret = qseecom_send_resp();
3941 atomic_dec(&data->ioctl_count);
3942 wake_up_all(&data->abort_wq);
3943 if (ret)
3944 pr_err("failed qseecom_send_resp: %d\n", ret);
3945 break;
3946 }
3947 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003948 if ((data->type != QSEECOM_CLIENT_APP) &&
3949 (data->type != QSEECOM_GENERIC) &&
3950 (data->type != QSEECOM_SECURE_SERVICE)) {
3951 pr_err("set mem param req: invalid handle (%d)\n",
3952 data->type);
3953 ret = -EINVAL;
3954 break;
3955 }
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05303956 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%pK\n", data);
Zhen Kongf8f3e1b2017-02-27 23:41:00 +02003957 mutex_lock(&app_access_lock);
Zhen Kong96f5c012017-05-23 10:21:20 +08003958 atomic_inc(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003959 ret = qseecom_set_client_mem_param(data, argp);
Zhen Kongf8f3e1b2017-02-27 23:41:00 +02003960 atomic_dec(&data->ioctl_count);
Zhen Kong96f5c012017-05-23 10:21:20 +08003961 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003962 if (ret)
3963 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3964 ret);
3965 break;
3966 }
3967 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003968 if ((data->type != QSEECOM_GENERIC) &&
3969 (data->type != QSEECOM_CLIENT_APP)) {
3970 pr_err("load app req: invalid handle (%d)\n",
3971 data->type);
3972 ret = -EINVAL;
3973 break;
3974 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003975 data->type = QSEECOM_CLIENT_APP;
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05303976 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%pK\n", data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003977 mutex_lock(&app_access_lock);
3978 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003979 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3980 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003981 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003982 if (ret == 0)
3983 qseecom.commonlib_loaded = true;
3984 }
3985 }
3986 if (ret == 0)
3987 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003988 atomic_dec(&data->ioctl_count);
3989 mutex_unlock(&app_access_lock);
3990 if (ret)
3991 pr_err("failed load_app request: %d\n", ret);
3992 break;
3993 }
3994 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003995 if ((data->client.app_id == 0) ||
3996 (data->type != QSEECOM_CLIENT_APP)) {
3997 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3998 data->type, data->client.app_id);
3999 ret = -EINVAL;
4000 break;
4001 }
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05304002 pr_debug("UNLOAD_APP: qseecom_addr = 0x%pK\n", data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004003 mutex_lock(&app_access_lock);
4004 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004005 ret = qseecom_unload_app(data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004006 atomic_dec(&data->ioctl_count);
4007 mutex_unlock(&app_access_lock);
4008 if (ret)
4009 pr_err("failed unload_app request: %d\n", ret);
4010 break;
4011 }
4012 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
4013 atomic_inc(&data->ioctl_count);
4014 ret = qseecom_get_qseos_version(data, argp);
4015 if (ret)
4016 pr_err("qseecom_get_qseos_version: %d\n", ret);
4017 atomic_dec(&data->ioctl_count);
4018 break;
4019 }
4020 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004021 if ((data->type != QSEECOM_GENERIC) &&
4022 (data->type != QSEECOM_CLIENT_APP)) {
4023 pr_err("perf enable req: invalid handle (%d)\n",
4024 data->type);
4025 ret = -EINVAL;
4026 break;
4027 }
4028 if ((data->type == QSEECOM_CLIENT_APP) &&
4029 (data->client.app_id == 0)) {
4030 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
4031 data->type, data->client.app_id);
4032 ret = -EINVAL;
4033 break;
4034 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004035 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004036 if (qseecom.support_bus_scaling) {
4037 mutex_lock(&qsee_bw_mutex);
4038 __qseecom_register_bus_bandwidth_needs(data, HIGH);
4039 mutex_unlock(&qsee_bw_mutex);
4040 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07004041 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004042 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07004043 pr_err("Fail to vote for clocks %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004044 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004045 atomic_dec(&data->ioctl_count);
4046 break;
4047 }
4048 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004049 if ((data->type != QSEECOM_SECURE_SERVICE) &&
4050 (data->type != QSEECOM_CLIENT_APP)) {
4051 pr_err("perf disable req: invalid handle (%d)\n",
4052 data->type);
4053 ret = -EINVAL;
4054 break;
4055 }
4056 if ((data->type == QSEECOM_CLIENT_APP) &&
4057 (data->client.app_id == 0)) {
4058 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
4059 data->type, data->client.app_id);
4060 ret = -EINVAL;
4061 break;
4062 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004063 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004064 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004065 qsee_disable_clock_vote(data, CLK_DFAB);
4066 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07004067 } else {
4068 mutex_lock(&qsee_bw_mutex);
4069 qseecom_unregister_bus_bandwidth_needs(data);
4070 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004071 }
4072 atomic_dec(&data->ioctl_count);
4073 break;
4074 }
4075
4076 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
4077 if ((data->client.app_id == 0) ||
4078 (data->type != QSEECOM_CLIENT_APP)) {
4079 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
4080 data->type, data->client.app_id);
4081 ret = -EINVAL;
4082 break;
4083 }
4084 atomic_inc(&data->ioctl_count);
4085 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004086 atomic_dec(&data->ioctl_count);
4087 break;
4088 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004089 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004090 if (data->type != QSEECOM_GENERIC) {
4091 pr_err("load ext elf req: invalid client handle (%d)\n",
4092 data->type);
4093 ret = -EINVAL;
4094 break;
4095 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004096 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004097 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004098 mutex_lock(&app_access_lock);
4099 atomic_inc(&data->ioctl_count);
4100 ret = qseecom_load_external_elf(data, argp);
4101 atomic_dec(&data->ioctl_count);
4102 mutex_unlock(&app_access_lock);
4103 if (ret)
4104 pr_err("failed load_external_elf request: %d\n", ret);
4105 break;
4106 }
4107 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004108 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
4109 pr_err("unload ext elf req: invalid handle (%d)\n",
4110 data->type);
4111 ret = -EINVAL;
4112 break;
4113 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004114 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004115 mutex_lock(&app_access_lock);
4116 atomic_inc(&data->ioctl_count);
4117 ret = qseecom_unload_external_elf(data);
4118 atomic_dec(&data->ioctl_count);
4119 mutex_unlock(&app_access_lock);
4120 if (ret)
4121 pr_err("failed unload_app request: %d\n", ret);
4122 break;
4123 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004124 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Zhen Kong513199d2019-08-27 14:02:35 -07004125 if ((data->type != QSEECOM_GENERIC) &&
4126 (data->type != QSEECOM_CLIENT_APP)) {
4127 pr_err("app loaded query req: invalid handle (%d)\n",
4128 data->type);
4129 ret = -EINVAL;
4130 break;
4131 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004132 data->type = QSEECOM_CLIENT_APP;
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05304133 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%pK\n", data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004134 mutex_lock(&app_access_lock);
4135 atomic_inc(&data->ioctl_count);
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05304136 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%pK\n", data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004137 ret = qseecom_query_app_loaded(data, argp);
4138 atomic_dec(&data->ioctl_count);
4139 mutex_unlock(&app_access_lock);
4140 break;
4141 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004142 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004143 if (data->type != QSEECOM_GENERIC) {
4144 pr_err("send cmd svc req: invalid handle (%d)\n",
4145 data->type);
4146 ret = -EINVAL;
4147 break;
4148 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004149 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004150 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004151 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004152 qseecom.qsee_version);
4153 return -EINVAL;
4154 }
4155 mutex_lock(&app_access_lock);
4156 atomic_inc(&data->ioctl_count);
4157 ret = qseecom_send_service_cmd(data, argp);
4158 atomic_dec(&data->ioctl_count);
4159 mutex_unlock(&app_access_lock);
4160 break;
4161 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004162 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004163 if (!(qseecom.support_pfe || qseecom.support_fde))
4164 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004165 if (data->type != QSEECOM_GENERIC) {
4166 pr_err("create key req: invalid handle (%d)\n",
4167 data->type);
4168 ret = -EINVAL;
4169 break;
4170 }
Zhen Kong336636e2013-04-15 11:04:54 -07004171 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004172 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004173 qseecom.qsee_version);
4174 return -EINVAL;
4175 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004176 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004177 atomic_inc(&data->ioctl_count);
4178 ret = qseecom_create_key(data, argp);
4179 if (ret)
4180 pr_err("failed to create encryption key: %d\n", ret);
4181
4182 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004183 break;
4184 }
4185 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004186 if (!(qseecom.support_pfe || qseecom.support_fde))
4187 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004188 if (data->type != QSEECOM_GENERIC) {
4189 pr_err("wipe key req: invalid handle (%d)\n",
4190 data->type);
4191 ret = -EINVAL;
4192 break;
4193 }
Zhen Kong336636e2013-04-15 11:04:54 -07004194 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004195 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004196 qseecom.qsee_version);
4197 return -EINVAL;
4198 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004199 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004200 atomic_inc(&data->ioctl_count);
4201 ret = qseecom_wipe_key(data, argp);
4202 if (ret)
4203 pr_err("failed to wipe encryption key: %d\n", ret);
4204 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08004205 break;
4206 }
4207 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004208 if (!(qseecom.support_pfe || qseecom.support_fde))
4209 pr_err("Features requiring key init not supported\n");
Zhen Kong9730ddf2013-12-17 16:49:43 -08004210 if (data->type != QSEECOM_GENERIC) {
4211 pr_err("update key req: invalid handle (%d)\n",
4212 data->type);
4213 ret = -EINVAL;
4214 break;
4215 }
4216 if (qseecom.qsee_version < QSEE_VERSION_05) {
4217 pr_err("Update Key feature unsupported in qsee ver %u\n",
4218 qseecom.qsee_version);
4219 return -EINVAL;
4220 }
4221 data->released = true;
4222 atomic_inc(&data->ioctl_count);
4223 ret = qseecom_update_key_user_info(data, argp);
4224 if (ret)
4225 pr_err("failed to update key user info: %d\n", ret);
4226 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004227 break;
4228 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004229 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004230 if (data->type != QSEECOM_GENERIC) {
4231 pr_err("save part hash req: invalid handle (%d)\n",
4232 data->type);
4233 ret = -EINVAL;
4234 break;
4235 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004236 data->released = true;
4237 mutex_lock(&app_access_lock);
4238 atomic_inc(&data->ioctl_count);
4239 ret = qseecom_save_partition_hash(argp);
4240 atomic_dec(&data->ioctl_count);
4241 mutex_unlock(&app_access_lock);
4242 break;
4243 }
4244 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004245 if (data->type != QSEECOM_GENERIC) {
4246 pr_err("ES activated req: invalid handle (%d)\n",
4247 data->type);
4248 ret = -EINVAL;
4249 break;
4250 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004251 data->released = true;
4252 mutex_lock(&app_access_lock);
4253 atomic_inc(&data->ioctl_count);
4254 ret = qseecom_is_es_activated(argp);
4255 atomic_dec(&data->ioctl_count);
4256 mutex_unlock(&app_access_lock);
4257 break;
4258 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004259 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004260 if ((data->listener.id == 0) ||
4261 (data->type != QSEECOM_LISTENER_SERVICE)) {
4262 pr_err("receive req: invalid handle (%d), lid(%d)\n",
4263 data->type, data->listener.id);
4264 ret = -EINVAL;
4265 break;
4266 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004267 /* Only one client allowed here at a time */
4268 atomic_inc(&data->ioctl_count);
4269 ret = qseecom_send_modfd_resp(data, argp);
4270 atomic_dec(&data->ioctl_count);
4271 wake_up_all(&data->abort_wq);
4272 if (ret)
4273 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
4274 break;
4275 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004276 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07004277 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004278 return -EINVAL;
4279 }
4280 return ret;
4281}
4282
4283static int qseecom_open(struct inode *inode, struct file *file)
4284{
4285 int ret = 0;
4286 struct qseecom_dev_handle *data;
4287
4288 data = kzalloc(sizeof(*data), GFP_KERNEL);
4289 if (!data) {
4290 pr_err("kmalloc failed\n");
4291 return -ENOMEM;
4292 }
4293 file->private_data = data;
4294 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004295 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004296 data->released = false;
William Clarkc7a043d2014-05-23 15:08:52 -07004297 memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004298 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004299 init_waitqueue_head(&data->abort_wq);
4300 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07004301
Mona Hossain2892b6b2012-02-17 13:53:11 -08004302 return ret;
4303}
4304
4305static int qseecom_release(struct inode *inode, struct file *file)
4306{
4307 struct qseecom_dev_handle *data = file->private_data;
4308 int ret = 0;
4309
4310 if (data->released == false) {
Mallikarjuna Reddy Amireddy6e1ac942016-07-25 18:14:39 +05304311 pr_debug("data: released = false, type = %d, data = 0x%pK\n",
4312 data->type, data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004313 switch (data->type) {
4314 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004315 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004316 break;
4317 case QSEECOM_CLIENT_APP:
Zhen Kong9bfacc52015-06-09 14:49:36 -07004318 mutex_lock(&app_access_lock);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004319 ret = qseecom_unload_app(data, true);
Zhen Kong9bfacc52015-06-09 14:49:36 -07004320 mutex_unlock(&app_access_lock);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004321 break;
4322 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07004323 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004324 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004325 if (ret)
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07004326 pr_err("Ion Unmap failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004327 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05304328 case QSEECOM_UNAVAILABLE_CLIENT_APP:
4329 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004330 default:
4331 pr_err("Unsupported clnt_handle_type %d",
4332 data->type);
4333 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004334 }
4335 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004336
Zhen Kong2edf90d2013-08-27 12:05:06 -07004337 if (qseecom.support_bus_scaling) {
4338 mutex_lock(&qsee_bw_mutex);
4339 if (data->mode != INACTIVE) {
4340 qseecom_unregister_bus_bandwidth_needs(data);
4341 if (qseecom.cumulative_mode == INACTIVE) {
4342 ret = __qseecom_set_msm_bus_request(INACTIVE);
4343 if (ret)
4344 pr_err("Fail to scale down bus\n");
4345 }
4346 }
4347 mutex_unlock(&qsee_bw_mutex);
4348 } else {
4349 if (data->fast_load_enabled == true)
4350 qsee_disable_clock_vote(data, CLK_SFPB);
4351 if (data->perf_enabled == true)
4352 qsee_disable_clock_vote(data, CLK_DFAB);
4353 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004354 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08004355
Mona Hossain2892b6b2012-02-17 13:53:11 -08004356 return ret;
4357}
4358
Mona Hossain2892b6b2012-02-17 13:53:11 -08004359static const struct file_operations qseecom_fops = {
4360 .owner = THIS_MODULE,
4361 .unlocked_ioctl = qseecom_ioctl,
4362 .open = qseecom_open,
4363 .release = qseecom_release
4364};
4365
Mona Hossainc92629e2013-04-01 13:37:46 -07004366static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004367{
4368 int rc = 0;
4369 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004370 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07004371 char *core_clk_src = NULL;
4372 char *core_clk = NULL;
4373 char *iface_clk = NULL;
4374 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004375
Mona Hossainc92629e2013-04-01 13:37:46 -07004376 switch (ce) {
4377 case CLK_QSEE: {
4378 core_clk_src = "core_clk_src";
4379 core_clk = "core_clk";
4380 iface_clk = "iface_clk";
4381 bus_clk = "bus_clk";
4382 qclk = &qseecom.qsee;
4383 qclk->instance = CLK_QSEE;
4384 break;
4385 };
4386 case CLK_CE_DRV: {
4387 core_clk_src = "ce_drv_core_clk_src";
4388 core_clk = "ce_drv_core_clk";
4389 iface_clk = "ce_drv_iface_clk";
4390 bus_clk = "ce_drv_bus_clk";
4391 qclk = &qseecom.ce_drv;
4392 qclk->instance = CLK_CE_DRV;
4393 break;
4394 };
4395 default:
4396 pr_err("Invalid ce hw instance: %d!\n", ce);
4397 return -EIO;
4398 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004399 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004400
Mona Hossainc92629e2013-04-01 13:37:46 -07004401 /* Get CE3 src core clk. */
4402 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004403 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08004404 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07004405 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004406 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07004407 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004408 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08004409 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004410 }
4411 } else {
4412 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004413 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004414 }
4415
4416 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004417 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004418 if (IS_ERR(qclk->ce_core_clk)) {
4419 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004420 pr_err("Unable to get CE core 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);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004423 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004424 }
4425
4426 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004427 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004428 if (IS_ERR(qclk->ce_clk)) {
4429 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004430 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004431 if (qclk->ce_core_src_clk != NULL)
4432 clk_put(qclk->ce_core_src_clk);
4433 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004434 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004435 }
4436
4437 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004438 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004439 if (IS_ERR(qclk->ce_bus_clk)) {
4440 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004441 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004442 if (qclk->ce_core_src_clk != NULL)
4443 clk_put(qclk->ce_core_src_clk);
4444 clk_put(qclk->ce_core_clk);
4445 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004446 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004447 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004448 return rc;
4449}
4450
Mona Hossainc92629e2013-04-01 13:37:46 -07004451static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004452{
Mona Hossain17a4faf2013-03-22 16:40:56 -07004453 struct qseecom_clk *qclk;
4454
Mona Hossainc92629e2013-04-01 13:37:46 -07004455 if (ce == CLK_QSEE)
4456 qclk = &qseecom.qsee;
4457 else
4458 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004459
4460 if (qclk->ce_clk != NULL) {
4461 clk_put(qclk->ce_clk);
4462 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004463 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004464 if (qclk->ce_core_clk != NULL) {
4465 clk_put(qclk->ce_core_clk);
4466 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004467 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004468 if (qclk->ce_bus_clk != NULL) {
4469 clk_put(qclk->ce_bus_clk);
4470 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004471 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004472 if (qclk->ce_core_src_clk != NULL) {
4473 clk_put(qclk->ce_core_src_clk);
4474 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004475 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004476}
4477
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004478static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004479{
4480 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004481 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004482 struct device *class_dev;
4483 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07004484 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004485 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
4486
Mona Hossain17a4faf2013-03-22 16:40:56 -07004487 qseecom.qsee_bw_count = 0;
4488 qseecom.qsee_perf_client = 0;
4489 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004490
Mona Hossain17a4faf2013-03-22 16:40:56 -07004491 qseecom.qsee.ce_core_clk = NULL;
4492 qseecom.qsee.ce_clk = NULL;
4493 qseecom.qsee.ce_core_src_clk = NULL;
4494 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07004495
Zhen Kong2edf90d2013-08-27 12:05:06 -07004496 qseecom.cumulative_mode = 0;
4497 qseecom.current_mode = INACTIVE;
4498 qseecom.support_bus_scaling = false;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004499 qseecom.support_fde = false;
4500 qseecom.support_pfe = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004501
Mona Hossainc92629e2013-04-01 13:37:46 -07004502 qseecom.ce_drv.ce_core_clk = NULL;
4503 qseecom.ce_drv.ce_clk = NULL;
4504 qseecom.ce_drv.ce_core_src_clk = NULL;
4505 qseecom.ce_drv.ce_bus_clk = NULL;
4506
Mona Hossain2892b6b2012-02-17 13:53:11 -08004507 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
4508 if (rc < 0) {
4509 pr_err("alloc_chrdev_region failed %d\n", rc);
4510 return rc;
4511 }
4512
4513 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
4514 if (IS_ERR(driver_class)) {
4515 rc = -ENOMEM;
4516 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304517 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004518 }
4519
4520 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
4521 QSEECOM_DEV);
4522 if (!class_dev) {
4523 pr_err("class_device_create failed %d\n", rc);
4524 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304525 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004526 }
4527
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304528 cdev_init(&qseecom.cdev, &qseecom_fops);
4529 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004530
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304531 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004532 if (rc < 0) {
4533 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304534 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004535 }
4536
4537 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
4538 spin_lock_init(&qseecom.registered_listener_list_lock);
4539 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
4540 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07004541 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
4542 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004543 init_waitqueue_head(&qseecom.send_resp_wq);
4544 qseecom.send_resp_flag = 0;
4545
4546 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
4547 &qsee_not_legacy, sizeof(qsee_not_legacy));
4548 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07004549 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304550 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004551 }
Mona Hossain05c73562012-10-29 17:49:01 -07004552 if (qsee_not_legacy) {
4553 uint32_t feature = 10;
4554
4555 qseecom.qsee_version = QSEEE_VERSION_00;
4556 rc = scm_call(6, 3, &feature, sizeof(feature),
4557 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
4558 if (rc) {
4559 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304560 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07004561 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004562 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07004563 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07004564 pr_err("QSEE legacy version is not supported:");
4565 pr_err("Support for TZ1.3 and earlier is deprecated\n");
4566 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304567 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004568 }
Mona Hossain05c73562012-10-29 17:49:01 -07004569 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004570 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004571 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07004572 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08004573 if (qseecom.ion_clnt == NULL) {
4574 pr_err("Ion client cannot be created\n");
4575 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304576 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004577 }
4578
4579 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004580 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05304581 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004582 qseecom.support_bus_scaling =
4583 of_property_read_bool((&pdev->dev)->of_node,
4584 "qcom,support-bus-scaling");
4585 pr_warn("support_bus_scaling=0x%x",
4586 qseecom.support_bus_scaling);
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004587 qseecom.support_fde =
4588 of_property_read_bool((&pdev->dev)->of_node,
4589 "qcom,support-fde");
4590 if (qseecom.support_fde) {
4591 if (of_property_read_u32((&pdev->dev)->of_node,
Mona Hossain4cf78a92013-02-14 12:06:41 -08004592 "qcom,disk-encrypt-pipe-pair",
4593 &qseecom.ce_info.disk_encrypt_pipe)) {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004594 pr_err("Fail to get FDE pipe information.\n");
4595 rc = -EINVAL;
4596 goto exit_destroy_ion_client;
4597 } else {
4598 pr_warn("disk-encrypt-pipe-pair=0x%x",
4599 qseecom.ce_info.disk_encrypt_pipe);
4600 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004601 } else {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004602 pr_warn("Device does not support FDE");
4603 qseecom.ce_info.disk_encrypt_pipe = 0xff;
4604 }
4605 qseecom.support_pfe =
4606 of_property_read_bool((&pdev->dev)->of_node,
4607 "qcom,support-pfe");
4608 if (qseecom.support_pfe) {
4609 if (of_property_read_u32((&pdev->dev)->of_node,
4610 "qcom,file-encrypt-pipe-pair",
4611 &qseecom.ce_info.disk_encrypt_pipe)) {
4612 pr_err("Fail to get PFE pipe information.\n");
4613 rc = -EINVAL;
4614 goto exit_destroy_ion_client;
4615 } else {
4616 pr_warn("file-encrypt-pipe-pair=0x%x",
4617 qseecom.ce_info.file_encrypt_pipe);
4618 }
4619 } else {
4620 pr_warn("Device does not support PFE");
4621 qseecom.ce_info.file_encrypt_pipe = 0xff;
4622 }
4623 if (qseecom.support_pfe || qseecom.support_fde) {
4624 if (of_property_read_u32((&pdev->dev)->of_node,
4625 "qcom,hlos-ce-hw-instance",
4626 &qseecom.ce_info.hlos_ce_hw_instance)) {
4627 pr_err("Fail: get hlos ce hw instanc info\n");
4628 rc = -EINVAL;
4629 goto exit_destroy_ion_client;
4630 } else {
4631 pr_warn("hlos-ce-hw-instance=0x%x",
4632 qseecom.ce_info.hlos_ce_hw_instance);
4633 }
4634 } else {
4635 pr_warn("Device does not support PFE/FDE");
4636 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004637 }
4638
4639 if (of_property_read_u32((&pdev->dev)->of_node,
4640 "qcom,qsee-ce-hw-instance",
4641 &qseecom.ce_info.qsee_ce_hw_instance)) {
4642 pr_err("Fail to get qsee ce hw instance information.\n");
Mona Hossain4cf78a92013-02-14 12:06:41 -08004643 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304644 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004645 } else {
4646 pr_warn("qsee-ce-hw-instance=0x%x",
4647 qseecom.ce_info.qsee_ce_hw_instance);
4648 }
4649
Zhen Kong56d62642015-03-10 16:29:53 -07004650 qseecom.appsbl_qseecom_support =
4651 of_property_read_bool((&pdev->dev)->of_node,
4652 "qcom,appsbl-qseecom-support");
4653 pr_info("qseecom.appsbl_qseecom_support = 0x%x",
4654 qseecom.appsbl_qseecom_support);
4655
Mona Hossainc92629e2013-04-01 13:37:46 -07004656 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
4657 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
4658
4659 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004660 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304661 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08004662
Zhen Konga10dcab2014-03-19 10:32:27 -07004663 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4664 (qseecom.support_pfe || qseecom.support_fde)) {
Mona Hossainc92629e2013-04-01 13:37:46 -07004665 ret = __qseecom_init_clk(CLK_CE_DRV);
4666 if (ret) {
4667 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304668 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07004669 }
4670 } else {
4671 struct qseecom_clk *qclk;
4672
4673 qclk = &qseecom.qsee;
4674 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
4675 qseecom.ce_drv.ce_clk = qclk->ce_clk;
4676 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
4677 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
4678 }
4679
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004680 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4681 msm_bus_cl_get_pdata(pdev);
Zhen Kong56d62642015-03-10 16:29:53 -07004682 if (qseecom.qsee_version >= (QSEE_VERSION_02) &&
4683 !qseecom.appsbl_qseecom_support) {
Mona Hossain5b76a622012-11-15 20:09:08 -08004684 struct resource *resource = NULL;
4685 struct qsee_apps_region_info_ireq req;
4686 struct qseecom_command_scm_resp resp;
4687
4688 resource = platform_get_resource_byname(pdev,
4689 IORESOURCE_MEM, "secapp-region");
4690 if (resource) {
4691 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
4692 req.addr = resource->start;
4693 req.size = resource_size(resource);
4694 pr_warn("secure app region addr=0x%x size=0x%x",
4695 req.addr, req.size);
4696 } else {
4697 pr_err("Fail to get secure app region info\n");
4698 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304699 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004700 }
4701 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
4702 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07004703 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
4704 pr_err("send secapp reg fail %d resp.res %d\n",
4705 rc, resp.result);
4706 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304707 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004708 }
4709 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004710 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004711 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4712 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004713 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004714 if (qseecom.support_bus_scaling) {
4715 init_timer(&(qseecom.bw_scale_down_timer));
4716 INIT_WORK(&qseecom.bw_inactive_req_ws,
4717 qseecom_bw_inactive_req_work);
4718 qseecom.bw_scale_down_timer.function =
4719 qseecom_scale_bus_bandwidth_timer_callback;
4720 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004721 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004722 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004723 qseecom_platform_support);
4724
Mona Hossain17a4faf2013-03-22 16:40:56 -07004725 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004726 pr_err("Unable to register bus client\n");
4727 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304728
4729exit_destroy_ion_client:
4730 ion_client_destroy(qseecom.ion_clnt);
4731exit_del_cdev:
4732 cdev_del(&qseecom.cdev);
4733exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004734 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304735exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004736 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304737exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004738 unregister_chrdev_region(qseecom_device_no, 1);
4739 return rc;
4740}
4741
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004742static int __devinit qseecom_remove(struct platform_device *pdev)
4743{
Mona Hossaind44a3842012-10-15 09:41:35 -07004744 struct qseecom_registered_kclient_list *kclient = NULL;
Monika Singh3d486ed2018-04-24 09:54:50 +05304745 struct qseecom_registered_kclient_list *kclient_tmp = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07004746 unsigned long flags = 0;
4747 int ret = 0;
4748
Mona Hossaind44a3842012-10-15 09:41:35 -07004749 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304750
Monika Singh3d486ed2018-04-24 09:54:50 +05304751 list_for_each_entry_safe(kclient, kclient_tmp,
4752 &qseecom.registered_kclient_list_head, list) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004753
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304754 /* Break the loop if client handle is NULL */
4755 if (!kclient->handle)
4756 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004757
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304758 if (list_empty(&kclient->list))
4759 goto exit_free_kc_handle;
4760
4761 list_del(&kclient->list);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004762 ret = qseecom_unload_app(kclient->handle->dev, false);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304763 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004764 kzfree(kclient->handle->dev);
4765 kzfree(kclient->handle);
4766 kzfree(kclient);
4767 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004768 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304769
4770exit_free_kc_handle:
4771 kzfree(kclient->handle);
4772exit_free_kclient:
4773 kzfree(kclient);
Monika Singh3d486ed2018-04-24 09:54:50 +05304774
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304775 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4776
4777 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004778 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004779
Mona Hossain17a4faf2013-03-22 16:40:56 -07004780 if (qseecom.qsee_perf_client)
4781 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4782 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304783 if (pdev->dev.platform_data != NULL)
4784 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4785
Zhen Kong2edf90d2013-08-27 12:05:06 -07004786 if (qseecom.support_bus_scaling) {
4787 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4788 del_timer_sync(&qseecom.bw_scale_down_timer);
4789 }
4790
Mona Hossaind39e33b2012-11-05 13:36:40 -08004791 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004792 if (pdev->dev.of_node) {
4793 __qseecom_deinit_clk(CLK_QSEE);
Zhen Konga10dcab2014-03-19 10:32:27 -07004794 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4795 (qseecom.support_pfe || qseecom.support_fde))
Mona Hossainc92629e2013-04-01 13:37:46 -07004796 __qseecom_deinit_clk(CLK_CE_DRV);
4797 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304798
4799 ion_client_destroy(qseecom.ion_clnt);
4800
4801 cdev_del(&qseecom.cdev);
4802
4803 device_destroy(driver_class, qseecom_device_no);
4804
4805 class_destroy(driver_class);
4806
4807 unregister_chrdev_region(qseecom_device_no, 1);
4808
Mona Hossaind44a3842012-10-15 09:41:35 -07004809 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304810}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004811
Zhen Konga0944b82013-11-06 17:02:00 -08004812static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4813{
4814 int ret = 0;
4815 struct qseecom_clk *qclk;
4816 qclk = &qseecom.qsee;
4817
Zhen Konge5b434e2014-04-17 16:47:06 -07004818 mutex_lock(&qsee_bw_mutex);
4819 mutex_lock(&clk_access_lock);
4820
Zhen Kong60f4f702014-10-15 17:57:17 -07004821 if (qseecom.current_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004822 ret = msm_bus_scale_client_update_request(
4823 qseecom.qsee_perf_client, INACTIVE);
Zhen Konga0944b82013-11-06 17:02:00 -08004824 if (ret)
4825 pr_err("Fail to scale down bus\n");
Zhen Konge5b434e2014-04-17 16:47:06 -07004826 else
4827 qseecom.current_mode = INACTIVE;
Zhen Konga0944b82013-11-06 17:02:00 -08004828 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004829
Zhen Konga0944b82013-11-06 17:02:00 -08004830 if (qclk->clk_access_cnt) {
4831 if (qclk->ce_clk != NULL)
4832 clk_disable_unprepare(qclk->ce_clk);
4833 if (qclk->ce_core_clk != NULL)
4834 clk_disable_unprepare(qclk->ce_core_clk);
4835 if (qclk->ce_bus_clk != NULL)
4836 clk_disable_unprepare(qclk->ce_bus_clk);
4837 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004838
4839 del_timer_sync(&(qseecom.bw_scale_down_timer));
4840 qseecom.timer_running = false;
4841
Zhen Konga0944b82013-11-06 17:02:00 -08004842 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004843 mutex_unlock(&qsee_bw_mutex);
4844
Zhen Konga0944b82013-11-06 17:02:00 -08004845 return 0;
4846}
4847
4848static int qseecom_resume(struct platform_device *pdev)
4849{
4850 int mode = 0;
4851 int ret = 0;
4852 struct qseecom_clk *qclk;
4853 qclk = &qseecom.qsee;
4854
Zhen Konge5b434e2014-04-17 16:47:06 -07004855 mutex_lock(&qsee_bw_mutex);
4856 mutex_lock(&clk_access_lock);
Zhen Konga0944b82013-11-06 17:02:00 -08004857 if (qseecom.cumulative_mode >= HIGH)
4858 mode = HIGH;
4859 else
4860 mode = qseecom.cumulative_mode;
4861
4862 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004863 ret = msm_bus_scale_client_update_request(
Zhen Kong98b0e512014-04-04 10:12:24 -07004864 qseecom.qsee_perf_client, mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004865 if (ret)
Zhen Kong98b0e512014-04-04 10:12:24 -07004866 pr_err("Fail to scale up bus to %d\n", mode);
Zhen Konge5b434e2014-04-17 16:47:06 -07004867 else
4868 qseecom.current_mode = mode;
Zhen Konga0944b82013-11-06 17:02:00 -08004869 }
4870
Zhen Konga0944b82013-11-06 17:02:00 -08004871 if (qclk->clk_access_cnt) {
4872
4873 ret = clk_prepare_enable(qclk->ce_core_clk);
4874 if (ret) {
4875 pr_err("Unable to enable/prepare CE core clk\n");
4876 qclk->clk_access_cnt = 0;
4877 goto err;
4878 }
4879
4880 ret = clk_prepare_enable(qclk->ce_clk);
4881 if (ret) {
4882 pr_err("Unable to enable/prepare CE iface clk\n");
4883 qclk->clk_access_cnt = 0;
4884 goto ce_clk_err;
4885 }
4886
4887 ret = clk_prepare_enable(qclk->ce_bus_clk);
4888 if (ret) {
4889 pr_err("Unable to enable/prepare CE bus clk\n");
4890 qclk->clk_access_cnt = 0;
4891 goto ce_bus_clk_err;
4892 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004893 }
4894
4895 if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004896 qseecom.bw_scale_down_timer.expires = jiffies +
4897 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge5b434e2014-04-17 16:47:06 -07004898 mod_timer(&(qseecom.bw_scale_down_timer),
4899 qseecom.bw_scale_down_timer.expires);
Zhen Kongca4c2d52014-03-12 13:22:46 -07004900 qseecom.timer_running = true;
Zhen Konga0944b82013-11-06 17:02:00 -08004901 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004902
Zhen Konga0944b82013-11-06 17:02:00 -08004903 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004904 mutex_unlock(&qsee_bw_mutex);
4905
4906
Zhen Konga0944b82013-11-06 17:02:00 -08004907 return 0;
4908
4909ce_bus_clk_err:
4910 clk_disable_unprepare(qclk->ce_clk);
4911ce_clk_err:
4912 clk_disable_unprepare(qclk->ce_core_clk);
4913err:
4914 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004915 mutex_unlock(&qsee_bw_mutex);
Zhen Konga0944b82013-11-06 17:02:00 -08004916 return -EIO;
4917}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004918static struct of_device_id qseecom_match[] = {
4919 {
4920 .compatible = "qcom,qseecom",
4921 },
4922 {}
4923};
4924
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004925static struct platform_driver qseecom_plat_driver = {
4926 .probe = qseecom_probe,
4927 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004928 .suspend = qseecom_suspend,
4929 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004930 .driver = {
4931 .name = "qseecom",
4932 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004933 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004934 },
4935};
4936
4937static int __devinit qseecom_init(void)
4938{
4939 return platform_driver_register(&qseecom_plat_driver);
4940}
4941
4942static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004943{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304944 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004945}
4946
4947MODULE_LICENSE("GPL v2");
4948MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4949
4950module_init(qseecom_init);
4951module_exit(qseecom_exit);