blob: ff1701aafffa161f7b7d59e1a458dd3eb1ca4fb6 [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 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800395 init_waitqueue_head(&new_entry->rcv_req_wq);
396
397 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
398 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
399 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800400
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
Mona Hossaind4613de2013-05-15 16:49:29 -0700414 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
415 req.listener_id = data->listener.id;
416 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800417
Mona Hossaind4613de2013-05-15 16:49:29 -0700418 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800419 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700420 if (ret) {
421 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
422 ret, data->listener.id);
423 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800424 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700425
426 if (resp.result != QSEOS_RESULT_SUCCESS) {
427 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
428 resp.result, data->listener.id);
429 return -EPERM;
430 }
431
Mona Hossain2892b6b2012-02-17 13:53:11 -0800432 data->abort = 1;
433 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
434 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
435 list) {
436 if (ptr_svc->svc.listener_id == data->listener.id) {
437 wake_up_all(&ptr_svc->rcv_req_wq);
438 break;
439 }
440 }
441 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
442
443 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700444 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800445 atomic_read(&data->ioctl_count) <= 1)) {
446 pr_err("Interrupted from abort\n");
447 ret = -ERESTARTSYS;
448 break;
449 }
450 }
451
452 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
453 list_for_each_entry(ptr_svc,
454 &qseecom.registered_listener_list_head,
455 list)
456 {
457 if (ptr_svc->svc.listener_id == data->listener.id) {
458 if (ptr_svc->sb_virt) {
459 unmap_mem = 1;
460 ihandle = ptr_svc->ihandle;
461 }
462 list_del(&ptr_svc->list);
463 kzfree(ptr_svc);
464 break;
465 }
466 }
467 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
468
469 /* Unmap the memory */
470 if (unmap_mem) {
471 if (!IS_ERR_OR_NULL(ihandle)) {
472 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
473 ion_free(qseecom.ion_clnt, ihandle);
474 }
475 }
476 data->released = true;
477 return ret;
478}
479
Zhen Kong2edf90d2013-08-27 12:05:06 -0700480static int __qseecom_set_msm_bus_request(uint32_t mode)
481{
482 int ret = 0;
483 struct qseecom_clk *qclk;
484
485 qclk = &qseecom.qsee;
486 if (qclk->ce_core_src_clk != NULL) {
487 if (mode == INACTIVE) {
488 __qseecom_disable_clk(CLK_QSEE);
489 } else {
490 ret = __qseecom_enable_clk(CLK_QSEE);
491 if (ret)
492 pr_err("CLK enabling failed (%d) MODE (%d)\n",
493 ret, mode);
494 }
495 }
496
497 if ((!ret) && (qseecom.current_mode != mode)) {
498 ret = msm_bus_scale_client_update_request(
499 qseecom.qsee_perf_client, mode);
500 if (ret) {
501 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
502 ret, mode);
503 if (qclk->ce_core_src_clk != NULL) {
504 if (mode == INACTIVE)
505 __qseecom_enable_clk(CLK_QSEE);
506 else
507 __qseecom_disable_clk(CLK_QSEE);
508 }
509 }
510 qseecom.current_mode = mode;
511 }
512 return ret;
513}
514
515static void qseecom_bw_inactive_req_work(struct work_struct *work)
516{
517 mutex_lock(&app_access_lock);
518 mutex_lock(&qsee_bw_mutex);
519 __qseecom_set_msm_bus_request(INACTIVE);
520 pr_debug("current_mode = %d, cumulative_mode = %d\n",
521 qseecom.current_mode, qseecom.cumulative_mode);
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800522 qseecom.timer_running = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700523 mutex_unlock(&qsee_bw_mutex);
524 mutex_unlock(&app_access_lock);
525 return;
526}
527
528static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
529{
530 schedule_work(&qseecom.bw_inactive_req_ws);
531 return;
532}
533
Zhen Kongca4c2d52014-03-12 13:22:46 -0700534static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800535{
536 struct qseecom_clk *qclk;
Zhen Kongca4c2d52014-03-12 13:22:46 -0700537 int ret = 0;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800538 mutex_lock(&clk_access_lock);
539 if (ce == CLK_QSEE)
540 qclk = &qseecom.qsee;
541 else
542 qclk = &qseecom.ce_drv;
543
Zhen Kongca4c2d52014-03-12 13:22:46 -0700544 if (qclk->clk_access_cnt > 2) {
545 pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
546 ret = -EINVAL;
547 goto err_dec_ref_cnt;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800548 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700549 if (qclk->clk_access_cnt == 2)
550 qclk->clk_access_cnt--;
551
552err_dec_ref_cnt:
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800553 mutex_unlock(&clk_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -0700554 return ret;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800555}
556
557
Zhen Kongaf950192014-02-05 17:36:23 -0800558static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700559{
560 int32_t ret = 0;
561 int32_t request_mode = INACTIVE;
562
563 mutex_lock(&qsee_bw_mutex);
564 if (mode == 0) {
565 if (qseecom.cumulative_mode > MEDIUM)
566 request_mode = HIGH;
567 else
568 request_mode = qseecom.cumulative_mode;
569 } else {
570 request_mode = mode;
571 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700572
Zhen Kongca4c2d52014-03-12 13:22:46 -0700573 ret = __qseecom_set_msm_bus_request(request_mode);
574 if (ret) {
575 pr_err("set msm bus request failed (%d),request_mode (%d)\n",
576 ret, request_mode);
577 goto err_scale_timer;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800578 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700579
580 if (qseecom.timer_running) {
581 ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
582 if (ret) {
583 pr_err("Failed to decrease clk ref count.\n");
584 goto err_scale_timer;
585 }
586 del_timer_sync(&(qseecom.bw_scale_down_timer));
587 qseecom.timer_running = false;
588 }
589err_scale_timer:
Zhen Kong2edf90d2013-08-27 12:05:06 -0700590 mutex_unlock(&qsee_bw_mutex);
591 return ret;
592}
593
594
595static int qseecom_unregister_bus_bandwidth_needs(
596 struct qseecom_dev_handle *data)
597{
598 int32_t ret = 0;
599
600 qseecom.cumulative_mode -= data->mode;
601 data->mode = INACTIVE;
602
603 return ret;
604}
605
606static int __qseecom_register_bus_bandwidth_needs(
607 struct qseecom_dev_handle *data, uint32_t request_mode)
608{
609 int32_t ret = 0;
610
611 if (data->mode == INACTIVE) {
612 qseecom.cumulative_mode += request_mode;
613 data->mode = request_mode;
614 } else {
615 if (data->mode != request_mode) {
616 qseecom.cumulative_mode -= data->mode;
617 qseecom.cumulative_mode += request_mode;
618 data->mode = request_mode;
619 }
620 }
621 return ret;
622}
623
Zhen Kongd08301c2014-10-08 17:02:54 -0700624static int qseecom_perf_enable(struct qseecom_dev_handle *data)
625{
626 int ret = 0;
627 ret = qsee_vote_for_clock(data, CLK_DFAB);
628 if (ret) {
629 pr_err("Failed to vote for DFAB clock with err %d\n", ret);
630 goto perf_enable_exit;
631 }
632 ret = qsee_vote_for_clock(data, CLK_SFPB);
633 if (ret) {
634 qsee_disable_clock_vote(data, CLK_DFAB);
635 pr_err("Failed to vote for SFPB clock with err %d\n", ret);
636 goto perf_enable_exit;
637 }
638
639perf_enable_exit:
640 return ret;
641}
642
Zhen Kong2edf90d2013-08-27 12:05:06 -0700643static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
644 void __user *argp)
645{
646 int32_t ret = 0;
647 int32_t req_mode;
648
649 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
650 if (ret) {
651 pr_err("copy_from_user failed\n");
652 return ret;
653 }
654 if (req_mode > HIGH) {
655 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
Mona Hossain268c3122014-11-03 17:05:48 -0800656 return -EINVAL;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700657 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700658
Zhen Kongd08301c2014-10-08 17:02:54 -0700659 /*
660 * Register bus bandwidth needs if bus scaling feature is enabled;
661 * otherwise, qseecom enable/disable clocks for the client directly.
662 */
663 if (qseecom.support_bus_scaling) {
664 mutex_lock(&qsee_bw_mutex);
665 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
666 mutex_unlock(&qsee_bw_mutex);
667 } else {
668 pr_debug("Bus scaling feature is NOT enabled\n");
669 pr_debug("request bandwidth mode %d for the client\n",
670 req_mode);
671 if (req_mode != INACTIVE) {
672 ret = qseecom_perf_enable(data);
673 if (ret)
674 pr_err("Failed to vote for clock with err %d\n",
675 ret);
676 } else {
677 qsee_disable_clock_vote(data, CLK_DFAB);
678 qsee_disable_clock_vote(data, CLK_SFPB);
679 }
680 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700681 return ret;
682}
683
Zhen Kongaf950192014-02-05 17:36:23 -0800684static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
685{
686 mutex_lock(&qsee_bw_mutex);
687 qseecom.bw_scale_down_timer.expires = jiffies +
688 msecs_to_jiffies(duration);
Zhen Konge5b434e2014-04-17 16:47:06 -0700689 mod_timer(&(qseecom.bw_scale_down_timer),
690 qseecom.bw_scale_down_timer.expires);
Zhen Kongaf950192014-02-05 17:36:23 -0800691 qseecom.timer_running = true;
692 mutex_unlock(&qsee_bw_mutex);
693}
694
Zhen Kong2edf90d2013-08-27 12:05:06 -0700695static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
696{
697 if (!qseecom.support_bus_scaling)
698 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -0800699 else
700 __qseecom_add_bw_scale_down_timer(
701 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700702 return;
703}
704
705static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
706{
707 int ret = 0;
708 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -0700709 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
710 if (ret)
711 pr_err("Failed to set bw MEDIUM.\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700712 } else {
713 ret = qsee_vote_for_clock(data, CLK_SFPB);
714 if (ret)
715 pr_err("Fail vote for clk SFPB ret %d\n", ret);
716 }
717 return ret;
718}
719
Mona Hossain2892b6b2012-02-17 13:53:11 -0800720static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
721 void __user *argp)
722{
723 ion_phys_addr_t pa;
724 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800725 struct qseecom_set_sb_mem_param_req req;
726 uint32_t len;
727
728 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700729 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800730 return -EFAULT;
731
Mona Hossaina1124de2013-10-01 13:41:09 -0700732 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
733 (req.sb_len == 0)) {
734 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
735 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
736 return -EFAULT;
737 }
Zhen Kongf4948192013-11-25 13:05:35 -0800738 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
739 req.sb_len))
740 return -EFAULT;
741
Mona Hossain2892b6b2012-02-17 13:53:11 -0800742 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800743 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
744 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800745 if (IS_ERR_OR_NULL(data->client.ihandle)) {
746 pr_err("Ion client could not retrieve the handle\n");
747 return -ENOMEM;
748 }
749 /* Get the physical address of the ION BUF */
750 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800751 if (ret) {
752
753 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
754 ret);
755 return ret;
756 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800757 /* Populate the structure for sending scm call to load image */
758 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700759 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800760 data->client.sb_phys = pa;
761 data->client.sb_length = req.sb_len;
762 data->client.user_virt_sb_base = req.virt_sb_base;
763 return 0;
764}
765
Mona Hossain2892b6b2012-02-17 13:53:11 -0800766static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
767{
768 int ret;
769 ret = (qseecom.send_resp_flag != 0);
770 return ret || data->abort;
771}
772
773static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
774 struct qseecom_command_scm_resp *resp)
775{
776 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800777 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800778 uint32_t lstnr;
779 unsigned long flags;
780 struct qseecom_client_listener_data_irsp send_data_rsp;
781 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700782 sigset_t new_sigset;
783 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800784
Mona Hossain2892b6b2012-02-17 13:53:11 -0800785 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
786 lstnr = resp->data;
787 /*
788 * Wake up blocking lsitener service with the lstnr id
789 */
790 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
791 flags);
792 list_for_each_entry(ptr_svc,
793 &qseecom.registered_listener_list_head, list) {
794 if (ptr_svc->svc.listener_id == lstnr) {
795 ptr_svc->rcv_req_flag = 1;
796 wake_up_interruptible(&ptr_svc->rcv_req_wq);
797 break;
798 }
799 }
800 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
801 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700802
803 if (ptr_svc == NULL) {
804 pr_err("Listener Svc %d does not exist\n", lstnr);
805 return -EINVAL;
806 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800807 if (ptr_svc->svc.listener_id != lstnr) {
808 pr_warning("Service requested for does on exist\n");
809 return -ERESTARTSYS;
810 }
811 pr_debug("waking up rcv_req_wq and "
812 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800813
Mona Hossain91da2c52013-03-29 17:28:31 -0700814 /* initialize the new signal mask with all signals*/
815 sigfillset(&new_sigset);
816 /* block all signals */
817 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
818
819 do {
820 if (!wait_event_freezable(qseecom.send_resp_wq,
821 __qseecom_listener_has_sent_rsp(data)))
822 break;
823 } while (1);
824
825 /* restore signal mask */
826 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
827 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700828 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
829 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700830 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800831 send_data_rsp.status = QSEOS_RESULT_FAILURE;
832 } else {
833 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800834 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800835
Mona Hossain2892b6b2012-02-17 13:53:11 -0800836 qseecom.send_resp_flag = 0;
837 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
838 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700839 if (ptr_svc)
840 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
841 ptr_svc->sb_virt, ptr_svc->sb_length,
842 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700843
844 if (lstnr == RPMB_SERVICE)
845 __qseecom_enable_clk(CLK_QSEE);
846
Mona Hossain2892b6b2012-02-17 13:53:11 -0800847 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
848 (const void *)&send_data_rsp,
849 sizeof(send_data_rsp), resp,
850 sizeof(*resp));
851 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700852 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800853 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700854 if (lstnr == RPMB_SERVICE)
855 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800856 return ret;
857 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800858 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
859 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
860 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
861 resp->result, data->client.app_id, lstnr);
862 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700863 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700864 if (lstnr == RPMB_SERVICE)
865 __qseecom_disable_clk(CLK_QSEE);
866
Mona Hossain2892b6b2012-02-17 13:53:11 -0800867 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800868 if (rc)
869 return rc;
870
Mona Hossain2892b6b2012-02-17 13:53:11 -0800871 return ret;
872}
873
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700874static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
875{
876 int32_t ret;
877 struct qseecom_command_scm_resp resp;
878
879 /* SCM_CALL to check if app_id for the mentioned app exists */
880 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
881 sizeof(struct qseecom_check_app_ireq),
882 &resp, sizeof(resp));
883 if (ret) {
884 pr_err("scm_call to check if app is already loaded failed\n");
885 return -EINVAL;
886 }
887
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700888 if (resp.result == QSEOS_RESULT_FAILURE) {
889 return 0;
890 } else {
891 switch (resp.resp_type) {
892 /*qsee returned listener type response */
893 case QSEOS_LISTENER_ID:
894 pr_err("resp type is of listener type instead of app");
895 return -EINVAL;
896 break;
897 case QSEOS_APP_ID:
898 return resp.data;
899 default:
900 pr_err("invalid resp type (%d) from qsee",
901 resp.resp_type);
902 return -ENODEV;
903 break;
904 }
905 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700906}
907
Mona Hossain2892b6b2012-02-17 13:53:11 -0800908static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
909{
910 struct qseecom_registered_app_list *entry = NULL;
911 unsigned long flags = 0;
912 u32 app_id = 0;
913 struct ion_handle *ihandle; /* Ion handle */
914 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700915 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800916 ion_phys_addr_t pa = 0;
917 uint32_t len;
918 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800919 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700920 struct qseecom_load_app_ireq load_req;
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +0800921 bool first_time = false;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700922
Mona Hossain2892b6b2012-02-17 13:53:11 -0800923 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700924 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800925 (void __user *)argp,
926 sizeof(struct qseecom_load_img_req))) {
927 pr_err("copy_from_user failed\n");
928 return -EFAULT;
929 }
Zhen Kong4bead3c2014-04-14 15:07:13 -0700930
931 if (qseecom.support_bus_scaling) {
932 mutex_lock(&qsee_bw_mutex);
933 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
934 mutex_unlock(&qsee_bw_mutex);
935 if (ret)
936 return ret;
937 }
938
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700939 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700940 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700941 if (ret)
Zhen Kong4bead3c2014-04-14 15:07:13 -0700942 goto enable_clk_err;
943
Mona Hossain436b75f2012-11-20 17:10:40 -0800944 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700945 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -0700946 strlcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800947
Mona Hossain436b75f2012-11-20 17:10:40 -0800948 ret = __qseecom_check_app_exists(req);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700949 if (ret < 0)
950 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800951
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530952 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800953 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700954 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800955 (char *)(req.app_name));
956 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
957 list_for_each_entry(entry,
958 &qseecom.registered_app_list_head, list){
959 if (entry->app_id == app_id) {
960 entry->ref_cnt++;
961 break;
962 }
963 }
964 spin_unlock_irqrestore(
965 &qseecom.registered_app_list_lock, flags);
Zhen Kong3a5eaac2014-06-12 12:16:12 -0700966 ret = 0;
Mona Hossain436b75f2012-11-20 17:10:40 -0800967 } else {
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +0800968 first_time = true;
Mona Hossain436b75f2012-11-20 17:10:40 -0800969 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700970 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800971 /* Get the handle of the shared fd */
972 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800973 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800974 if (IS_ERR_OR_NULL(ihandle)) {
975 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -0700976 ret = -ENOMEM;
977 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800978 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800979
Mona Hossain436b75f2012-11-20 17:10:40 -0800980 /* Get the physical address of the ION BUF */
981 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800982 if (ret) {
983 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
984 ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700985 goto loadapp_err;
Zhen Kong05ed4462014-01-28 18:21:30 -0800986 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800987
Mona Hossain436b75f2012-11-20 17:10:40 -0800988 /* Populate the structure for sending scm call to load image */
William Clarkba7f03c2015-03-09 12:07:49 -0700989 strlcpy(load_req.app_name, load_img_req.img_name,
Mona Hossain436b75f2012-11-20 17:10:40 -0800990 MAX_APP_NAME_SIZE);
991 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
992 load_req.mdt_len = load_img_req.mdt_len;
993 load_req.img_len = load_img_req.img_len;
994 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700995 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
996 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800997
Mona Hossain436b75f2012-11-20 17:10:40 -0800998 /* SCM_CALL to load the app and get the app_id back */
999 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001000 sizeof(struct qseecom_load_app_ireq),
1001 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001002 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -08001003 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -08001004 if (!IS_ERR_OR_NULL(ihandle))
1005 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001006 ret = -EINVAL;
1007 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001008 }
1009
1010 if (resp.result == QSEOS_RESULT_FAILURE) {
1011 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001012 if (!IS_ERR_OR_NULL(ihandle))
1013 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001014 ret = -EFAULT;
1015 goto loadapp_err;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001016 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001017
Mona Hossain436b75f2012-11-20 17:10:40 -08001018 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1019 ret = __qseecom_process_incomplete_cmd(data, &resp);
1020 if (ret) {
1021 pr_err("process_incomplete_cmd failed err: %d\n",
1022 ret);
1023 if (!IS_ERR_OR_NULL(ihandle))
1024 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001025 ret = -EFAULT;
1026 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001027 }
1028 }
1029
1030 if (resp.result != QSEOS_RESULT_SUCCESS) {
1031 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001032 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -08001033 if (!IS_ERR_OR_NULL(ihandle))
1034 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001035 ret = -EFAULT;
1036 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001037 }
1038
1039 app_id = resp.data;
1040
1041 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1042 if (!entry) {
1043 pr_err("kmalloc failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001044 ret = -ENOMEM;
1045 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -08001046 }
1047 entry->app_id = app_id;
1048 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07001049 strlcpy(entry->app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001050 MAX_APP_NAME_SIZE);
Mona Hossain436b75f2012-11-20 17:10:40 -08001051 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001052 if (!IS_ERR_OR_NULL(ihandle))
1053 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001054
Mona Hossain436b75f2012-11-20 17:10:40 -08001055 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1056 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1057 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1058 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001059
Mona Hossain436b75f2012-11-20 17:10:40 -08001060 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -07001061 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -08001062 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001063 data->client.app_id = app_id;
William Clarkba7f03c2015-03-09 12:07:49 -07001064 strlcpy(data->client.app_name, load_img_req.img_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001065 MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001066 load_img_req.app_id = app_id;
1067 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
1068 pr_err("copy_to_user failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -07001069 ret = -EFAULT;
Mallikarjuna Reddy Amireddy2329a5c2017-01-13 12:54:54 +08001070 if (first_time == true) {
1071 spin_lock_irqsave(
1072 &qseecom.registered_app_list_lock, flags);
1073 list_del(&entry->list);
1074 spin_unlock_irqrestore(
1075 &qseecom.registered_app_list_lock, flags);
1076 kzfree(entry);
1077 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001078 }
Zhen Kong4bead3c2014-04-14 15:07:13 -07001079
1080loadapp_err:
Zhen Kong2edf90d2013-08-27 12:05:06 -07001081 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001082enable_clk_err:
1083 if (qseecom.support_bus_scaling) {
1084 mutex_lock(&qsee_bw_mutex);
1085 qseecom_unregister_bus_bandwidth_needs(data);
1086 mutex_unlock(&qsee_bw_mutex);
1087 }
1088 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001089}
1090
1091static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
1092{
1093 wake_up_all(&qseecom.send_resp_wq);
1094 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001095 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001096 atomic_read(&data->ioctl_count) <= 1)) {
1097 pr_err("Interrupted from abort\n");
1098 return -ERESTARTSYS;
1099 break;
1100 }
1101 }
1102 /* Set unload app */
1103 return 1;
1104}
1105
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001106static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
1107{
1108 int ret = 0;
1109 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
1110 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
1111 ion_free(qseecom.ion_clnt, data->client.ihandle);
1112 data->client.ihandle = NULL;
1113 }
1114 return ret;
1115}
1116
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001117static int qseecom_unload_app(struct qseecom_dev_handle *data,
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001118 bool app_crash)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001119{
1120 unsigned long flags;
William Clarkc7a043d2014-05-23 15:08:52 -07001121 unsigned long flags1;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001122 int ret = 0;
1123 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001124 struct qseecom_registered_app_list *ptr_app = NULL;
Mona Hossain340dba82012-08-07 19:54:46 -07001125 bool unload = false;
1126 bool found_app = false;
William Clarkc7a043d2014-05-23 15:08:52 -07001127 bool found_dead_app = false;
1128
1129 if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
Zhen Kong763307c2014-09-12 12:58:13 -07001130 pr_debug("Do not unload keymaster app from tz\n");
1131 goto unload_exit;
William Clarkc7a043d2014-05-23 15:08:52 -07001132 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001133
Mona Hossaind4613de2013-05-15 16:49:29 -07001134 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001135 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1136 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001137 list) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001138 if (ptr_app->app_id == data->client.app_id) {
William Clarkc7a043d2014-05-23 15:08:52 -07001139 if (!memcmp((void *)ptr_app->app_name,
1140 (void *)data->client.app_name,
1141 strlen(data->client.app_name))) {
1142 found_app = true;
1143 if (app_crash || ptr_app->ref_cnt == 1)
1144 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001145 break;
1146 } else {
William Clarkc7a043d2014-05-23 15:08:52 -07001147 found_dead_app = true;
1148 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001149 }
1150 }
1151 }
1152 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1153 flags);
William Clarkc7a043d2014-05-23 15:08:52 -07001154 if (found_app == false && found_dead_app == false) {
1155 pr_err("Cannot find app with id = %d (%s)\n",
1156 data->client.app_id,
1157 (char *)data->client.app_name);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001158 return -EINVAL;
1159 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001160 }
1161
William Clarkc7a043d2014-05-23 15:08:52 -07001162 if (found_dead_app) {
1163 pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
1164 (char *)data->client.app_name);
1165 __qseecom_cleanup_app(data);
1166 }
1167
Mona Hossaind4613de2013-05-15 16:49:29 -07001168 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001169 struct qseecom_unload_app_ireq req;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001170 /* Populate the structure for sending scm call to load image */
1171 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1172 req.app_id = data->client.app_id;
1173
1174 /* SCM_CALL to unload the app */
1175 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1176 sizeof(struct qseecom_unload_app_ireq),
1177 &resp, sizeof(resp));
1178 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001179 pr_err("scm_call to unload app (id = %d) failed\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001180 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001181 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001182 } else {
1183 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001184 }
William Clarkc7a043d2014-05-23 15:08:52 -07001185 if (resp.result == QSEOS_RESULT_FAILURE) {
1186 pr_err("app (%d) unload_failed!!\n",
1187 data->client.app_id);
1188 return -EFAULT;
1189 }
1190 if (resp.result == QSEOS_RESULT_SUCCESS)
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301191 pr_debug("App (%d) is unloaded!!\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001192 data->client.app_id);
1193 __qseecom_cleanup_app(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001194 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1195 ret = __qseecom_process_incomplete_cmd(data, &resp);
1196 if (ret) {
1197 pr_err("process_incomplete_cmd fail err: %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001198 ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001199 return ret;
1200 }
1201 }
1202 }
William Clarkc7a043d2014-05-23 15:08:52 -07001203
1204 if (found_app) {
1205 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
1206 if (app_crash) {
1207 ptr_app->ref_cnt = 0;
1208 pr_debug("app_crash: ref_count = 0\n");
1209 } else {
1210 if (ptr_app->ref_cnt == 1) {
1211 ptr_app->ref_cnt = 0;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301212 pr_debug("ref_count set to 0\n");
William Clarkc7a043d2014-05-23 15:08:52 -07001213 } else {
1214 ptr_app->ref_cnt--;
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05301215 pr_debug("Can't unload app(%d) inuse\n",
William Clarkc7a043d2014-05-23 15:08:52 -07001216 ptr_app->app_id);
1217 }
1218 }
1219 if (unload) {
1220 list_del(&ptr_app->list);
1221 kzfree(ptr_app);
1222 }
1223 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1224 flags1);
1225 }
Zhen Kong763307c2014-09-12 12:58:13 -07001226unload_exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001227 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001228 data->released = true;
1229 return ret;
1230}
1231
1232static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1233 uint32_t virt)
1234{
1235 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1236}
1237
Zhen Kongf4948192013-11-25 13:05:35 -08001238static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1239 uint32_t virt)
1240{
1241 return (uint32_t)data->client.sb_virt +
1242 (virt - data->client.user_virt_sb_base);
1243}
1244
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001245int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1246 struct qseecom_send_svc_cmd_req *req_ptr,
1247 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1248{
1249 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001250 void *req_buf = NULL;
1251
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001252 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
Jeron Susan84186d42016-11-03 10:02:25 +08001253 pr_err("Error with pointer: req_ptr = %pK, send_svc_ptr = %pK\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001254 req_ptr, send_svc_ireq_ptr);
1255 return -EINVAL;
1256 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001257
Zhen Kong581df352017-04-28 16:13:57 +08001258
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001259 /* Clients need to ensure req_buf is at base offset of shared buffer */
1260 if ((uint32_t)req_ptr->cmd_req_buf !=
1261 data_ptr->client.user_virt_sb_base) {
1262 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001263 return -EINVAL;
1264 }
1265
Zhen Kong581df352017-04-28 16:13:57 +08001266 if (data_ptr->client.sb_length <
1267 sizeof(struct qseecom_rpmb_provision_key)) {
1268 pr_err("shared buffer is too small to hold key type\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001269 return -EINVAL;
1270 }
1271
1272 req_buf = data_ptr->client.sb_virt;
1273
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001274 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1275 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001276 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001277 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1278 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1279 (uint32_t)req_ptr->resp_buf));
1280 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1281
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001282 return ret;
1283}
1284
Zhen Kong581df352017-04-28 16:13:57 +08001285static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
1286 struct qseecom_send_svc_cmd_req *req)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001287{
Zhen Kong581df352017-04-28 16:13:57 +08001288 if (!req || !req->resp_buf || !req->cmd_req_buf) {
1289 pr_err("req or cmd buffer or response buffer is null\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001290 return -EINVAL;
1291 }
1292
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001293 if (data->client.sb_virt == NULL) {
1294 pr_err("sb_virt null\n");
1295 return -EINVAL;
1296 }
1297
1298 if (data->client.user_virt_sb_base == 0) {
1299 pr_err("user_virt_sb_base is null\n");
1300 return -EINVAL;
1301 }
1302
1303 if (data->client.sb_length == 0) {
1304 pr_err("sb_length is 0\n");
1305 return -EINVAL;
1306 }
1307
Zhen Kong581df352017-04-28 16:13:57 +08001308 if (((uintptr_t)req->cmd_req_buf <
1309 data->client.user_virt_sb_base) ||
1310 ((uintptr_t)req->cmd_req_buf >=
1311 (data->client.user_virt_sb_base + data->client.sb_length))) {
1312 pr_err("cmd buffer address not within shared bufffer\n");
1313 return -EINVAL;
1314 }
1315 if (((uintptr_t)req->resp_buf <
1316 data->client.user_virt_sb_base) ||
1317 ((uintptr_t)req->resp_buf >=
1318 (data->client.user_virt_sb_base + data->client.sb_length))) {
1319 pr_err("response buffer address not within shared bufffer\n");
1320 return -EINVAL;
1321 }
1322 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
1323 (req->cmd_req_len > data->client.sb_length) ||
1324 (req->resp_len > data->client.sb_length)) {
1325 pr_err("cmd buf length or response buf length not valid\n");
1326 return -EINVAL;
1327 }
1328 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1329 pr_err("Integer overflow detected in req_len & rsp_len\n");
1330 return -EINVAL;
1331 }
1332
1333 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1334 pr_debug("Not enough memory to fit cmd_buf.\n");
1335 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1336 (req->cmd_req_len + req->resp_len),
1337 data->client.sb_length);
1338 return -ENOMEM;
1339 }
1340 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1341 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1342 return -EINVAL;
1343 }
1344 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1345 pr_err("Integer overflow in resp_len & resp_buf\n");
1346 return -EINVAL;
1347 }
1348 if (data->client.user_virt_sb_base >
1349 (ULONG_MAX - data->client.sb_length)) {
1350 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1351 return -EINVAL;
1352 }
1353 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1354 ((uintptr_t)data->client.user_virt_sb_base +
1355 data->client.sb_length)) ||
1356 (((uintptr_t)req->resp_buf + req->resp_len) >
1357 ((uintptr_t)data->client.user_virt_sb_base +
1358 data->client.sb_length))) {
1359 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1360 return -EINVAL;
1361 }
1362 return 0;
1363}
1364
1365static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1366 void __user *argp)
1367{
1368 int ret = 0;
1369 struct qseecom_client_send_service_ireq send_svc_ireq;
1370 struct qseecom_command_scm_resp resp;
1371 struct qseecom_send_svc_cmd_req req;
1372
1373 /*struct qseecom_command_scm_resp resp;*/
1374
1375 if (copy_from_user(&req,
1376 (void __user *)argp,
1377 sizeof(req))) {
1378 pr_err("copy_from_user failed\n");
1379 return -EFAULT;
1380 }
1381
1382 if (__validate_send_service_cmd_inputs(data, &req))
1383 return -EINVAL;
1384
Zhen Kong2edf90d2013-08-27 12:05:06 -07001385 data->type = QSEECOM_SECURE_SERVICE;
1386
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001387 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001388 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1389 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001390 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1391 &send_svc_ireq))
1392 return -EINVAL;
1393 break;
1394 default:
1395 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1396 return -EINVAL;
1397 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301398
Zhen Kong2edf90d2013-08-27 12:05:06 -07001399 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001400 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001401 if (ret) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001402 pr_err("Fail to set bw HIGH\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -07001403 return ret;
1404 }
1405 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07001406 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001407 if (ret) {
Zhen Kongd08301c2014-10-08 17:02:54 -07001408 pr_err("Failed to vote for clocks with err %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001409 goto exit;
1410 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301411 }
1412
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001413 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1414 data->client.sb_virt, data->client.sb_length,
1415 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001416 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1417 sizeof(send_svc_ireq),
1418 &resp, sizeof(resp));
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_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001422 if (ret) {
1423 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001424 if (!qseecom.support_bus_scaling) {
1425 qsee_disable_clock_vote(data, CLK_DFAB);
1426 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -08001427 } else {
1428 __qseecom_add_bw_scale_down_timer(
1429 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001430 }
1431 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001432 }
1433
1434 switch (resp.result) {
1435 case QSEOS_RESULT_SUCCESS:
1436 break;
1437 case QSEOS_RESULT_INCOMPLETE:
1438 pr_err("qseos_result_incomplete\n");
1439 ret = __qseecom_process_incomplete_cmd(data, &resp);
1440 if (ret) {
1441 pr_err("process_incomplete_cmd fail: err: %d\n",
1442 ret);
1443 }
1444 break;
1445 case QSEOS_RESULT_FAILURE:
1446 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1447 break;
1448 default:
1449 pr_err("Response result %d not supported\n",
1450 resp.result);
1451 ret = -EINVAL;
1452 break;
1453 }
Zhen Kongaf950192014-02-05 17:36:23 -08001454 if (!qseecom.support_bus_scaling) {
1455 qsee_disable_clock_vote(data, CLK_DFAB);
1456 qsee_disable_clock_vote(data, CLK_SFPB);
1457 } else {
1458 __qseecom_add_bw_scale_down_timer(
1459 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1460 }
1461
Zhen Kong2edf90d2013-08-27 12:05:06 -07001462exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001463 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001464}
1465
Mona Hossain268c3122014-11-03 17:05:48 -08001466static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
1467 struct qseecom_send_cmd_req *req)
1468{
1469 if (!data || !data->client.ihandle) {
1470 pr_err("Client or client handle is not initialized\n");
1471 return -EINVAL;
1472 }
1473 if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
1474 (req->cmd_req_buf == NULL)) {
1475 pr_err("cmd buffer or response buffer is null\n");
1476 return -EINVAL;
1477 }
1478 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1479 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1480 data->client.sb_length))) {
1481 pr_err("cmd buffer address not within shared bufffer\n");
1482 return -EINVAL;
1483 }
1484 if (((uintptr_t)req->resp_buf <
1485 data->client.user_virt_sb_base) ||
1486 ((uintptr_t)req->resp_buf >=
1487 (data->client.user_virt_sb_base + data->client.sb_length))) {
1488 pr_err("response buffer address not within shared bufffer\n");
1489 return -EINVAL;
1490 }
1491 if ((req->cmd_req_len == 0) ||
1492 (req->cmd_req_len > data->client.sb_length) ||
1493 (req->resp_len > data->client.sb_length)) {
1494 pr_err("cmd buf length or response buf length not valid\n");
1495 return -EINVAL;
1496 }
1497 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1498 pr_err("Integer overflow detected in req_len & rsp_len\n");
1499 return -EINVAL;
1500 }
1501
1502 if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
1503 pr_debug("Not enough memory to fit cmd_buf.\n");
1504 pr_debug("resp_buf. Required: %u, Available: %zu\n",
1505 (req->cmd_req_len + req->resp_len),
1506 data->client.sb_length);
1507 return -ENOMEM;
1508 }
1509 if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
1510 pr_err("Integer overflow in req_len & cmd_req_buf\n");
1511 return -EINVAL;
1512 }
1513 if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
1514 pr_err("Integer overflow in resp_len & resp_buf\n");
1515 return -EINVAL;
1516 }
1517 if (data->client.user_virt_sb_base >
1518 (ULONG_MAX - data->client.sb_length)) {
1519 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
1520 return -EINVAL;
1521 }
1522 if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
1523 ((uintptr_t)data->client.user_virt_sb_base +
1524 data->client.sb_length)) ||
1525 (((uintptr_t)req->resp_buf + req->resp_len) >
1526 ((uintptr_t)data->client.user_virt_sb_base +
1527 data->client.sb_length))) {
1528 pr_err("cmd buf or resp buf is out of shared buffer region\n");
1529 return -EINVAL;
1530 }
1531 return 0;
1532}
1533
Mona Hossain2892b6b2012-02-17 13:53:11 -08001534static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1535 struct qseecom_send_cmd_req *req)
1536{
1537 int ret = 0;
1538 u32 reqd_len_sb_in = 0;
1539 struct qseecom_client_send_data_ireq send_data_req;
1540 struct qseecom_command_scm_resp resp;
William Clarkc7a043d2014-05-23 15:08:52 -07001541 unsigned long flags;
1542 struct qseecom_registered_app_list *ptr_app;
1543 bool found_app = false;
William Clark3f378a42014-07-03 15:32:13 -07001544 int name_len = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001545
Mona Hossain2892b6b2012-02-17 13:53:11 -08001546 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
William Clarkc7a043d2014-05-23 15:08:52 -07001547 /* find app_id & img_name from list */
1548 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1549 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
1550 list) {
William Clark3f378a42014-07-03 15:32:13 -07001551 name_len = min(strlen(data->client.app_name),
1552 strlen(ptr_app->app_name));
William Clarkc7a043d2014-05-23 15:08:52 -07001553 if ((ptr_app->app_id == data->client.app_id) &&
Zhen Kong44c2a6f2014-10-31 11:33:34 -07001554 (!memcmp(ptr_app->app_name,
1555 data->client.app_name, name_len))) {
William Clarkc7a043d2014-05-23 15:08:52 -07001556 found_app = true;
1557 break;
1558 }
1559 }
1560 spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
1561
1562 if (!found_app) {
1563 pr_err("app_id %d (%s) is not found\n", data->client.app_id,
1564 (char *)data->client.app_name);
1565 return -EINVAL;
1566 }
1567
Mona Hossain2892b6b2012-02-17 13:53:11 -08001568 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1569 send_data_req.app_id = data->client.app_id;
1570 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1571 (uint32_t)req->cmd_req_buf));
1572 send_data_req.req_len = req->cmd_req_len;
1573 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1574 (uint32_t)req->resp_buf));
1575 send_data_req.rsp_len = req->resp_len;
1576
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001577 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1578 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001579 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001580 ION_IOC_CLEAN_INV_CACHES);
1581
Mona Hossain2892b6b2012-02-17 13:53:11 -08001582 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1583 sizeof(send_data_req),
1584 &resp, sizeof(resp));
1585 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001586 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1587 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001588 return ret;
1589 }
1590
1591 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1592 ret = __qseecom_process_incomplete_cmd(data, &resp);
1593 if (ret) {
1594 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1595 return ret;
1596 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001597 } else {
1598 if (resp.result != QSEOS_RESULT_SUCCESS) {
1599 pr_err("Response result %d not supported\n",
1600 resp.result);
1601 ret = -EINVAL;
1602 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001603 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001604 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1605 data->client.sb_virt, data->client.sb_length,
1606 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001607 return ret;
1608}
1609
Mona Hossain2892b6b2012-02-17 13:53:11 -08001610static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1611{
1612 int ret = 0;
1613 struct qseecom_send_cmd_req req;
1614
1615 ret = copy_from_user(&req, argp, sizeof(req));
1616 if (ret) {
1617 pr_err("copy_from_user failed\n");
1618 return ret;
1619 }
Mona Hossain268c3122014-11-03 17:05:48 -08001620
1621 if (__validate_send_cmd_inputs(data, &req))
1622 return -EINVAL;
1623
Mona Hossaind4613de2013-05-15 16:49:29 -07001624 ret = __qseecom_send_cmd(data, &req);
1625
Mona Hossain2892b6b2012-02-17 13:53:11 -08001626 if (ret)
1627 return ret;
1628
Mona Hossain2892b6b2012-02-17 13:53:11 -08001629 return ret;
1630}
1631
Mona Hossain268c3122014-11-03 17:05:48 -08001632int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
Mona Hossainb9470692014-10-09 12:00:03 -07001633 struct qseecom_send_modfd_listener_resp *lstnr_resp,
1634 struct qseecom_dev_handle *data, bool listener_svc,
1635 int i) {
Mona Hossainb9470692014-10-09 12:00:03 -07001636
1637 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001638 if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
1639 (cmd_req->ifd_data[i].cmd_buf_offset >
1640 cmd_req->cmd_req_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001641 pr_err("Invalid offset 0x%x\n",
1642 cmd_req->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001643 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001644 }
1645 } else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001646 if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
1647 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1648 lstnr_resp->resp_len - sizeof(uint32_t))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001649 pr_err("Invalid offset 0x%x\n",
1650 lstnr_resp->ifd_data[i].cmd_buf_offset);
Mona Hossain268c3122014-11-03 17:05:48 -08001651 return -EINVAL;
Mona Hossainb9470692014-10-09 12:00:03 -07001652 }
1653 }
Mona Hossain268c3122014-11-03 17:05:48 -08001654 return 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001655}
1656
Mona Hossain268c3122014-11-03 17:05:48 -08001657#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001658static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1659 struct qseecom_dev_handle *data,
1660 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001661{
1662 struct ion_handle *ihandle;
1663 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001664 int ret = 0;
1665 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001666 uint32_t len = 0;
1667 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001668 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1669 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1670 struct qseecom_registered_listener_list *this_lstnr = NULL;
1671
1672 if (msg == NULL) {
1673 pr_err("Invalid address\n");
1674 return -EINVAL;
1675 }
1676 if (listener_svc) {
1677 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1678 this_lstnr = __qseecom_find_svc(data->listener.id);
1679 if (IS_ERR_OR_NULL(this_lstnr)) {
1680 pr_err("Invalid listener ID\n");
1681 return -ENOMEM;
1682 }
1683 } else {
1684 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1685 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001686
1687 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001688 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001689 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001690 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001691 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001692 if (IS_ERR_OR_NULL(ihandle)) {
1693 pr_err("Ion client can't retrieve the handle\n");
1694 return -ENOMEM;
1695 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001696 field = (char *) cmd_req->cmd_req_buf +
1697 cmd_req->ifd_data[i].cmd_buf_offset;
1698 } else if ((listener_svc) &&
1699 (lstnr_resp->ifd_data[i].fd > 0)) {
1700 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1701 lstnr_resp->ifd_data[i].fd);
1702 if (IS_ERR_OR_NULL(ihandle)) {
1703 pr_err("Ion client can't retrieve the handle\n");
1704 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001705 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001706 field = lstnr_resp->resp_buf_ptr +
1707 lstnr_resp->ifd_data[i].cmd_buf_offset;
1708 } else {
1709 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001710 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001711 /* Populate the cmd data structure with the phys_addr */
1712 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1713 if (sg_ptr == NULL) {
1714 pr_err("IOn client could not retrieve sg table\n");
1715 goto err;
1716 }
1717 if (sg_ptr->nents == 0) {
1718 pr_err("Num of scattered entries is 0\n");
1719 goto err;
1720 }
1721 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1722 pr_err("Num of scattered entries");
1723 pr_err(" (%d) is greater than max supported %d\n",
1724 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1725 goto err;
1726 }
1727 sg = sg_ptr->sgl;
1728 if (sg_ptr->nents == 1) {
1729 uint32_t *update;
1730 update = (uint32_t *) field;
Mona Hossainb9470692014-10-09 12:00:03 -07001731
Mona Hossain268c3122014-11-03 17:05:48 -08001732 if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
Mona Hossainb9470692014-10-09 12:00:03 -07001733 listener_svc, i))
1734 goto err;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001735 if (cleanup)
1736 *update = 0;
1737 else
1738 *update = (uint32_t)sg_dma_address(
1739 sg_ptr->sgl);
1740 len += (uint32_t)sg->length;
1741 } else {
1742 struct qseecom_sg_entry *update;
1743 int j = 0;
Mona Hossainb9470692014-10-09 12:00:03 -07001744
1745 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001746 if ((cmd_req->cmd_req_len <
1747 SG_ENTRY_SZ * sg_ptr->nents) ||
1748 (cmd_req->ifd_data[i].cmd_buf_offset >
1749 (cmd_req->cmd_req_len -
1750 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001751 pr_err("Invalid offset = 0x%x\n",
1752 cmd_req->ifd_data[i].
1753 cmd_buf_offset);
1754 goto err;
1755 }
1756 } else if ((listener_svc) &&
1757 (lstnr_resp->ifd_data[i].fd > 0)) {
Mona Hossain268c3122014-11-03 17:05:48 -08001758 if ((lstnr_resp->resp_len <
1759 SG_ENTRY_SZ * sg_ptr->nents) ||
1760 (lstnr_resp->ifd_data[i].cmd_buf_offset >
1761 (lstnr_resp->resp_len -
1762 SG_ENTRY_SZ * sg_ptr->nents))) {
Mona Hossainb9470692014-10-09 12:00:03 -07001763 pr_err("Invalid offset = 0x%x\n",
1764 lstnr_resp->ifd_data[i].
1765 cmd_buf_offset);
1766 goto err;
1767 }
1768 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001769 update = (struct qseecom_sg_entry *) field;
1770 for (j = 0; j < sg_ptr->nents; j++) {
1771 if (cleanup) {
1772 update->phys_addr = 0;
1773 update->len = 0;
1774 } else {
1775 update->phys_addr = (uint32_t)
1776 sg_dma_address(sg);
1777 update->len = sg->length;
1778 }
1779 len += sg->length;
1780 update++;
1781 sg = sg_next(sg);
1782 }
1783 }
1784 if (cleanup)
1785 msm_ion_do_cache_op(qseecom.ion_clnt,
1786 ihandle, NULL, len,
1787 ION_IOC_INV_CACHES);
1788 else
1789 msm_ion_do_cache_op(qseecom.ion_clnt,
1790 ihandle, NULL, len,
1791 ION_IOC_CLEAN_INV_CACHES);
1792 /* Deallocate the handle */
1793 if (!IS_ERR_OR_NULL(ihandle))
1794 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001795 }
1796 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001797err:
1798 if (!IS_ERR_OR_NULL(ihandle))
1799 ion_free(qseecom.ion_clnt, ihandle);
1800 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001801}
1802
1803static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1804 void __user *argp)
1805{
1806 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001807 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001808 struct qseecom_send_modfd_cmd_req req;
1809 struct qseecom_send_cmd_req send_cmd_req;
1810
1811 ret = copy_from_user(&req, argp, sizeof(req));
1812 if (ret) {
1813 pr_err("copy_from_user failed\n");
1814 return ret;
1815 }
Zhen Kongf4948192013-11-25 13:05:35 -08001816
jeronf5cf7042016-07-26 16:13:50 +08001817 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1818 pr_err("cmd buffer or response buffer is null\n");
1819 return -EINVAL;
1820 }
1821 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1822 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1823 data->client.sb_length))) {
1824 pr_err("cmd buffer address not within shared bufffer\n");
1825 return -EINVAL;
1826 }
1827
1828 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1829 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1830 data->client.sb_length))){
1831 pr_err("response buffer address not within shared bufffer\n");
1832 return -EINVAL;
1833 }
Teow Wan Yee1a428fd2016-07-27 14:01:01 +08001834
1835 if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
1836 req.resp_len > data->client.sb_length) {
1837 pr_err("cmd or response buffer length not valid\n");
1838 return -EINVAL;
1839 }
1840
Mona Hossain2892b6b2012-02-17 13:53:11 -08001841 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1842 send_cmd_req.cmd_req_len = req.cmd_req_len;
1843 send_cmd_req.resp_buf = req.resp_buf;
1844 send_cmd_req.resp_len = req.resp_len;
1845
Mona Hossain268c3122014-11-03 17:05:48 -08001846 if (__validate_send_cmd_inputs(data, &send_cmd_req))
1847 return -EINVAL;
1848
Mona Hossaindddf4442013-10-01 14:08:20 -07001849 /* validate offsets */
1850 for (i = 0; i < MAX_ION_FD; i++) {
1851 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1852 pr_err("Invalid offset %d = 0x%x\n",
1853 i, req.ifd_data[i].cmd_buf_offset);
1854 return -EINVAL;
1855 }
1856 }
Zhen Kongf4948192013-11-25 13:05:35 -08001857 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1858 (uint32_t)req.cmd_req_buf);
1859 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1860 (uint32_t)req.resp_buf);
1861
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001862 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001863 if (ret)
1864 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001865 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001866 if (ret)
1867 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001868 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001869 if (ret)
1870 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001871
Mona Hossain2892b6b2012-02-17 13:53:11 -08001872 return ret;
1873}
1874
1875static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1876 struct qseecom_registered_listener_list *svc)
1877{
1878 int ret;
1879 ret = (svc->rcv_req_flag != 0);
1880 return ret || data->abort;
1881}
1882
1883static int qseecom_receive_req(struct qseecom_dev_handle *data)
1884{
1885 int ret = 0;
1886 struct qseecom_registered_listener_list *this_lstnr;
1887
1888 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301889 if (!this_lstnr) {
1890 pr_err("Invalid listener ID\n");
1891 return -ENODATA;
1892 }
1893
Mona Hossain2892b6b2012-02-17 13:53:11 -08001894 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001895 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001896 __qseecom_listener_has_rcvd_req(data,
1897 this_lstnr))) {
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05301898 pr_debug("Interrupted: exiting Listener Service = %d\n",
Mona Hossain17a4faf2013-03-22 16:40:56 -07001899 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001900 /* woken up for different reason */
1901 return -ERESTARTSYS;
1902 }
1903
1904 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001905 pr_err("Aborting Listener Service = %d\n",
1906 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001907 return -ENODEV;
1908 }
1909 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001910 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001911 }
1912 return ret;
1913}
1914
Mona Hossaind44a3842012-10-15 09:41:35 -07001915static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1916{
1917 struct elf32_hdr *ehdr;
1918
1919 if (fw_entry->size < sizeof(*ehdr)) {
1920 pr_err("%s: Not big enough to be an elf header\n",
1921 qseecom.pdev->init_name);
1922 return false;
1923 }
1924 ehdr = (struct elf32_hdr *)fw_entry->data;
1925 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1926 pr_err("%s: Not an elf header\n",
1927 qseecom.pdev->init_name);
1928 return false;
1929 }
1930
1931 if (ehdr->e_phnum == 0) {
1932 pr_err("%s: No loadable segments\n",
1933 qseecom.pdev->init_name);
1934 return false;
1935 }
1936 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1937 sizeof(struct elf32_hdr) > fw_entry->size) {
1938 pr_err("%s: Program headers not within mdt\n",
1939 qseecom.pdev->init_name);
1940 return false;
1941 }
1942 return true;
1943}
1944
Zhen Kong82e296d2016-10-20 17:34:20 -07001945static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size)
Mona Hossaind44a3842012-10-15 09:41:35 -07001946{
1947 int ret = -1;
1948 int i = 0, rc = 0;
1949 const struct firmware *fw_entry = NULL;
1950 struct elf32_phdr *phdr;
1951 char fw_name[MAX_APP_NAME_SIZE];
1952 struct elf32_hdr *ehdr;
1953 int num_images = 0;
1954
1955 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1956 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1957 if (rc) {
1958 pr_err("error with request_firmware\n");
1959 ret = -EIO;
1960 goto err;
1961 }
1962 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1963 ret = -EIO;
1964 goto err;
1965 }
1966 *fw_size = fw_entry->size;
1967 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1968 ehdr = (struct elf32_hdr *)fw_entry->data;
1969 num_images = ehdr->e_phnum;
1970 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07001971 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001972 for (i = 0; i < num_images; i++, phdr++) {
1973 memset(fw_name, 0, sizeof(fw_name));
1974 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1975 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1976 if (ret)
1977 goto err;
Zhen Kong82e296d2016-10-20 17:34:20 -07001978 if (*fw_size > U32_MAX - fw_entry->size) {
1979 pr_err("QSEE %s app file size overflow\n", appname);
1980 ret = -EINVAL;
1981 goto err;
1982 }
Mona Hossaind44a3842012-10-15 09:41:35 -07001983 *fw_size += fw_entry->size;
1984 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07001985 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07001986 }
1987 return ret;
1988err:
1989 if (fw_entry)
1990 release_firmware(fw_entry);
1991 *fw_size = 0;
1992 return ret;
1993}
1994
Zhen Kong82e296d2016-10-20 17:34:20 -07001995static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
1996 uint32_t fw_size,
1997 struct qseecom_load_app_ireq *load_req)
Mona Hossaind44a3842012-10-15 09:41:35 -07001998{
1999 int ret = -1;
2000 int i = 0, rc = 0;
2001 const struct firmware *fw_entry = NULL;
2002 char fw_name[MAX_APP_NAME_SIZE];
2003 u8 *img_data_ptr = img_data;
2004 struct elf32_hdr *ehdr;
2005 int num_images = 0;
2006
2007 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
2008 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2009 if (rc) {
2010 ret = -EIO;
2011 goto err;
2012 }
2013 load_req->img_len = fw_entry->size;
Zhen Kong82e296d2016-10-20 17:34:20 -07002014 if (load_req->img_len > fw_size) {
2015 pr_err("app %s size %zu is larger than buf size %u\n",
2016 appname, fw_entry->size, fw_size);
2017 ret = -EINVAL;
2018 goto err;
2019 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002020 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2021 img_data_ptr = img_data_ptr + fw_entry->size;
2022 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
2023 ehdr = (struct elf32_hdr *)fw_entry->data;
2024 num_images = ehdr->e_phnum;
2025 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07002026 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002027 for (i = 0; i < num_images; i++) {
2028 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
2029 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
2030 if (ret) {
2031 pr_err("Failed to locate blob %s\n", fw_name);
2032 goto err;
2033 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002034 if ((fw_entry->size > U32_MAX - load_req->img_len) ||
2035 (fw_entry->size + load_req->img_len > fw_size)) {
2036 pr_err("Invalid file size for %s\n", fw_name);
2037 ret = -EINVAL;
2038 goto err;
2039 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002040 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
2041 img_data_ptr = img_data_ptr + fw_entry->size;
2042 load_req->img_len += fw_entry->size;
2043 release_firmware(fw_entry);
Zhen Kong82e296d2016-10-20 17:34:20 -07002044 fw_entry = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07002045 }
2046 load_req->phy_addr = virt_to_phys(img_data);
2047 return ret;
2048err:
2049 release_firmware(fw_entry);
2050 return ret;
2051}
2052
2053static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
2054{
2055 int ret = -1;
2056 uint32_t fw_size = 0;
2057 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2058 struct qseecom_command_scm_resp resp;
2059 u8 *img_data = NULL;
2060
2061 if (__qseecom_get_fw_size(appname, &fw_size))
2062 return -EIO;
2063
2064 img_data = kzalloc(fw_size, GFP_KERNEL);
2065 if (!img_data) {
2066 pr_err("Failied to allocate memory for copying image data\n");
2067 return -ENOMEM;
2068 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002069 ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
Mona Hossaind44a3842012-10-15 09:41:35 -07002070 if (ret) {
2071 kzfree(img_data);
2072 return -EIO;
2073 }
2074
2075 /* Populate the remaining parameters */
2076 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002077 strlcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002078
2079 if (qseecom.support_bus_scaling) {
2080 mutex_lock(&qsee_bw_mutex);
2081 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2082 mutex_unlock(&qsee_bw_mutex);
2083 if (ret) {
2084 kzfree(img_data);
2085 return ret;
2086 }
2087 }
2088
Zhen Kong2edf90d2013-08-27 12:05:06 -07002089 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08002090 if (ret) {
Zhen Kong4bead3c2014-04-14 15:07:13 -07002091 ret = -EIO;
2092 goto loadfw_err;
Mona Hossain60f9fb02012-11-05 13:51:50 -08002093 }
2094
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002095 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07002096 /* SCM_CALL to load the image */
2097 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2098 sizeof(struct qseecom_load_app_ireq),
2099 &resp, sizeof(resp));
Mona Hossaind44a3842012-10-15 09:41:35 -07002100 if (ret) {
2101 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002102 ret = -EIO;
2103 goto loadfw_err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002104 }
2105
2106 switch (resp.result) {
2107 case QSEOS_RESULT_SUCCESS:
2108 ret = resp.data;
2109 break;
2110 case QSEOS_RESULT_INCOMPLETE:
2111 ret = __qseecom_process_incomplete_cmd(data, &resp);
2112 if (ret)
2113 pr_err("process_incomplete_cmd FAILED\n");
2114 else
2115 ret = resp.data;
2116 break;
2117 case QSEOS_RESULT_FAILURE:
2118 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
2119 break;
2120 default:
2121 pr_err("scm call return unknown response %d\n", resp.result);
2122 ret = -EINVAL;
2123 break;
2124 }
Mona Hossain60f9fb02012-11-05 13:51:50 -08002125
Zhen Kong4bead3c2014-04-14 15:07:13 -07002126loadfw_err:
William Clarkd83bdcb2014-07-17 14:40:41 -07002127 kzfree(img_data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002128 __qseecom_disable_clk_scale_down(data);
2129 if (qseecom.support_bus_scaling) {
2130 mutex_lock(&qsee_bw_mutex);
2131 qseecom_unregister_bus_bandwidth_needs(data);
2132 mutex_unlock(&qsee_bw_mutex);
2133 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002134 return ret;
2135}
2136
Mona Hossain9498f5e2013-01-23 18:08:45 -08002137static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07002138{
Zhen Kongc46b5842013-12-12 13:09:16 +05302139 int ret = 0;
Zhen Kongfd64c982013-12-19 16:35:43 -08002140 int len = 0;
Mona Hossain05c73562012-10-29 17:49:01 -07002141 uint32_t fw_size = 0;
2142 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
2143 struct qseecom_command_scm_resp resp;
2144 u8 *img_data = NULL;
Zhen Kongfd64c982013-12-19 16:35:43 -08002145 ion_phys_addr_t pa;
Mona Hossain05c73562012-10-29 17:49:01 -07002146
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08002147 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07002148 return -EIO;
2149
Zhen Kongc46b5842013-12-12 13:09:16 +05302150 qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
2151 SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2152 if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002153 pr_err("ION alloc failed\n");
Mona Hossain05c73562012-10-29 17:49:01 -07002154 return -ENOMEM;
2155 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302156
2157 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
2158 qseecom.cmnlib_ion_handle);
2159 if (IS_ERR_OR_NULL(img_data)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08002160 pr_err("ION memory mapping for cmnlib failed\n");
Zhen Kongc46b5842013-12-12 13:09:16 +05302161 ret = -ENOMEM;
2162 goto exit_ion_free;
2163 }
Zhen Kong82e296d2016-10-20 17:34:20 -07002164 ret = __qseecom_get_fw_data("cmnlib", img_data, fw_size, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07002165 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302166 ret = -EIO;
2167 goto exit_ion_unmap_kernel;
Mona Hossain05c73562012-10-29 17:49:01 -07002168 }
Zhen Kongfd64c982013-12-19 16:35:43 -08002169 /* Get the physical address of the ION BUF */
2170 ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
2171 &pa, &len);
2172 load_req.phy_addr = (s32)pa;
2173 if (ret) {
2174 pr_err("physical memory retrieval failure\n");
2175 ret = -EIO;
2176 goto exit_ion_unmap_kernel;
2177 }
Mona Hossain05c73562012-10-29 17:49:01 -07002178 /* Populate the remaining parameters */
2179 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002180
2181 if (qseecom.support_bus_scaling) {
2182 mutex_lock(&qsee_bw_mutex);
2183 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2184 mutex_unlock(&qsee_bw_mutex);
2185 if (ret) {
2186 ret = -EIO;
2187 goto exit_ion_unmap_kernel;
2188 }
2189 }
2190
Mona Hossain6311d572013-03-01 15:54:02 -08002191 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002192 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002193 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05302194 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002195 goto exit_unregister_bus_bw_need;
Mona Hossain6311d572013-03-01 15:54:02 -08002196 }
2197
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002198 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07002199 /* SCM_CALL to load the image */
2200 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2201 sizeof(struct qseecom_load_lib_image_ireq),
2202 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07002203 if (ret) {
2204 pr_err("scm_call to load failed : ret %d\n", ret);
2205 ret = -EIO;
Zhen Kongc46b5842013-12-12 13:09:16 +05302206 goto exit_disable_clk_vote;
Mona Hossain05c73562012-10-29 17:49:01 -07002207 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302208
2209 switch (resp.result) {
2210 case QSEOS_RESULT_SUCCESS:
2211 break;
2212 case QSEOS_RESULT_FAILURE:
2213 pr_err("scm call failed w/response result%d\n", resp.result);
2214 ret = -EINVAL;
2215 goto exit_disable_clk_vote;
2216 case QSEOS_RESULT_INCOMPLETE:
2217 ret = __qseecom_process_incomplete_cmd(data, &resp);
2218 if (ret) {
2219 pr_err("process_incomplete_cmd failed err: %d\n", ret);
2220 goto exit_disable_clk_vote;
2221 }
2222 break;
2223 default:
2224 pr_err("scm call return unknown response %d\n", resp.result);
2225 ret = -EINVAL;
2226 goto exit_disable_clk_vote;
2227 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07002228 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002229 if (qseecom.support_bus_scaling) {
2230 mutex_lock(&qsee_bw_mutex);
2231 qseecom_unregister_bus_bandwidth_needs(data);
2232 mutex_unlock(&qsee_bw_mutex);
2233 }
Mona Hossain05c73562012-10-29 17:49:01 -07002234 return ret;
Zhen Kongc46b5842013-12-12 13:09:16 +05302235
2236exit_disable_clk_vote:
2237 __qseecom_disable_clk_scale_down(data);
2238
Zhen Kong4bead3c2014-04-14 15:07:13 -07002239exit_unregister_bus_bw_need:
2240 if (qseecom.support_bus_scaling) {
2241 mutex_lock(&qsee_bw_mutex);
2242 qseecom_unregister_bus_bandwidth_needs(data);
2243 mutex_unlock(&qsee_bw_mutex);
2244 }
2245
Zhen Kongc46b5842013-12-12 13:09:16 +05302246exit_ion_unmap_kernel:
2247 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2248
2249exit_ion_free:
2250 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2251 qseecom.cmnlib_ion_handle = NULL;
2252 return ret;
Mona Hossain05c73562012-10-29 17:49:01 -07002253}
2254
2255static int qseecom_unload_commonlib_image(void)
2256{
2257 int ret = -EINVAL;
2258 struct qseecom_unload_lib_image_ireq unload_req = {0};
2259 struct qseecom_command_scm_resp resp;
2260
2261 /* Populate the remaining parameters */
2262 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
2263 /* SCM_CALL to load the image */
2264 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
2265 sizeof(struct qseecom_unload_lib_image_ireq),
2266 &resp, sizeof(resp));
2267 if (ret) {
2268 pr_err("scm_call to unload lib failed : ret %d\n", ret);
2269 ret = -EIO;
2270 } else {
2271 switch (resp.result) {
2272 case QSEOS_RESULT_SUCCESS:
2273 break;
2274 case QSEOS_RESULT_FAILURE:
2275 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
2276 break;
2277 default:
2278 pr_err("scm call return unknown response %d\n",
2279 resp.result);
2280 ret = -EINVAL;
2281 break;
2282 }
2283 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302284
2285 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2286 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2287 qseecom.cmnlib_ion_handle = NULL;
2288
Mona Hossain05c73562012-10-29 17:49:01 -07002289 return ret;
2290}
2291
Mona Hossaind44a3842012-10-15 09:41:35 -07002292int qseecom_start_app(struct qseecom_handle **handle,
2293 char *app_name, uint32_t size)
2294{
Mona Hossain05c73562012-10-29 17:49:01 -07002295 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002296 unsigned long flags = 0;
2297 struct qseecom_dev_handle *data = NULL;
2298 struct qseecom_check_app_ireq app_ireq;
2299 struct qseecom_registered_app_list *entry = NULL;
2300 struct qseecom_registered_kclient_list *kclient_entry = NULL;
2301 bool found_app = false;
2302 uint32_t len;
2303 ion_phys_addr_t pa;
2304
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002305 if (!app_name || strlen(app_name) >= MAX_APP_NAME_SIZE) {
2306 pr_err("The app_name (%s) is not valid\n", app_name);
2307 return -EINVAL;
2308 }
2309
Mona Hossain823f9882012-11-23 14:42:20 -08002310 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
2311 if (!(*handle)) {
2312 pr_err("failed to allocate memory for kernel client handle\n");
2313 return -ENOMEM;
2314 }
2315
Mona Hossaind44a3842012-10-15 09:41:35 -07002316 data = kzalloc(sizeof(*data), GFP_KERNEL);
2317 if (!data) {
2318 pr_err("kmalloc failed\n");
2319 if (ret == 0) {
2320 kfree(*handle);
2321 *handle = NULL;
2322 }
2323 return -ENOMEM;
2324 }
2325 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002326 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07002327 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002328 data->client.sb_length = size;
2329 data->client.user_virt_sb_base = 0;
2330 data->client.ihandle = NULL;
2331
2332 init_waitqueue_head(&data->abort_wq);
2333 atomic_set(&data->ioctl_count, 0);
2334
2335 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
2336 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2337 if (IS_ERR_OR_NULL(data->client.ihandle)) {
2338 pr_err("Ion client could not retrieve the handle\n");
2339 kfree(data);
2340 kfree(*handle);
2341 *handle = NULL;
2342 return -EINVAL;
2343 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002344 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002345 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002346 if (qseecom.commonlib_loaded == false) {
2347 ret = qseecom_load_commonlib_image(data);
2348 if (ret == 0)
2349 qseecom.commonlib_loaded = true;
2350 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002351 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002352 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002353 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002354 ret = -EIO;
2355 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08002356 }
2357
2358 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
William Clarkba7f03c2015-03-09 12:07:49 -07002359 strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002360 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002361 if (ret < 0)
2362 goto err;
2363
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07002364 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002365 if (ret > 0) {
2366 pr_warn("App id %d for [%s] app exists\n", ret,
2367 (char *)app_ireq.app_name);
2368 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2369 list_for_each_entry(entry,
2370 &qseecom.registered_app_list_head, list){
2371 if (entry->app_id == ret) {
2372 entry->ref_cnt++;
2373 found_app = true;
2374 break;
2375 }
2376 }
2377 spin_unlock_irqrestore(
2378 &qseecom.registered_app_list_lock, flags);
2379 if (!found_app)
2380 pr_warn("App_id %d [%s] was loaded but not registered\n",
2381 ret, (char *)app_ireq.app_name);
2382 } else {
2383 /* load the app and get the app_id */
2384 pr_debug("%s: Loading app for the first time'\n",
2385 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07002386 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002387 if (ret < 0)
2388 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002389 data->client.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07002390 strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002391 }
2392 if (!found_app) {
2393 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2394 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002395 pr_err("kmalloc for app entry failed\n");
2396 ret = -ENOMEM;
2397 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002398 }
2399 entry->app_id = ret;
2400 entry->ref_cnt = 1;
William Clarkba7f03c2015-03-09 12:07:49 -07002401 strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
Mona Hossaind44a3842012-10-15 09:41:35 -07002402
2403 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2404 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2405 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2406 flags);
2407 }
2408
2409 /* Get the physical address of the ION BUF */
2410 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002411 if (ret) {
2412 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2413 ret);
2414 goto err;
2415 }
2416
Mona Hossaind44a3842012-10-15 09:41:35 -07002417 /* Populate the structure for sending scm call to load image */
2418 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
2419 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08002420 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07002421 data->client.sb_phys = pa;
2422 (*handle)->dev = (void *)data;
2423 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
2424 (*handle)->sbuf_len = data->client.sb_length;
2425
2426 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
2427 if (!kclient_entry) {
2428 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002429 ret = -ENOMEM;
2430 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002431 }
2432 kclient_entry->handle = *handle;
2433
2434 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2435 list_add_tail(&kclient_entry->list,
2436 &qseecom.registered_kclient_list_head);
2437 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2438
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002439 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002440 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002441
2442err:
2443 kfree(data);
2444 kfree(*handle);
2445 *handle = NULL;
2446 mutex_unlock(&app_access_lock);
2447 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002448}
2449EXPORT_SYMBOL(qseecom_start_app);
2450
2451int qseecom_shutdown_app(struct qseecom_handle **handle)
2452{
2453 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002454 struct qseecom_dev_handle *data;
2455
Mona Hossaind44a3842012-10-15 09:41:35 -07002456 struct qseecom_registered_kclient_list *kclient = NULL;
2457 unsigned long flags = 0;
2458 bool found_handle = false;
2459
Mona Hossain33824022013-02-25 09:32:33 -08002460 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002461 pr_err("Handle is not initialized\n");
2462 return -EINVAL;
2463 }
Mona Hossain33824022013-02-25 09:32:33 -08002464 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002465 mutex_lock(&app_access_lock);
2466 atomic_inc(&data->ioctl_count);
2467
Mona Hossaind44a3842012-10-15 09:41:35 -07002468 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2469 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2470 list) {
2471 if (kclient->handle == (*handle)) {
2472 list_del(&kclient->list);
2473 found_handle = true;
2474 break;
2475 }
2476 }
2477 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2478 if (!found_handle)
2479 pr_err("Unable to find the handle, exiting\n");
2480 else
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07002481 ret = qseecom_unload_app(data, false);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002482
2483 if (qseecom.support_bus_scaling) {
2484 mutex_lock(&qsee_bw_mutex);
2485 if (data->mode != INACTIVE) {
2486 qseecom_unregister_bus_bandwidth_needs(data);
2487 if (qseecom.cumulative_mode == INACTIVE) {
2488 ret = __qseecom_set_msm_bus_request(INACTIVE);
2489 if (ret)
2490 pr_err("Fail to scale down bus\n");
2491 }
2492 }
2493 mutex_unlock(&qsee_bw_mutex);
2494 } else {
2495 if (data->fast_load_enabled == true)
2496 qsee_disable_clock_vote(data, CLK_SFPB);
2497 if (data->perf_enabled == true)
2498 qsee_disable_clock_vote(data, CLK_DFAB);
2499 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002500
2501 atomic_dec(&data->ioctl_count);
2502 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002503 if (ret == 0) {
2504 kzfree(data);
2505 kzfree(*handle);
2506 kzfree(kclient);
2507 *handle = NULL;
2508 }
Zhen Kong44c2a6f2014-10-31 11:33:34 -07002509
Mona Hossaind44a3842012-10-15 09:41:35 -07002510 return ret;
2511}
2512EXPORT_SYMBOL(qseecom_shutdown_app);
2513
2514int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2515 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2516{
2517 int ret = 0;
2518 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2519 struct qseecom_dev_handle *data;
Zhen Kongd08301c2014-10-08 17:02:54 -07002520 bool perf_enabled = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002521
Mona Hossaind44a3842012-10-15 09:41:35 -07002522 if (handle == NULL) {
2523 pr_err("Handle is not initialized\n");
2524 return -EINVAL;
2525 }
2526 data = handle->dev;
2527
2528 req.cmd_req_len = sbuf_len;
2529 req.resp_len = rbuf_len;
2530 req.cmd_req_buf = send_buf;
2531 req.resp_buf = resp_buf;
2532
Mona Hossain268c3122014-11-03 17:05:48 -08002533 if (__validate_send_cmd_inputs(data, &req))
2534 return -EINVAL;
2535
Mona Hossaind44a3842012-10-15 09:41:35 -07002536 mutex_lock(&app_access_lock);
2537 atomic_inc(&data->ioctl_count);
Zhen Kongca4c2d52014-03-12 13:22:46 -07002538 if (qseecom.support_bus_scaling) {
2539 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
2540 if (ret) {
2541 pr_err("Failed to set bw.\n");
2542 atomic_dec(&data->ioctl_count);
2543 mutex_unlock(&app_access_lock);
2544 return ret;
2545 }
2546 }
Zhen Kong1e15c272014-09-18 12:33:07 -07002547 /*
2548 * On targets where crypto clock is handled by HLOS,
2549 * if clk_access_cnt is zero and perf_enabled is false,
2550 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07002551 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07002552 */
2553 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07002554 pr_debug("ce clock is not enabled!\n");
2555 ret = qseecom_perf_enable(data);
2556 if (ret) {
2557 pr_err("Failed to vote for clock with err %d\n",
2558 ret);
2559 atomic_dec(&data->ioctl_count);
2560 mutex_unlock(&app_access_lock);
2561 return -EINVAL;
2562 }
2563 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07002564 }
2565
Mona Hossaind44a3842012-10-15 09:41:35 -07002566 ret = __qseecom_send_cmd(data, &req);
Zhen Kongaf950192014-02-05 17:36:23 -08002567 if (qseecom.support_bus_scaling)
2568 __qseecom_add_bw_scale_down_timer(
2569 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002570
Zhen Kongd08301c2014-10-08 17:02:54 -07002571 if (perf_enabled) {
2572 qsee_disable_clock_vote(data, CLK_DFAB);
2573 qsee_disable_clock_vote(data, CLK_SFPB);
2574 }
2575
Mona Hossaind44a3842012-10-15 09:41:35 -07002576 atomic_dec(&data->ioctl_count);
2577 mutex_unlock(&app_access_lock);
2578
2579 if (ret)
2580 return ret;
2581
Jeron Susan84186d42016-11-03 10:02:25 +08002582 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%pK\n",
Mona Hossaind44a3842012-10-15 09:41:35 -07002583 req.resp_len, req.resp_buf);
2584 return ret;
2585}
2586EXPORT_SYMBOL(qseecom_send_command);
2587
Mona Hossain91a8fc92012-11-07 19:58:30 -08002588int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2589{
Mona Hossainfca6f422013-01-12 13:00:35 -08002590 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002591 if ((handle == NULL) || (handle->dev == NULL)) {
2592 pr_err("No valid kernel client\n");
2593 return -EINVAL;
2594 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002595 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002596 if (qseecom.support_bus_scaling) {
2597 mutex_lock(&qsee_bw_mutex);
2598 __qseecom_register_bus_bandwidth_needs(handle->dev,
2599 HIGH);
2600 mutex_unlock(&qsee_bw_mutex);
2601 if (ret)
2602 pr_err("Failed to scale bus (med) %d\n", ret);
2603 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07002604 ret = qseecom_perf_enable(handle->dev);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002605 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07002606 pr_err("Failed to vote for clock with err %d\n",
2607 ret);
Mona Hossainfca6f422013-01-12 13:00:35 -08002608 }
2609 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002610 if (!qseecom.support_bus_scaling) {
2611 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2612 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07002613 } else {
2614 mutex_lock(&qsee_bw_mutex);
2615 qseecom_unregister_bus_bandwidth_needs(handle->dev);
2616 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002617 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002618 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002619 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002620}
2621EXPORT_SYMBOL(qseecom_set_bandwidth);
2622
Mona Hossain2892b6b2012-02-17 13:53:11 -08002623static int qseecom_send_resp(void)
2624{
2625 qseecom.send_resp_flag = 1;
2626 wake_up_interruptible(&qseecom.send_resp_wq);
2627 return 0;
2628}
2629
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002630
Zhen Kong66e478b2016-07-18 13:20:18 -07002631static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
2632 struct qseecom_send_modfd_listener_resp *resp,
2633 struct qseecom_registered_listener_list *this_lstnr)
2634{
2635 int i;
2636
2637 if (!data || !resp || !this_lstnr) {
2638 pr_err("listener handle or resp msg is null\n");
2639 return -EINVAL;
2640 }
2641
2642 if (resp->resp_buf_ptr == NULL) {
2643 pr_err("resp buffer is null\n");
2644 return -EINVAL;
2645 }
2646 /* validate resp buf length */
2647 if ((resp->resp_len == 0) ||
2648 (resp->resp_len > this_lstnr->sb_length)) {
2649 pr_err("resp buf length %d not valid\n", resp->resp_len);
2650 return -EINVAL;
2651 }
2652
2653 if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
2654 pr_err("Integer overflow in resp_len & resp_buf\n");
2655 return -EINVAL;
2656 }
2657 if ((uintptr_t)this_lstnr->user_virt_sb_base >
2658 (ULONG_MAX - this_lstnr->sb_length)) {
2659 pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
2660 return -EINVAL;
2661 }
2662 /* validate resp buf */
2663 if (((uintptr_t)resp->resp_buf_ptr <
2664 (uintptr_t)this_lstnr->user_virt_sb_base) ||
2665 ((uintptr_t)resp->resp_buf_ptr >=
2666 ((uintptr_t)this_lstnr->user_virt_sb_base +
2667 this_lstnr->sb_length)) ||
2668 (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
2669 ((uintptr_t)this_lstnr->user_virt_sb_base +
2670 this_lstnr->sb_length))) {
2671 pr_err("resp buf is out of shared buffer region\n");
2672 return -EINVAL;
2673 }
2674
2675 /* validate offsets */
2676 for (i = 0; i < MAX_ION_FD; i++) {
2677 if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
2678 pr_err("Invalid offset %d = 0x%x\n",
2679 i, resp->ifd_data[i].cmd_buf_offset);
2680 return -EINVAL;
2681 }
2682 }
2683
2684 return 0;
2685}
2686
2687static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2688 void __user *argp, bool is_64bit_addr)
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002689{
2690 struct qseecom_send_modfd_listener_resp resp;
Zhen Kongf4948192013-11-25 13:05:35 -08002691 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002692
2693 if (copy_from_user(&resp, argp, sizeof(resp))) {
2694 pr_err("copy_from_user failed");
2695 return -EINVAL;
2696 }
Zhen Kong66e478b2016-07-18 13:20:18 -07002697
Zhen Kongf4948192013-11-25 13:05:35 -08002698 this_lstnr = __qseecom_find_svc(data->listener.id);
2699 if (this_lstnr == NULL)
2700 return -EINVAL;
2701
Zhen Kong66e478b2016-07-18 13:20:18 -07002702 if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
Zhen Kongf4948192013-11-25 13:05:35 -08002703 return -EINVAL;
Zhen Kongf4948192013-11-25 13:05:35 -08002704
Zhen Kongf4948192013-11-25 13:05:35 -08002705 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2706 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002707 __qseecom_update_cmd_buf(&resp, false, data, true);
2708 qseecom.send_resp_flag = 1;
2709 wake_up_interruptible(&qseecom.send_resp_wq);
2710 return 0;
2711}
2712
Zhen Kong66e478b2016-07-18 13:20:18 -07002713static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2714 void __user *argp)
2715{
2716 return __qseecom_send_modfd_resp(data, argp, false);
2717}
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002718
Mona Hossain2892b6b2012-02-17 13:53:11 -08002719static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2720 void __user *argp)
2721{
2722 struct qseecom_qseos_version_req req;
2723
2724 if (copy_from_user(&req, argp, sizeof(req))) {
2725 pr_err("copy_from_user failed");
2726 return -EINVAL;
2727 }
2728 req.qseos_version = qseecom.qseos_version;
2729 if (copy_to_user(argp, &req, sizeof(req))) {
2730 pr_err("copy_to_user failed");
2731 return -EINVAL;
2732 }
2733 return 0;
2734}
2735
Mona Hossainc92629e2013-04-01 13:37:46 -07002736static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002737{
2738 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002739 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002740
Mona Hossainc92629e2013-04-01 13:37:46 -07002741 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002742 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002743 else
2744 qclk = &qseecom.ce_drv;
2745
2746 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002747
2748 if (qclk->clk_access_cnt == ULONG_MAX)
2749 goto err;
2750
Mona Hossainc92629e2013-04-01 13:37:46 -07002751 if (qclk->clk_access_cnt > 0) {
2752 qclk->clk_access_cnt++;
2753 mutex_unlock(&clk_access_lock);
2754 return rc;
2755 }
2756
Mona Hossain6311d572013-03-01 15:54:02 -08002757 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002758 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002759 if (rc) {
2760 pr_err("Unable to enable/prepare CE core clk\n");
2761 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002762 }
2763 /* Enable CE clk */
2764 rc = clk_prepare_enable(qclk->ce_clk);
2765 if (rc) {
2766 pr_err("Unable to enable/prepare CE iface clk\n");
2767 goto ce_clk_err;
2768 }
2769 /* Enable AXI clk */
2770 rc = clk_prepare_enable(qclk->ce_bus_clk);
2771 if (rc) {
2772 pr_err("Unable to enable/prepare CE bus clk\n");
2773 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002774 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002775 qclk->clk_access_cnt++;
2776 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002777 return 0;
2778
2779ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002780 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002781ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002782 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002783err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002784 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002785 return -EIO;
2786}
2787
Mona Hossainc92629e2013-04-01 13:37:46 -07002788static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002789{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002790 struct qseecom_clk *qclk;
2791
Mona Hossainc92629e2013-04-01 13:37:46 -07002792 if (ce == CLK_QSEE)
2793 qclk = &qseecom.qsee;
2794 else
2795 qclk = &qseecom.ce_drv;
2796
2797 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002798
2799 if (qclk->clk_access_cnt == 0) {
2800 mutex_unlock(&clk_access_lock);
2801 return;
2802 }
2803
Mona Hossainc92629e2013-04-01 13:37:46 -07002804 if (qclk->clk_access_cnt == 1) {
2805 if (qclk->ce_clk != NULL)
2806 clk_disable_unprepare(qclk->ce_clk);
2807 if (qclk->ce_core_clk != NULL)
2808 clk_disable_unprepare(qclk->ce_core_clk);
2809 if (qclk->ce_bus_clk != NULL)
2810 clk_disable_unprepare(qclk->ce_bus_clk);
2811 }
2812 qclk->clk_access_cnt--;
2813 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002814}
2815
Mona Hossain04d3fac2012-12-03 10:10:37 -08002816static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2817 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002818{
2819 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002820 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002821
Mona Hossain17a4faf2013-03-22 16:40:56 -07002822 qclk = &qseecom.qsee;
2823 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002824 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002825
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002826 switch (clk_type) {
2827 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002828 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002829 if (!qseecom.qsee_bw_count) {
2830 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002831 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002832 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002833 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002834 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002835 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002836 if (!ret) {
2837 ret =
2838 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002839 qseecom.qsee_perf_client, 1);
2840 if ((ret) &&
2841 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002842 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002843 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002844 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002845 if (ret)
2846 pr_err("DFAB Bandwidth req failed (%d)\n",
2847 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002848 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002849 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002850 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002851 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002852 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002853 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002854 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002855 }
2856 mutex_unlock(&qsee_bw_mutex);
2857 break;
2858 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002859 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002860 if (!qseecom.qsee_sfpb_bw_count) {
2861 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002862 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002863 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002864 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002865 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002866 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002867 if (!ret) {
2868 ret =
2869 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002870 qseecom.qsee_perf_client, 2);
2871 if ((ret) &&
2872 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002873 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002874 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002875 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002876
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002877 if (ret)
2878 pr_err("SFPB Bandwidth req failed (%d)\n",
2879 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002880 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002881 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002882 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002883 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002884 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002885 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002886 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002887 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002888 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002889 break;
2890 default:
2891 pr_err("Clock type not defined\n");
2892 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002893 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002894 return ret;
2895}
2896
Mona Hossain04d3fac2012-12-03 10:10:37 -08002897static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2898 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002899{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002900 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002901 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002902
Mona Hossain17a4faf2013-03-22 16:40:56 -07002903 qclk = &qseecom.qsee;
2904 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002905 return;
2906
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002907 switch (clk_type) {
2908 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002909 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002910 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002911 pr_err("Client error.Extra call to disable DFAB clk\n");
2912 mutex_unlock(&qsee_bw_mutex);
2913 return;
2914 }
2915
Mona Hossain17a4faf2013-03-22 16:40:56 -07002916 if (qseecom.qsee_bw_count == 1) {
2917 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002918 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002919 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002920 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002921 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002922 qseecom.qsee_perf_client, 0);
2923 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002924 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002925 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002926 if (ret)
2927 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002928 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002929 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002930 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002931 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002932 }
2933 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002934 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002935 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002936 }
2937 mutex_unlock(&qsee_bw_mutex);
2938 break;
2939 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002940 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002941 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002942 pr_err("Client error.Extra call to disable SFPB clk\n");
2943 mutex_unlock(&qsee_bw_mutex);
2944 return;
2945 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002946 if (qseecom.qsee_sfpb_bw_count == 1) {
2947 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002948 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002949 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002950 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002951 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002952 qseecom.qsee_perf_client, 0);
2953 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002954 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002955 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002956 if (ret)
2957 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002958 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002959 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002960 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002961 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002962 }
2963 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002964 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002965 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002966 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002967 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002968 break;
2969 default:
2970 pr_err("Clock type not defined\n");
2971 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002972 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002973
Mona Hossain2892b6b2012-02-17 13:53:11 -08002974}
2975
Mona Hossain5ab9d772012-04-11 21:00:40 -07002976static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2977 void __user *argp)
2978{
2979 struct ion_handle *ihandle; /* Ion handle */
2980 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002981 int ret;
2982 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002983 ion_phys_addr_t pa = 0;
2984 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002985 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002986 struct qseecom_load_app_ireq load_req;
2987 struct qseecom_command_scm_resp resp;
2988
2989 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002990 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002991 (void __user *)argp,
2992 sizeof(struct qseecom_load_img_req))) {
2993 pr_err("copy_from_user failed\n");
2994 return -EFAULT;
2995 }
2996
2997 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002998 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002999 load_img_req.ifd_data_fd);
3000 if (IS_ERR_OR_NULL(ihandle)) {
3001 pr_err("Ion client could not retrieve the handle\n");
3002 return -ENOMEM;
3003 }
3004
3005 /* Get the physical address of the ION BUF */
3006 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08003007 if (ret) {
3008 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
3009 ret);
3010 return ret;
3011 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003012 /* Populate the structure for sending scm call to load image */
3013 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
3014 load_req.mdt_len = load_img_req.mdt_len;
3015 load_req.img_len = load_img_req.img_len;
3016 load_req.phy_addr = pa;
3017
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003018 /* SCM_CALL tied to Core0 */
3019 mask = CPU_MASK_CPU0;
3020 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3021 if (set_cpu_ret) {
3022 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3023 set_cpu_ret);
3024 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303025 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003026 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303027
Zhen Kong4bead3c2014-04-14 15:07:13 -07003028 if (qseecom.support_bus_scaling) {
3029 mutex_lock(&qsee_bw_mutex);
3030 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
3031 mutex_unlock(&qsee_bw_mutex);
3032 if (ret) {
3033 ret = -EIO;
3034 goto exit_cpu_restore;
3035 }
3036 }
3037
Mona Hossain6311d572013-03-01 15:54:02 -08003038 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07003039 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08003040 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08003041 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07003042 goto exit_register_bus_bandwidth_needs;
Mona Hossain6311d572013-03-01 15:54:02 -08003043 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003044 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
3045 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003046 /* SCM_CALL to load the external elf */
3047 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
3048 sizeof(struct qseecom_load_app_ireq),
3049 &resp, sizeof(resp));
3050 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003051 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07003052 ret);
3053 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303054 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003055 }
3056
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303057 switch (resp.result) {
3058 case QSEOS_RESULT_SUCCESS:
3059 break;
3060 case QSEOS_RESULT_INCOMPLETE:
3061 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003062 ret = __qseecom_process_incomplete_cmd(data, &resp);
3063 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303064 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
3065 break;
3066 case QSEOS_RESULT_FAILURE:
3067 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
3068 ret = -EFAULT;
3069 break;
3070 default:
3071 pr_err("scm_call response result %d not supported\n",
3072 resp.result);
3073 ret = -EFAULT;
3074 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003075 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003076
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303077exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07003078 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07003079
3080exit_register_bus_bandwidth_needs:
3081 if (qseecom.support_bus_scaling) {
3082 mutex_lock(&qsee_bw_mutex);
3083 ret = qseecom_unregister_bus_bandwidth_needs(data);
3084 mutex_unlock(&qsee_bw_mutex);
3085 }
3086
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303087exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003088 /* Restore the CPU mask */
3089 mask = CPU_MASK_ALL;
3090 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3091 if (set_cpu_ret) {
3092 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3093 set_cpu_ret);
3094 ret = -EFAULT;
3095 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05303096exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07003097 /* Deallocate the handle */
3098 if (!IS_ERR_OR_NULL(ihandle))
3099 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07003100 return ret;
3101}
3102
3103static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
3104{
3105 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003106 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003107 struct qseecom_command_scm_resp resp;
3108 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003109 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003110
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303111 /* unavailable client app */
3112 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
3113
Mona Hossain5ab9d772012-04-11 21:00:40 -07003114 /* Populate the structure for sending scm call to unload image */
3115 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003116
3117 /* SCM_CALL tied to Core0 */
3118 mask = CPU_MASK_CPU0;
3119 ret = set_cpus_allowed_ptr(current, &mask);
3120 if (ret) {
3121 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
3122 ret);
3123 return -EFAULT;
3124 }
3125
Mona Hossain5ab9d772012-04-11 21:00:40 -07003126 /* SCM_CALL to unload the external elf */
3127 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
3128 sizeof(struct qseecom_unload_app_ireq),
3129 &resp, sizeof(resp));
3130 if (ret) {
3131 pr_err("scm_call to unload failed : ret %d\n",
3132 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003133 ret = -EFAULT;
3134 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003135 }
3136 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
3137 ret = __qseecom_process_incomplete_cmd(data, &resp);
3138 if (ret)
3139 pr_err("process_incomplete_cmd fail err: %d\n",
3140 ret);
3141 } else {
3142 if (resp.result != QSEOS_RESULT_SUCCESS) {
3143 pr_err("scm_call to unload image failed resp.result =%d\n",
3144 resp.result);
3145 ret = -EFAULT;
3146 }
3147 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07003148
3149qseecom_unload_external_elf_scm_err:
3150 /* Restore the CPU mask */
3151 mask = CPU_MASK_ALL;
3152 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
3153 if (set_cpu_ret) {
3154 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
3155 set_cpu_ret);
3156 ret = -EFAULT;
3157 }
3158
Mona Hossain5ab9d772012-04-11 21:00:40 -07003159 return ret;
3160}
Mona Hossain2892b6b2012-02-17 13:53:11 -08003161
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003162static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
3163 void __user *argp)
3164{
3165
3166 int32_t ret;
3167 struct qseecom_qseos_app_load_query query_req;
3168 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003169 struct qseecom_registered_app_list *entry = NULL;
3170 unsigned long flags = 0;
Zhen Kong59155a72015-05-20 13:50:04 -07003171 bool found_app = false;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003172
3173 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07003174 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003175 (void __user *)argp,
3176 sizeof(struct qseecom_qseos_app_load_query))) {
3177 pr_err("copy_from_user failed\n");
3178 return -EFAULT;
3179 }
3180
3181 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07003182 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
William Clarkba7f03c2015-03-09 12:07:49 -07003183 strlcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003184
3185 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003186
3187 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003188 pr_err(" scm call to check if app is loaded failed");
3189 return ret; /* scm call failed */
3190 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07003191 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003192 (char *)(req.app_name));
3193 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
3194 list_for_each_entry(entry,
3195 &qseecom.registered_app_list_head, list){
3196 if (entry->app_id == ret) {
3197 entry->ref_cnt++;
Zhen Kong59155a72015-05-20 13:50:04 -07003198 found_app = true;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003199 break;
3200 }
3201 }
3202 spin_unlock_irqrestore(
3203 &qseecom.registered_app_list_lock, flags);
3204 data->client.app_id = ret;
3205 query_req.app_id = ret;
William Clarkba7f03c2015-03-09 12:07:49 -07003206 strlcpy(data->client.app_name, query_req.app_name,
Zhen Kong44c2a6f2014-10-31 11:33:34 -07003207 MAX_APP_NAME_SIZE);
Zhen Kong59155a72015-05-20 13:50:04 -07003208 /*
3209 * If app was loaded by appsbl or kernel client before
3210 * and was not registered, regiser this app now.
3211 */
3212 if (!found_app) {
3213 pr_debug("Register app %d [%s] which was loaded before\n",
3214 ret, (char *)query_req.app_name);
3215 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
3216 if (!entry) {
3217 pr_err("kmalloc for app entry failed\n");
3218 return -ENOMEM;
3219 }
3220 entry->app_id = ret;
3221 entry->ref_cnt = 1;
3222 strlcpy(entry->app_name, data->client.app_name,
3223 MAX_APP_NAME_SIZE);
3224 spin_lock_irqsave(&qseecom.registered_app_list_lock,
3225 flags);
3226 list_add_tail(&entry->list,
3227 &qseecom.registered_app_list_head);
3228 spin_unlock_irqrestore(
3229 &qseecom.registered_app_list_lock, flags);
3230 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07003231 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
3232 pr_err("copy_to_user failed\n");
3233 return -EFAULT;
3234 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003235 return -EEXIST; /* app already loaded */
3236 } else {
3237 return 0; /* app not loaded */
3238 }
3239}
3240
Mona Hossain4cf78a92013-02-14 12:06:41 -08003241static int __qseecom_get_ce_pipe_info(
3242 enum qseecom_key_management_usage_type usage,
3243 uint32_t *pipe, uint32_t *ce_hw)
3244{
3245 int ret;
3246 switch (usage) {
3247 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003248 if (qseecom.support_fde) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003249 *pipe = qseecom.ce_info.disk_encrypt_pipe;
3250 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3251 ret = 0;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003252
3253 } else {
3254 pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
3255 qseecom.ce_info.disk_encrypt_pipe,
3256 qseecom.ce_info.hlos_ce_hw_instance);
3257 ret = -EINVAL;
3258 }
3259 break;
3260 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
3261 if (qseecom.support_pfe) {
3262 *pipe = qseecom.ce_info.file_encrypt_pipe;
3263 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
3264 ret = 0;
3265 } else {
3266 pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
3267 qseecom.ce_info.file_encrypt_pipe,
3268 qseecom.ce_info.hlos_ce_hw_instance);
3269 ret = -EINVAL;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003270 }
3271 break;
3272 default:
3273 ret = -EINVAL;
3274 break;
3275 }
3276 return ret;
3277}
3278
3279static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
3280 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003281 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003282{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003283 struct qseecom_command_scm_resp resp;
3284 int ret;
3285
Zhen Kong9730ddf2013-12-17 16:49:43 -08003286 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3287 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003288 pr_err("Error:: unsupported usage %d\n", usage);
3289 return -EFAULT;
3290 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003291 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003292
3293 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003294 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003295 &resp, sizeof(resp));
3296 if (ret) {
3297 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003298 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003299 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003300 }
3301
3302 switch (resp.result) {
3303 case QSEOS_RESULT_SUCCESS:
3304 break;
Zhen Kong336636e2013-04-15 11:04:54 -07003305 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongba69dfe2014-02-28 15:19:53 -08003306 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07003307 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003308 case QSEOS_RESULT_INCOMPLETE:
3309 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07003310 if (ret) {
3311 if (resp.result == 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 ret = 0;
3314 } else {
3315 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3316 resp.result);
3317 }
3318 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003319 break;
3320 case QSEOS_RESULT_FAILURE:
3321 default:
3322 pr_err("gen key scm call failed resp.result %d\n", resp.result);
3323 ret = -EINVAL;
3324 break;
3325 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003326 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003327 return ret;
3328}
3329
3330static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
3331 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003332 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003333{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003334 struct qseecom_command_scm_resp resp;
3335 int ret;
3336
Amir Samuelov48a1e7d2014-06-23 11:49:05 +03003337 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3338 usage >= QSEOS_KM_USAGE_MAX) {
3339 pr_err("Error:: unsupported usage %d\n", usage);
3340 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003341 }
3342
Mona Hossainc92629e2013-04-01 13:37:46 -07003343 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07003344
3345 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003346 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003347 &resp, sizeof(struct qseecom_command_scm_resp));
3348 if (ret) {
3349 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07003350 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003351 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003352 }
3353
3354 switch (resp.result) {
3355 case QSEOS_RESULT_SUCCESS:
3356 break;
3357 case QSEOS_RESULT_INCOMPLETE:
3358 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003359 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003360 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3361 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003362 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3363 pr_debug("Max attempts to input password reached.\n");
3364 ret = -ERANGE;
3365 }
3366 }
3367 break;
3368 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3369 pr_debug("Max attempts to input password reached.\n");
3370 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003371 break;
3372 case QSEOS_RESULT_FAILURE:
3373 default:
3374 pr_err("Delete key scm call failed resp.result %d\n",
3375 resp.result);
3376 ret = -EINVAL;
3377 break;
3378 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003379 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003380 return ret;
3381}
3382
3383static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
3384 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003385 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08003386{
Mona Hossain4cf78a92013-02-14 12:06:41 -08003387 struct qseecom_command_scm_resp resp;
3388 int ret;
3389
Zhen Kong9730ddf2013-12-17 16:49:43 -08003390 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3391 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003392 pr_err("Error:: unsupported usage %d\n", usage);
3393 return -EFAULT;
3394 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003395
Zhen Kongdb2bf742013-05-13 23:55:42 -07003396 __qseecom_enable_clk(CLK_QSEE);
3397 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003398 __qseecom_enable_clk(CLK_CE_DRV);
3399
Zhen Kong336636e2013-04-15 11:04:54 -07003400 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003401 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003402 &resp, sizeof(struct qseecom_command_scm_resp));
3403 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003404 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07003405 __qseecom_disable_clk(CLK_QSEE);
3406 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3407 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08003408 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07003409 }
3410
Mona Hossain4cf78a92013-02-14 12:06:41 -08003411 switch (resp.result) {
3412 case QSEOS_RESULT_SUCCESS:
3413 break;
3414 case QSEOS_RESULT_INCOMPLETE:
3415 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003416 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003417 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3418 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003419 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3420 pr_debug("Max attempts to input password reached.\n");
3421 ret = -ERANGE;
3422 }
3423 }
3424 break;
3425 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3426 pr_debug("Max attempts to input password reached.\n");
3427 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003428 break;
3429 case QSEOS_RESULT_FAILURE:
3430 default:
3431 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3432 ret = -EINVAL;
3433 break;
3434 }
3435
Zhen Kongdb2bf742013-05-13 23:55:42 -07003436 __qseecom_disable_clk(CLK_QSEE);
3437 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003438 __qseecom_disable_clk(CLK_CE_DRV);
3439
Mona Hossain4cf78a92013-02-14 12:06:41 -08003440 return ret;
3441}
3442
Zhen Kong9730ddf2013-12-17 16:49:43 -08003443static int __qseecom_update_current_key_user_info(
3444 struct qseecom_dev_handle *data,
3445 enum qseecom_key_management_usage_type usage,
3446 struct qseecom_key_userinfo_update_ireq *ireq)
3447{
3448 struct qseecom_command_scm_resp resp;
3449 int ret;
3450
3451 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3452 usage >= QSEOS_KM_USAGE_MAX) {
3453 pr_err("Error:: unsupported usage %d\n", usage);
3454 return -EFAULT;
3455 }
3456
3457 __qseecom_enable_clk(CLK_QSEE);
3458
3459 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
3460 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
3461 &resp, sizeof(struct qseecom_command_scm_resp));
3462 if (ret) {
3463 pr_err("scm call to update key userinfo failed : %d\n", ret);
3464 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003465 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003466 }
3467
3468 switch (resp.result) {
3469 case QSEOS_RESULT_SUCCESS:
3470 break;
3471 case QSEOS_RESULT_INCOMPLETE:
3472 ret = __qseecom_process_incomplete_cmd(data, &resp);
3473 if (ret)
3474 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3475 resp.result);
3476 break;
3477 case QSEOS_RESULT_FAILURE:
3478 default:
3479 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3480 ret = -EINVAL;
3481 break;
3482 }
3483
3484 __qseecom_disable_clk(CLK_QSEE);
3485 return ret;
3486}
3487
Mona Hossain4cf78a92013-02-14 12:06:41 -08003488static int qseecom_create_key(struct qseecom_dev_handle *data,
3489 void __user *argp)
3490{
3491 uint32_t ce_hw = 0;
3492 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003493 int ret = 0;
3494 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003495 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003496 struct qseecom_key_generate_ireq generate_key_ireq;
3497 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003498
3499 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
3500 if (ret) {
3501 pr_err("copy_from_user failed\n");
3502 return ret;
3503 }
3504
Zhen Kong9730ddf2013-12-17 16:49:43 -08003505 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3506 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003507 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
3508 return -EFAULT;
3509 }
3510
3511 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
3512 if (ret) {
3513 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3514 return -EINVAL;
3515 }
3516
Zhen Kong9730ddf2013-12-17 16:49:43 -08003517 generate_key_ireq.flags = flags;
3518 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
3519 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3520 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3521 memcpy((void *)generate_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003522 (void *)key_id_array[create_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003523 QSEECOM_KEY_ID_SIZE);
3524 memcpy((void *)generate_key_ireq.hash32,
3525 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
3526
Mona Hossain4cf78a92013-02-14 12:06:41 -08003527 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003528 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003529 if (ret) {
3530 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003531 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003532 }
3533
Zhen Kong9730ddf2013-12-17 16:49:43 -08003534 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3535 set_key_ireq.ce = ce_hw;
3536 set_key_ireq.pipe = pipe;
3537 set_key_ireq.flags = flags;
3538
3539 /* set both PIPE_ENC and PIPE_ENC_XTS*/
3540 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
3541 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3542 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3543 memcpy((void *)set_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003544 (void *)key_id_array[create_key_req.usage].desc,
3545 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003546 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08003547 QSEECOM_HASH_SIZE);
3548
3549 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003550 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003551 if (ret) {
3552 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
3553 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003554 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003555 }
3556
3557 return ret;
3558}
3559
3560static int qseecom_wipe_key(struct qseecom_dev_handle *data,
3561 void __user *argp)
3562{
3563 uint32_t ce_hw = 0;
3564 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003565 int ret = 0;
3566 uint32_t flags = 0;
3567 int i;
3568 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003569 struct qseecom_key_delete_ireq delete_key_ireq;
3570 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003571
3572 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
3573 if (ret) {
3574 pr_err("copy_from_user failed\n");
3575 return ret;
3576 }
3577
Zhen Kong9730ddf2013-12-17 16:49:43 -08003578 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3579 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003580 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3581 return -EFAULT;
3582 }
3583
3584 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3585 if (ret) {
3586 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3587 return -EINVAL;
3588 }
3589
Zhen Kongba69dfe2014-02-28 15:19:53 -08003590 if (wipe_key_req.wipe_key_flag) {
3591 delete_key_ireq.flags = flags;
3592 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3593 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3594 memcpy((void *)delete_key_ireq.key_id,
3595 (void *)key_id_array[wipe_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003596 QSEECOM_KEY_ID_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003597 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003598
Zhen Kongba69dfe2014-02-28 15:19:53 -08003599 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003600 &delete_key_ireq);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003601 if (ret) {
3602 pr_err("Failed to delete key from ssd storage: %d\n",
3603 ret);
3604 return -EFAULT;
3605 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003606 }
3607
Zhen Kong9730ddf2013-12-17 16:49:43 -08003608 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3609 clear_key_ireq.ce = ce_hw;
3610 clear_key_ireq.pipe = pipe;
3611 clear_key_ireq.flags = flags;
3612 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003613 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kongba69dfe2014-02-28 15:19:53 -08003614 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003615 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3616
Mona Hossain4cf78a92013-02-14 12:06:41 -08003617 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003618 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003619 if (ret) {
3620 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3621 pipe, ce_hw, ret);
3622 return -EFAULT;
3623 }
3624
3625 return ret;
3626}
3627
Zhen Kong9730ddf2013-12-17 16:49:43 -08003628static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3629 void __user *argp)
3630{
3631 int ret = 0;
3632 uint32_t flags = 0;
3633 struct qseecom_update_key_userinfo_req update_key_req;
3634 struct qseecom_key_userinfo_update_ireq ireq;
3635
3636 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3637 if (ret) {
3638 pr_err("copy_from_user failed\n");
3639 return ret;
3640 }
3641
3642 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3643 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3644 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3645 return -EFAULT;
3646 }
3647
3648 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3649 ireq.flags = flags;
3650 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3651 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3652 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003653 memcpy((void *)ireq.key_id,
3654 (void *)key_id_array[update_key_req.usage].desc,
3655 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003656 memcpy((void *)ireq.current_hash32,
3657 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3658 memcpy((void *)ireq.new_hash32,
3659 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3660
3661 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3662 &ireq);
3663 if (ret) {
3664 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003665 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003666 }
3667 return ret;
3668
3669}
3670
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003671static int qseecom_is_es_activated(void __user *argp)
3672{
3673 struct qseecom_is_es_activated_req req;
3674 int ret;
3675 int resp_buf;
3676
3677 if (qseecom.qsee_version < QSEE_VERSION_04) {
3678 pr_err("invalid qsee version");
3679 return -ENODEV;
3680 }
3681
3682 if (argp == NULL) {
3683 pr_err("arg is null");
3684 return -EINVAL;
3685 }
3686
3687 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3688 (void *) &resp_buf, sizeof(resp_buf));
3689 if (ret) {
3690 pr_err("scm_call failed");
3691 return ret;
3692 }
3693
3694 req.is_activated = resp_buf;
3695 ret = copy_to_user(argp, &req, sizeof(req));
3696 if (ret) {
3697 pr_err("copy_to_user failed");
3698 return ret;
3699 }
3700
3701 return 0;
3702}
3703
3704static int qseecom_save_partition_hash(void __user *argp)
3705{
3706 struct qseecom_save_partition_hash_req req;
3707 int ret;
3708
3709 if (qseecom.qsee_version < QSEE_VERSION_04) {
3710 pr_err("invalid qsee version ");
3711 return -ENODEV;
3712 }
3713
3714 if (argp == NULL) {
3715 pr_err("arg is null");
3716 return -EINVAL;
3717 }
3718
3719 ret = copy_from_user(&req, argp, sizeof(req));
3720 if (ret) {
3721 pr_err("copy_from_user failed");
3722 return ret;
3723 }
3724
3725 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3726 (void *) &req, sizeof(req), NULL, 0);
3727 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003728 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003729 return ret;
3730 }
3731
3732 return 0;
3733}
3734
Mona Hossain2892b6b2012-02-17 13:53:11 -08003735static long qseecom_ioctl(struct file *file, unsigned cmd,
3736 unsigned long arg)
3737{
3738 int ret = 0;
3739 struct qseecom_dev_handle *data = file->private_data;
3740 void __user *argp = (void __user *) arg;
Zhen Kongd08301c2014-10-08 17:02:54 -07003741 bool perf_enabled = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003742
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303743 if (!data) {
3744 pr_err("Invalid/uninitialized device handle\n");
3745 return -EINVAL;
3746 }
3747
Mona Hossain2892b6b2012-02-17 13:53:11 -08003748 if (data->abort) {
3749 pr_err("Aborting qseecom driver\n");
3750 return -ENODEV;
3751 }
3752
3753 switch (cmd) {
3754 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003755 if (data->type != QSEECOM_GENERIC) {
3756 pr_err("reg lstnr req: invalid handle (%d)\n",
3757 data->type);
3758 ret = -EINVAL;
3759 break;
3760 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003761 pr_debug("ioctl register_listener_req()\n");
3762 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003763 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003764 ret = qseecom_register_listener(data, argp);
3765 atomic_dec(&data->ioctl_count);
3766 wake_up_all(&data->abort_wq);
3767 if (ret)
3768 pr_err("failed qseecom_register_listener: %d\n", ret);
3769 break;
3770 }
3771 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003772 if ((data->listener.id == 0) ||
3773 (data->type != QSEECOM_LISTENER_SERVICE)) {
3774 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3775 data->type, data->listener.id);
3776 ret = -EINVAL;
3777 break;
3778 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003779 pr_debug("ioctl unregister_listener_req()\n");
3780 atomic_inc(&data->ioctl_count);
3781 ret = qseecom_unregister_listener(data);
3782 atomic_dec(&data->ioctl_count);
3783 wake_up_all(&data->abort_wq);
3784 if (ret)
3785 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3786 break;
3787 }
3788 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003789 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003790 if ((data->client.app_id == 0) ||
3791 (data->type != QSEECOM_CLIENT_APP)) {
3792 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3793 data->type, data->client.app_id);
3794 ret = -EINVAL;
3795 break;
3796 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003797 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003798 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003799 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003800 /* register bus bw in case the client doesn't do it */
3801 if (!data->mode) {
3802 mutex_lock(&qsee_bw_mutex);
3803 __qseecom_register_bus_bandwidth_needs(
3804 data, HIGH);
3805 mutex_unlock(&qsee_bw_mutex);
3806 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003807 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3808 if (ret) {
3809 pr_err("Failed to set bw.\n");
3810 ret = -EINVAL;
3811 mutex_unlock(&app_access_lock);
3812 break;
3813 }
3814 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003815 /*
3816 * On targets where crypto clock is handled by HLOS,
3817 * if clk_access_cnt is zero and perf_enabled is false,
3818 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003819 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003820 */
3821 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003822 pr_debug("ce clock is not enabled!\n");
3823 ret = qseecom_perf_enable(data);
3824 if (ret) {
3825 pr_err("Failed to vote for clock with err %d\n",
3826 ret);
3827 mutex_unlock(&app_access_lock);
3828 ret = -EINVAL;
3829 break;
3830 }
3831 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003832 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003833 atomic_inc(&data->ioctl_count);
3834 ret = qseecom_send_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003835 if (qseecom.support_bus_scaling)
3836 __qseecom_add_bw_scale_down_timer(
3837 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003838 if (perf_enabled) {
3839 qsee_disable_clock_vote(data, CLK_DFAB);
3840 qsee_disable_clock_vote(data, CLK_SFPB);
3841 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003842 atomic_dec(&data->ioctl_count);
3843 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003844 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003845 if (ret)
3846 pr_err("failed qseecom_send_cmd: %d\n", ret);
3847 break;
3848 }
3849 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003850 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003851 if ((data->client.app_id == 0) ||
3852 (data->type != QSEECOM_CLIENT_APP)) {
3853 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3854 data->type, data->client.app_id);
3855 ret = -EINVAL;
3856 break;
3857 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003858 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003859 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003860 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003861 if (!data->mode) {
3862 mutex_lock(&qsee_bw_mutex);
3863 __qseecom_register_bus_bandwidth_needs(
3864 data, HIGH);
3865 mutex_unlock(&qsee_bw_mutex);
3866 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003867 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3868 if (ret) {
3869 pr_err("Failed to set bw.\n");
3870 mutex_unlock(&app_access_lock);
3871 ret = -EINVAL;
3872 break;
3873 }
3874 }
Zhen Kong1e15c272014-09-18 12:33:07 -07003875 /*
3876 * On targets where crypto clock is handled by HLOS,
3877 * if clk_access_cnt is zero and perf_enabled is false,
3878 * then the crypto clock was not enabled before sending cmd
Zhen Kongd08301c2014-10-08 17:02:54 -07003879 * to tz, qseecom will enable the clock to avoid service failure.
Zhen Kong1e15c272014-09-18 12:33:07 -07003880 */
3881 if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
Zhen Kongd08301c2014-10-08 17:02:54 -07003882 pr_debug("ce clock is not enabled!\n");
3883 ret = qseecom_perf_enable(data);
3884 if (ret) {
3885 pr_err("Failed to vote for clock with err %d\n",
3886 ret);
3887 mutex_unlock(&app_access_lock);
3888 ret = -EINVAL;
3889 break;
3890 }
3891 perf_enabled = true;
Zhen Kong1e15c272014-09-18 12:33:07 -07003892 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003893 atomic_inc(&data->ioctl_count);
3894 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003895 if (qseecom.support_bus_scaling)
3896 __qseecom_add_bw_scale_down_timer(
3897 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kongd08301c2014-10-08 17:02:54 -07003898 if (perf_enabled) {
3899 qsee_disable_clock_vote(data, CLK_DFAB);
3900 qsee_disable_clock_vote(data, CLK_SFPB);
3901 }
Zhen Konge8a02082014-03-11 17:36:50 -07003902 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003903 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003904 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003905 if (ret)
3906 pr_err("failed qseecom_send_cmd: %d\n", ret);
3907 break;
3908 }
3909 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003910 if ((data->listener.id == 0) ||
3911 (data->type != QSEECOM_LISTENER_SERVICE)) {
3912 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3913 data->type, data->listener.id);
3914 ret = -EINVAL;
3915 break;
3916 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003917 atomic_inc(&data->ioctl_count);
3918 ret = qseecom_receive_req(data);
3919 atomic_dec(&data->ioctl_count);
3920 wake_up_all(&data->abort_wq);
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05303921 if (ret && (ret != -ERESTARTSYS))
Mona Hossain2892b6b2012-02-17 13:53:11 -08003922 pr_err("failed qseecom_receive_req: %d\n", ret);
3923 break;
3924 }
3925 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003926 if ((data->listener.id == 0) ||
3927 (data->type != QSEECOM_LISTENER_SERVICE)) {
3928 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3929 data->type, data->listener.id);
3930 ret = -EINVAL;
3931 break;
3932 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003933 atomic_inc(&data->ioctl_count);
3934 ret = qseecom_send_resp();
3935 atomic_dec(&data->ioctl_count);
3936 wake_up_all(&data->abort_wq);
3937 if (ret)
3938 pr_err("failed qseecom_send_resp: %d\n", ret);
3939 break;
3940 }
3941 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003942 if ((data->type != QSEECOM_CLIENT_APP) &&
3943 (data->type != QSEECOM_GENERIC) &&
3944 (data->type != QSEECOM_SECURE_SERVICE)) {
3945 pr_err("set mem param req: invalid handle (%d)\n",
3946 data->type);
3947 ret = -EINVAL;
3948 break;
3949 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003950 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Zhen Kongf8f3e1b2017-02-27 23:41:00 +02003951 mutex_lock(&app_access_lock);
Zhen Kong96f5c012017-05-23 10:21:20 +08003952 atomic_inc(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003953 ret = qseecom_set_client_mem_param(data, argp);
Zhen Kongf8f3e1b2017-02-27 23:41:00 +02003954 atomic_dec(&data->ioctl_count);
Zhen Kong96f5c012017-05-23 10:21:20 +08003955 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003956 if (ret)
3957 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3958 ret);
3959 break;
3960 }
3961 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003962 if ((data->type != QSEECOM_GENERIC) &&
3963 (data->type != QSEECOM_CLIENT_APP)) {
3964 pr_err("load app req: invalid handle (%d)\n",
3965 data->type);
3966 ret = -EINVAL;
3967 break;
3968 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003969 data->type = QSEECOM_CLIENT_APP;
3970 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003971 mutex_lock(&app_access_lock);
3972 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003973 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3974 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003975 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003976 if (ret == 0)
3977 qseecom.commonlib_loaded = true;
3978 }
3979 }
3980 if (ret == 0)
3981 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003982 atomic_dec(&data->ioctl_count);
3983 mutex_unlock(&app_access_lock);
3984 if (ret)
3985 pr_err("failed load_app request: %d\n", ret);
3986 break;
3987 }
3988 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003989 if ((data->client.app_id == 0) ||
3990 (data->type != QSEECOM_CLIENT_APP)) {
3991 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3992 data->type, data->client.app_id);
3993 ret = -EINVAL;
3994 break;
3995 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003996 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003997 mutex_lock(&app_access_lock);
3998 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07003999 ret = qseecom_unload_app(data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004000 atomic_dec(&data->ioctl_count);
4001 mutex_unlock(&app_access_lock);
4002 if (ret)
4003 pr_err("failed unload_app request: %d\n", ret);
4004 break;
4005 }
4006 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
4007 atomic_inc(&data->ioctl_count);
4008 ret = qseecom_get_qseos_version(data, argp);
4009 if (ret)
4010 pr_err("qseecom_get_qseos_version: %d\n", ret);
4011 atomic_dec(&data->ioctl_count);
4012 break;
4013 }
4014 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004015 if ((data->type != QSEECOM_GENERIC) &&
4016 (data->type != QSEECOM_CLIENT_APP)) {
4017 pr_err("perf enable req: invalid handle (%d)\n",
4018 data->type);
4019 ret = -EINVAL;
4020 break;
4021 }
4022 if ((data->type == QSEECOM_CLIENT_APP) &&
4023 (data->client.app_id == 0)) {
4024 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
4025 data->type, data->client.app_id);
4026 ret = -EINVAL;
4027 break;
4028 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004029 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004030 if (qseecom.support_bus_scaling) {
4031 mutex_lock(&qsee_bw_mutex);
4032 __qseecom_register_bus_bandwidth_needs(data, HIGH);
4033 mutex_unlock(&qsee_bw_mutex);
4034 } else {
Zhen Kongd08301c2014-10-08 17:02:54 -07004035 ret = qseecom_perf_enable(data);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004036 if (ret)
Zhen Kongd08301c2014-10-08 17:02:54 -07004037 pr_err("Fail to vote for clocks %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004038 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004039 atomic_dec(&data->ioctl_count);
4040 break;
4041 }
4042 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07004043 if ((data->type != QSEECOM_SECURE_SERVICE) &&
4044 (data->type != QSEECOM_CLIENT_APP)) {
4045 pr_err("perf disable req: invalid handle (%d)\n",
4046 data->type);
4047 ret = -EINVAL;
4048 break;
4049 }
4050 if ((data->type == QSEECOM_CLIENT_APP) &&
4051 (data->client.app_id == 0)) {
4052 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
4053 data->type, data->client.app_id);
4054 ret = -EINVAL;
4055 break;
4056 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004057 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004058 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004059 qsee_disable_clock_vote(data, CLK_DFAB);
4060 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07004061 } else {
4062 mutex_lock(&qsee_bw_mutex);
4063 qseecom_unregister_bus_bandwidth_needs(data);
4064 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004065 }
4066 atomic_dec(&data->ioctl_count);
4067 break;
4068 }
4069
4070 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
4071 if ((data->client.app_id == 0) ||
4072 (data->type != QSEECOM_CLIENT_APP)) {
4073 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
4074 data->type, data->client.app_id);
4075 ret = -EINVAL;
4076 break;
4077 }
4078 atomic_inc(&data->ioctl_count);
4079 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004080 atomic_dec(&data->ioctl_count);
4081 break;
4082 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004083 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004084 if (data->type != QSEECOM_GENERIC) {
4085 pr_err("load ext elf req: invalid client handle (%d)\n",
4086 data->type);
4087 ret = -EINVAL;
4088 break;
4089 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004090 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004091 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004092 mutex_lock(&app_access_lock);
4093 atomic_inc(&data->ioctl_count);
4094 ret = qseecom_load_external_elf(data, argp);
4095 atomic_dec(&data->ioctl_count);
4096 mutex_unlock(&app_access_lock);
4097 if (ret)
4098 pr_err("failed load_external_elf request: %d\n", ret);
4099 break;
4100 }
4101 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004102 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
4103 pr_err("unload ext elf req: invalid handle (%d)\n",
4104 data->type);
4105 ret = -EINVAL;
4106 break;
4107 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07004108 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07004109 mutex_lock(&app_access_lock);
4110 atomic_inc(&data->ioctl_count);
4111 ret = qseecom_unload_external_elf(data);
4112 atomic_dec(&data->ioctl_count);
4113 mutex_unlock(&app_access_lock);
4114 if (ret)
4115 pr_err("failed unload_app request: %d\n", ret);
4116 break;
4117 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004118 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004119 data->type = QSEECOM_CLIENT_APP;
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07004120 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004121 mutex_lock(&app_access_lock);
4122 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004123 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07004124 ret = qseecom_query_app_loaded(data, argp);
4125 atomic_dec(&data->ioctl_count);
4126 mutex_unlock(&app_access_lock);
4127 break;
4128 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004129 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004130 if (data->type != QSEECOM_GENERIC) {
4131 pr_err("send cmd svc req: invalid handle (%d)\n",
4132 data->type);
4133 ret = -EINVAL;
4134 break;
4135 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004136 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004137 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004138 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004139 qseecom.qsee_version);
4140 return -EINVAL;
4141 }
4142 mutex_lock(&app_access_lock);
4143 atomic_inc(&data->ioctl_count);
4144 ret = qseecom_send_service_cmd(data, argp);
4145 atomic_dec(&data->ioctl_count);
4146 mutex_unlock(&app_access_lock);
4147 break;
4148 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004149 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004150 if (!(qseecom.support_pfe || qseecom.support_fde))
4151 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004152 if (data->type != QSEECOM_GENERIC) {
4153 pr_err("create key req: invalid handle (%d)\n",
4154 data->type);
4155 ret = -EINVAL;
4156 break;
4157 }
Zhen Kong336636e2013-04-15 11:04:54 -07004158 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004159 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004160 qseecom.qsee_version);
4161 return -EINVAL;
4162 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004163 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004164 atomic_inc(&data->ioctl_count);
4165 ret = qseecom_create_key(data, argp);
4166 if (ret)
4167 pr_err("failed to create encryption key: %d\n", ret);
4168
4169 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004170 break;
4171 }
4172 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004173 if (!(qseecom.support_pfe || qseecom.support_fde))
4174 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07004175 if (data->type != QSEECOM_GENERIC) {
4176 pr_err("wipe key req: invalid handle (%d)\n",
4177 data->type);
4178 ret = -EINVAL;
4179 break;
4180 }
Zhen Kong336636e2013-04-15 11:04:54 -07004181 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07004182 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07004183 qseecom.qsee_version);
4184 return -EINVAL;
4185 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004186 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004187 atomic_inc(&data->ioctl_count);
4188 ret = qseecom_wipe_key(data, argp);
4189 if (ret)
4190 pr_err("failed to wipe encryption key: %d\n", ret);
4191 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08004192 break;
4193 }
4194 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07004195 if (!(qseecom.support_pfe || qseecom.support_fde))
4196 pr_err("Features requiring key init not supported\n");
Zhen Kong9730ddf2013-12-17 16:49:43 -08004197 if (data->type != QSEECOM_GENERIC) {
4198 pr_err("update key req: invalid handle (%d)\n",
4199 data->type);
4200 ret = -EINVAL;
4201 break;
4202 }
4203 if (qseecom.qsee_version < QSEE_VERSION_05) {
4204 pr_err("Update Key feature unsupported in qsee ver %u\n",
4205 qseecom.qsee_version);
4206 return -EINVAL;
4207 }
4208 data->released = true;
4209 atomic_inc(&data->ioctl_count);
4210 ret = qseecom_update_key_user_info(data, argp);
4211 if (ret)
4212 pr_err("failed to update key user info: %d\n", ret);
4213 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08004214 break;
4215 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004216 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004217 if (data->type != QSEECOM_GENERIC) {
4218 pr_err("save part hash req: invalid handle (%d)\n",
4219 data->type);
4220 ret = -EINVAL;
4221 break;
4222 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004223 data->released = true;
4224 mutex_lock(&app_access_lock);
4225 atomic_inc(&data->ioctl_count);
4226 ret = qseecom_save_partition_hash(argp);
4227 atomic_dec(&data->ioctl_count);
4228 mutex_unlock(&app_access_lock);
4229 break;
4230 }
4231 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004232 if (data->type != QSEECOM_GENERIC) {
4233 pr_err("ES activated req: invalid handle (%d)\n",
4234 data->type);
4235 ret = -EINVAL;
4236 break;
4237 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02004238 data->released = true;
4239 mutex_lock(&app_access_lock);
4240 atomic_inc(&data->ioctl_count);
4241 ret = qseecom_is_es_activated(argp);
4242 atomic_dec(&data->ioctl_count);
4243 mutex_unlock(&app_access_lock);
4244 break;
4245 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004246 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07004247 if ((data->listener.id == 0) ||
4248 (data->type != QSEECOM_LISTENER_SERVICE)) {
4249 pr_err("receive req: invalid handle (%d), lid(%d)\n",
4250 data->type, data->listener.id);
4251 ret = -EINVAL;
4252 break;
4253 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07004254 /* Only one client allowed here at a time */
4255 atomic_inc(&data->ioctl_count);
4256 ret = qseecom_send_modfd_resp(data, argp);
4257 atomic_dec(&data->ioctl_count);
4258 wake_up_all(&data->abort_wq);
4259 if (ret)
4260 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
4261 break;
4262 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004263 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07004264 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004265 return -EINVAL;
4266 }
4267 return ret;
4268}
4269
4270static int qseecom_open(struct inode *inode, struct file *file)
4271{
4272 int ret = 0;
4273 struct qseecom_dev_handle *data;
4274
4275 data = kzalloc(sizeof(*data), GFP_KERNEL);
4276 if (!data) {
4277 pr_err("kmalloc failed\n");
4278 return -ENOMEM;
4279 }
4280 file->private_data = data;
4281 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004282 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004283 data->released = false;
William Clarkc7a043d2014-05-23 15:08:52 -07004284 memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07004285 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004286 init_waitqueue_head(&data->abort_wq);
4287 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07004288
Mona Hossain2892b6b2012-02-17 13:53:11 -08004289 return ret;
4290}
4291
4292static int qseecom_release(struct inode *inode, struct file *file)
4293{
4294 struct qseecom_dev_handle *data = file->private_data;
4295 int ret = 0;
4296
4297 if (data->released == false) {
AnilKumar Chimata58eddab2015-04-17 17:17:35 +05304298 pr_debug("data: released = false, type = %d, data = 0x%x\n",
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07004299 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004300 switch (data->type) {
4301 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004302 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004303 break;
4304 case QSEECOM_CLIENT_APP:
Zhen Kong9bfacc52015-06-09 14:49:36 -07004305 mutex_lock(&app_access_lock);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004306 ret = qseecom_unload_app(data, true);
Zhen Kong9bfacc52015-06-09 14:49:36 -07004307 mutex_unlock(&app_access_lock);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004308 break;
4309 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07004310 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004311 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07004312 if (ret)
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07004313 pr_err("Ion Unmap failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004314 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05304315 case QSEECOM_UNAVAILABLE_CLIENT_APP:
4316 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004317 default:
4318 pr_err("Unsupported clnt_handle_type %d",
4319 data->type);
4320 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004321 }
4322 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08004323
Zhen Kong2edf90d2013-08-27 12:05:06 -07004324 if (qseecom.support_bus_scaling) {
4325 mutex_lock(&qsee_bw_mutex);
4326 if (data->mode != INACTIVE) {
4327 qseecom_unregister_bus_bandwidth_needs(data);
4328 if (qseecom.cumulative_mode == INACTIVE) {
4329 ret = __qseecom_set_msm_bus_request(INACTIVE);
4330 if (ret)
4331 pr_err("Fail to scale down bus\n");
4332 }
4333 }
4334 mutex_unlock(&qsee_bw_mutex);
4335 } else {
4336 if (data->fast_load_enabled == true)
4337 qsee_disable_clock_vote(data, CLK_SFPB);
4338 if (data->perf_enabled == true)
4339 qsee_disable_clock_vote(data, CLK_DFAB);
4340 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004341 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08004342
Mona Hossain2892b6b2012-02-17 13:53:11 -08004343 return ret;
4344}
4345
Mona Hossain2892b6b2012-02-17 13:53:11 -08004346static const struct file_operations qseecom_fops = {
4347 .owner = THIS_MODULE,
4348 .unlocked_ioctl = qseecom_ioctl,
4349 .open = qseecom_open,
4350 .release = qseecom_release
4351};
4352
Mona Hossainc92629e2013-04-01 13:37:46 -07004353static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004354{
4355 int rc = 0;
4356 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004357 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07004358 char *core_clk_src = NULL;
4359 char *core_clk = NULL;
4360 char *iface_clk = NULL;
4361 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004362
Mona Hossainc92629e2013-04-01 13:37:46 -07004363 switch (ce) {
4364 case CLK_QSEE: {
4365 core_clk_src = "core_clk_src";
4366 core_clk = "core_clk";
4367 iface_clk = "iface_clk";
4368 bus_clk = "bus_clk";
4369 qclk = &qseecom.qsee;
4370 qclk->instance = CLK_QSEE;
4371 break;
4372 };
4373 case CLK_CE_DRV: {
4374 core_clk_src = "ce_drv_core_clk_src";
4375 core_clk = "ce_drv_core_clk";
4376 iface_clk = "ce_drv_iface_clk";
4377 bus_clk = "ce_drv_bus_clk";
4378 qclk = &qseecom.ce_drv;
4379 qclk->instance = CLK_CE_DRV;
4380 break;
4381 };
4382 default:
4383 pr_err("Invalid ce hw instance: %d!\n", ce);
4384 return -EIO;
4385 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004386 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004387
Mona Hossainc92629e2013-04-01 13:37:46 -07004388 /* Get CE3 src core clk. */
4389 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004390 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08004391 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07004392 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004393 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07004394 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004395 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08004396 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004397 }
4398 } else {
4399 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004400 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004401 }
4402
4403 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004404 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004405 if (IS_ERR(qclk->ce_core_clk)) {
4406 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004407 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004408 if (qclk->ce_core_src_clk != NULL)
4409 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004410 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004411 }
4412
4413 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004414 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004415 if (IS_ERR(qclk->ce_clk)) {
4416 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004417 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004418 if (qclk->ce_core_src_clk != NULL)
4419 clk_put(qclk->ce_core_src_clk);
4420 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004421 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004422 }
4423
4424 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07004425 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07004426 if (IS_ERR(qclk->ce_bus_clk)) {
4427 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004428 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07004429 if (qclk->ce_core_src_clk != NULL)
4430 clk_put(qclk->ce_core_src_clk);
4431 clk_put(qclk->ce_core_clk);
4432 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08004433 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004434 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004435 return rc;
4436}
4437
Mona Hossainc92629e2013-04-01 13:37:46 -07004438static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004439{
Mona Hossain17a4faf2013-03-22 16:40:56 -07004440 struct qseecom_clk *qclk;
4441
Mona Hossainc92629e2013-04-01 13:37:46 -07004442 if (ce == CLK_QSEE)
4443 qclk = &qseecom.qsee;
4444 else
4445 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004446
4447 if (qclk->ce_clk != NULL) {
4448 clk_put(qclk->ce_clk);
4449 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004450 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004451 if (qclk->ce_core_clk != NULL) {
4452 clk_put(qclk->ce_core_clk);
4453 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004454 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004455 if (qclk->ce_bus_clk != NULL) {
4456 clk_put(qclk->ce_bus_clk);
4457 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004458 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004459 if (qclk->ce_core_src_clk != NULL) {
4460 clk_put(qclk->ce_core_src_clk);
4461 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004462 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004463}
4464
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004465static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004466{
4467 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004468 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004469 struct device *class_dev;
4470 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07004471 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004472 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
4473
Mona Hossain17a4faf2013-03-22 16:40:56 -07004474 qseecom.qsee_bw_count = 0;
4475 qseecom.qsee_perf_client = 0;
4476 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004477
Mona Hossain17a4faf2013-03-22 16:40:56 -07004478 qseecom.qsee.ce_core_clk = NULL;
4479 qseecom.qsee.ce_clk = NULL;
4480 qseecom.qsee.ce_core_src_clk = NULL;
4481 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07004482
Zhen Kong2edf90d2013-08-27 12:05:06 -07004483 qseecom.cumulative_mode = 0;
4484 qseecom.current_mode = INACTIVE;
4485 qseecom.support_bus_scaling = false;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004486 qseecom.support_fde = false;
4487 qseecom.support_pfe = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004488
Mona Hossainc92629e2013-04-01 13:37:46 -07004489 qseecom.ce_drv.ce_core_clk = NULL;
4490 qseecom.ce_drv.ce_clk = NULL;
4491 qseecom.ce_drv.ce_core_src_clk = NULL;
4492 qseecom.ce_drv.ce_bus_clk = NULL;
4493
Mona Hossain2892b6b2012-02-17 13:53:11 -08004494 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
4495 if (rc < 0) {
4496 pr_err("alloc_chrdev_region failed %d\n", rc);
4497 return rc;
4498 }
4499
4500 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
4501 if (IS_ERR(driver_class)) {
4502 rc = -ENOMEM;
4503 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304504 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004505 }
4506
4507 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
4508 QSEECOM_DEV);
4509 if (!class_dev) {
4510 pr_err("class_device_create failed %d\n", rc);
4511 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304512 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004513 }
4514
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304515 cdev_init(&qseecom.cdev, &qseecom_fops);
4516 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004517
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304518 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004519 if (rc < 0) {
4520 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304521 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004522 }
4523
4524 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
4525 spin_lock_init(&qseecom.registered_listener_list_lock);
4526 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
4527 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07004528 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
4529 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004530 init_waitqueue_head(&qseecom.send_resp_wq);
4531 qseecom.send_resp_flag = 0;
4532
4533 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
4534 &qsee_not_legacy, sizeof(qsee_not_legacy));
4535 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07004536 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304537 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004538 }
Mona Hossain05c73562012-10-29 17:49:01 -07004539 if (qsee_not_legacy) {
4540 uint32_t feature = 10;
4541
4542 qseecom.qsee_version = QSEEE_VERSION_00;
4543 rc = scm_call(6, 3, &feature, sizeof(feature),
4544 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
4545 if (rc) {
4546 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304547 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07004548 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004549 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07004550 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07004551 pr_err("QSEE legacy version is not supported:");
4552 pr_err("Support for TZ1.3 and earlier is deprecated\n");
4553 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304554 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004555 }
Mona Hossain05c73562012-10-29 17:49:01 -07004556 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004557 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004558 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07004559 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08004560 if (qseecom.ion_clnt == NULL) {
4561 pr_err("Ion client cannot be created\n");
4562 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304563 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004564 }
4565
4566 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004567 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05304568 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004569 qseecom.support_bus_scaling =
4570 of_property_read_bool((&pdev->dev)->of_node,
4571 "qcom,support-bus-scaling");
4572 pr_warn("support_bus_scaling=0x%x",
4573 qseecom.support_bus_scaling);
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004574 qseecom.support_fde =
4575 of_property_read_bool((&pdev->dev)->of_node,
4576 "qcom,support-fde");
4577 if (qseecom.support_fde) {
4578 if (of_property_read_u32((&pdev->dev)->of_node,
Mona Hossain4cf78a92013-02-14 12:06:41 -08004579 "qcom,disk-encrypt-pipe-pair",
4580 &qseecom.ce_info.disk_encrypt_pipe)) {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004581 pr_err("Fail to get FDE pipe information.\n");
4582 rc = -EINVAL;
4583 goto exit_destroy_ion_client;
4584 } else {
4585 pr_warn("disk-encrypt-pipe-pair=0x%x",
4586 qseecom.ce_info.disk_encrypt_pipe);
4587 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004588 } else {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004589 pr_warn("Device does not support FDE");
4590 qseecom.ce_info.disk_encrypt_pipe = 0xff;
4591 }
4592 qseecom.support_pfe =
4593 of_property_read_bool((&pdev->dev)->of_node,
4594 "qcom,support-pfe");
4595 if (qseecom.support_pfe) {
4596 if (of_property_read_u32((&pdev->dev)->of_node,
4597 "qcom,file-encrypt-pipe-pair",
4598 &qseecom.ce_info.disk_encrypt_pipe)) {
4599 pr_err("Fail to get PFE pipe information.\n");
4600 rc = -EINVAL;
4601 goto exit_destroy_ion_client;
4602 } else {
4603 pr_warn("file-encrypt-pipe-pair=0x%x",
4604 qseecom.ce_info.file_encrypt_pipe);
4605 }
4606 } else {
4607 pr_warn("Device does not support PFE");
4608 qseecom.ce_info.file_encrypt_pipe = 0xff;
4609 }
4610 if (qseecom.support_pfe || qseecom.support_fde) {
4611 if (of_property_read_u32((&pdev->dev)->of_node,
4612 "qcom,hlos-ce-hw-instance",
4613 &qseecom.ce_info.hlos_ce_hw_instance)) {
4614 pr_err("Fail: get hlos ce hw instanc info\n");
4615 rc = -EINVAL;
4616 goto exit_destroy_ion_client;
4617 } else {
4618 pr_warn("hlos-ce-hw-instance=0x%x",
4619 qseecom.ce_info.hlos_ce_hw_instance);
4620 }
4621 } else {
4622 pr_warn("Device does not support PFE/FDE");
4623 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004624 }
4625
4626 if (of_property_read_u32((&pdev->dev)->of_node,
4627 "qcom,qsee-ce-hw-instance",
4628 &qseecom.ce_info.qsee_ce_hw_instance)) {
4629 pr_err("Fail to get qsee ce hw instance information.\n");
Mona Hossain4cf78a92013-02-14 12:06:41 -08004630 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304631 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004632 } else {
4633 pr_warn("qsee-ce-hw-instance=0x%x",
4634 qseecom.ce_info.qsee_ce_hw_instance);
4635 }
4636
Zhen Kong56d62642015-03-10 16:29:53 -07004637 qseecom.appsbl_qseecom_support =
4638 of_property_read_bool((&pdev->dev)->of_node,
4639 "qcom,appsbl-qseecom-support");
4640 pr_info("qseecom.appsbl_qseecom_support = 0x%x",
4641 qseecom.appsbl_qseecom_support);
4642
Mona Hossainc92629e2013-04-01 13:37:46 -07004643 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
4644 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
4645
4646 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004647 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304648 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08004649
Zhen Konga10dcab2014-03-19 10:32:27 -07004650 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4651 (qseecom.support_pfe || qseecom.support_fde)) {
Mona Hossainc92629e2013-04-01 13:37:46 -07004652 ret = __qseecom_init_clk(CLK_CE_DRV);
4653 if (ret) {
4654 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304655 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07004656 }
4657 } else {
4658 struct qseecom_clk *qclk;
4659
4660 qclk = &qseecom.qsee;
4661 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
4662 qseecom.ce_drv.ce_clk = qclk->ce_clk;
4663 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
4664 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
4665 }
4666
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004667 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4668 msm_bus_cl_get_pdata(pdev);
Zhen Kong56d62642015-03-10 16:29:53 -07004669 if (qseecom.qsee_version >= (QSEE_VERSION_02) &&
4670 !qseecom.appsbl_qseecom_support) {
Mona Hossain5b76a622012-11-15 20:09:08 -08004671 struct resource *resource = NULL;
4672 struct qsee_apps_region_info_ireq req;
4673 struct qseecom_command_scm_resp resp;
4674
4675 resource = platform_get_resource_byname(pdev,
4676 IORESOURCE_MEM, "secapp-region");
4677 if (resource) {
4678 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
4679 req.addr = resource->start;
4680 req.size = resource_size(resource);
4681 pr_warn("secure app region addr=0x%x size=0x%x",
4682 req.addr, req.size);
4683 } else {
4684 pr_err("Fail to get secure app region info\n");
4685 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304686 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004687 }
4688 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
4689 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07004690 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
4691 pr_err("send secapp reg fail %d resp.res %d\n",
4692 rc, resp.result);
4693 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304694 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004695 }
4696 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004697 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004698 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4699 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004700 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004701 if (qseecom.support_bus_scaling) {
4702 init_timer(&(qseecom.bw_scale_down_timer));
4703 INIT_WORK(&qseecom.bw_inactive_req_ws,
4704 qseecom_bw_inactive_req_work);
4705 qseecom.bw_scale_down_timer.function =
4706 qseecom_scale_bus_bandwidth_timer_callback;
4707 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004708 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004709 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004710 qseecom_platform_support);
4711
Mona Hossain17a4faf2013-03-22 16:40:56 -07004712 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004713 pr_err("Unable to register bus client\n");
4714 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304715
4716exit_destroy_ion_client:
4717 ion_client_destroy(qseecom.ion_clnt);
4718exit_del_cdev:
4719 cdev_del(&qseecom.cdev);
4720exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004721 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304722exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004723 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304724exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004725 unregister_chrdev_region(qseecom_device_no, 1);
4726 return rc;
4727}
4728
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004729static int __devinit qseecom_remove(struct platform_device *pdev)
4730{
Mona Hossaind44a3842012-10-15 09:41:35 -07004731 struct qseecom_registered_kclient_list *kclient = NULL;
Monika Singh3d486ed2018-04-24 09:54:50 +05304732 struct qseecom_registered_kclient_list *kclient_tmp = NULL;
Mona Hossaind44a3842012-10-15 09:41:35 -07004733 unsigned long flags = 0;
4734 int ret = 0;
4735
Mona Hossaind44a3842012-10-15 09:41:35 -07004736 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304737
Monika Singh3d486ed2018-04-24 09:54:50 +05304738 list_for_each_entry_safe(kclient, kclient_tmp,
4739 &qseecom.registered_kclient_list_head, list) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004740
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304741 /* Break the loop if client handle is NULL */
4742 if (!kclient->handle)
4743 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004744
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304745 if (list_empty(&kclient->list))
4746 goto exit_free_kc_handle;
4747
4748 list_del(&kclient->list);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004749 ret = qseecom_unload_app(kclient->handle->dev, false);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304750 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004751 kzfree(kclient->handle->dev);
4752 kzfree(kclient->handle);
4753 kzfree(kclient);
4754 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004755 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304756
4757exit_free_kc_handle:
4758 kzfree(kclient->handle);
4759exit_free_kclient:
4760 kzfree(kclient);
Monika Singh3d486ed2018-04-24 09:54:50 +05304761
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304762 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4763
4764 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004765 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004766
Mona Hossain17a4faf2013-03-22 16:40:56 -07004767 if (qseecom.qsee_perf_client)
4768 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4769 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304770 if (pdev->dev.platform_data != NULL)
4771 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4772
Zhen Kong2edf90d2013-08-27 12:05:06 -07004773 if (qseecom.support_bus_scaling) {
4774 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4775 del_timer_sync(&qseecom.bw_scale_down_timer);
4776 }
4777
Mona Hossaind39e33b2012-11-05 13:36:40 -08004778 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004779 if (pdev->dev.of_node) {
4780 __qseecom_deinit_clk(CLK_QSEE);
Zhen Konga10dcab2014-03-19 10:32:27 -07004781 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4782 (qseecom.support_pfe || qseecom.support_fde))
Mona Hossainc92629e2013-04-01 13:37:46 -07004783 __qseecom_deinit_clk(CLK_CE_DRV);
4784 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304785
4786 ion_client_destroy(qseecom.ion_clnt);
4787
4788 cdev_del(&qseecom.cdev);
4789
4790 device_destroy(driver_class, qseecom_device_no);
4791
4792 class_destroy(driver_class);
4793
4794 unregister_chrdev_region(qseecom_device_no, 1);
4795
Mona Hossaind44a3842012-10-15 09:41:35 -07004796 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304797}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004798
Zhen Konga0944b82013-11-06 17:02:00 -08004799static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4800{
4801 int ret = 0;
4802 struct qseecom_clk *qclk;
4803 qclk = &qseecom.qsee;
4804
Zhen Konge5b434e2014-04-17 16:47:06 -07004805 mutex_lock(&qsee_bw_mutex);
4806 mutex_lock(&clk_access_lock);
4807
Zhen Kong60f4f702014-10-15 17:57:17 -07004808 if (qseecom.current_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004809 ret = msm_bus_scale_client_update_request(
4810 qseecom.qsee_perf_client, INACTIVE);
Zhen Konga0944b82013-11-06 17:02:00 -08004811 if (ret)
4812 pr_err("Fail to scale down bus\n");
Zhen Konge5b434e2014-04-17 16:47:06 -07004813 else
4814 qseecom.current_mode = INACTIVE;
Zhen Konga0944b82013-11-06 17:02:00 -08004815 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004816
Zhen Konga0944b82013-11-06 17:02:00 -08004817 if (qclk->clk_access_cnt) {
4818 if (qclk->ce_clk != NULL)
4819 clk_disable_unprepare(qclk->ce_clk);
4820 if (qclk->ce_core_clk != NULL)
4821 clk_disable_unprepare(qclk->ce_core_clk);
4822 if (qclk->ce_bus_clk != NULL)
4823 clk_disable_unprepare(qclk->ce_bus_clk);
4824 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004825
4826 del_timer_sync(&(qseecom.bw_scale_down_timer));
4827 qseecom.timer_running = false;
4828
Zhen Konga0944b82013-11-06 17:02:00 -08004829 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004830 mutex_unlock(&qsee_bw_mutex);
4831
Zhen Konga0944b82013-11-06 17:02:00 -08004832 return 0;
4833}
4834
4835static int qseecom_resume(struct platform_device *pdev)
4836{
4837 int mode = 0;
4838 int ret = 0;
4839 struct qseecom_clk *qclk;
4840 qclk = &qseecom.qsee;
4841
Zhen Konge5b434e2014-04-17 16:47:06 -07004842 mutex_lock(&qsee_bw_mutex);
4843 mutex_lock(&clk_access_lock);
Zhen Konga0944b82013-11-06 17:02:00 -08004844 if (qseecom.cumulative_mode >= HIGH)
4845 mode = HIGH;
4846 else
4847 mode = qseecom.cumulative_mode;
4848
4849 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004850 ret = msm_bus_scale_client_update_request(
Zhen Kong98b0e512014-04-04 10:12:24 -07004851 qseecom.qsee_perf_client, mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004852 if (ret)
Zhen Kong98b0e512014-04-04 10:12:24 -07004853 pr_err("Fail to scale up bus to %d\n", mode);
Zhen Konge5b434e2014-04-17 16:47:06 -07004854 else
4855 qseecom.current_mode = mode;
Zhen Konga0944b82013-11-06 17:02:00 -08004856 }
4857
Zhen Konga0944b82013-11-06 17:02:00 -08004858 if (qclk->clk_access_cnt) {
4859
4860 ret = clk_prepare_enable(qclk->ce_core_clk);
4861 if (ret) {
4862 pr_err("Unable to enable/prepare CE core clk\n");
4863 qclk->clk_access_cnt = 0;
4864 goto err;
4865 }
4866
4867 ret = clk_prepare_enable(qclk->ce_clk);
4868 if (ret) {
4869 pr_err("Unable to enable/prepare CE iface clk\n");
4870 qclk->clk_access_cnt = 0;
4871 goto ce_clk_err;
4872 }
4873
4874 ret = clk_prepare_enable(qclk->ce_bus_clk);
4875 if (ret) {
4876 pr_err("Unable to enable/prepare CE bus clk\n");
4877 qclk->clk_access_cnt = 0;
4878 goto ce_bus_clk_err;
4879 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004880 }
4881
4882 if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004883 qseecom.bw_scale_down_timer.expires = jiffies +
4884 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge5b434e2014-04-17 16:47:06 -07004885 mod_timer(&(qseecom.bw_scale_down_timer),
4886 qseecom.bw_scale_down_timer.expires);
Zhen Kongca4c2d52014-03-12 13:22:46 -07004887 qseecom.timer_running = true;
Zhen Konga0944b82013-11-06 17:02:00 -08004888 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004889
Zhen Konga0944b82013-11-06 17:02:00 -08004890 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004891 mutex_unlock(&qsee_bw_mutex);
4892
4893
Zhen Konga0944b82013-11-06 17:02:00 -08004894 return 0;
4895
4896ce_bus_clk_err:
4897 clk_disable_unprepare(qclk->ce_clk);
4898ce_clk_err:
4899 clk_disable_unprepare(qclk->ce_core_clk);
4900err:
4901 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004902 mutex_unlock(&qsee_bw_mutex);
Zhen Konga0944b82013-11-06 17:02:00 -08004903 return -EIO;
4904}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004905static struct of_device_id qseecom_match[] = {
4906 {
4907 .compatible = "qcom,qseecom",
4908 },
4909 {}
4910};
4911
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004912static struct platform_driver qseecom_plat_driver = {
4913 .probe = qseecom_probe,
4914 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004915 .suspend = qseecom_suspend,
4916 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004917 .driver = {
4918 .name = "qseecom",
4919 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004920 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004921 },
4922};
4923
4924static int __devinit qseecom_init(void)
4925{
4926 return platform_driver_register(&qseecom_plat_driver);
4927}
4928
4929static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004930{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304931 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004932}
4933
4934MODULE_LICENSE("GPL v2");
4935MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4936
4937module_init(qseecom_init);
4938module_exit(qseecom_exit);