blob: f9e4477d5078a5e4f933c698bc9363f395610a8c [file] [log] [blame]
Mona Hossaind44a3842012-10-15 09:41:35 -07001/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
Mona Hossain2892b6b2012-02-17 13:53:11 -08002 *
Zhen Kongca39e442013-12-25 22:57:08 -08003 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Mona Hossain2892b6b2012-02-17 13:53:11 -08004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/platform_device.h>
22#include <linux/debugfs.h>
23#include <linux/cdev.h>
24#include <linux/uaccess.h>
25#include <linux/sched.h>
26#include <linux/list.h>
27#include <linux/mutex.h>
28#include <linux/io.h>
Mitchel Humpherys4f8be2e2012-09-06 10:41:41 -070029#include <linux/msm_ion.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080030#include <linux/types.h>
31#include <linux/clk.h>
32#include <linux/qseecom.h>
Mona Hossaind44a3842012-10-15 09:41:35 -070033#include <linux/elf.h>
34#include <linux/firmware.h>
Mona Hossainacea1022012-04-09 13:37:27 -070035#include <linux/freezer.h>
Mona Hossainf1f2ed62012-11-15 19:51:33 -080036#include <linux/scatterlist.h>
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070037#include <mach/board.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080038#include <mach/msm_bus.h>
39#include <mach/msm_bus_board.h>
40#include <mach/scm.h>
Stephen Boyd77db8bb2012-06-27 15:15:16 -070041#include <mach/subsystem_restart.h>
Ramesh Masavarapuff377032012-09-14 12:11:32 -070042#include <mach/socinfo.h>
Mona Hossain803c3d92012-11-21 13:33:42 -080043#include <mach/qseecomi.h>
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -070044#include <asm/cacheflush.h>
Mona Hossain2892b6b2012-02-17 13:53:11 -080045#include "qseecom_legacy.h"
Mona Hossaind44a3842012-10-15 09:41:35 -070046#include "qseecom_kernel.h"
Mona Hossain2892b6b2012-02-17 13:53:11 -080047
48#define QSEECOM_DEV "qseecom"
Mona Hossain2892b6b2012-02-17 13:53:11 -080049#define QSEOS_VERSION_14 0x14
Mona Hossain05c73562012-10-29 17:49:01 -070050#define QSEEE_VERSION_00 0x400000
Mona Hossain5b76a622012-11-15 20:09:08 -080051#define QSEE_VERSION_01 0x401000
52#define QSEE_VERSION_02 0x402000
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080053#define QSEE_VERSION_03 0x403000
Amir Samuelovd1fc7412013-03-10 16:56:13 +020054#define QSEE_VERSION_04 0x404000
Zhen Kong336636e2013-04-15 11:04:54 -070055#define QSEE_VERSION_05 0x405000
56
Mona Hossain5b76a622012-11-15 20:09:08 -080057
Mona Hossain05c73562012-10-29 17:49:01 -070058
59#define QSEOS_CHECK_VERSION_CMD 0x00001803
Mona Hossain2892b6b2012-02-17 13:53:11 -080060
Mona Hossaind39e33b2012-11-05 13:36:40 -080061#define QSEE_CE_CLK_100MHZ 100000000
Mona Hossaind39e33b2012-11-05 13:36:40 -080062
Mona Hossain13dd8922013-01-03 06:11:09 -080063#define QSEECOM_MAX_SG_ENTRY 512
Zhen Kongba69dfe2014-02-28 15:19:53 -080064#define QSEECOM_INVALID_KEY_ID 0xff
Mona Hossainf1f2ed62012-11-15 19:51:33 -080065
Amir Samuelovd1fc7412013-03-10 16:56:13 +020066/* Save partition image hash for authentication check */
67#define SCM_SAVE_PARTITION_HASH_ID 0x01
68
69/* Check if enterprise security is activate */
70#define SCM_IS_ACTIVATED_ID 0x02
71
Zhen Kong7812dc12013-07-09 17:12:55 -070072#define RPMB_SERVICE 0x2000
73
Zhen Kong2edf90d2013-08-27 12:05:06 -070074#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
75#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
76
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070077enum qseecom_clk_definitions {
78 CLK_DFAB = 0,
79 CLK_SFPB,
80};
81
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080082enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053083 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080084 QSEECOM_LISTENER_SERVICE,
85 QSEECOM_SECURE_SERVICE,
86 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053087 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080088};
89
Mona Hossainc92629e2013-04-01 13:37:46 -070090enum qseecom_ce_hw_instance {
91 CLK_QSEE = 0,
92 CLK_CE_DRV,
93};
94
Mona Hossain2892b6b2012-02-17 13:53:11 -080095static struct class *driver_class;
96static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -080097
Mona Hossain2892b6b2012-02-17 13:53:11 -080098static DEFINE_MUTEX(qsee_bw_mutex);
99static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -0700100static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800101
Mona Hossain2892b6b2012-02-17 13:53:11 -0800102struct qseecom_registered_listener_list {
103 struct list_head list;
104 struct qseecom_register_listener_req svc;
Zhen Kongf4948192013-11-25 13:05:35 -0800105 uint32_t user_virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800106 u8 *sb_virt;
107 s32 sb_phys;
108 size_t sb_length;
109 struct ion_handle *ihandle; /* Retrieve phy addr */
110
111 wait_queue_head_t rcv_req_wq;
112 int rcv_req_flag;
113};
114
115struct qseecom_registered_app_list {
116 struct list_head list;
117 u32 app_id;
118 u32 ref_cnt;
119};
120
Mona Hossaind44a3842012-10-15 09:41:35 -0700121struct qseecom_registered_kclient_list {
122 struct list_head list;
123 struct qseecom_handle *handle;
124};
125
Mona Hossain4cf78a92013-02-14 12:06:41 -0800126struct ce_hw_usage_info {
127 uint32_t qsee_ce_hw_instance;
128 uint32_t hlos_ce_hw_instance;
129 uint32_t disk_encrypt_pipe;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800130 uint32_t file_encrypt_pipe;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800131};
132
Mona Hossain17a4faf2013-03-22 16:40:56 -0700133struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700134 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700135 struct clk *ce_core_clk;
136 struct clk *ce_clk;
137 struct clk *ce_core_src_clk;
138 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700139 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700140};
141
Mona Hossain2892b6b2012-02-17 13:53:11 -0800142struct qseecom_control {
143 struct ion_client *ion_clnt; /* Ion client */
144 struct list_head registered_listener_list_head;
145 spinlock_t registered_listener_list_lock;
146
147 struct list_head registered_app_list_head;
148 spinlock_t registered_app_list_lock;
149
Mona Hossaind44a3842012-10-15 09:41:35 -0700150 struct list_head registered_kclient_list_head;
151 spinlock_t registered_kclient_list_lock;
152
Mona Hossain2892b6b2012-02-17 13:53:11 -0800153 wait_queue_head_t send_resp_wq;
154 int send_resp_flag;
155
156 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700157 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700158 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700159 bool commonlib_loaded;
Zhen Kongc46b5842013-12-12 13:09:16 +0530160 struct ion_handle *cmnlib_ion_handle;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800161 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700162
163 int qsee_bw_count;
164 int qsee_sfpb_bw_count;
165
166 uint32_t qsee_perf_client;
167 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700168 struct qseecom_clk ce_drv;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700169
170 bool support_bus_scaling;
Zhen Kong4ffeacf2014-02-27 17:21:08 -0800171 bool support_fde;
172 bool support_pfe;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700173 uint32_t cumulative_mode;
174 enum qseecom_bandwidth_request_mode current_mode;
175 struct timer_list bw_scale_down_timer;
176 struct work_struct bw_inactive_req_ws;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800177 struct cdev cdev;
178 bool timer_running;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800179};
180
181struct qseecom_client_handle {
182 u32 app_id;
183 u8 *sb_virt;
184 s32 sb_phys;
185 uint32_t user_virt_sb_base;
186 size_t sb_length;
187 struct ion_handle *ihandle; /* Retrieve phy addr */
188};
189
190struct qseecom_listener_handle {
191 u32 id;
192};
193
194static struct qseecom_control qseecom;
195
196struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800197 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800198 union {
199 struct qseecom_client_handle client;
200 struct qseecom_listener_handle listener;
201 };
202 bool released;
203 int abort;
204 wait_queue_head_t abort_wq;
205 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700206 bool perf_enabled;
207 bool fast_load_enabled;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700208 enum qseecom_bandwidth_request_mode mode;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800209};
210
Mona Hossain4cf78a92013-02-14 12:06:41 -0800211enum qseecom_set_clear_key_flag {
212 QSEECOM_CLEAR_CE_KEY_CMD = 0,
213 QSEECOM_SET_CE_KEY_CMD,
214};
215
216struct qseecom_set_key_parameter {
217 uint32_t ce_hw;
218 uint32_t pipe;
219 uint32_t flags;
220 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
221 unsigned char hash32[QSEECOM_HASH_SIZE];
222 enum qseecom_set_clear_key_flag set_clear_key_flag;
223};
224
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800225struct qseecom_sg_entry {
226 uint32_t phys_addr;
227 uint32_t len;
228};
229
Zhen Kongba69dfe2014-02-28 15:19:53 -0800230struct qseecom_key_id_usage_desc {
231 uint8_t desc[QSEECOM_KEY_ID_SIZE];
232};
233
234static struct qseecom_key_id_usage_desc key_id_array[] = {
235 {
236 .desc = "Undefined Usage Index",
237 },
238
239 {
240 .desc = "Full Disk Encryption",
241 },
242
243 {
244 .desc = "Per File Encryption",
245 },
Zhen Kong9730ddf2013-12-17 16:49:43 -0800246};
247
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700248/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800249static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
250static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700251static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
252static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700253
Mona Hossain2892b6b2012-02-17 13:53:11 -0800254static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800255 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800256{
257 struct qseecom_registered_listener_list *ptr;
258 int unique = 1;
259 unsigned long flags;
260
261 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
262 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800263 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800264 pr_err("Service id: %u is already registered\n",
265 ptr->svc.listener_id);
266 unique = 0;
267 break;
268 }
269 }
270 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
271 return unique;
272}
273
274static struct qseecom_registered_listener_list *__qseecom_find_svc(
275 int32_t listener_id)
276{
277 struct qseecom_registered_listener_list *entry = NULL;
278 unsigned long flags;
279
280 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
281 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
282 {
283 if (entry->svc.listener_id == listener_id)
284 break;
285 }
286 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530287
288 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
289 pr_err("Service id: %u is not found\n", listener_id);
290 return NULL;
291 }
292
Mona Hossain2892b6b2012-02-17 13:53:11 -0800293 return entry;
294}
295
296static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
297 struct qseecom_dev_handle *handle,
298 struct qseecom_register_listener_req *listener)
299{
300 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800301 struct qseecom_register_listener_ireq req;
302 struct qseecom_command_scm_resp resp;
303 ion_phys_addr_t pa;
304
305 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800306 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
307 listener->ifd_data_fd);
Hariprasad Dhalinarasimha1401bc02014-02-18 13:46:37 -0800308 if (IS_ERR_OR_NULL(svc->ihandle)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800309 pr_err("Ion client could not retrieve the handle\n");
310 return -ENOMEM;
311 }
312
313 /* Get the physical address of the ION BUF */
314 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
Zhen Kong05ed4462014-01-28 18:21:30 -0800315 if (ret) {
316 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
317 ret);
318 return ret;
319 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800320 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700321 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800322 svc->sb_phys = pa;
323
Mona Hossaind4613de2013-05-15 16:49:29 -0700324 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
325 req.listener_id = svc->svc.listener_id;
326 req.sb_len = svc->sb_length;
327 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800328
Mona Hossaind4613de2013-05-15 16:49:29 -0700329 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800330
Mona Hossaind4613de2013-05-15 16:49:29 -0700331 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800332 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700333 if (ret) {
334 pr_err("qseecom_scm_call failed with err: %d\n", ret);
335 return -EINVAL;
336 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800337
Mona Hossaind4613de2013-05-15 16:49:29 -0700338 if (resp.result != QSEOS_RESULT_SUCCESS) {
339 pr_err("Error SB registration req: resp.result = %d\n",
340 resp.result);
341 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800342 }
343 return 0;
344}
345
346static int qseecom_register_listener(struct qseecom_dev_handle *data,
347 void __user *argp)
348{
349 int ret = 0;
350 unsigned long flags;
351 struct qseecom_register_listener_req rcvd_lstnr;
352 struct qseecom_registered_listener_list *new_entry;
353
354 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
355 if (ret) {
356 pr_err("copy_from_user failed\n");
357 return ret;
358 }
Zhen Kongf4948192013-11-25 13:05:35 -0800359 if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
360 rcvd_lstnr.sb_size))
361 return -EFAULT;
362
Mona Hossain0af10ab2012-02-28 18:26:41 -0800363 data->listener.id = 0;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800364 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800365 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800366 data->released = true;
367 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800368 }
369
370 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
371 if (!new_entry) {
372 pr_err("kmalloc failed\n");
373 return -ENOMEM;
374 }
375 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
376 new_entry->rcv_req_flag = 0;
377
378 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
379 new_entry->sb_length = rcvd_lstnr.sb_size;
Zhen Kongf4948192013-11-25 13:05:35 -0800380 new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800381 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
382 pr_err("qseecom_set_sb_memoryfailed\n");
383 kzfree(new_entry);
384 return -ENOMEM;
385 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800386
Mona Hossain2892b6b2012-02-17 13:53:11 -0800387 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800388 init_waitqueue_head(&new_entry->rcv_req_wq);
389
390 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
391 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
392 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800393
Mona Hossain2892b6b2012-02-17 13:53:11 -0800394 return ret;
395}
396
397static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
398{
399 int ret = 0;
400 unsigned long flags;
401 uint32_t unmap_mem = 0;
402 struct qseecom_register_listener_ireq req;
403 struct qseecom_registered_listener_list *ptr_svc = NULL;
404 struct qseecom_command_scm_resp resp;
405 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
406
Mona Hossaind4613de2013-05-15 16:49:29 -0700407 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
408 req.listener_id = data->listener.id;
409 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800410
Mona Hossaind4613de2013-05-15 16:49:29 -0700411 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800412 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700413 if (ret) {
414 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
415 ret, data->listener.id);
416 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800417 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700418
419 if (resp.result != QSEOS_RESULT_SUCCESS) {
420 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
421 resp.result, data->listener.id);
422 return -EPERM;
423 }
424
Mona Hossain2892b6b2012-02-17 13:53:11 -0800425 data->abort = 1;
426 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
427 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
428 list) {
429 if (ptr_svc->svc.listener_id == data->listener.id) {
430 wake_up_all(&ptr_svc->rcv_req_wq);
431 break;
432 }
433 }
434 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
435
436 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700437 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800438 atomic_read(&data->ioctl_count) <= 1)) {
439 pr_err("Interrupted from abort\n");
440 ret = -ERESTARTSYS;
441 break;
442 }
443 }
444
445 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
446 list_for_each_entry(ptr_svc,
447 &qseecom.registered_listener_list_head,
448 list)
449 {
450 if (ptr_svc->svc.listener_id == data->listener.id) {
451 if (ptr_svc->sb_virt) {
452 unmap_mem = 1;
453 ihandle = ptr_svc->ihandle;
454 }
455 list_del(&ptr_svc->list);
456 kzfree(ptr_svc);
457 break;
458 }
459 }
460 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
461
462 /* Unmap the memory */
463 if (unmap_mem) {
464 if (!IS_ERR_OR_NULL(ihandle)) {
465 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
466 ion_free(qseecom.ion_clnt, ihandle);
467 }
468 }
469 data->released = true;
470 return ret;
471}
472
Zhen Kong2edf90d2013-08-27 12:05:06 -0700473static int __qseecom_set_msm_bus_request(uint32_t mode)
474{
475 int ret = 0;
476 struct qseecom_clk *qclk;
477
478 qclk = &qseecom.qsee;
479 if (qclk->ce_core_src_clk != NULL) {
480 if (mode == INACTIVE) {
481 __qseecom_disable_clk(CLK_QSEE);
482 } else {
483 ret = __qseecom_enable_clk(CLK_QSEE);
484 if (ret)
485 pr_err("CLK enabling failed (%d) MODE (%d)\n",
486 ret, mode);
487 }
488 }
489
490 if ((!ret) && (qseecom.current_mode != mode)) {
491 ret = msm_bus_scale_client_update_request(
492 qseecom.qsee_perf_client, mode);
493 if (ret) {
494 pr_err("Bandwidth req failed(%d) MODE (%d)\n",
495 ret, mode);
496 if (qclk->ce_core_src_clk != NULL) {
497 if (mode == INACTIVE)
498 __qseecom_enable_clk(CLK_QSEE);
499 else
500 __qseecom_disable_clk(CLK_QSEE);
501 }
502 }
503 qseecom.current_mode = mode;
504 }
505 return ret;
506}
507
508static void qseecom_bw_inactive_req_work(struct work_struct *work)
509{
510 mutex_lock(&app_access_lock);
511 mutex_lock(&qsee_bw_mutex);
512 __qseecom_set_msm_bus_request(INACTIVE);
513 pr_debug("current_mode = %d, cumulative_mode = %d\n",
514 qseecom.current_mode, qseecom.cumulative_mode);
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800515 qseecom.timer_running = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700516 mutex_unlock(&qsee_bw_mutex);
517 mutex_unlock(&app_access_lock);
518 return;
519}
520
521static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
522{
523 schedule_work(&qseecom.bw_inactive_req_ws);
524 return;
525}
526
Zhen Kongca4c2d52014-03-12 13:22:46 -0700527static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800528{
529 struct qseecom_clk *qclk;
Zhen Kongca4c2d52014-03-12 13:22:46 -0700530 int ret = 0;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800531 mutex_lock(&clk_access_lock);
532 if (ce == CLK_QSEE)
533 qclk = &qseecom.qsee;
534 else
535 qclk = &qseecom.ce_drv;
536
Zhen Kongca4c2d52014-03-12 13:22:46 -0700537 if (qclk->clk_access_cnt > 2) {
538 pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
539 ret = -EINVAL;
540 goto err_dec_ref_cnt;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800541 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700542 if (qclk->clk_access_cnt == 2)
543 qclk->clk_access_cnt--;
544
545err_dec_ref_cnt:
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800546 mutex_unlock(&clk_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -0700547 return ret;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800548}
549
550
Zhen Kongaf950192014-02-05 17:36:23 -0800551static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700552{
553 int32_t ret = 0;
554 int32_t request_mode = INACTIVE;
555
556 mutex_lock(&qsee_bw_mutex);
557 if (mode == 0) {
558 if (qseecom.cumulative_mode > MEDIUM)
559 request_mode = HIGH;
560 else
561 request_mode = qseecom.cumulative_mode;
562 } else {
563 request_mode = mode;
564 }
Zhen Kong2edf90d2013-08-27 12:05:06 -0700565
Zhen Kongca4c2d52014-03-12 13:22:46 -0700566 ret = __qseecom_set_msm_bus_request(request_mode);
567 if (ret) {
568 pr_err("set msm bus request failed (%d),request_mode (%d)\n",
569 ret, request_mode);
570 goto err_scale_timer;
Zhen Kongea5d4bb2014-02-18 14:59:53 -0800571 }
Zhen Kongca4c2d52014-03-12 13:22:46 -0700572
573 if (qseecom.timer_running) {
574 ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
575 if (ret) {
576 pr_err("Failed to decrease clk ref count.\n");
577 goto err_scale_timer;
578 }
579 del_timer_sync(&(qseecom.bw_scale_down_timer));
580 qseecom.timer_running = false;
581 }
582err_scale_timer:
Zhen Kong2edf90d2013-08-27 12:05:06 -0700583 mutex_unlock(&qsee_bw_mutex);
584 return ret;
585}
586
587
588static int qseecom_unregister_bus_bandwidth_needs(
589 struct qseecom_dev_handle *data)
590{
591 int32_t ret = 0;
592
593 qseecom.cumulative_mode -= data->mode;
594 data->mode = INACTIVE;
595
596 return ret;
597}
598
599static int __qseecom_register_bus_bandwidth_needs(
600 struct qseecom_dev_handle *data, uint32_t request_mode)
601{
602 int32_t ret = 0;
603
604 if (data->mode == INACTIVE) {
605 qseecom.cumulative_mode += request_mode;
606 data->mode = request_mode;
607 } else {
608 if (data->mode != request_mode) {
609 qseecom.cumulative_mode -= data->mode;
610 qseecom.cumulative_mode += request_mode;
611 data->mode = request_mode;
612 }
613 }
614 return ret;
615}
616
617static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
618 void __user *argp)
619{
620 int32_t ret = 0;
621 int32_t req_mode;
622
623 ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
624 if (ret) {
625 pr_err("copy_from_user failed\n");
626 return ret;
627 }
628 if (req_mode > HIGH) {
629 pr_err("Invalid bandwidth mode (%d)\n", req_mode);
630 return ret;
631 }
632 mutex_lock(&qsee_bw_mutex);
633 ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
634 mutex_unlock(&qsee_bw_mutex);
635
636 return ret;
637}
638
Zhen Kongaf950192014-02-05 17:36:23 -0800639static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
640{
641 mutex_lock(&qsee_bw_mutex);
642 qseecom.bw_scale_down_timer.expires = jiffies +
643 msecs_to_jiffies(duration);
644 add_timer(&(qseecom.bw_scale_down_timer));
645 qseecom.timer_running = true;
646 mutex_unlock(&qsee_bw_mutex);
647}
648
Zhen Kong2edf90d2013-08-27 12:05:06 -0700649static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
650{
651 if (!qseecom.support_bus_scaling)
652 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -0800653 else
654 __qseecom_add_bw_scale_down_timer(
655 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700656 return;
657}
658
659static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
660{
661 int ret = 0;
662 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -0700663 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
664 if (ret)
665 pr_err("Failed to set bw MEDIUM.\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700666 } else {
667 ret = qsee_vote_for_clock(data, CLK_SFPB);
668 if (ret)
669 pr_err("Fail vote for clk SFPB ret %d\n", ret);
670 }
671 return ret;
672}
673
Mona Hossain2892b6b2012-02-17 13:53:11 -0800674static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
675 void __user *argp)
676{
677 ion_phys_addr_t pa;
678 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800679 struct qseecom_set_sb_mem_param_req req;
680 uint32_t len;
681
682 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700683 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800684 return -EFAULT;
685
Mona Hossaina1124de2013-10-01 13:41:09 -0700686 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
687 (req.sb_len == 0)) {
688 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
689 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
690 return -EFAULT;
691 }
Zhen Kongf4948192013-11-25 13:05:35 -0800692 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
693 req.sb_len))
694 return -EFAULT;
695
Mona Hossain2892b6b2012-02-17 13:53:11 -0800696 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800697 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
698 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800699 if (IS_ERR_OR_NULL(data->client.ihandle)) {
700 pr_err("Ion client could not retrieve the handle\n");
701 return -ENOMEM;
702 }
703 /* Get the physical address of the ION BUF */
704 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800705 if (ret) {
706
707 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
708 ret);
709 return ret;
710 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800711 /* Populate the structure for sending scm call to load image */
712 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700713 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800714 data->client.sb_phys = pa;
715 data->client.sb_length = req.sb_len;
716 data->client.user_virt_sb_base = req.virt_sb_base;
717 return 0;
718}
719
Mona Hossain2892b6b2012-02-17 13:53:11 -0800720static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
721{
722 int ret;
723 ret = (qseecom.send_resp_flag != 0);
724 return ret || data->abort;
725}
726
727static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
728 struct qseecom_command_scm_resp *resp)
729{
730 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800731 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800732 uint32_t lstnr;
733 unsigned long flags;
734 struct qseecom_client_listener_data_irsp send_data_rsp;
735 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700736 sigset_t new_sigset;
737 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800738
Mona Hossain2892b6b2012-02-17 13:53:11 -0800739 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
740 lstnr = resp->data;
741 /*
742 * Wake up blocking lsitener service with the lstnr id
743 */
744 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
745 flags);
746 list_for_each_entry(ptr_svc,
747 &qseecom.registered_listener_list_head, list) {
748 if (ptr_svc->svc.listener_id == lstnr) {
749 ptr_svc->rcv_req_flag = 1;
750 wake_up_interruptible(&ptr_svc->rcv_req_wq);
751 break;
752 }
753 }
754 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
755 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700756
757 if (ptr_svc == NULL) {
758 pr_err("Listener Svc %d does not exist\n", lstnr);
759 return -EINVAL;
760 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800761 if (ptr_svc->svc.listener_id != lstnr) {
762 pr_warning("Service requested for does on exist\n");
763 return -ERESTARTSYS;
764 }
765 pr_debug("waking up rcv_req_wq and "
766 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800767
Mona Hossain91da2c52013-03-29 17:28:31 -0700768 /* initialize the new signal mask with all signals*/
769 sigfillset(&new_sigset);
770 /* block all signals */
771 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
772
773 do {
774 if (!wait_event_freezable(qseecom.send_resp_wq,
775 __qseecom_listener_has_sent_rsp(data)))
776 break;
777 } while (1);
778
779 /* restore signal mask */
780 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
781 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700782 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
783 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700784 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800785 send_data_rsp.status = QSEOS_RESULT_FAILURE;
786 } else {
787 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800788 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800789
Mona Hossain2892b6b2012-02-17 13:53:11 -0800790 qseecom.send_resp_flag = 0;
791 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
792 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700793 if (ptr_svc)
794 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
795 ptr_svc->sb_virt, ptr_svc->sb_length,
796 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700797
798 if (lstnr == RPMB_SERVICE)
799 __qseecom_enable_clk(CLK_QSEE);
800
Mona Hossain2892b6b2012-02-17 13:53:11 -0800801 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
802 (const void *)&send_data_rsp,
803 sizeof(send_data_rsp), resp,
804 sizeof(*resp));
805 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700806 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800807 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700808 if (lstnr == RPMB_SERVICE)
809 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800810 return ret;
811 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800812 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
813 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
814 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
815 resp->result, data->client.app_id, lstnr);
816 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700817 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700818 if (lstnr == RPMB_SERVICE)
819 __qseecom_disable_clk(CLK_QSEE);
820
Mona Hossain2892b6b2012-02-17 13:53:11 -0800821 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800822 if (rc)
823 return rc;
824
Mona Hossain2892b6b2012-02-17 13:53:11 -0800825 return ret;
826}
827
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700828static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
829{
830 int32_t ret;
831 struct qseecom_command_scm_resp resp;
832
833 /* SCM_CALL to check if app_id for the mentioned app exists */
834 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
835 sizeof(struct qseecom_check_app_ireq),
836 &resp, sizeof(resp));
837 if (ret) {
838 pr_err("scm_call to check if app is already loaded failed\n");
839 return -EINVAL;
840 }
841
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700842 if (resp.result == QSEOS_RESULT_FAILURE) {
843 return 0;
844 } else {
845 switch (resp.resp_type) {
846 /*qsee returned listener type response */
847 case QSEOS_LISTENER_ID:
848 pr_err("resp type is of listener type instead of app");
849 return -EINVAL;
850 break;
851 case QSEOS_APP_ID:
852 return resp.data;
853 default:
854 pr_err("invalid resp type (%d) from qsee",
855 resp.resp_type);
856 return -ENODEV;
857 break;
858 }
859 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700860}
861
Mona Hossain2892b6b2012-02-17 13:53:11 -0800862static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
863{
864 struct qseecom_registered_app_list *entry = NULL;
865 unsigned long flags = 0;
866 u32 app_id = 0;
867 struct ion_handle *ihandle; /* Ion handle */
868 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700869 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800870 ion_phys_addr_t pa = 0;
871 uint32_t len;
872 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800873 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700874 struct qseecom_load_app_ireq load_req;
875
Mona Hossain2892b6b2012-02-17 13:53:11 -0800876 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700877 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800878 (void __user *)argp,
879 sizeof(struct qseecom_load_img_req))) {
880 pr_err("copy_from_user failed\n");
881 return -EFAULT;
882 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700883 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700884 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700885 if (ret)
Zhen Kong2edf90d2013-08-27 12:05:06 -0700886 return ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800887 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700888 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800889 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800890
Mona Hossain436b75f2012-11-20 17:10:40 -0800891 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530892 if (ret < 0) {
Zhen Kong2edf90d2013-08-27 12:05:06 -0700893 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800894 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530895 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800896
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530897 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800898 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700899 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800900 (char *)(req.app_name));
901 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
902 list_for_each_entry(entry,
903 &qseecom.registered_app_list_head, list){
904 if (entry->app_id == app_id) {
905 entry->ref_cnt++;
906 break;
907 }
908 }
909 spin_unlock_irqrestore(
910 &qseecom.registered_app_list_lock, flags);
911 } else {
912 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700913 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800914 /* Get the handle of the shared fd */
915 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800916 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800917 if (IS_ERR_OR_NULL(ihandle)) {
918 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700919 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800920 return -ENOMEM;
921 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800922
Mona Hossain436b75f2012-11-20 17:10:40 -0800923 /* Get the physical address of the ION BUF */
924 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800925 if (ret) {
926 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
927 ret);
928 return ret;
929 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800930
Mona Hossain436b75f2012-11-20 17:10:40 -0800931 /* Populate the structure for sending scm call to load image */
932 memcpy(load_req.app_name, load_img_req.img_name,
933 MAX_APP_NAME_SIZE);
934 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
935 load_req.mdt_len = load_img_req.mdt_len;
936 load_req.img_len = load_img_req.img_len;
937 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700938 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
939 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800940
Mona Hossain436b75f2012-11-20 17:10:40 -0800941 /* SCM_CALL to load the app and get the app_id back */
942 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700943 sizeof(struct qseecom_load_app_ireq),
944 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700945 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800946 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800947 if (!IS_ERR_OR_NULL(ihandle))
948 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700949 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800950 return -EINVAL;
951 }
952
953 if (resp.result == QSEOS_RESULT_FAILURE) {
954 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700955 if (!IS_ERR_OR_NULL(ihandle))
956 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700957 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800958 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700959 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700960
Mona Hossain436b75f2012-11-20 17:10:40 -0800961 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
962 ret = __qseecom_process_incomplete_cmd(data, &resp);
963 if (ret) {
964 pr_err("process_incomplete_cmd failed err: %d\n",
965 ret);
966 if (!IS_ERR_OR_NULL(ihandle))
967 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700968 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800969 return ret;
970 }
971 }
972
973 if (resp.result != QSEOS_RESULT_SUCCESS) {
974 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700975 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800976 if (!IS_ERR_OR_NULL(ihandle))
977 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700978 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800979 return -EFAULT;
980 }
981
982 app_id = resp.data;
983
984 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
985 if (!entry) {
986 pr_err("kmalloc failed\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700987 __qseecom_disable_clk_scale_down(data);
Mona Hossain436b75f2012-11-20 17:10:40 -0800988 return -ENOMEM;
989 }
990 entry->app_id = app_id;
991 entry->ref_cnt = 1;
992
993 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700994 if (!IS_ERR_OR_NULL(ihandle))
995 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700996
Mona Hossain436b75f2012-11-20 17:10:40 -0800997 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
998 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
999 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1000 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001001
Mona Hossain436b75f2012-11-20 17:10:40 -08001002 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -07001003 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -08001004 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001005 data->client.app_id = app_id;
1006 load_img_req.app_id = app_id;
1007 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
1008 pr_err("copy_to_user failed\n");
1009 kzfree(entry);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001010 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001011 return -EFAULT;
1012 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001013 __qseecom_disable_clk_scale_down(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001014 return 0;
1015}
1016
1017static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
1018{
1019 wake_up_all(&qseecom.send_resp_wq);
1020 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001021 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001022 atomic_read(&data->ioctl_count) <= 1)) {
1023 pr_err("Interrupted from abort\n");
1024 return -ERESTARTSYS;
1025 break;
1026 }
1027 }
1028 /* Set unload app */
1029 return 1;
1030}
1031
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001032static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
1033{
1034 int ret = 0;
1035 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
1036 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
1037 ion_free(qseecom.ion_clnt, data->client.ihandle);
1038 data->client.ihandle = NULL;
1039 }
1040 return ret;
1041}
1042
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001043static int qseecom_unload_app(struct qseecom_dev_handle *data,
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001044 bool app_crash)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001045{
1046 unsigned long flags;
1047 int ret = 0;
1048 struct qseecom_command_scm_resp resp;
1049 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -07001050 bool unload = false;
1051 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001052
Mona Hossaind4613de2013-05-15 16:49:29 -07001053 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001054 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1055 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001056 list) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001057 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -07001058 found_app = true;
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001059 if (app_crash) {
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001060 ptr_app->ref_cnt = 0;
Mona Hossain340dba82012-08-07 19:54:46 -07001061 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001062 break;
1063 } else {
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001064 if (ptr_app->ref_cnt == 1) {
1065 unload = true;
1066 break;
1067 } else {
1068 ptr_app->ref_cnt--;
1069 pr_debug("Can't unload app(%d) inuse\n",
1070 ptr_app->app_id);
1071 break;
1072 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001073 }
1074 }
1075 }
1076 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1077 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001078 if (found_app == false) {
1079 pr_err("Cannot find app with id = %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001080 data->client.app_id);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001081 return -EINVAL;
1082 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001083 }
1084
Mona Hossaind4613de2013-05-15 16:49:29 -07001085 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001086 struct qseecom_unload_app_ireq req;
1087
Mona Hossain340dba82012-08-07 19:54:46 -07001088 __qseecom_cleanup_app(data);
1089 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1090 list_del(&ptr_app->list);
1091 kzfree(ptr_app);
1092 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1093 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001094 /* Populate the structure for sending scm call to load image */
1095 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1096 req.app_id = data->client.app_id;
1097
1098 /* SCM_CALL to unload the app */
1099 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1100 sizeof(struct qseecom_unload_app_ireq),
1101 &resp, sizeof(resp));
1102 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001103 pr_err("scm_call to unload app (id = %d) failed\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001104 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001105 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001106 } else {
1107 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001108 }
1109 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1110 ret = __qseecom_process_incomplete_cmd(data, &resp);
1111 if (ret) {
1112 pr_err("process_incomplete_cmd fail err: %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001113 ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001114 return ret;
1115 }
1116 }
1117 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001118 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001119 data->released = true;
1120 return ret;
1121}
1122
1123static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1124 uint32_t virt)
1125{
1126 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1127}
1128
Zhen Kongf4948192013-11-25 13:05:35 -08001129static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1130 uint32_t virt)
1131{
1132 return (uint32_t)data->client.sb_virt +
1133 (virt - data->client.user_virt_sb_base);
1134}
1135
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001136int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1137 struct qseecom_send_svc_cmd_req *req_ptr,
1138 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1139{
1140 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001141 void *req_buf = NULL;
1142
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001143 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1144 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1145 req_ptr, send_svc_ireq_ptr);
1146 return -EINVAL;
1147 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001148
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -08001149 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
1150 pr_err("Invalid req/resp buffer, exiting\n");
1151 return -EINVAL;
1152 }
1153
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001154 /* Clients need to ensure req_buf is at base offset of shared buffer */
1155 if ((uint32_t)req_ptr->cmd_req_buf !=
1156 data_ptr->client.user_virt_sb_base) {
1157 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001158 return -EINVAL;
1159 }
1160
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001161 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1162 || ((uint32_t)req_ptr->resp_buf >=
1163 (data_ptr->client.user_virt_sb_base +
1164 data_ptr->client.sb_length))){
1165 pr_err("response buffer address not within shared bufffer\n");
1166 return -EINVAL;
1167 }
1168
1169 req_buf = data_ptr->client.sb_virt;
1170
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001171 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1172 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001173 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001174 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1175 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1176 (uint32_t)req_ptr->resp_buf));
1177 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1178
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001179 return ret;
1180}
1181
1182static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1183 void __user *argp)
1184{
1185 int ret = 0;
1186 struct qseecom_client_send_service_ireq send_svc_ireq;
1187 struct qseecom_command_scm_resp resp;
1188 struct qseecom_send_svc_cmd_req req;
1189 /*struct qseecom_command_scm_resp resp;*/
1190
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001191 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001192 (void __user *)argp,
1193 sizeof(req))) {
1194 pr_err("copy_from_user failed\n");
1195 return -EFAULT;
1196 }
1197
1198 if (req.resp_buf == NULL) {
1199 pr_err("cmd buffer or response buffer is null\n");
1200 return -EINVAL;
1201 }
1202
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001203 if (data->client.sb_virt == NULL) {
1204 pr_err("sb_virt null\n");
1205 return -EINVAL;
1206 }
1207
1208 if (data->client.user_virt_sb_base == 0) {
1209 pr_err("user_virt_sb_base is null\n");
1210 return -EINVAL;
1211 }
1212
1213 if (data->client.sb_length == 0) {
1214 pr_err("sb_length is 0\n");
1215 return -EINVAL;
1216 }
1217
Zhen Kong2edf90d2013-08-27 12:05:06 -07001218 data->type = QSEECOM_SECURE_SERVICE;
1219
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001220 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001221 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1222 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001223 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1224 &send_svc_ireq))
1225 return -EINVAL;
1226 break;
1227 default:
1228 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1229 return -EINVAL;
1230 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301231
Zhen Kong2edf90d2013-08-27 12:05:06 -07001232 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001233 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001234 if (ret) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001235 pr_err("Fail to set bw HIGH\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -07001236 return ret;
1237 }
1238 } else {
1239 ret = qsee_vote_for_clock(data, CLK_DFAB);
1240 if (ret) {
1241 pr_err("Failed to vote for DFAB clock%d\n", ret);
1242 return ret;
1243 }
1244 ret = qsee_vote_for_clock(data, CLK_SFPB);
1245 if (ret) {
1246 qsee_disable_clock_vote(data, CLK_DFAB);
1247 pr_err("Failed to vote for SFPB clock%d\n", ret);
1248 goto exit;
1249 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301250 }
1251
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001252 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1253 data->client.sb_virt, data->client.sb_length,
1254 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001255 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1256 sizeof(send_svc_ireq),
1257 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001258 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1259 data->client.sb_virt, data->client.sb_length,
1260 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001261 if (ret) {
1262 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001263 if (!qseecom.support_bus_scaling) {
1264 qsee_disable_clock_vote(data, CLK_DFAB);
1265 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -08001266 } else {
1267 __qseecom_add_bw_scale_down_timer(
1268 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001269 }
1270 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001271 }
1272
1273 switch (resp.result) {
1274 case QSEOS_RESULT_SUCCESS:
1275 break;
1276 case QSEOS_RESULT_INCOMPLETE:
1277 pr_err("qseos_result_incomplete\n");
1278 ret = __qseecom_process_incomplete_cmd(data, &resp);
1279 if (ret) {
1280 pr_err("process_incomplete_cmd fail: err: %d\n",
1281 ret);
1282 }
1283 break;
1284 case QSEOS_RESULT_FAILURE:
1285 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1286 break;
1287 default:
1288 pr_err("Response result %d not supported\n",
1289 resp.result);
1290 ret = -EINVAL;
1291 break;
1292 }
Zhen Kongaf950192014-02-05 17:36:23 -08001293 if (!qseecom.support_bus_scaling) {
1294 qsee_disable_clock_vote(data, CLK_DFAB);
1295 qsee_disable_clock_vote(data, CLK_SFPB);
1296 } else {
1297 __qseecom_add_bw_scale_down_timer(
1298 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1299 }
1300
Zhen Kong2edf90d2013-08-27 12:05:06 -07001301exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001302 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001303}
1304
Mona Hossain2892b6b2012-02-17 13:53:11 -08001305static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1306 struct qseecom_send_cmd_req *req)
1307{
1308 int ret = 0;
1309 u32 reqd_len_sb_in = 0;
1310 struct qseecom_client_send_data_ireq send_data_req;
1311 struct qseecom_command_scm_resp resp;
1312
1313 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1314 pr_err("cmd buffer or response buffer is null\n");
1315 return -EINVAL;
1316 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001317 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1318 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1319 data->client.sb_length))) {
1320 pr_err("cmd buffer address not within shared bufffer\n");
1321 return -EINVAL;
1322 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001323
Mona Hossaindddf4442013-10-01 14:08:20 -07001324
1325 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1326 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1327 data->client.sb_length))){
1328 pr_err("response buffer address not within shared bufffer\n");
1329 return -EINVAL;
1330 }
1331
1332 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001333 req->cmd_req_len > data->client.sb_length ||
1334 req->resp_len > data->client.sb_length) {
1335 pr_err("cmd buffer length or "
1336 "response buffer length not valid\n");
1337 return -EINVAL;
1338 }
1339
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001340 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1341 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1342 return -EINVAL;
1343 }
1344
Mona Hossain2892b6b2012-02-17 13:53:11 -08001345 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1346 if (reqd_len_sb_in > data->client.sb_length) {
1347 pr_debug("Not enough memory to fit cmd_buf and "
1348 "resp_buf. Required: %u, Available: %u\n",
1349 reqd_len_sb_in, data->client.sb_length);
1350 return -ENOMEM;
1351 }
1352
1353 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1354 send_data_req.app_id = data->client.app_id;
1355 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1356 (uint32_t)req->cmd_req_buf));
1357 send_data_req.req_len = req->cmd_req_len;
1358 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1359 (uint32_t)req->resp_buf));
1360 send_data_req.rsp_len = req->resp_len;
1361
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001362 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1363 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001364 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001365 ION_IOC_CLEAN_INV_CACHES);
1366
Mona Hossain2892b6b2012-02-17 13:53:11 -08001367 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1368 sizeof(send_data_req),
1369 &resp, sizeof(resp));
1370 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001371 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1372 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001373 return ret;
1374 }
1375
1376 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1377 ret = __qseecom_process_incomplete_cmd(data, &resp);
1378 if (ret) {
1379 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1380 return ret;
1381 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001382 } else {
1383 if (resp.result != QSEOS_RESULT_SUCCESS) {
1384 pr_err("Response result %d not supported\n",
1385 resp.result);
1386 ret = -EINVAL;
1387 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001388 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001389 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1390 data->client.sb_virt, data->client.sb_length,
1391 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001392 return ret;
1393}
1394
Mona Hossain2892b6b2012-02-17 13:53:11 -08001395static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1396{
1397 int ret = 0;
1398 struct qseecom_send_cmd_req req;
1399
1400 ret = copy_from_user(&req, argp, sizeof(req));
1401 if (ret) {
1402 pr_err("copy_from_user failed\n");
1403 return ret;
1404 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001405 ret = __qseecom_send_cmd(data, &req);
1406
Mona Hossain2892b6b2012-02-17 13:53:11 -08001407 if (ret)
1408 return ret;
1409
Mona Hossain2892b6b2012-02-17 13:53:11 -08001410 return ret;
1411}
1412
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001413static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1414 struct qseecom_dev_handle *data,
1415 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001416{
1417 struct ion_handle *ihandle;
1418 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001419 int ret = 0;
1420 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001421 uint32_t len = 0;
1422 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001423 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1424 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1425 struct qseecom_registered_listener_list *this_lstnr = NULL;
1426
1427 if (msg == NULL) {
1428 pr_err("Invalid address\n");
1429 return -EINVAL;
1430 }
1431 if (listener_svc) {
1432 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1433 this_lstnr = __qseecom_find_svc(data->listener.id);
1434 if (IS_ERR_OR_NULL(this_lstnr)) {
1435 pr_err("Invalid listener ID\n");
1436 return -ENOMEM;
1437 }
1438 } else {
1439 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1440 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001441
1442 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001443 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001444 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001445 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001446 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001447 if (IS_ERR_OR_NULL(ihandle)) {
1448 pr_err("Ion client can't retrieve the handle\n");
1449 return -ENOMEM;
1450 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001451 field = (char *) cmd_req->cmd_req_buf +
1452 cmd_req->ifd_data[i].cmd_buf_offset;
1453 } else if ((listener_svc) &&
1454 (lstnr_resp->ifd_data[i].fd > 0)) {
1455 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1456 lstnr_resp->ifd_data[i].fd);
1457 if (IS_ERR_OR_NULL(ihandle)) {
1458 pr_err("Ion client can't retrieve the handle\n");
1459 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001460 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001461 field = lstnr_resp->resp_buf_ptr +
1462 lstnr_resp->ifd_data[i].cmd_buf_offset;
1463 } else {
1464 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001465 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001466 /* Populate the cmd data structure with the phys_addr */
1467 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1468 if (sg_ptr == NULL) {
1469 pr_err("IOn client could not retrieve sg table\n");
1470 goto err;
1471 }
1472 if (sg_ptr->nents == 0) {
1473 pr_err("Num of scattered entries is 0\n");
1474 goto err;
1475 }
1476 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1477 pr_err("Num of scattered entries");
1478 pr_err(" (%d) is greater than max supported %d\n",
1479 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1480 goto err;
1481 }
1482 sg = sg_ptr->sgl;
1483 if (sg_ptr->nents == 1) {
1484 uint32_t *update;
1485 update = (uint32_t *) field;
1486 if (cleanup)
1487 *update = 0;
1488 else
1489 *update = (uint32_t)sg_dma_address(
1490 sg_ptr->sgl);
1491 len += (uint32_t)sg->length;
1492 } else {
1493 struct qseecom_sg_entry *update;
1494 int j = 0;
1495 update = (struct qseecom_sg_entry *) field;
1496 for (j = 0; j < sg_ptr->nents; j++) {
1497 if (cleanup) {
1498 update->phys_addr = 0;
1499 update->len = 0;
1500 } else {
1501 update->phys_addr = (uint32_t)
1502 sg_dma_address(sg);
1503 update->len = sg->length;
1504 }
1505 len += sg->length;
1506 update++;
1507 sg = sg_next(sg);
1508 }
1509 }
1510 if (cleanup)
1511 msm_ion_do_cache_op(qseecom.ion_clnt,
1512 ihandle, NULL, len,
1513 ION_IOC_INV_CACHES);
1514 else
1515 msm_ion_do_cache_op(qseecom.ion_clnt,
1516 ihandle, NULL, len,
1517 ION_IOC_CLEAN_INV_CACHES);
1518 /* Deallocate the handle */
1519 if (!IS_ERR_OR_NULL(ihandle))
1520 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001521 }
1522 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001523err:
1524 if (!IS_ERR_OR_NULL(ihandle))
1525 ion_free(qseecom.ion_clnt, ihandle);
1526 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001527}
1528
1529static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1530 void __user *argp)
1531{
1532 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001533 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001534 struct qseecom_send_modfd_cmd_req req;
1535 struct qseecom_send_cmd_req send_cmd_req;
1536
1537 ret = copy_from_user(&req, argp, sizeof(req));
1538 if (ret) {
1539 pr_err("copy_from_user failed\n");
1540 return ret;
1541 }
Zhen Kongf4948192013-11-25 13:05:35 -08001542
1543 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1544 pr_err("cmd buffer or response buffer is null\n");
1545 return -EINVAL;
1546 }
1547 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1548 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1549 data->client.sb_length))) {
1550 pr_err("cmd buffer address not within shared bufffer\n");
1551 return -EINVAL;
1552 }
1553
1554 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1555 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1556 data->client.sb_length))){
1557 pr_err("response buffer address not within shared bufffer\n");
1558 return -EINVAL;
1559 }
Zhen Konga69c16e2014-03-27 12:44:15 -07001560
1561 if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
1562 req.resp_len > data->client.sb_length) {
1563 pr_err("cmd or response buffer length not valid\n");
1564 return -EINVAL;
1565 }
1566
Mona Hossain2892b6b2012-02-17 13:53:11 -08001567 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1568 send_cmd_req.cmd_req_len = req.cmd_req_len;
1569 send_cmd_req.resp_buf = req.resp_buf;
1570 send_cmd_req.resp_len = req.resp_len;
1571
Mona Hossaindddf4442013-10-01 14:08:20 -07001572 /* validate offsets */
1573 for (i = 0; i < MAX_ION_FD; i++) {
1574 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1575 pr_err("Invalid offset %d = 0x%x\n",
1576 i, req.ifd_data[i].cmd_buf_offset);
1577 return -EINVAL;
1578 }
1579 }
Zhen Kongf4948192013-11-25 13:05:35 -08001580 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1581 (uint32_t)req.cmd_req_buf);
1582 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1583 (uint32_t)req.resp_buf);
1584
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001585 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001586 if (ret)
1587 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001588 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001589 if (ret)
1590 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001591 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001592 if (ret)
1593 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001594
Mona Hossain2892b6b2012-02-17 13:53:11 -08001595 return ret;
1596}
1597
1598static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1599 struct qseecom_registered_listener_list *svc)
1600{
1601 int ret;
1602 ret = (svc->rcv_req_flag != 0);
1603 return ret || data->abort;
1604}
1605
1606static int qseecom_receive_req(struct qseecom_dev_handle *data)
1607{
1608 int ret = 0;
1609 struct qseecom_registered_listener_list *this_lstnr;
1610
1611 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301612 if (!this_lstnr) {
1613 pr_err("Invalid listener ID\n");
1614 return -ENODATA;
1615 }
1616
Mona Hossain2892b6b2012-02-17 13:53:11 -08001617 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001618 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001619 __qseecom_listener_has_rcvd_req(data,
1620 this_lstnr))) {
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05301621 pr_debug("Interrupted: exiting Listener Service = %d\n",
Mona Hossain17a4faf2013-03-22 16:40:56 -07001622 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001623 /* woken up for different reason */
1624 return -ERESTARTSYS;
1625 }
1626
1627 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001628 pr_err("Aborting Listener Service = %d\n",
1629 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001630 return -ENODEV;
1631 }
1632 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001633 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001634 }
1635 return ret;
1636}
1637
Mona Hossaind44a3842012-10-15 09:41:35 -07001638static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1639{
1640 struct elf32_hdr *ehdr;
1641
1642 if (fw_entry->size < sizeof(*ehdr)) {
1643 pr_err("%s: Not big enough to be an elf header\n",
1644 qseecom.pdev->init_name);
1645 return false;
1646 }
1647 ehdr = (struct elf32_hdr *)fw_entry->data;
1648 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1649 pr_err("%s: Not an elf header\n",
1650 qseecom.pdev->init_name);
1651 return false;
1652 }
1653
1654 if (ehdr->e_phnum == 0) {
1655 pr_err("%s: No loadable segments\n",
1656 qseecom.pdev->init_name);
1657 return false;
1658 }
1659 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1660 sizeof(struct elf32_hdr) > fw_entry->size) {
1661 pr_err("%s: Program headers not within mdt\n",
1662 qseecom.pdev->init_name);
1663 return false;
1664 }
1665 return true;
1666}
1667
1668static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1669{
1670 int ret = -1;
1671 int i = 0, rc = 0;
1672 const struct firmware *fw_entry = NULL;
1673 struct elf32_phdr *phdr;
1674 char fw_name[MAX_APP_NAME_SIZE];
1675 struct elf32_hdr *ehdr;
1676 int num_images = 0;
1677
1678 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1679 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1680 if (rc) {
1681 pr_err("error with request_firmware\n");
1682 ret = -EIO;
1683 goto err;
1684 }
1685 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1686 ret = -EIO;
1687 goto err;
1688 }
1689 *fw_size = fw_entry->size;
1690 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1691 ehdr = (struct elf32_hdr *)fw_entry->data;
1692 num_images = ehdr->e_phnum;
1693 release_firmware(fw_entry);
1694 for (i = 0; i < num_images; i++, phdr++) {
1695 memset(fw_name, 0, sizeof(fw_name));
1696 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1697 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1698 if (ret)
1699 goto err;
1700 *fw_size += fw_entry->size;
1701 release_firmware(fw_entry);
1702 }
1703 return ret;
1704err:
1705 if (fw_entry)
1706 release_firmware(fw_entry);
1707 *fw_size = 0;
1708 return ret;
1709}
1710
1711static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1712 struct qseecom_load_app_ireq *load_req)
1713{
1714 int ret = -1;
1715 int i = 0, rc = 0;
1716 const struct firmware *fw_entry = NULL;
1717 char fw_name[MAX_APP_NAME_SIZE];
1718 u8 *img_data_ptr = img_data;
1719 struct elf32_hdr *ehdr;
1720 int num_images = 0;
1721
1722 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1723 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1724 if (rc) {
1725 ret = -EIO;
1726 goto err;
1727 }
1728 load_req->img_len = fw_entry->size;
1729 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1730 img_data_ptr = img_data_ptr + fw_entry->size;
1731 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1732 ehdr = (struct elf32_hdr *)fw_entry->data;
1733 num_images = ehdr->e_phnum;
1734 release_firmware(fw_entry);
1735 for (i = 0; i < num_images; i++) {
1736 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1737 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1738 if (ret) {
1739 pr_err("Failed to locate blob %s\n", fw_name);
1740 goto err;
1741 }
1742 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1743 img_data_ptr = img_data_ptr + fw_entry->size;
1744 load_req->img_len += fw_entry->size;
1745 release_firmware(fw_entry);
1746 }
1747 load_req->phy_addr = virt_to_phys(img_data);
1748 return ret;
1749err:
1750 release_firmware(fw_entry);
1751 return ret;
1752}
1753
1754static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1755{
1756 int ret = -1;
1757 uint32_t fw_size = 0;
1758 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1759 struct qseecom_command_scm_resp resp;
1760 u8 *img_data = NULL;
1761
1762 if (__qseecom_get_fw_size(appname, &fw_size))
1763 return -EIO;
1764
1765 img_data = kzalloc(fw_size, GFP_KERNEL);
1766 if (!img_data) {
1767 pr_err("Failied to allocate memory for copying image data\n");
1768 return -ENOMEM;
1769 }
1770 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1771 if (ret) {
1772 kzfree(img_data);
1773 return -EIO;
1774 }
1775
1776 /* Populate the remaining parameters */
1777 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1778 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001779 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001780 if (ret) {
1781 kzfree(img_data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001782 return -EIO;
1783 }
1784
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001785 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001786 /* SCM_CALL to load the image */
1787 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1788 sizeof(struct qseecom_load_app_ireq),
1789 &resp, sizeof(resp));
1790 kzfree(img_data);
1791 if (ret) {
1792 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001793 __qseecom_disable_clk_scale_down(data);
Mona Hossaind44a3842012-10-15 09:41:35 -07001794 return -EIO;
1795 }
1796
1797 switch (resp.result) {
1798 case QSEOS_RESULT_SUCCESS:
1799 ret = resp.data;
1800 break;
1801 case QSEOS_RESULT_INCOMPLETE:
1802 ret = __qseecom_process_incomplete_cmd(data, &resp);
1803 if (ret)
1804 pr_err("process_incomplete_cmd FAILED\n");
1805 else
1806 ret = resp.data;
1807 break;
1808 case QSEOS_RESULT_FAILURE:
1809 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1810 break;
1811 default:
1812 pr_err("scm call return unknown response %d\n", resp.result);
1813 ret = -EINVAL;
1814 break;
1815 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001816 __qseecom_disable_clk_scale_down(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001817
Mona Hossaind44a3842012-10-15 09:41:35 -07001818 return ret;
1819}
1820
Mona Hossain9498f5e2013-01-23 18:08:45 -08001821static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001822{
Zhen Kongc46b5842013-12-12 13:09:16 +05301823 int ret = 0;
Zhen Kongfd64c982013-12-19 16:35:43 -08001824 int len = 0;
Mona Hossain05c73562012-10-29 17:49:01 -07001825 uint32_t fw_size = 0;
1826 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1827 struct qseecom_command_scm_resp resp;
1828 u8 *img_data = NULL;
Zhen Kongfd64c982013-12-19 16:35:43 -08001829 ion_phys_addr_t pa;
Mona Hossain05c73562012-10-29 17:49:01 -07001830
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001831 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001832 return -EIO;
1833
Zhen Kongc46b5842013-12-12 13:09:16 +05301834 qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
1835 SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1836 if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08001837 pr_err("ION alloc failed\n");
Mona Hossain05c73562012-10-29 17:49:01 -07001838 return -ENOMEM;
1839 }
Zhen Kongc46b5842013-12-12 13:09:16 +05301840
1841 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
1842 qseecom.cmnlib_ion_handle);
1843 if (IS_ERR_OR_NULL(img_data)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08001844 pr_err("ION memory mapping for cmnlib failed\n");
Zhen Kongc46b5842013-12-12 13:09:16 +05301845 ret = -ENOMEM;
1846 goto exit_ion_free;
1847 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001848 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001849 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05301850 ret = -EIO;
1851 goto exit_ion_unmap_kernel;
Mona Hossain05c73562012-10-29 17:49:01 -07001852 }
Zhen Kongfd64c982013-12-19 16:35:43 -08001853 /* Get the physical address of the ION BUF */
1854 ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
1855 &pa, &len);
1856 load_req.phy_addr = (s32)pa;
1857 if (ret) {
1858 pr_err("physical memory retrieval failure\n");
1859 ret = -EIO;
1860 goto exit_ion_unmap_kernel;
1861 }
Mona Hossain05c73562012-10-29 17:49:01 -07001862 /* Populate the remaining parameters */
1863 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001864 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001865 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001866 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05301867 ret = -EIO;
1868 goto exit_ion_unmap_kernel;
Mona Hossain6311d572013-03-01 15:54:02 -08001869 }
1870
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001871 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001872 /* SCM_CALL to load the image */
1873 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1874 sizeof(struct qseecom_load_lib_image_ireq),
1875 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001876 if (ret) {
1877 pr_err("scm_call to load failed : ret %d\n", ret);
1878 ret = -EIO;
Zhen Kongc46b5842013-12-12 13:09:16 +05301879 goto exit_disable_clk_vote;
Mona Hossain05c73562012-10-29 17:49:01 -07001880 }
Zhen Kongc46b5842013-12-12 13:09:16 +05301881
1882 switch (resp.result) {
1883 case QSEOS_RESULT_SUCCESS:
1884 break;
1885 case QSEOS_RESULT_FAILURE:
1886 pr_err("scm call failed w/response result%d\n", resp.result);
1887 ret = -EINVAL;
1888 goto exit_disable_clk_vote;
1889 case QSEOS_RESULT_INCOMPLETE:
1890 ret = __qseecom_process_incomplete_cmd(data, &resp);
1891 if (ret) {
1892 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1893 goto exit_disable_clk_vote;
1894 }
1895 break;
1896 default:
1897 pr_err("scm call return unknown response %d\n", resp.result);
1898 ret = -EINVAL;
1899 goto exit_disable_clk_vote;
1900 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001901 __qseecom_disable_clk_scale_down(data);
Mona Hossain05c73562012-10-29 17:49:01 -07001902 return ret;
Zhen Kongc46b5842013-12-12 13:09:16 +05301903
1904exit_disable_clk_vote:
1905 __qseecom_disable_clk_scale_down(data);
1906
1907exit_ion_unmap_kernel:
1908 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1909
1910exit_ion_free:
1911 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1912 qseecom.cmnlib_ion_handle = NULL;
1913 return ret;
Mona Hossain05c73562012-10-29 17:49:01 -07001914}
1915
1916static int qseecom_unload_commonlib_image(void)
1917{
1918 int ret = -EINVAL;
1919 struct qseecom_unload_lib_image_ireq unload_req = {0};
1920 struct qseecom_command_scm_resp resp;
1921
1922 /* Populate the remaining parameters */
1923 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1924 /* SCM_CALL to load the image */
1925 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1926 sizeof(struct qseecom_unload_lib_image_ireq),
1927 &resp, sizeof(resp));
1928 if (ret) {
1929 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1930 ret = -EIO;
1931 } else {
1932 switch (resp.result) {
1933 case QSEOS_RESULT_SUCCESS:
1934 break;
1935 case QSEOS_RESULT_FAILURE:
1936 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1937 break;
1938 default:
1939 pr_err("scm call return unknown response %d\n",
1940 resp.result);
1941 ret = -EINVAL;
1942 break;
1943 }
1944 }
Zhen Kongc46b5842013-12-12 13:09:16 +05301945
1946 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1947 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1948 qseecom.cmnlib_ion_handle = NULL;
1949
Mona Hossain05c73562012-10-29 17:49:01 -07001950 return ret;
1951}
1952
Mona Hossaind44a3842012-10-15 09:41:35 -07001953int qseecom_start_app(struct qseecom_handle **handle,
1954 char *app_name, uint32_t size)
1955{
Mona Hossain05c73562012-10-29 17:49:01 -07001956 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001957 unsigned long flags = 0;
1958 struct qseecom_dev_handle *data = NULL;
1959 struct qseecom_check_app_ireq app_ireq;
1960 struct qseecom_registered_app_list *entry = NULL;
1961 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1962 bool found_app = false;
1963 uint32_t len;
1964 ion_phys_addr_t pa;
1965
Mona Hossain823f9882012-11-23 14:42:20 -08001966 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1967 if (!(*handle)) {
1968 pr_err("failed to allocate memory for kernel client handle\n");
1969 return -ENOMEM;
1970 }
1971
Mona Hossaind44a3842012-10-15 09:41:35 -07001972 data = kzalloc(sizeof(*data), GFP_KERNEL);
1973 if (!data) {
1974 pr_err("kmalloc failed\n");
1975 if (ret == 0) {
1976 kfree(*handle);
1977 *handle = NULL;
1978 }
1979 return -ENOMEM;
1980 }
1981 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001982 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001983 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001984 data->client.sb_length = size;
1985 data->client.user_virt_sb_base = 0;
1986 data->client.ihandle = NULL;
1987
1988 init_waitqueue_head(&data->abort_wq);
1989 atomic_set(&data->ioctl_count, 0);
1990
1991 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1992 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1993 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1994 pr_err("Ion client could not retrieve the handle\n");
1995 kfree(data);
1996 kfree(*handle);
1997 *handle = NULL;
1998 return -EINVAL;
1999 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002000 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002001 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002002 if (qseecom.commonlib_loaded == false) {
2003 ret = qseecom_load_commonlib_image(data);
2004 if (ret == 0)
2005 qseecom.commonlib_loaded = true;
2006 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002007 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002008 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002009 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002010 ret = -EIO;
2011 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08002012 }
2013
2014 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2015 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
2016 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002017 if (ret < 0)
2018 goto err;
2019
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07002020 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002021 if (ret > 0) {
2022 pr_warn("App id %d for [%s] app exists\n", ret,
2023 (char *)app_ireq.app_name);
2024 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2025 list_for_each_entry(entry,
2026 &qseecom.registered_app_list_head, list){
2027 if (entry->app_id == ret) {
2028 entry->ref_cnt++;
2029 found_app = true;
2030 break;
2031 }
2032 }
2033 spin_unlock_irqrestore(
2034 &qseecom.registered_app_list_lock, flags);
2035 if (!found_app)
2036 pr_warn("App_id %d [%s] was loaded but not registered\n",
2037 ret, (char *)app_ireq.app_name);
2038 } else {
2039 /* load the app and get the app_id */
2040 pr_debug("%s: Loading app for the first time'\n",
2041 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07002042 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002043 if (ret < 0)
2044 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002045 data->client.app_id = ret;
2046 }
2047 if (!found_app) {
2048 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2049 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002050 pr_err("kmalloc for app entry failed\n");
2051 ret = -ENOMEM;
2052 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002053 }
2054 entry->app_id = ret;
2055 entry->ref_cnt = 1;
2056
2057 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2058 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2059 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2060 flags);
2061 }
2062
2063 /* Get the physical address of the ION BUF */
2064 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002065 if (ret) {
2066 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2067 ret);
2068 goto err;
2069 }
2070
Mona Hossaind44a3842012-10-15 09:41:35 -07002071 /* Populate the structure for sending scm call to load image */
2072 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
2073 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08002074 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07002075 data->client.sb_phys = pa;
2076 (*handle)->dev = (void *)data;
2077 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
2078 (*handle)->sbuf_len = data->client.sb_length;
2079
2080 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
2081 if (!kclient_entry) {
2082 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002083 ret = -ENOMEM;
2084 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002085 }
2086 kclient_entry->handle = *handle;
2087
2088 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2089 list_add_tail(&kclient_entry->list,
2090 &qseecom.registered_kclient_list_head);
2091 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2092
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002093 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002094 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002095
2096err:
2097 kfree(data);
2098 kfree(*handle);
2099 *handle = NULL;
2100 mutex_unlock(&app_access_lock);
2101 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002102}
2103EXPORT_SYMBOL(qseecom_start_app);
2104
2105int qseecom_shutdown_app(struct qseecom_handle **handle)
2106{
2107 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002108 struct qseecom_dev_handle *data;
2109
Mona Hossaind44a3842012-10-15 09:41:35 -07002110 struct qseecom_registered_kclient_list *kclient = NULL;
2111 unsigned long flags = 0;
2112 bool found_handle = false;
2113
Mona Hossain33824022013-02-25 09:32:33 -08002114 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002115 pr_err("Handle is not initialized\n");
2116 return -EINVAL;
2117 }
Mona Hossain33824022013-02-25 09:32:33 -08002118 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07002119 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2120 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2121 list) {
2122 if (kclient->handle == (*handle)) {
2123 list_del(&kclient->list);
2124 found_handle = true;
2125 break;
2126 }
2127 }
2128 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2129 if (!found_handle)
2130 pr_err("Unable to find the handle, exiting\n");
2131 else
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07002132 ret = qseecom_unload_app(data, false);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002133
2134 if (qseecom.support_bus_scaling) {
2135 mutex_lock(&qsee_bw_mutex);
2136 if (data->mode != INACTIVE) {
2137 qseecom_unregister_bus_bandwidth_needs(data);
2138 if (qseecom.cumulative_mode == INACTIVE) {
2139 ret = __qseecom_set_msm_bus_request(INACTIVE);
2140 if (ret)
2141 pr_err("Fail to scale down bus\n");
2142 }
2143 }
2144 mutex_unlock(&qsee_bw_mutex);
2145 } else {
2146 if (data->fast_load_enabled == true)
2147 qsee_disable_clock_vote(data, CLK_SFPB);
2148 if (data->perf_enabled == true)
2149 qsee_disable_clock_vote(data, CLK_DFAB);
2150 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002151 if (ret == 0) {
2152 kzfree(data);
2153 kzfree(*handle);
2154 kzfree(kclient);
2155 *handle = NULL;
2156 }
2157 return ret;
2158}
2159EXPORT_SYMBOL(qseecom_shutdown_app);
2160
2161int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2162 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2163{
2164 int ret = 0;
2165 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2166 struct qseecom_dev_handle *data;
2167
Mona Hossaind44a3842012-10-15 09:41:35 -07002168 if (handle == NULL) {
2169 pr_err("Handle is not initialized\n");
2170 return -EINVAL;
2171 }
2172 data = handle->dev;
2173
2174 req.cmd_req_len = sbuf_len;
2175 req.resp_len = rbuf_len;
2176 req.cmd_req_buf = send_buf;
2177 req.resp_buf = resp_buf;
2178
2179 mutex_lock(&app_access_lock);
2180 atomic_inc(&data->ioctl_count);
Zhen Kongca4c2d52014-03-12 13:22:46 -07002181 if (qseecom.support_bus_scaling) {
2182 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
2183 if (ret) {
2184 pr_err("Failed to set bw.\n");
2185 atomic_dec(&data->ioctl_count);
2186 mutex_unlock(&app_access_lock);
2187 return ret;
2188 }
2189 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002190 ret = __qseecom_send_cmd(data, &req);
Zhen Kongaf950192014-02-05 17:36:23 -08002191 if (qseecom.support_bus_scaling)
2192 __qseecom_add_bw_scale_down_timer(
2193 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002194
2195 atomic_dec(&data->ioctl_count);
2196 mutex_unlock(&app_access_lock);
2197
2198 if (ret)
2199 return ret;
2200
2201 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2202 req.resp_len, req.resp_buf);
2203 return ret;
2204}
2205EXPORT_SYMBOL(qseecom_send_command);
2206
Mona Hossain91a8fc92012-11-07 19:58:30 -08002207int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2208{
Mona Hossainfca6f422013-01-12 13:00:35 -08002209 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002210 if ((handle == NULL) || (handle->dev == NULL)) {
2211 pr_err("No valid kernel client\n");
2212 return -EINVAL;
2213 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002214 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002215 if (qseecom.support_bus_scaling) {
2216 mutex_lock(&qsee_bw_mutex);
2217 __qseecom_register_bus_bandwidth_needs(handle->dev,
2218 HIGH);
2219 mutex_unlock(&qsee_bw_mutex);
2220 if (ret)
2221 pr_err("Failed to scale bus (med) %d\n", ret);
2222 } else {
2223 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2224 if (ret)
2225 pr_err("Failed to vote for DFAB clock%d\n",
2226 ret);
2227 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2228 if (ret) {
2229 pr_err("Failed to vote for SFPB clock%d\n",
2230 ret);
2231 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2232 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002233 }
2234 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002235 if (!qseecom.support_bus_scaling) {
2236 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2237 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
2238 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002239 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002240 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002241}
2242EXPORT_SYMBOL(qseecom_set_bandwidth);
2243
Mona Hossain2892b6b2012-02-17 13:53:11 -08002244static int qseecom_send_resp(void)
2245{
2246 qseecom.send_resp_flag = 1;
2247 wake_up_interruptible(&qseecom.send_resp_wq);
2248 return 0;
2249}
2250
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002251
2252static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2253 void __user *argp)
2254{
2255 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002256 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002257 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002258
2259 if (copy_from_user(&resp, argp, sizeof(resp))) {
2260 pr_err("copy_from_user failed");
2261 return -EINVAL;
2262 }
Zhen Kongf4948192013-11-25 13:05:35 -08002263 this_lstnr = __qseecom_find_svc(data->listener.id);
2264 if (this_lstnr == NULL)
2265 return -EINVAL;
2266
2267 if (resp.resp_buf_ptr == NULL) {
2268 pr_err("Invalid resp_buf_ptr\n");
2269 return -EINVAL;
2270 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002271 /* validate offsets */
2272 for (i = 0; i < MAX_ION_FD; i++) {
2273 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2274 pr_err("Invalid offset %d = 0x%x\n",
2275 i, resp.ifd_data[i].cmd_buf_offset);
2276 return -EINVAL;
2277 }
2278 }
Zhen Kongf4948192013-11-25 13:05:35 -08002279
2280 if (((uint32_t)resp.resp_buf_ptr <
2281 this_lstnr->user_virt_sb_base)
2282 || ((uint32_t)resp.resp_buf_ptr >=
2283 (this_lstnr->user_virt_sb_base +
2284 this_lstnr->sb_length))) {
2285 pr_err("resp_buf_ptr address not within shared buffer\n");
2286 return -EINVAL;
2287 }
2288 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2289 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002290 __qseecom_update_cmd_buf(&resp, false, data, true);
2291 qseecom.send_resp_flag = 1;
2292 wake_up_interruptible(&qseecom.send_resp_wq);
2293 return 0;
2294}
2295
2296
Mona Hossain2892b6b2012-02-17 13:53:11 -08002297static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2298 void __user *argp)
2299{
2300 struct qseecom_qseos_version_req req;
2301
2302 if (copy_from_user(&req, argp, sizeof(req))) {
2303 pr_err("copy_from_user failed");
2304 return -EINVAL;
2305 }
2306 req.qseos_version = qseecom.qseos_version;
2307 if (copy_to_user(argp, &req, sizeof(req))) {
2308 pr_err("copy_to_user failed");
2309 return -EINVAL;
2310 }
2311 return 0;
2312}
2313
Mona Hossainc92629e2013-04-01 13:37:46 -07002314static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002315{
2316 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002317 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002318
Mona Hossainc92629e2013-04-01 13:37:46 -07002319 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002320 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002321 else
2322 qclk = &qseecom.ce_drv;
2323
2324 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002325
2326 if (qclk->clk_access_cnt == ULONG_MAX)
2327 goto err;
2328
Mona Hossainc92629e2013-04-01 13:37:46 -07002329 if (qclk->clk_access_cnt > 0) {
2330 qclk->clk_access_cnt++;
2331 mutex_unlock(&clk_access_lock);
2332 return rc;
2333 }
2334
Mona Hossain6311d572013-03-01 15:54:02 -08002335 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002336 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002337 if (rc) {
2338 pr_err("Unable to enable/prepare CE core clk\n");
2339 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002340 }
2341 /* Enable CE clk */
2342 rc = clk_prepare_enable(qclk->ce_clk);
2343 if (rc) {
2344 pr_err("Unable to enable/prepare CE iface clk\n");
2345 goto ce_clk_err;
2346 }
2347 /* Enable AXI clk */
2348 rc = clk_prepare_enable(qclk->ce_bus_clk);
2349 if (rc) {
2350 pr_err("Unable to enable/prepare CE bus clk\n");
2351 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002352 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002353 qclk->clk_access_cnt++;
2354 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002355 return 0;
2356
2357ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002358 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002359ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002360 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002361err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002362 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002363 return -EIO;
2364}
2365
Mona Hossainc92629e2013-04-01 13:37:46 -07002366static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002367{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002368 struct qseecom_clk *qclk;
2369
Mona Hossainc92629e2013-04-01 13:37:46 -07002370 if (ce == CLK_QSEE)
2371 qclk = &qseecom.qsee;
2372 else
2373 qclk = &qseecom.ce_drv;
2374
2375 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002376
2377 if (qclk->clk_access_cnt == 0) {
2378 mutex_unlock(&clk_access_lock);
2379 return;
2380 }
2381
Mona Hossainc92629e2013-04-01 13:37:46 -07002382 if (qclk->clk_access_cnt == 1) {
2383 if (qclk->ce_clk != NULL)
2384 clk_disable_unprepare(qclk->ce_clk);
2385 if (qclk->ce_core_clk != NULL)
2386 clk_disable_unprepare(qclk->ce_core_clk);
2387 if (qclk->ce_bus_clk != NULL)
2388 clk_disable_unprepare(qclk->ce_bus_clk);
2389 }
2390 qclk->clk_access_cnt--;
2391 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002392}
2393
Mona Hossain04d3fac2012-12-03 10:10:37 -08002394static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2395 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002396{
2397 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002398 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002399
Mona Hossain17a4faf2013-03-22 16:40:56 -07002400 qclk = &qseecom.qsee;
2401 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002402 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002403
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002404 switch (clk_type) {
2405 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002406 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002407 if (!qseecom.qsee_bw_count) {
2408 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002409 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002410 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002411 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002412 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002413 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002414 if (!ret) {
2415 ret =
2416 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002417 qseecom.qsee_perf_client, 1);
2418 if ((ret) &&
2419 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002420 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002421 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002422 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002423 if (ret)
2424 pr_err("DFAB Bandwidth req failed (%d)\n",
2425 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002426 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002427 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002428 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002429 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002430 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002431 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002432 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002433 }
2434 mutex_unlock(&qsee_bw_mutex);
2435 break;
2436 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002437 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002438 if (!qseecom.qsee_sfpb_bw_count) {
2439 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002440 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002441 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002442 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002443 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002444 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002445 if (!ret) {
2446 ret =
2447 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002448 qseecom.qsee_perf_client, 2);
2449 if ((ret) &&
2450 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002451 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002452 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002453 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002454
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002455 if (ret)
2456 pr_err("SFPB Bandwidth req failed (%d)\n",
2457 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002458 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002459 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002460 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002461 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002462 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002463 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002464 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002465 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002466 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002467 break;
2468 default:
2469 pr_err("Clock type not defined\n");
2470 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002471 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002472 return ret;
2473}
2474
Mona Hossain04d3fac2012-12-03 10:10:37 -08002475static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2476 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002477{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002478 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002479 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002480
Mona Hossain17a4faf2013-03-22 16:40:56 -07002481 qclk = &qseecom.qsee;
2482 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002483 return;
2484
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002485 switch (clk_type) {
2486 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002487 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002488 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002489 pr_err("Client error.Extra call to disable DFAB clk\n");
2490 mutex_unlock(&qsee_bw_mutex);
2491 return;
2492 }
2493
Mona Hossain17a4faf2013-03-22 16:40:56 -07002494 if (qseecom.qsee_bw_count == 1) {
2495 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002496 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002497 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002498 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002499 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002500 qseecom.qsee_perf_client, 0);
2501 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002502 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002503 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002504 if (ret)
2505 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002506 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002507 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002508 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002509 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002510 }
2511 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002512 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002513 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002514 }
2515 mutex_unlock(&qsee_bw_mutex);
2516 break;
2517 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002518 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002519 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002520 pr_err("Client error.Extra call to disable SFPB clk\n");
2521 mutex_unlock(&qsee_bw_mutex);
2522 return;
2523 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002524 if (qseecom.qsee_sfpb_bw_count == 1) {
2525 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002526 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002527 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002528 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002529 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002530 qseecom.qsee_perf_client, 0);
2531 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002532 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002533 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002534 if (ret)
2535 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002536 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002537 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002538 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002539 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002540 }
2541 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002542 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002543 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002544 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002545 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002546 break;
2547 default:
2548 pr_err("Clock type not defined\n");
2549 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002550 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002551
Mona Hossain2892b6b2012-02-17 13:53:11 -08002552}
2553
Mona Hossain5ab9d772012-04-11 21:00:40 -07002554static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2555 void __user *argp)
2556{
2557 struct ion_handle *ihandle; /* Ion handle */
2558 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002559 int ret;
2560 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002561 ion_phys_addr_t pa = 0;
2562 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002563 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002564 struct qseecom_load_app_ireq load_req;
2565 struct qseecom_command_scm_resp resp;
2566
2567 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002568 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002569 (void __user *)argp,
2570 sizeof(struct qseecom_load_img_req))) {
2571 pr_err("copy_from_user failed\n");
2572 return -EFAULT;
2573 }
2574
2575 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002576 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002577 load_img_req.ifd_data_fd);
2578 if (IS_ERR_OR_NULL(ihandle)) {
2579 pr_err("Ion client could not retrieve the handle\n");
2580 return -ENOMEM;
2581 }
2582
2583 /* Get the physical address of the ION BUF */
2584 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002585 if (ret) {
2586 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2587 ret);
2588 return ret;
2589 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002590 /* Populate the structure for sending scm call to load image */
2591 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2592 load_req.mdt_len = load_img_req.mdt_len;
2593 load_req.img_len = load_img_req.img_len;
2594 load_req.phy_addr = pa;
2595
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002596 /* SCM_CALL tied to Core0 */
2597 mask = CPU_MASK_CPU0;
2598 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2599 if (set_cpu_ret) {
2600 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2601 set_cpu_ret);
2602 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302603 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002604 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302605
Mona Hossain6311d572013-03-01 15:54:02 -08002606 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002607 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002608 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002609 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302610 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002611 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002612 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2613 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002614 /* SCM_CALL to load the external elf */
2615 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2616 sizeof(struct qseecom_load_app_ireq),
2617 &resp, sizeof(resp));
2618 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002619 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002620 ret);
2621 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302622 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002623 }
2624
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302625 switch (resp.result) {
2626 case QSEOS_RESULT_SUCCESS:
2627 break;
2628 case QSEOS_RESULT_INCOMPLETE:
2629 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002630 ret = __qseecom_process_incomplete_cmd(data, &resp);
2631 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302632 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2633 break;
2634 case QSEOS_RESULT_FAILURE:
2635 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2636 ret = -EFAULT;
2637 break;
2638 default:
2639 pr_err("scm_call response result %d not supported\n",
2640 resp.result);
2641 ret = -EFAULT;
2642 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002643 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002644
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302645exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002646 __qseecom_disable_clk_scale_down(data);
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302647exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002648 /* Restore the CPU mask */
2649 mask = CPU_MASK_ALL;
2650 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2651 if (set_cpu_ret) {
2652 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2653 set_cpu_ret);
2654 ret = -EFAULT;
2655 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302656exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002657 /* Deallocate the handle */
2658 if (!IS_ERR_OR_NULL(ihandle))
2659 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002660 return ret;
2661}
2662
2663static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2664{
2665 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002666 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002667 struct qseecom_command_scm_resp resp;
2668 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002669 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002670
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302671 /* unavailable client app */
2672 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2673
Mona Hossain5ab9d772012-04-11 21:00:40 -07002674 /* Populate the structure for sending scm call to unload image */
2675 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002676
2677 /* SCM_CALL tied to Core0 */
2678 mask = CPU_MASK_CPU0;
2679 ret = set_cpus_allowed_ptr(current, &mask);
2680 if (ret) {
2681 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2682 ret);
2683 return -EFAULT;
2684 }
2685
Mona Hossain5ab9d772012-04-11 21:00:40 -07002686 /* SCM_CALL to unload the external elf */
2687 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2688 sizeof(struct qseecom_unload_app_ireq),
2689 &resp, sizeof(resp));
2690 if (ret) {
2691 pr_err("scm_call to unload failed : ret %d\n",
2692 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002693 ret = -EFAULT;
2694 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002695 }
2696 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2697 ret = __qseecom_process_incomplete_cmd(data, &resp);
2698 if (ret)
2699 pr_err("process_incomplete_cmd fail err: %d\n",
2700 ret);
2701 } else {
2702 if (resp.result != QSEOS_RESULT_SUCCESS) {
2703 pr_err("scm_call to unload image failed resp.result =%d\n",
2704 resp.result);
2705 ret = -EFAULT;
2706 }
2707 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002708
2709qseecom_unload_external_elf_scm_err:
2710 /* Restore the CPU mask */
2711 mask = CPU_MASK_ALL;
2712 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2713 if (set_cpu_ret) {
2714 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2715 set_cpu_ret);
2716 ret = -EFAULT;
2717 }
2718
Mona Hossain5ab9d772012-04-11 21:00:40 -07002719 return ret;
2720}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002721
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002722static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2723 void __user *argp)
2724{
2725
2726 int32_t ret;
2727 struct qseecom_qseos_app_load_query query_req;
2728 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002729 struct qseecom_registered_app_list *entry = NULL;
2730 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002731
2732 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002733 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002734 (void __user *)argp,
2735 sizeof(struct qseecom_qseos_app_load_query))) {
2736 pr_err("copy_from_user failed\n");
2737 return -EFAULT;
2738 }
2739
2740 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002741 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002742 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2743
2744 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002745
2746 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002747 pr_err(" scm call to check if app is loaded failed");
2748 return ret; /* scm call failed */
2749 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002750 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002751 (char *)(req.app_name));
2752 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2753 list_for_each_entry(entry,
2754 &qseecom.registered_app_list_head, list){
2755 if (entry->app_id == ret) {
2756 entry->ref_cnt++;
2757 break;
2758 }
2759 }
2760 spin_unlock_irqrestore(
2761 &qseecom.registered_app_list_lock, flags);
2762 data->client.app_id = ret;
2763 query_req.app_id = ret;
2764
2765 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2766 pr_err("copy_to_user failed\n");
2767 return -EFAULT;
2768 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002769 return -EEXIST; /* app already loaded */
2770 } else {
2771 return 0; /* app not loaded */
2772 }
2773}
2774
Mona Hossain4cf78a92013-02-14 12:06:41 -08002775static int __qseecom_get_ce_pipe_info(
2776 enum qseecom_key_management_usage_type usage,
2777 uint32_t *pipe, uint32_t *ce_hw)
2778{
2779 int ret;
2780 switch (usage) {
2781 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
Zhen Kong4ffeacf2014-02-27 17:21:08 -08002782 if (qseecom.support_fde) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002783 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2784 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2785 ret = 0;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08002786
2787 } else {
2788 pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
2789 qseecom.ce_info.disk_encrypt_pipe,
2790 qseecom.ce_info.hlos_ce_hw_instance);
2791 ret = -EINVAL;
2792 }
2793 break;
2794 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
2795 if (qseecom.support_pfe) {
2796 *pipe = qseecom.ce_info.file_encrypt_pipe;
2797 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2798 ret = 0;
2799 } else {
2800 pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
2801 qseecom.ce_info.file_encrypt_pipe,
2802 qseecom.ce_info.hlos_ce_hw_instance);
2803 ret = -EINVAL;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002804 }
2805 break;
2806 default:
2807 ret = -EINVAL;
2808 break;
2809 }
2810 return ret;
2811}
2812
2813static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2814 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002815 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002816{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002817 struct qseecom_command_scm_resp resp;
2818 int ret;
2819
Zhen Kong9730ddf2013-12-17 16:49:43 -08002820 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2821 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002822 pr_err("Error:: unsupported usage %d\n", usage);
2823 return -EFAULT;
2824 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002825 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002826
2827 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002828 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002829 &resp, sizeof(resp));
2830 if (ret) {
2831 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002832 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002833 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002834 }
2835
2836 switch (resp.result) {
2837 case QSEOS_RESULT_SUCCESS:
2838 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002839 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongba69dfe2014-02-28 15:19:53 -08002840 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002841 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002842 case QSEOS_RESULT_INCOMPLETE:
2843 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002844 if (ret) {
2845 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongba69dfe2014-02-28 15:19:53 -08002846 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002847 ret = 0;
2848 } else {
2849 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2850 resp.result);
2851 }
2852 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002853 break;
2854 case QSEOS_RESULT_FAILURE:
2855 default:
2856 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2857 ret = -EINVAL;
2858 break;
2859 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002860 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002861 return ret;
2862}
2863
2864static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2865 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002866 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002867{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002868 struct qseecom_command_scm_resp resp;
2869 int ret;
2870
2871 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2872 pr_err("Error:: unsupported usage %d\n", usage);
2873 return -EFAULT;
2874 }
2875
Mona Hossainc92629e2013-04-01 13:37:46 -07002876 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002877
2878 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002879 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002880 &resp, sizeof(struct qseecom_command_scm_resp));
2881 if (ret) {
2882 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002883 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002884 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002885 }
2886
2887 switch (resp.result) {
2888 case QSEOS_RESULT_SUCCESS:
2889 break;
2890 case QSEOS_RESULT_INCOMPLETE:
2891 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002892 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002893 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2894 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002895 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2896 pr_debug("Max attempts to input password reached.\n");
2897 ret = -ERANGE;
2898 }
2899 }
2900 break;
2901 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2902 pr_debug("Max attempts to input password reached.\n");
2903 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002904 break;
2905 case QSEOS_RESULT_FAILURE:
2906 default:
2907 pr_err("Delete key scm call failed resp.result %d\n",
2908 resp.result);
2909 ret = -EINVAL;
2910 break;
2911 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002912 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002913 return ret;
2914}
2915
2916static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2917 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002918 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002919{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002920 struct qseecom_command_scm_resp resp;
2921 int ret;
2922
Zhen Kong9730ddf2013-12-17 16:49:43 -08002923 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2924 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002925 pr_err("Error:: unsupported usage %d\n", usage);
2926 return -EFAULT;
2927 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002928
Zhen Kongdb2bf742013-05-13 23:55:42 -07002929 __qseecom_enable_clk(CLK_QSEE);
2930 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002931 __qseecom_enable_clk(CLK_CE_DRV);
2932
Zhen Kong336636e2013-04-15 11:04:54 -07002933 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002934 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002935 &resp, sizeof(struct qseecom_command_scm_resp));
2936 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002937 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002938 __qseecom_disable_clk(CLK_QSEE);
2939 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2940 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08002941 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07002942 }
2943
Mona Hossain4cf78a92013-02-14 12:06:41 -08002944 switch (resp.result) {
2945 case QSEOS_RESULT_SUCCESS:
2946 break;
2947 case QSEOS_RESULT_INCOMPLETE:
2948 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002949 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002950 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2951 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002952 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2953 pr_debug("Max attempts to input password reached.\n");
2954 ret = -ERANGE;
2955 }
2956 }
2957 break;
2958 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2959 pr_debug("Max attempts to input password reached.\n");
2960 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002961 break;
2962 case QSEOS_RESULT_FAILURE:
2963 default:
2964 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2965 ret = -EINVAL;
2966 break;
2967 }
2968
Zhen Kongdb2bf742013-05-13 23:55:42 -07002969 __qseecom_disable_clk(CLK_QSEE);
2970 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002971 __qseecom_disable_clk(CLK_CE_DRV);
2972
Mona Hossain4cf78a92013-02-14 12:06:41 -08002973 return ret;
2974}
2975
Zhen Kong9730ddf2013-12-17 16:49:43 -08002976static int __qseecom_update_current_key_user_info(
2977 struct qseecom_dev_handle *data,
2978 enum qseecom_key_management_usage_type usage,
2979 struct qseecom_key_userinfo_update_ireq *ireq)
2980{
2981 struct qseecom_command_scm_resp resp;
2982 int ret;
2983
2984 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2985 usage >= QSEOS_KM_USAGE_MAX) {
2986 pr_err("Error:: unsupported usage %d\n", usage);
2987 return -EFAULT;
2988 }
2989
2990 __qseecom_enable_clk(CLK_QSEE);
2991
2992 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
2993 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
2994 &resp, sizeof(struct qseecom_command_scm_resp));
2995 if (ret) {
2996 pr_err("scm call to update key userinfo failed : %d\n", ret);
2997 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002998 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08002999 }
3000
3001 switch (resp.result) {
3002 case QSEOS_RESULT_SUCCESS:
3003 break;
3004 case QSEOS_RESULT_INCOMPLETE:
3005 ret = __qseecom_process_incomplete_cmd(data, &resp);
3006 if (ret)
3007 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3008 resp.result);
3009 break;
3010 case QSEOS_RESULT_FAILURE:
3011 default:
3012 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3013 ret = -EINVAL;
3014 break;
3015 }
3016
3017 __qseecom_disable_clk(CLK_QSEE);
3018 return ret;
3019}
3020
Mona Hossain4cf78a92013-02-14 12:06:41 -08003021static int qseecom_create_key(struct qseecom_dev_handle *data,
3022 void __user *argp)
3023{
3024 uint32_t ce_hw = 0;
3025 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003026 int ret = 0;
3027 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003028 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003029 struct qseecom_key_generate_ireq generate_key_ireq;
3030 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003031
3032 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
3033 if (ret) {
3034 pr_err("copy_from_user failed\n");
3035 return ret;
3036 }
3037
Zhen Kong9730ddf2013-12-17 16:49:43 -08003038 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3039 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003040 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
3041 return -EFAULT;
3042 }
3043
3044 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
3045 if (ret) {
3046 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3047 return -EINVAL;
3048 }
3049
Zhen Kong9730ddf2013-12-17 16:49:43 -08003050 generate_key_ireq.flags = flags;
3051 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
3052 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3053 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3054 memcpy((void *)generate_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003055 (void *)key_id_array[create_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003056 QSEECOM_KEY_ID_SIZE);
3057 memcpy((void *)generate_key_ireq.hash32,
3058 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
3059
Mona Hossain4cf78a92013-02-14 12:06:41 -08003060 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003061 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003062 if (ret) {
3063 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003064 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003065 }
3066
Zhen Kong9730ddf2013-12-17 16:49:43 -08003067 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3068 set_key_ireq.ce = ce_hw;
3069 set_key_ireq.pipe = pipe;
3070 set_key_ireq.flags = flags;
3071
3072 /* set both PIPE_ENC and PIPE_ENC_XTS*/
3073 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
3074 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3075 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3076 memcpy((void *)set_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003077 (void *)key_id_array[create_key_req.usage].desc,
3078 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003079 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08003080 QSEECOM_HASH_SIZE);
3081
3082 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003083 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003084 if (ret) {
3085 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
3086 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003087 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003088 }
3089
3090 return ret;
3091}
3092
3093static int qseecom_wipe_key(struct qseecom_dev_handle *data,
3094 void __user *argp)
3095{
3096 uint32_t ce_hw = 0;
3097 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003098 int ret = 0;
3099 uint32_t flags = 0;
3100 int i;
3101 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003102 struct qseecom_key_delete_ireq delete_key_ireq;
3103 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003104
3105 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
3106 if (ret) {
3107 pr_err("copy_from_user failed\n");
3108 return ret;
3109 }
3110
Zhen Kong9730ddf2013-12-17 16:49:43 -08003111 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3112 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003113 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3114 return -EFAULT;
3115 }
3116
3117 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3118 if (ret) {
3119 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3120 return -EINVAL;
3121 }
3122
Zhen Kongba69dfe2014-02-28 15:19:53 -08003123 if (wipe_key_req.wipe_key_flag) {
3124 delete_key_ireq.flags = flags;
3125 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3126 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3127 memcpy((void *)delete_key_ireq.key_id,
3128 (void *)key_id_array[wipe_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003129 QSEECOM_KEY_ID_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003130 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003131
Zhen Kongba69dfe2014-02-28 15:19:53 -08003132 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003133 &delete_key_ireq);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003134 if (ret) {
3135 pr_err("Failed to delete key from ssd storage: %d\n",
3136 ret);
3137 return -EFAULT;
3138 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003139 }
3140
Zhen Kong9730ddf2013-12-17 16:49:43 -08003141 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3142 clear_key_ireq.ce = ce_hw;
3143 clear_key_ireq.pipe = pipe;
3144 clear_key_ireq.flags = flags;
3145 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003146 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kongba69dfe2014-02-28 15:19:53 -08003147 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003148 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3149
Mona Hossain4cf78a92013-02-14 12:06:41 -08003150 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003151 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003152 if (ret) {
3153 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3154 pipe, ce_hw, ret);
3155 return -EFAULT;
3156 }
3157
3158 return ret;
3159}
3160
Zhen Kong9730ddf2013-12-17 16:49:43 -08003161static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3162 void __user *argp)
3163{
3164 int ret = 0;
3165 uint32_t flags = 0;
3166 struct qseecom_update_key_userinfo_req update_key_req;
3167 struct qseecom_key_userinfo_update_ireq ireq;
3168
3169 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3170 if (ret) {
3171 pr_err("copy_from_user failed\n");
3172 return ret;
3173 }
3174
3175 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3176 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3177 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3178 return -EFAULT;
3179 }
3180
3181 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3182 ireq.flags = flags;
3183 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3184 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3185 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003186 memcpy((void *)ireq.key_id,
3187 (void *)key_id_array[update_key_req.usage].desc,
3188 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003189 memcpy((void *)ireq.current_hash32,
3190 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3191 memcpy((void *)ireq.new_hash32,
3192 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3193
3194 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3195 &ireq);
3196 if (ret) {
3197 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003198 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003199 }
3200 return ret;
3201
3202}
3203
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003204static int qseecom_is_es_activated(void __user *argp)
3205{
3206 struct qseecom_is_es_activated_req req;
3207 int ret;
3208 int resp_buf;
3209
3210 if (qseecom.qsee_version < QSEE_VERSION_04) {
3211 pr_err("invalid qsee version");
3212 return -ENODEV;
3213 }
3214
3215 if (argp == NULL) {
3216 pr_err("arg is null");
3217 return -EINVAL;
3218 }
3219
3220 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3221 (void *) &resp_buf, sizeof(resp_buf));
3222 if (ret) {
3223 pr_err("scm_call failed");
3224 return ret;
3225 }
3226
3227 req.is_activated = resp_buf;
3228 ret = copy_to_user(argp, &req, sizeof(req));
3229 if (ret) {
3230 pr_err("copy_to_user failed");
3231 return ret;
3232 }
3233
3234 return 0;
3235}
3236
3237static int qseecom_save_partition_hash(void __user *argp)
3238{
3239 struct qseecom_save_partition_hash_req req;
3240 int ret;
3241
3242 if (qseecom.qsee_version < QSEE_VERSION_04) {
3243 pr_err("invalid qsee version ");
3244 return -ENODEV;
3245 }
3246
3247 if (argp == NULL) {
3248 pr_err("arg is null");
3249 return -EINVAL;
3250 }
3251
3252 ret = copy_from_user(&req, argp, sizeof(req));
3253 if (ret) {
3254 pr_err("copy_from_user failed");
3255 return ret;
3256 }
3257
3258 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3259 (void *) &req, sizeof(req), NULL, 0);
3260 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003261 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003262 return ret;
3263 }
3264
3265 return 0;
3266}
3267
Mona Hossain2892b6b2012-02-17 13:53:11 -08003268static long qseecom_ioctl(struct file *file, unsigned cmd,
3269 unsigned long arg)
3270{
3271 int ret = 0;
3272 struct qseecom_dev_handle *data = file->private_data;
3273 void __user *argp = (void __user *) arg;
3274
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303275 if (!data) {
3276 pr_err("Invalid/uninitialized device handle\n");
3277 return -EINVAL;
3278 }
3279
Mona Hossain2892b6b2012-02-17 13:53:11 -08003280 if (data->abort) {
3281 pr_err("Aborting qseecom driver\n");
3282 return -ENODEV;
3283 }
3284
3285 switch (cmd) {
3286 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003287 if (data->type != QSEECOM_GENERIC) {
3288 pr_err("reg lstnr req: invalid handle (%d)\n",
3289 data->type);
3290 ret = -EINVAL;
3291 break;
3292 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003293 pr_debug("ioctl register_listener_req()\n");
3294 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003295 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003296 ret = qseecom_register_listener(data, argp);
3297 atomic_dec(&data->ioctl_count);
3298 wake_up_all(&data->abort_wq);
3299 if (ret)
3300 pr_err("failed qseecom_register_listener: %d\n", ret);
3301 break;
3302 }
3303 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003304 if ((data->listener.id == 0) ||
3305 (data->type != QSEECOM_LISTENER_SERVICE)) {
3306 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3307 data->type, data->listener.id);
3308 ret = -EINVAL;
3309 break;
3310 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003311 pr_debug("ioctl unregister_listener_req()\n");
3312 atomic_inc(&data->ioctl_count);
3313 ret = qseecom_unregister_listener(data);
3314 atomic_dec(&data->ioctl_count);
3315 wake_up_all(&data->abort_wq);
3316 if (ret)
3317 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3318 break;
3319 }
3320 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003321 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003322 if ((data->client.app_id == 0) ||
3323 (data->type != QSEECOM_CLIENT_APP)) {
3324 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3325 data->type, data->client.app_id);
3326 ret = -EINVAL;
3327 break;
3328 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003329 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003330 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003331 if (qseecom.support_bus_scaling) {
3332 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3333 if (ret) {
3334 pr_err("Failed to set bw.\n");
3335 ret = -EINVAL;
3336 mutex_unlock(&app_access_lock);
3337 break;
3338 }
3339 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003340 atomic_inc(&data->ioctl_count);
3341 ret = qseecom_send_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003342 if (qseecom.support_bus_scaling)
3343 __qseecom_add_bw_scale_down_timer(
3344 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003345 atomic_dec(&data->ioctl_count);
3346 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003347 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003348 if (ret)
3349 pr_err("failed qseecom_send_cmd: %d\n", ret);
3350 break;
3351 }
3352 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003353 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003354 if ((data->client.app_id == 0) ||
3355 (data->type != QSEECOM_CLIENT_APP)) {
3356 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3357 data->type, data->client.app_id);
3358 ret = -EINVAL;
3359 break;
3360 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003361 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003362 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003363 if (qseecom.support_bus_scaling) {
3364 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3365 if (ret) {
3366 pr_err("Failed to set bw.\n");
3367 mutex_unlock(&app_access_lock);
3368 ret = -EINVAL;
3369 break;
3370 }
3371 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003372 atomic_inc(&data->ioctl_count);
3373 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003374 if (qseecom.support_bus_scaling)
3375 __qseecom_add_bw_scale_down_timer(
3376 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge8a02082014-03-11 17:36:50 -07003377 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003378 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003379 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003380 if (ret)
3381 pr_err("failed qseecom_send_cmd: %d\n", ret);
3382 break;
3383 }
3384 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003385 if ((data->listener.id == 0) ||
3386 (data->type != QSEECOM_LISTENER_SERVICE)) {
3387 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3388 data->type, data->listener.id);
3389 ret = -EINVAL;
3390 break;
3391 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003392 atomic_inc(&data->ioctl_count);
3393 ret = qseecom_receive_req(data);
3394 atomic_dec(&data->ioctl_count);
3395 wake_up_all(&data->abort_wq);
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05303396 if (ret && (ret != -ERESTARTSYS))
Mona Hossain2892b6b2012-02-17 13:53:11 -08003397 pr_err("failed qseecom_receive_req: %d\n", ret);
3398 break;
3399 }
3400 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003401 if ((data->listener.id == 0) ||
3402 (data->type != QSEECOM_LISTENER_SERVICE)) {
3403 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3404 data->type, data->listener.id);
3405 ret = -EINVAL;
3406 break;
3407 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003408 atomic_inc(&data->ioctl_count);
3409 ret = qseecom_send_resp();
3410 atomic_dec(&data->ioctl_count);
3411 wake_up_all(&data->abort_wq);
3412 if (ret)
3413 pr_err("failed qseecom_send_resp: %d\n", ret);
3414 break;
3415 }
3416 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003417 if ((data->type != QSEECOM_CLIENT_APP) &&
3418 (data->type != QSEECOM_GENERIC) &&
3419 (data->type != QSEECOM_SECURE_SERVICE)) {
3420 pr_err("set mem param req: invalid handle (%d)\n",
3421 data->type);
3422 ret = -EINVAL;
3423 break;
3424 }
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003425 data->type = QSEECOM_CLIENT_APP;
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003426 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003427 ret = qseecom_set_client_mem_param(data, argp);
3428 if (ret)
3429 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3430 ret);
3431 break;
3432 }
3433 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003434 if ((data->type != QSEECOM_GENERIC) &&
3435 (data->type != QSEECOM_CLIENT_APP)) {
3436 pr_err("load app req: invalid handle (%d)\n",
3437 data->type);
3438 ret = -EINVAL;
3439 break;
3440 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003441 data->type = QSEECOM_CLIENT_APP;
3442 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003443 mutex_lock(&app_access_lock);
3444 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003445 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3446 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003447 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003448 if (ret == 0)
3449 qseecom.commonlib_loaded = true;
3450 }
3451 }
3452 if (ret == 0)
3453 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003454 atomic_dec(&data->ioctl_count);
3455 mutex_unlock(&app_access_lock);
3456 if (ret)
3457 pr_err("failed load_app request: %d\n", ret);
3458 break;
3459 }
3460 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003461 if ((data->client.app_id == 0) ||
3462 (data->type != QSEECOM_CLIENT_APP)) {
3463 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3464 data->type, data->client.app_id);
3465 ret = -EINVAL;
3466 break;
3467 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003468 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003469 mutex_lock(&app_access_lock);
3470 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07003471 ret = qseecom_unload_app(data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003472 atomic_dec(&data->ioctl_count);
3473 mutex_unlock(&app_access_lock);
3474 if (ret)
3475 pr_err("failed unload_app request: %d\n", ret);
3476 break;
3477 }
3478 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3479 atomic_inc(&data->ioctl_count);
3480 ret = qseecom_get_qseos_version(data, argp);
3481 if (ret)
3482 pr_err("qseecom_get_qseos_version: %d\n", ret);
3483 atomic_dec(&data->ioctl_count);
3484 break;
3485 }
3486 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003487 if ((data->type != QSEECOM_GENERIC) &&
3488 (data->type != QSEECOM_CLIENT_APP)) {
3489 pr_err("perf enable req: invalid handle (%d)\n",
3490 data->type);
3491 ret = -EINVAL;
3492 break;
3493 }
3494 if ((data->type == QSEECOM_CLIENT_APP) &&
3495 (data->client.app_id == 0)) {
3496 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3497 data->type, data->client.app_id);
3498 ret = -EINVAL;
3499 break;
3500 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003501 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003502 if (qseecom.support_bus_scaling) {
3503 mutex_lock(&qsee_bw_mutex);
3504 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3505 mutex_unlock(&qsee_bw_mutex);
3506 } else {
3507 ret = qsee_vote_for_clock(data, CLK_DFAB);
3508 if (ret)
3509 pr_err("Fail to vote for DFAB clock%d\n", ret);
3510 ret = qsee_vote_for_clock(data, CLK_SFPB);
3511 if (ret)
3512 pr_err("Fail to vote for SFPB clock%d\n", ret);
3513 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003514 atomic_dec(&data->ioctl_count);
3515 break;
3516 }
3517 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003518 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3519 (data->type != QSEECOM_CLIENT_APP)) {
3520 pr_err("perf disable req: invalid handle (%d)\n",
3521 data->type);
3522 ret = -EINVAL;
3523 break;
3524 }
3525 if ((data->type == QSEECOM_CLIENT_APP) &&
3526 (data->client.app_id == 0)) {
3527 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3528 data->type, data->client.app_id);
3529 ret = -EINVAL;
3530 break;
3531 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003532 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003533 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003534 qsee_disable_clock_vote(data, CLK_DFAB);
3535 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003536 }
3537 atomic_dec(&data->ioctl_count);
3538 break;
3539 }
3540
3541 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3542 if ((data->client.app_id == 0) ||
3543 (data->type != QSEECOM_CLIENT_APP)) {
3544 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3545 data->type, data->client.app_id);
3546 ret = -EINVAL;
3547 break;
3548 }
3549 atomic_inc(&data->ioctl_count);
3550 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003551 atomic_dec(&data->ioctl_count);
3552 break;
3553 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003554 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003555 if (data->type != QSEECOM_GENERIC) {
3556 pr_err("load ext elf req: invalid client handle (%d)\n",
3557 data->type);
3558 ret = -EINVAL;
3559 break;
3560 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003561 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003562 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003563 mutex_lock(&app_access_lock);
3564 atomic_inc(&data->ioctl_count);
3565 ret = qseecom_load_external_elf(data, argp);
3566 atomic_dec(&data->ioctl_count);
3567 mutex_unlock(&app_access_lock);
3568 if (ret)
3569 pr_err("failed load_external_elf request: %d\n", ret);
3570 break;
3571 }
3572 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003573 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3574 pr_err("unload ext elf req: invalid handle (%d)\n",
3575 data->type);
3576 ret = -EINVAL;
3577 break;
3578 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003579 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003580 mutex_lock(&app_access_lock);
3581 atomic_inc(&data->ioctl_count);
3582 ret = qseecom_unload_external_elf(data);
3583 atomic_dec(&data->ioctl_count);
3584 mutex_unlock(&app_access_lock);
3585 if (ret)
3586 pr_err("failed unload_app request: %d\n", ret);
3587 break;
3588 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003589 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003590 data->type = QSEECOM_CLIENT_APP;
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003591 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003592 mutex_lock(&app_access_lock);
3593 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003594 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003595 ret = qseecom_query_app_loaded(data, argp);
3596 atomic_dec(&data->ioctl_count);
3597 mutex_unlock(&app_access_lock);
3598 break;
3599 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003600 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003601 if (data->type != QSEECOM_GENERIC) {
3602 pr_err("send cmd svc req: invalid handle (%d)\n",
3603 data->type);
3604 ret = -EINVAL;
3605 break;
3606 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003607 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003608 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003609 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003610 qseecom.qsee_version);
3611 return -EINVAL;
3612 }
3613 mutex_lock(&app_access_lock);
3614 atomic_inc(&data->ioctl_count);
3615 ret = qseecom_send_service_cmd(data, argp);
3616 atomic_dec(&data->ioctl_count);
3617 mutex_unlock(&app_access_lock);
3618 break;
3619 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003620 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003621 if (!(qseecom.support_pfe || qseecom.support_fde))
3622 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07003623 if (data->type != QSEECOM_GENERIC) {
3624 pr_err("create key req: invalid handle (%d)\n",
3625 data->type);
3626 ret = -EINVAL;
3627 break;
3628 }
Zhen Kong336636e2013-04-15 11:04:54 -07003629 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003630 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003631 qseecom.qsee_version);
3632 return -EINVAL;
3633 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003634 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003635 atomic_inc(&data->ioctl_count);
3636 ret = qseecom_create_key(data, argp);
3637 if (ret)
3638 pr_err("failed to create encryption key: %d\n", ret);
3639
3640 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003641 break;
3642 }
3643 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003644 if (!(qseecom.support_pfe || qseecom.support_fde))
3645 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07003646 if (data->type != QSEECOM_GENERIC) {
3647 pr_err("wipe key req: invalid handle (%d)\n",
3648 data->type);
3649 ret = -EINVAL;
3650 break;
3651 }
Zhen Kong336636e2013-04-15 11:04:54 -07003652 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003653 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003654 qseecom.qsee_version);
3655 return -EINVAL;
3656 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003657 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003658 atomic_inc(&data->ioctl_count);
3659 ret = qseecom_wipe_key(data, argp);
3660 if (ret)
3661 pr_err("failed to wipe encryption key: %d\n", ret);
3662 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003663 break;
3664 }
3665 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003666 if (!(qseecom.support_pfe || qseecom.support_fde))
3667 pr_err("Features requiring key init not supported\n");
Zhen Kong9730ddf2013-12-17 16:49:43 -08003668 if (data->type != QSEECOM_GENERIC) {
3669 pr_err("update key req: invalid handle (%d)\n",
3670 data->type);
3671 ret = -EINVAL;
3672 break;
3673 }
3674 if (qseecom.qsee_version < QSEE_VERSION_05) {
3675 pr_err("Update Key feature unsupported in qsee ver %u\n",
3676 qseecom.qsee_version);
3677 return -EINVAL;
3678 }
3679 data->released = true;
3680 atomic_inc(&data->ioctl_count);
3681 ret = qseecom_update_key_user_info(data, argp);
3682 if (ret)
3683 pr_err("failed to update key user info: %d\n", ret);
3684 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003685 break;
3686 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003687 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003688 if (data->type != QSEECOM_GENERIC) {
3689 pr_err("save part hash req: invalid handle (%d)\n",
3690 data->type);
3691 ret = -EINVAL;
3692 break;
3693 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003694 data->released = true;
3695 mutex_lock(&app_access_lock);
3696 atomic_inc(&data->ioctl_count);
3697 ret = qseecom_save_partition_hash(argp);
3698 atomic_dec(&data->ioctl_count);
3699 mutex_unlock(&app_access_lock);
3700 break;
3701 }
3702 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003703 if (data->type != QSEECOM_GENERIC) {
3704 pr_err("ES activated req: invalid handle (%d)\n",
3705 data->type);
3706 ret = -EINVAL;
3707 break;
3708 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003709 data->released = true;
3710 mutex_lock(&app_access_lock);
3711 atomic_inc(&data->ioctl_count);
3712 ret = qseecom_is_es_activated(argp);
3713 atomic_dec(&data->ioctl_count);
3714 mutex_unlock(&app_access_lock);
3715 break;
3716 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003717 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003718 if ((data->listener.id == 0) ||
3719 (data->type != QSEECOM_LISTENER_SERVICE)) {
3720 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3721 data->type, data->listener.id);
3722 ret = -EINVAL;
3723 break;
3724 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003725 /* Only one client allowed here at a time */
3726 atomic_inc(&data->ioctl_count);
3727 ret = qseecom_send_modfd_resp(data, argp);
3728 atomic_dec(&data->ioctl_count);
3729 wake_up_all(&data->abort_wq);
3730 if (ret)
3731 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3732 break;
3733 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003734 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003735 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003736 return -EINVAL;
3737 }
3738 return ret;
3739}
3740
3741static int qseecom_open(struct inode *inode, struct file *file)
3742{
3743 int ret = 0;
3744 struct qseecom_dev_handle *data;
3745
3746 data = kzalloc(sizeof(*data), GFP_KERNEL);
3747 if (!data) {
3748 pr_err("kmalloc failed\n");
3749 return -ENOMEM;
3750 }
3751 file->private_data = data;
3752 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003753 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003754 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003755 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003756 init_waitqueue_head(&data->abort_wq);
3757 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003758
Mona Hossain2892b6b2012-02-17 13:53:11 -08003759 return ret;
3760}
3761
3762static int qseecom_release(struct inode *inode, struct file *file)
3763{
3764 struct qseecom_dev_handle *data = file->private_data;
3765 int ret = 0;
3766
3767 if (data->released == false) {
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003768 pr_warn("data: released = false, type = %d, data = 0x%x\n",
3769 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003770 switch (data->type) {
3771 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003772 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003773 break;
3774 case QSEECOM_CLIENT_APP:
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07003775 ret = qseecom_unload_app(data, true);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003776 break;
3777 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003778 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003779 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003780 if (ret)
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003781 pr_err("Ion Unmap failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003782 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303783 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3784 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003785 default:
3786 pr_err("Unsupported clnt_handle_type %d",
3787 data->type);
3788 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003789 }
3790 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003791
Zhen Kong2edf90d2013-08-27 12:05:06 -07003792 if (qseecom.support_bus_scaling) {
3793 mutex_lock(&qsee_bw_mutex);
3794 if (data->mode != INACTIVE) {
3795 qseecom_unregister_bus_bandwidth_needs(data);
3796 if (qseecom.cumulative_mode == INACTIVE) {
3797 ret = __qseecom_set_msm_bus_request(INACTIVE);
3798 if (ret)
3799 pr_err("Fail to scale down bus\n");
3800 }
3801 }
3802 mutex_unlock(&qsee_bw_mutex);
3803 } else {
3804 if (data->fast_load_enabled == true)
3805 qsee_disable_clock_vote(data, CLK_SFPB);
3806 if (data->perf_enabled == true)
3807 qsee_disable_clock_vote(data, CLK_DFAB);
3808 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003809 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003810
Mona Hossain2892b6b2012-02-17 13:53:11 -08003811 return ret;
3812}
3813
Mona Hossain2892b6b2012-02-17 13:53:11 -08003814static const struct file_operations qseecom_fops = {
3815 .owner = THIS_MODULE,
3816 .unlocked_ioctl = qseecom_ioctl,
3817 .open = qseecom_open,
3818 .release = qseecom_release
3819};
3820
Mona Hossainc92629e2013-04-01 13:37:46 -07003821static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003822{
3823 int rc = 0;
3824 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003825 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003826 char *core_clk_src = NULL;
3827 char *core_clk = NULL;
3828 char *iface_clk = NULL;
3829 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003830
Mona Hossainc92629e2013-04-01 13:37:46 -07003831 switch (ce) {
3832 case CLK_QSEE: {
3833 core_clk_src = "core_clk_src";
3834 core_clk = "core_clk";
3835 iface_clk = "iface_clk";
3836 bus_clk = "bus_clk";
3837 qclk = &qseecom.qsee;
3838 qclk->instance = CLK_QSEE;
3839 break;
3840 };
3841 case CLK_CE_DRV: {
3842 core_clk_src = "ce_drv_core_clk_src";
3843 core_clk = "ce_drv_core_clk";
3844 iface_clk = "ce_drv_iface_clk";
3845 bus_clk = "ce_drv_bus_clk";
3846 qclk = &qseecom.ce_drv;
3847 qclk->instance = CLK_CE_DRV;
3848 break;
3849 };
3850 default:
3851 pr_err("Invalid ce hw instance: %d!\n", ce);
3852 return -EIO;
3853 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003854 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003855
Mona Hossainc92629e2013-04-01 13:37:46 -07003856 /* Get CE3 src core clk. */
3857 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003858 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003859 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003860 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003861 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003862 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003863 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003864 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003865 }
3866 } else {
3867 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003868 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003869 }
3870
3871 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003872 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003873 if (IS_ERR(qclk->ce_core_clk)) {
3874 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003875 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003876 if (qclk->ce_core_src_clk != NULL)
3877 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003878 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003879 }
3880
3881 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003882 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003883 if (IS_ERR(qclk->ce_clk)) {
3884 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003885 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003886 if (qclk->ce_core_src_clk != NULL)
3887 clk_put(qclk->ce_core_src_clk);
3888 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003889 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003890 }
3891
3892 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003893 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003894 if (IS_ERR(qclk->ce_bus_clk)) {
3895 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003896 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003897 if (qclk->ce_core_src_clk != NULL)
3898 clk_put(qclk->ce_core_src_clk);
3899 clk_put(qclk->ce_core_clk);
3900 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003901 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003902 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003903 return rc;
3904}
3905
Mona Hossainc92629e2013-04-01 13:37:46 -07003906static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003907{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003908 struct qseecom_clk *qclk;
3909
Mona Hossainc92629e2013-04-01 13:37:46 -07003910 if (ce == CLK_QSEE)
3911 qclk = &qseecom.qsee;
3912 else
3913 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003914
3915 if (qclk->ce_clk != NULL) {
3916 clk_put(qclk->ce_clk);
3917 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003918 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003919 if (qclk->ce_core_clk != NULL) {
3920 clk_put(qclk->ce_core_clk);
3921 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003922 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003923 if (qclk->ce_bus_clk != NULL) {
3924 clk_put(qclk->ce_bus_clk);
3925 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003926 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003927 if (qclk->ce_core_src_clk != NULL) {
3928 clk_put(qclk->ce_core_src_clk);
3929 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003930 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003931}
3932
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003933static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003934{
3935 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003936 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003937 struct device *class_dev;
3938 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003939 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003940 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3941
Mona Hossain17a4faf2013-03-22 16:40:56 -07003942 qseecom.qsee_bw_count = 0;
3943 qseecom.qsee_perf_client = 0;
3944 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003945
Mona Hossain17a4faf2013-03-22 16:40:56 -07003946 qseecom.qsee.ce_core_clk = NULL;
3947 qseecom.qsee.ce_clk = NULL;
3948 qseecom.qsee.ce_core_src_clk = NULL;
3949 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003950
Zhen Kong2edf90d2013-08-27 12:05:06 -07003951 qseecom.cumulative_mode = 0;
3952 qseecom.current_mode = INACTIVE;
3953 qseecom.support_bus_scaling = false;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08003954 qseecom.support_fde = false;
3955 qseecom.support_pfe = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003956
Mona Hossainc92629e2013-04-01 13:37:46 -07003957 qseecom.ce_drv.ce_core_clk = NULL;
3958 qseecom.ce_drv.ce_clk = NULL;
3959 qseecom.ce_drv.ce_core_src_clk = NULL;
3960 qseecom.ce_drv.ce_bus_clk = NULL;
3961
Mona Hossain2892b6b2012-02-17 13:53:11 -08003962 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3963 if (rc < 0) {
3964 pr_err("alloc_chrdev_region failed %d\n", rc);
3965 return rc;
3966 }
3967
3968 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3969 if (IS_ERR(driver_class)) {
3970 rc = -ENOMEM;
3971 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303972 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003973 }
3974
3975 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3976 QSEECOM_DEV);
3977 if (!class_dev) {
3978 pr_err("class_device_create failed %d\n", rc);
3979 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303980 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003981 }
3982
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303983 cdev_init(&qseecom.cdev, &qseecom_fops);
3984 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003985
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303986 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003987 if (rc < 0) {
3988 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303989 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003990 }
3991
3992 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3993 spin_lock_init(&qseecom.registered_listener_list_lock);
3994 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3995 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003996 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3997 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003998 init_waitqueue_head(&qseecom.send_resp_wq);
3999 qseecom.send_resp_flag = 0;
4000
4001 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
4002 &qsee_not_legacy, sizeof(qsee_not_legacy));
4003 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07004004 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304005 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004006 }
Mona Hossain05c73562012-10-29 17:49:01 -07004007 if (qsee_not_legacy) {
4008 uint32_t feature = 10;
4009
4010 qseecom.qsee_version = QSEEE_VERSION_00;
4011 rc = scm_call(6, 3, &feature, sizeof(feature),
4012 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
4013 if (rc) {
4014 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304015 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07004016 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004017 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07004018 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07004019 pr_err("QSEE legacy version is not supported:");
4020 pr_err("Support for TZ1.3 and earlier is deprecated\n");
4021 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304022 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004023 }
Mona Hossain05c73562012-10-29 17:49:01 -07004024 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004025 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004026 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07004027 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08004028 if (qseecom.ion_clnt == NULL) {
4029 pr_err("Ion client cannot be created\n");
4030 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304031 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004032 }
4033
4034 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004035 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05304036 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004037 qseecom.support_bus_scaling =
4038 of_property_read_bool((&pdev->dev)->of_node,
4039 "qcom,support-bus-scaling");
4040 pr_warn("support_bus_scaling=0x%x",
4041 qseecom.support_bus_scaling);
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004042 qseecom.support_fde =
4043 of_property_read_bool((&pdev->dev)->of_node,
4044 "qcom,support-fde");
4045 if (qseecom.support_fde) {
4046 if (of_property_read_u32((&pdev->dev)->of_node,
Mona Hossain4cf78a92013-02-14 12:06:41 -08004047 "qcom,disk-encrypt-pipe-pair",
4048 &qseecom.ce_info.disk_encrypt_pipe)) {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004049 pr_err("Fail to get FDE pipe information.\n");
4050 rc = -EINVAL;
4051 goto exit_destroy_ion_client;
4052 } else {
4053 pr_warn("disk-encrypt-pipe-pair=0x%x",
4054 qseecom.ce_info.disk_encrypt_pipe);
4055 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004056 } else {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004057 pr_warn("Device does not support FDE");
4058 qseecom.ce_info.disk_encrypt_pipe = 0xff;
4059 }
4060 qseecom.support_pfe =
4061 of_property_read_bool((&pdev->dev)->of_node,
4062 "qcom,support-pfe");
4063 if (qseecom.support_pfe) {
4064 if (of_property_read_u32((&pdev->dev)->of_node,
4065 "qcom,file-encrypt-pipe-pair",
4066 &qseecom.ce_info.disk_encrypt_pipe)) {
4067 pr_err("Fail to get PFE pipe information.\n");
4068 rc = -EINVAL;
4069 goto exit_destroy_ion_client;
4070 } else {
4071 pr_warn("file-encrypt-pipe-pair=0x%x",
4072 qseecom.ce_info.file_encrypt_pipe);
4073 }
4074 } else {
4075 pr_warn("Device does not support PFE");
4076 qseecom.ce_info.file_encrypt_pipe = 0xff;
4077 }
4078 if (qseecom.support_pfe || qseecom.support_fde) {
4079 if (of_property_read_u32((&pdev->dev)->of_node,
4080 "qcom,hlos-ce-hw-instance",
4081 &qseecom.ce_info.hlos_ce_hw_instance)) {
4082 pr_err("Fail: get hlos ce hw instanc info\n");
4083 rc = -EINVAL;
4084 goto exit_destroy_ion_client;
4085 } else {
4086 pr_warn("hlos-ce-hw-instance=0x%x",
4087 qseecom.ce_info.hlos_ce_hw_instance);
4088 }
4089 } else {
4090 pr_warn("Device does not support PFE/FDE");
4091 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004092 }
4093
4094 if (of_property_read_u32((&pdev->dev)->of_node,
4095 "qcom,qsee-ce-hw-instance",
4096 &qseecom.ce_info.qsee_ce_hw_instance)) {
4097 pr_err("Fail to get qsee ce hw instance information.\n");
Mona Hossain4cf78a92013-02-14 12:06:41 -08004098 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304099 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004100 } else {
4101 pr_warn("qsee-ce-hw-instance=0x%x",
4102 qseecom.ce_info.qsee_ce_hw_instance);
4103 }
4104
Mona Hossainc92629e2013-04-01 13:37:46 -07004105 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
4106 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
4107
4108 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004109 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304110 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08004111
Zhen Konga10dcab2014-03-19 10:32:27 -07004112 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4113 (qseecom.support_pfe || qseecom.support_fde)) {
Mona Hossainc92629e2013-04-01 13:37:46 -07004114 ret = __qseecom_init_clk(CLK_CE_DRV);
4115 if (ret) {
4116 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304117 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07004118 }
4119 } else {
4120 struct qseecom_clk *qclk;
4121
4122 qclk = &qseecom.qsee;
4123 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
4124 qseecom.ce_drv.ce_clk = qclk->ce_clk;
4125 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
4126 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
4127 }
4128
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004129 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4130 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08004131 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
4132 struct resource *resource = NULL;
4133 struct qsee_apps_region_info_ireq req;
4134 struct qseecom_command_scm_resp resp;
4135
4136 resource = platform_get_resource_byname(pdev,
4137 IORESOURCE_MEM, "secapp-region");
4138 if (resource) {
4139 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
4140 req.addr = resource->start;
4141 req.size = resource_size(resource);
4142 pr_warn("secure app region addr=0x%x size=0x%x",
4143 req.addr, req.size);
4144 } else {
4145 pr_err("Fail to get secure app region info\n");
4146 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304147 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004148 }
4149 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
4150 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07004151 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
4152 pr_err("send secapp reg fail %d resp.res %d\n",
4153 rc, resp.result);
4154 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304155 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004156 }
4157 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004158 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004159 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4160 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004161 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004162 if (qseecom.support_bus_scaling) {
4163 init_timer(&(qseecom.bw_scale_down_timer));
4164 INIT_WORK(&qseecom.bw_inactive_req_ws,
4165 qseecom_bw_inactive_req_work);
4166 qseecom.bw_scale_down_timer.function =
4167 qseecom_scale_bus_bandwidth_timer_callback;
4168 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004169 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004170 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004171 qseecom_platform_support);
4172
Mona Hossain17a4faf2013-03-22 16:40:56 -07004173 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004174 pr_err("Unable to register bus client\n");
4175 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304176
4177exit_destroy_ion_client:
4178 ion_client_destroy(qseecom.ion_clnt);
4179exit_del_cdev:
4180 cdev_del(&qseecom.cdev);
4181exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004182 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304183exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004184 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304185exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004186 unregister_chrdev_region(qseecom_device_no, 1);
4187 return rc;
4188}
4189
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004190static int __devinit qseecom_remove(struct platform_device *pdev)
4191{
Mona Hossaind44a3842012-10-15 09:41:35 -07004192 struct qseecom_registered_kclient_list *kclient = NULL;
4193 unsigned long flags = 0;
4194 int ret = 0;
4195
Mona Hossaind44a3842012-10-15 09:41:35 -07004196 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304197
Mona Hossaind44a3842012-10-15 09:41:35 -07004198 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304199 list) {
4200 if (!kclient)
4201 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07004202
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304203 /* Break the loop if client handle is NULL */
4204 if (!kclient->handle)
4205 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004206
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304207 if (list_empty(&kclient->list))
4208 goto exit_free_kc_handle;
4209
4210 list_del(&kclient->list);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004211 ret = qseecom_unload_app(kclient->handle->dev, false);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304212 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004213 kzfree(kclient->handle->dev);
4214 kzfree(kclient->handle);
4215 kzfree(kclient);
4216 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004217 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304218
4219exit_free_kc_handle:
4220 kzfree(kclient->handle);
4221exit_free_kclient:
4222 kzfree(kclient);
4223exit_irqrestore:
4224 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4225
4226 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004227 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004228
Mona Hossain17a4faf2013-03-22 16:40:56 -07004229 if (qseecom.qsee_perf_client)
4230 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4231 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304232 if (pdev->dev.platform_data != NULL)
4233 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4234
Zhen Kong2edf90d2013-08-27 12:05:06 -07004235 if (qseecom.support_bus_scaling) {
4236 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4237 del_timer_sync(&qseecom.bw_scale_down_timer);
4238 }
4239
Mona Hossaind39e33b2012-11-05 13:36:40 -08004240 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004241 if (pdev->dev.of_node) {
4242 __qseecom_deinit_clk(CLK_QSEE);
Zhen Konga10dcab2014-03-19 10:32:27 -07004243 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4244 (qseecom.support_pfe || qseecom.support_fde))
Mona Hossainc92629e2013-04-01 13:37:46 -07004245 __qseecom_deinit_clk(CLK_CE_DRV);
4246 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304247
4248 ion_client_destroy(qseecom.ion_clnt);
4249
4250 cdev_del(&qseecom.cdev);
4251
4252 device_destroy(driver_class, qseecom_device_no);
4253
4254 class_destroy(driver_class);
4255
4256 unregister_chrdev_region(qseecom_device_no, 1);
4257
Mona Hossaind44a3842012-10-15 09:41:35 -07004258 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304259}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004260
Zhen Konga0944b82013-11-06 17:02:00 -08004261static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4262{
4263 int ret = 0;
4264 struct qseecom_clk *qclk;
4265 qclk = &qseecom.qsee;
4266
4267 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004268 ret = msm_bus_scale_client_update_request(
4269 qseecom.qsee_perf_client, INACTIVE);
Zhen Konga0944b82013-11-06 17:02:00 -08004270 if (ret)
4271 pr_err("Fail to scale down bus\n");
4272 }
4273 mutex_lock(&clk_access_lock);
4274 if (qclk->clk_access_cnt) {
4275 if (qclk->ce_clk != NULL)
4276 clk_disable_unprepare(qclk->ce_clk);
4277 if (qclk->ce_core_clk != NULL)
4278 clk_disable_unprepare(qclk->ce_core_clk);
4279 if (qclk->ce_bus_clk != NULL)
4280 clk_disable_unprepare(qclk->ce_bus_clk);
Zhen Kongca4c2d52014-03-12 13:22:46 -07004281 if (qseecom.timer_running) {
4282 del_timer_sync(&(qseecom.bw_scale_down_timer));
4283 qseecom.timer_running = false;
4284 }
Zhen Konga0944b82013-11-06 17:02:00 -08004285 }
4286 mutex_unlock(&clk_access_lock);
4287 return 0;
4288}
4289
4290static int qseecom_resume(struct platform_device *pdev)
4291{
4292 int mode = 0;
4293 int ret = 0;
4294 struct qseecom_clk *qclk;
4295 qclk = &qseecom.qsee;
4296
4297 if (qseecom.cumulative_mode >= HIGH)
4298 mode = HIGH;
4299 else
4300 mode = qseecom.cumulative_mode;
4301
4302 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004303 ret = msm_bus_scale_client_update_request(
Zhen Kong98b0e512014-04-04 10:12:24 -07004304 qseecom.qsee_perf_client, mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004305 if (ret)
Zhen Kong98b0e512014-04-04 10:12:24 -07004306 pr_err("Fail to scale up bus to %d\n", mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004307 }
4308
4309 mutex_lock(&clk_access_lock);
4310 if (qclk->clk_access_cnt) {
4311
4312 ret = clk_prepare_enable(qclk->ce_core_clk);
4313 if (ret) {
4314 pr_err("Unable to enable/prepare CE core clk\n");
4315 qclk->clk_access_cnt = 0;
4316 goto err;
4317 }
4318
4319 ret = clk_prepare_enable(qclk->ce_clk);
4320 if (ret) {
4321 pr_err("Unable to enable/prepare CE iface clk\n");
4322 qclk->clk_access_cnt = 0;
4323 goto ce_clk_err;
4324 }
4325
4326 ret = clk_prepare_enable(qclk->ce_bus_clk);
4327 if (ret) {
4328 pr_err("Unable to enable/prepare CE bus clk\n");
4329 qclk->clk_access_cnt = 0;
4330 goto ce_bus_clk_err;
4331 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07004332 qseecom.bw_scale_down_timer.expires = jiffies +
4333 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
4334 add_timer(&(qseecom.bw_scale_down_timer));
4335 qseecom.timer_running = true;
4336
Zhen Konga0944b82013-11-06 17:02:00 -08004337 }
4338 mutex_unlock(&clk_access_lock);
4339 return 0;
4340
4341ce_bus_clk_err:
4342 clk_disable_unprepare(qclk->ce_clk);
4343ce_clk_err:
4344 clk_disable_unprepare(qclk->ce_core_clk);
4345err:
4346 mutex_unlock(&clk_access_lock);
4347 return -EIO;
4348}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004349static struct of_device_id qseecom_match[] = {
4350 {
4351 .compatible = "qcom,qseecom",
4352 },
4353 {}
4354};
4355
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004356static struct platform_driver qseecom_plat_driver = {
4357 .probe = qseecom_probe,
4358 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004359 .suspend = qseecom_suspend,
4360 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004361 .driver = {
4362 .name = "qseecom",
4363 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004364 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004365 },
4366};
4367
4368static int __devinit qseecom_init(void)
4369{
4370 return platform_driver_register(&qseecom_plat_driver);
4371}
4372
4373static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004374{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304375 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004376}
4377
4378MODULE_LICENSE("GPL v2");
4379MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4380
4381module_init(qseecom_init);
4382module_exit(qseecom_exit);