blob: 23edc8a1c8f9638d4035a342c02b9b8188525cb2 [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);
Zhen Konge5b434e2014-04-17 16:47:06 -0700644 mod_timer(&(qseecom.bw_scale_down_timer),
645 qseecom.bw_scale_down_timer.expires);
Zhen Kongaf950192014-02-05 17:36:23 -0800646 qseecom.timer_running = true;
647 mutex_unlock(&qsee_bw_mutex);
648}
649
Zhen Kong2edf90d2013-08-27 12:05:06 -0700650static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
651{
652 if (!qseecom.support_bus_scaling)
653 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -0800654 else
655 __qseecom_add_bw_scale_down_timer(
656 QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -0700657 return;
658}
659
660static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
661{
662 int ret = 0;
663 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -0700664 ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
665 if (ret)
666 pr_err("Failed to set bw MEDIUM.\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -0700667 } else {
668 ret = qsee_vote_for_clock(data, CLK_SFPB);
669 if (ret)
670 pr_err("Fail vote for clk SFPB ret %d\n", ret);
671 }
672 return ret;
673}
674
Mona Hossain2892b6b2012-02-17 13:53:11 -0800675static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
676 void __user *argp)
677{
678 ion_phys_addr_t pa;
679 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800680 struct qseecom_set_sb_mem_param_req req;
681 uint32_t len;
682
683 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700684 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800685 return -EFAULT;
686
Mona Hossaina1124de2013-10-01 13:41:09 -0700687 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
688 (req.sb_len == 0)) {
689 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
690 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
691 return -EFAULT;
692 }
Zhen Kongf4948192013-11-25 13:05:35 -0800693 if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
694 req.sb_len))
695 return -EFAULT;
696
Mona Hossain2892b6b2012-02-17 13:53:11 -0800697 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800698 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
699 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800700 if (IS_ERR_OR_NULL(data->client.ihandle)) {
701 pr_err("Ion client could not retrieve the handle\n");
702 return -ENOMEM;
703 }
704 /* Get the physical address of the ION BUF */
705 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800706 if (ret) {
707
708 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
709 ret);
710 return ret;
711 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800712 /* Populate the structure for sending scm call to load image */
713 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700714 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800715 data->client.sb_phys = pa;
716 data->client.sb_length = req.sb_len;
717 data->client.user_virt_sb_base = req.virt_sb_base;
718 return 0;
719}
720
Mona Hossain2892b6b2012-02-17 13:53:11 -0800721static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
722{
723 int ret;
724 ret = (qseecom.send_resp_flag != 0);
725 return ret || data->abort;
726}
727
728static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
729 struct qseecom_command_scm_resp *resp)
730{
731 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800732 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800733 uint32_t lstnr;
734 unsigned long flags;
735 struct qseecom_client_listener_data_irsp send_data_rsp;
736 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700737 sigset_t new_sigset;
738 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800739
Mona Hossain2892b6b2012-02-17 13:53:11 -0800740 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
741 lstnr = resp->data;
742 /*
743 * Wake up blocking lsitener service with the lstnr id
744 */
745 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
746 flags);
747 list_for_each_entry(ptr_svc,
748 &qseecom.registered_listener_list_head, list) {
749 if (ptr_svc->svc.listener_id == lstnr) {
750 ptr_svc->rcv_req_flag = 1;
751 wake_up_interruptible(&ptr_svc->rcv_req_wq);
752 break;
753 }
754 }
755 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
756 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700757
758 if (ptr_svc == NULL) {
759 pr_err("Listener Svc %d does not exist\n", lstnr);
760 return -EINVAL;
761 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800762 if (ptr_svc->svc.listener_id != lstnr) {
763 pr_warning("Service requested for does on exist\n");
764 return -ERESTARTSYS;
765 }
766 pr_debug("waking up rcv_req_wq and "
767 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800768
Mona Hossain91da2c52013-03-29 17:28:31 -0700769 /* initialize the new signal mask with all signals*/
770 sigfillset(&new_sigset);
771 /* block all signals */
772 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
773
774 do {
775 if (!wait_event_freezable(qseecom.send_resp_wq,
776 __qseecom_listener_has_sent_rsp(data)))
777 break;
778 } while (1);
779
780 /* restore signal mask */
781 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
782 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700783 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
784 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700785 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800786 send_data_rsp.status = QSEOS_RESULT_FAILURE;
787 } else {
788 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800789 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800790
Mona Hossain2892b6b2012-02-17 13:53:11 -0800791 qseecom.send_resp_flag = 0;
792 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
793 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700794 if (ptr_svc)
795 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
796 ptr_svc->sb_virt, ptr_svc->sb_length,
797 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700798
799 if (lstnr == RPMB_SERVICE)
800 __qseecom_enable_clk(CLK_QSEE);
801
Mona Hossain2892b6b2012-02-17 13:53:11 -0800802 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
803 (const void *)&send_data_rsp,
804 sizeof(send_data_rsp), resp,
805 sizeof(*resp));
806 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700807 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800808 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700809 if (lstnr == RPMB_SERVICE)
810 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800811 return ret;
812 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800813 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
814 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
815 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
816 resp->result, data->client.app_id, lstnr);
817 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700818 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700819 if (lstnr == RPMB_SERVICE)
820 __qseecom_disable_clk(CLK_QSEE);
821
Mona Hossain2892b6b2012-02-17 13:53:11 -0800822 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800823 if (rc)
824 return rc;
825
Mona Hossain2892b6b2012-02-17 13:53:11 -0800826 return ret;
827}
828
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700829static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
830{
831 int32_t ret;
832 struct qseecom_command_scm_resp resp;
833
834 /* SCM_CALL to check if app_id for the mentioned app exists */
835 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
836 sizeof(struct qseecom_check_app_ireq),
837 &resp, sizeof(resp));
838 if (ret) {
839 pr_err("scm_call to check if app is already loaded failed\n");
840 return -EINVAL;
841 }
842
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700843 if (resp.result == QSEOS_RESULT_FAILURE) {
844 return 0;
845 } else {
846 switch (resp.resp_type) {
847 /*qsee returned listener type response */
848 case QSEOS_LISTENER_ID:
849 pr_err("resp type is of listener type instead of app");
850 return -EINVAL;
851 break;
852 case QSEOS_APP_ID:
853 return resp.data;
854 default:
855 pr_err("invalid resp type (%d) from qsee",
856 resp.resp_type);
857 return -ENODEV;
858 break;
859 }
860 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700861}
862
Mona Hossain2892b6b2012-02-17 13:53:11 -0800863static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
864{
865 struct qseecom_registered_app_list *entry = NULL;
866 unsigned long flags = 0;
867 u32 app_id = 0;
868 struct ion_handle *ihandle; /* Ion handle */
869 struct qseecom_load_img_req load_img_req;
Zhen Kong2edf90d2013-08-27 12:05:06 -0700870 int32_t ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800871 ion_phys_addr_t pa = 0;
872 uint32_t len;
873 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800874 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700875 struct qseecom_load_app_ireq load_req;
876
Mona Hossain2892b6b2012-02-17 13:53:11 -0800877 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700878 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800879 (void __user *)argp,
880 sizeof(struct qseecom_load_img_req))) {
881 pr_err("copy_from_user failed\n");
882 return -EFAULT;
883 }
Zhen Kong4bead3c2014-04-14 15:07:13 -0700884
885 if (qseecom.support_bus_scaling) {
886 mutex_lock(&qsee_bw_mutex);
887 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
888 mutex_unlock(&qsee_bw_mutex);
889 if (ret)
890 return ret;
891 }
892
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700893 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -0700894 ret = __qseecom_enable_clk_scale_up(data);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700895 if (ret)
Zhen Kong4bead3c2014-04-14 15:07:13 -0700896 goto enable_clk_err;
897
Mona Hossain436b75f2012-11-20 17:10:40 -0800898 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700899 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800900 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800901
Mona Hossain436b75f2012-11-20 17:10:40 -0800902 ret = __qseecom_check_app_exists(req);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700903 if (ret < 0)
904 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800905
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530906 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800907 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700908 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800909 (char *)(req.app_name));
910 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
911 list_for_each_entry(entry,
912 &qseecom.registered_app_list_head, list){
913 if (entry->app_id == app_id) {
914 entry->ref_cnt++;
915 break;
916 }
917 }
918 spin_unlock_irqrestore(
919 &qseecom.registered_app_list_lock, flags);
920 } else {
921 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700922 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800923 /* Get the handle of the shared fd */
924 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800925 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800926 if (IS_ERR_OR_NULL(ihandle)) {
927 pr_err("Ion client could not retrieve the handle\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -0700928 ret = -ENOMEM;
929 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800930 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800931
Mona Hossain436b75f2012-11-20 17:10:40 -0800932 /* Get the physical address of the ION BUF */
933 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -0800934 if (ret) {
935 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
936 ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700937 goto loadapp_err;
Zhen Kong05ed4462014-01-28 18:21:30 -0800938 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800939
Mona Hossain436b75f2012-11-20 17:10:40 -0800940 /* Populate the structure for sending scm call to load image */
941 memcpy(load_req.app_name, load_img_req.img_name,
942 MAX_APP_NAME_SIZE);
943 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
944 load_req.mdt_len = load_img_req.mdt_len;
945 load_req.img_len = load_img_req.img_len;
946 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700947 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
948 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800949
Mona Hossain436b75f2012-11-20 17:10:40 -0800950 /* SCM_CALL to load the app and get the app_id back */
951 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700952 sizeof(struct qseecom_load_app_ireq),
953 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700954 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800955 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800956 if (!IS_ERR_OR_NULL(ihandle))
957 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700958 ret = -EINVAL;
959 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800960 }
961
962 if (resp.result == QSEOS_RESULT_FAILURE) {
963 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700964 if (!IS_ERR_OR_NULL(ihandle))
965 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700966 ret = -EFAULT;
967 goto loadapp_err;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700968 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700969
Mona Hossain436b75f2012-11-20 17:10:40 -0800970 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
971 ret = __qseecom_process_incomplete_cmd(data, &resp);
972 if (ret) {
973 pr_err("process_incomplete_cmd failed err: %d\n",
974 ret);
975 if (!IS_ERR_OR_NULL(ihandle))
976 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700977 ret = -EFAULT;
978 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800979 }
980 }
981
982 if (resp.result != QSEOS_RESULT_SUCCESS) {
983 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700984 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800985 if (!IS_ERR_OR_NULL(ihandle))
986 ion_free(qseecom.ion_clnt, ihandle);
Zhen Kong4bead3c2014-04-14 15:07:13 -0700987 ret = -EFAULT;
988 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800989 }
990
991 app_id = resp.data;
992
993 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
994 if (!entry) {
995 pr_err("kmalloc failed\n");
Zhen Kong4bead3c2014-04-14 15:07:13 -0700996 ret = -ENOMEM;
997 goto loadapp_err;
Mona Hossain436b75f2012-11-20 17:10:40 -0800998 }
999 entry->app_id = app_id;
1000 entry->ref_cnt = 1;
1001
1002 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001003 if (!IS_ERR_OR_NULL(ihandle))
1004 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001005
Mona Hossain436b75f2012-11-20 17:10:40 -08001006 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1007 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1008 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1009 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07001010
Mona Hossain436b75f2012-11-20 17:10:40 -08001011 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -07001012 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -08001013 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001014 data->client.app_id = app_id;
1015 load_img_req.app_id = app_id;
1016 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
1017 pr_err("copy_to_user failed\n");
1018 kzfree(entry);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001019 ret = -EFAULT;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001020 }
Zhen Kong4bead3c2014-04-14 15:07:13 -07001021
1022loadapp_err:
Zhen Kong2edf90d2013-08-27 12:05:06 -07001023 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001024enable_clk_err:
1025 if (qseecom.support_bus_scaling) {
1026 mutex_lock(&qsee_bw_mutex);
1027 qseecom_unregister_bus_bandwidth_needs(data);
1028 mutex_unlock(&qsee_bw_mutex);
1029 }
1030 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001031}
1032
1033static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
1034{
1035 wake_up_all(&qseecom.send_resp_wq);
1036 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001037 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001038 atomic_read(&data->ioctl_count) <= 1)) {
1039 pr_err("Interrupted from abort\n");
1040 return -ERESTARTSYS;
1041 break;
1042 }
1043 }
1044 /* Set unload app */
1045 return 1;
1046}
1047
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001048static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
1049{
1050 int ret = 0;
1051 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
1052 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
1053 ion_free(qseecom.ion_clnt, data->client.ihandle);
1054 data->client.ihandle = NULL;
1055 }
1056 return ret;
1057}
1058
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001059static int qseecom_unload_app(struct qseecom_dev_handle *data,
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001060 bool app_crash)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001061{
1062 unsigned long flags;
1063 int ret = 0;
1064 struct qseecom_command_scm_resp resp;
1065 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -07001066 bool unload = false;
1067 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001068
Mona Hossaind4613de2013-05-15 16:49:29 -07001069 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001070 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1071 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001072 list) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001073 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -07001074 found_app = true;
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07001075 if (app_crash) {
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001076 ptr_app->ref_cnt = 0;
Mona Hossain340dba82012-08-07 19:54:46 -07001077 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001078 break;
1079 } else {
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001080 if (ptr_app->ref_cnt == 1) {
1081 unload = true;
1082 break;
1083 } else {
1084 ptr_app->ref_cnt--;
1085 pr_debug("Can't unload app(%d) inuse\n",
1086 ptr_app->app_id);
1087 break;
1088 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001089 }
1090 }
1091 }
1092 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1093 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001094 if (found_app == false) {
1095 pr_err("Cannot find app with id = %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001096 data->client.app_id);
Mona Hossain1fb538f2012-08-30 16:19:38 -07001097 return -EINVAL;
1098 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001099 }
1100
Mona Hossaind4613de2013-05-15 16:49:29 -07001101 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -08001102 struct qseecom_unload_app_ireq req;
1103
Mona Hossain340dba82012-08-07 19:54:46 -07001104 __qseecom_cleanup_app(data);
1105 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1106 list_del(&ptr_app->list);
1107 kzfree(ptr_app);
1108 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1109 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001110 /* Populate the structure for sending scm call to load image */
1111 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
1112 req.app_id = data->client.app_id;
1113
1114 /* SCM_CALL to unload the app */
1115 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
1116 sizeof(struct qseecom_unload_app_ireq),
1117 &resp, sizeof(resp));
1118 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -07001119 pr_err("scm_call to unload app (id = %d) failed\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001120 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001121 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -07001122 } else {
1123 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001124 }
1125 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1126 ret = __qseecom_process_incomplete_cmd(data, &resp);
1127 if (ret) {
1128 pr_err("process_incomplete_cmd fail err: %d\n",
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07001129 ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001130 return ret;
1131 }
1132 }
1133 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001134 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001135 data->released = true;
1136 return ret;
1137}
1138
1139static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
1140 uint32_t virt)
1141{
1142 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
1143}
1144
Zhen Kongf4948192013-11-25 13:05:35 -08001145static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
1146 uint32_t virt)
1147{
1148 return (uint32_t)data->client.sb_virt +
1149 (virt - data->client.user_virt_sb_base);
1150}
1151
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001152int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
1153 struct qseecom_send_svc_cmd_req *req_ptr,
1154 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
1155{
1156 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001157 void *req_buf = NULL;
1158
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001159 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
1160 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
1161 req_ptr, send_svc_ireq_ptr);
1162 return -EINVAL;
1163 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001164
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -08001165 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
1166 pr_err("Invalid req/resp buffer, exiting\n");
1167 return -EINVAL;
1168 }
1169
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001170 /* Clients need to ensure req_buf is at base offset of shared buffer */
1171 if ((uint32_t)req_ptr->cmd_req_buf !=
1172 data_ptr->client.user_virt_sb_base) {
1173 pr_err("cmd buf not pointing to base offset of shared buffer\n");
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001174 return -EINVAL;
1175 }
1176
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001177 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
1178 || ((uint32_t)req_ptr->resp_buf >=
1179 (data_ptr->client.user_virt_sb_base +
1180 data_ptr->client.sb_length))){
1181 pr_err("response buffer address not within shared bufffer\n");
1182 return -EINVAL;
1183 }
1184
1185 req_buf = data_ptr->client.sb_virt;
1186
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001187 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
1188 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -07001189 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001190 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
1191 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
1192 (uint32_t)req_ptr->resp_buf));
1193 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
1194
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001195 return ret;
1196}
1197
1198static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
1199 void __user *argp)
1200{
1201 int ret = 0;
1202 struct qseecom_client_send_service_ireq send_svc_ireq;
1203 struct qseecom_command_scm_resp resp;
1204 struct qseecom_send_svc_cmd_req req;
1205 /*struct qseecom_command_scm_resp resp;*/
1206
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07001207 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001208 (void __user *)argp,
1209 sizeof(req))) {
1210 pr_err("copy_from_user failed\n");
1211 return -EFAULT;
1212 }
1213
1214 if (req.resp_buf == NULL) {
1215 pr_err("cmd buffer or response buffer is null\n");
1216 return -EINVAL;
1217 }
1218
Hariprasad Dhalinarasimha4b61e2a2014-02-12 19:43:02 -08001219 if (data->client.sb_virt == NULL) {
1220 pr_err("sb_virt null\n");
1221 return -EINVAL;
1222 }
1223
1224 if (data->client.user_virt_sb_base == 0) {
1225 pr_err("user_virt_sb_base is null\n");
1226 return -EINVAL;
1227 }
1228
1229 if (data->client.sb_length == 0) {
1230 pr_err("sb_length is 0\n");
1231 return -EINVAL;
1232 }
1233
Zhen Kong2edf90d2013-08-27 12:05:06 -07001234 data->type = QSEECOM_SECURE_SERVICE;
1235
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001236 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -07001237 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
1238 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001239 if (__qseecom_process_rpmb_svc_cmd(data, &req,
1240 &send_svc_ireq))
1241 return -EINVAL;
1242 break;
1243 default:
1244 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
1245 return -EINVAL;
1246 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301247
Zhen Kong2edf90d2013-08-27 12:05:06 -07001248 if (qseecom.support_bus_scaling) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001249 ret = qseecom_scale_bus_bandwidth_timer(HIGH);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001250 if (ret) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07001251 pr_err("Fail to set bw HIGH\n");
Zhen Kong2edf90d2013-08-27 12:05:06 -07001252 return ret;
1253 }
1254 } else {
1255 ret = qsee_vote_for_clock(data, CLK_DFAB);
1256 if (ret) {
1257 pr_err("Failed to vote for DFAB clock%d\n", ret);
1258 return ret;
1259 }
1260 ret = qsee_vote_for_clock(data, CLK_SFPB);
1261 if (ret) {
1262 qsee_disable_clock_vote(data, CLK_DFAB);
1263 pr_err("Failed to vote for SFPB clock%d\n", ret);
1264 goto exit;
1265 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +05301266 }
1267
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001268 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1269 data->client.sb_virt, data->client.sb_length,
1270 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001271 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
1272 sizeof(send_svc_ireq),
1273 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001274 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1275 data->client.sb_virt, data->client.sb_length,
1276 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001277 if (ret) {
1278 pr_err("qseecom_scm_call failed with err: %d\n", ret);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001279 if (!qseecom.support_bus_scaling) {
1280 qsee_disable_clock_vote(data, CLK_DFAB);
1281 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Kongaf950192014-02-05 17:36:23 -08001282 } else {
1283 __qseecom_add_bw_scale_down_timer(
1284 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Kong2edf90d2013-08-27 12:05:06 -07001285 }
1286 goto exit;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001287 }
1288
1289 switch (resp.result) {
1290 case QSEOS_RESULT_SUCCESS:
1291 break;
1292 case QSEOS_RESULT_INCOMPLETE:
1293 pr_err("qseos_result_incomplete\n");
1294 ret = __qseecom_process_incomplete_cmd(data, &resp);
1295 if (ret) {
1296 pr_err("process_incomplete_cmd fail: err: %d\n",
1297 ret);
1298 }
1299 break;
1300 case QSEOS_RESULT_FAILURE:
1301 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1302 break;
1303 default:
1304 pr_err("Response result %d not supported\n",
1305 resp.result);
1306 ret = -EINVAL;
1307 break;
1308 }
Zhen Kongaf950192014-02-05 17:36:23 -08001309 if (!qseecom.support_bus_scaling) {
1310 qsee_disable_clock_vote(data, CLK_DFAB);
1311 qsee_disable_clock_vote(data, CLK_SFPB);
1312 } else {
1313 __qseecom_add_bw_scale_down_timer(
1314 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
1315 }
1316
Zhen Kong2edf90d2013-08-27 12:05:06 -07001317exit:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001318 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001319}
1320
Mona Hossain2892b6b2012-02-17 13:53:11 -08001321static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1322 struct qseecom_send_cmd_req *req)
1323{
1324 int ret = 0;
1325 u32 reqd_len_sb_in = 0;
1326 struct qseecom_client_send_data_ireq send_data_req;
1327 struct qseecom_command_scm_resp resp;
1328
1329 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1330 pr_err("cmd buffer or response buffer is null\n");
1331 return -EINVAL;
1332 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001333 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1334 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1335 data->client.sb_length))) {
1336 pr_err("cmd buffer address not within shared bufffer\n");
1337 return -EINVAL;
1338 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001339
Mona Hossaindddf4442013-10-01 14:08:20 -07001340
1341 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1342 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1343 data->client.sb_length))){
1344 pr_err("response buffer address not within shared bufffer\n");
1345 return -EINVAL;
1346 }
1347
1348 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001349 req->cmd_req_len > data->client.sb_length ||
1350 req->resp_len > data->client.sb_length) {
1351 pr_err("cmd buffer length or "
1352 "response buffer length not valid\n");
1353 return -EINVAL;
1354 }
1355
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001356 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1357 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1358 return -EINVAL;
1359 }
1360
Mona Hossain2892b6b2012-02-17 13:53:11 -08001361 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1362 if (reqd_len_sb_in > data->client.sb_length) {
1363 pr_debug("Not enough memory to fit cmd_buf and "
1364 "resp_buf. Required: %u, Available: %u\n",
1365 reqd_len_sb_in, data->client.sb_length);
1366 return -ENOMEM;
1367 }
1368
1369 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1370 send_data_req.app_id = data->client.app_id;
1371 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1372 (uint32_t)req->cmd_req_buf));
1373 send_data_req.req_len = req->cmd_req_len;
1374 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1375 (uint32_t)req->resp_buf));
1376 send_data_req.rsp_len = req->resp_len;
1377
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001378 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1379 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001380 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001381 ION_IOC_CLEAN_INV_CACHES);
1382
Mona Hossain2892b6b2012-02-17 13:53:11 -08001383 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1384 sizeof(send_data_req),
1385 &resp, sizeof(resp));
1386 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001387 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1388 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001389 return ret;
1390 }
1391
1392 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1393 ret = __qseecom_process_incomplete_cmd(data, &resp);
1394 if (ret) {
1395 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1396 return ret;
1397 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001398 } else {
1399 if (resp.result != QSEOS_RESULT_SUCCESS) {
1400 pr_err("Response result %d not supported\n",
1401 resp.result);
1402 ret = -EINVAL;
1403 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001404 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001405 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1406 data->client.sb_virt, data->client.sb_length,
1407 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001408 return ret;
1409}
1410
Mona Hossain2892b6b2012-02-17 13:53:11 -08001411static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1412{
1413 int ret = 0;
1414 struct qseecom_send_cmd_req req;
1415
1416 ret = copy_from_user(&req, argp, sizeof(req));
1417 if (ret) {
1418 pr_err("copy_from_user failed\n");
1419 return ret;
1420 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001421 ret = __qseecom_send_cmd(data, &req);
1422
Mona Hossain2892b6b2012-02-17 13:53:11 -08001423 if (ret)
1424 return ret;
1425
Mona Hossain2892b6b2012-02-17 13:53:11 -08001426 return ret;
1427}
1428
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001429static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1430 struct qseecom_dev_handle *data,
1431 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001432{
1433 struct ion_handle *ihandle;
1434 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001435 int ret = 0;
1436 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001437 uint32_t len = 0;
1438 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001439 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1440 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1441 struct qseecom_registered_listener_list *this_lstnr = NULL;
1442
1443 if (msg == NULL) {
1444 pr_err("Invalid address\n");
1445 return -EINVAL;
1446 }
1447 if (listener_svc) {
1448 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1449 this_lstnr = __qseecom_find_svc(data->listener.id);
1450 if (IS_ERR_OR_NULL(this_lstnr)) {
1451 pr_err("Invalid listener ID\n");
1452 return -ENOMEM;
1453 }
1454 } else {
1455 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1456 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001457
1458 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001459 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001460 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001461 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001462 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001463 if (IS_ERR_OR_NULL(ihandle)) {
1464 pr_err("Ion client can't retrieve the handle\n");
1465 return -ENOMEM;
1466 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001467 field = (char *) cmd_req->cmd_req_buf +
1468 cmd_req->ifd_data[i].cmd_buf_offset;
1469 } else if ((listener_svc) &&
1470 (lstnr_resp->ifd_data[i].fd > 0)) {
1471 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1472 lstnr_resp->ifd_data[i].fd);
1473 if (IS_ERR_OR_NULL(ihandle)) {
1474 pr_err("Ion client can't retrieve the handle\n");
1475 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001476 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001477 field = lstnr_resp->resp_buf_ptr +
1478 lstnr_resp->ifd_data[i].cmd_buf_offset;
1479 } else {
1480 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001481 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001482 /* Populate the cmd data structure with the phys_addr */
1483 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1484 if (sg_ptr == NULL) {
1485 pr_err("IOn client could not retrieve sg table\n");
1486 goto err;
1487 }
1488 if (sg_ptr->nents == 0) {
1489 pr_err("Num of scattered entries is 0\n");
1490 goto err;
1491 }
1492 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1493 pr_err("Num of scattered entries");
1494 pr_err(" (%d) is greater than max supported %d\n",
1495 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1496 goto err;
1497 }
1498 sg = sg_ptr->sgl;
1499 if (sg_ptr->nents == 1) {
1500 uint32_t *update;
1501 update = (uint32_t *) field;
1502 if (cleanup)
1503 *update = 0;
1504 else
1505 *update = (uint32_t)sg_dma_address(
1506 sg_ptr->sgl);
1507 len += (uint32_t)sg->length;
1508 } else {
1509 struct qseecom_sg_entry *update;
1510 int j = 0;
1511 update = (struct qseecom_sg_entry *) field;
1512 for (j = 0; j < sg_ptr->nents; j++) {
1513 if (cleanup) {
1514 update->phys_addr = 0;
1515 update->len = 0;
1516 } else {
1517 update->phys_addr = (uint32_t)
1518 sg_dma_address(sg);
1519 update->len = sg->length;
1520 }
1521 len += sg->length;
1522 update++;
1523 sg = sg_next(sg);
1524 }
1525 }
1526 if (cleanup)
1527 msm_ion_do_cache_op(qseecom.ion_clnt,
1528 ihandle, NULL, len,
1529 ION_IOC_INV_CACHES);
1530 else
1531 msm_ion_do_cache_op(qseecom.ion_clnt,
1532 ihandle, NULL, len,
1533 ION_IOC_CLEAN_INV_CACHES);
1534 /* Deallocate the handle */
1535 if (!IS_ERR_OR_NULL(ihandle))
1536 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001537 }
1538 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001539err:
1540 if (!IS_ERR_OR_NULL(ihandle))
1541 ion_free(qseecom.ion_clnt, ihandle);
1542 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001543}
1544
1545static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1546 void __user *argp)
1547{
1548 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001549 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001550 struct qseecom_send_modfd_cmd_req req;
1551 struct qseecom_send_cmd_req send_cmd_req;
1552
1553 ret = copy_from_user(&req, argp, sizeof(req));
1554 if (ret) {
1555 pr_err("copy_from_user failed\n");
1556 return ret;
1557 }
Zhen Kongf4948192013-11-25 13:05:35 -08001558
1559 if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
1560 pr_err("cmd buffer or response buffer is null\n");
1561 return -EINVAL;
1562 }
1563 if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
1564 ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
1565 data->client.sb_length))) {
1566 pr_err("cmd buffer address not within shared bufffer\n");
1567 return -EINVAL;
1568 }
1569
1570 if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
1571 ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
1572 data->client.sb_length))){
1573 pr_err("response buffer address not within shared bufffer\n");
1574 return -EINVAL;
1575 }
Zhen Konga69c16e2014-03-27 12:44:15 -07001576
1577 if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
1578 req.resp_len > data->client.sb_length) {
1579 pr_err("cmd or response buffer length not valid\n");
1580 return -EINVAL;
1581 }
1582
Mona Hossain2892b6b2012-02-17 13:53:11 -08001583 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1584 send_cmd_req.cmd_req_len = req.cmd_req_len;
1585 send_cmd_req.resp_buf = req.resp_buf;
1586 send_cmd_req.resp_len = req.resp_len;
1587
Mona Hossaindddf4442013-10-01 14:08:20 -07001588 /* validate offsets */
1589 for (i = 0; i < MAX_ION_FD; i++) {
1590 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1591 pr_err("Invalid offset %d = 0x%x\n",
1592 i, req.ifd_data[i].cmd_buf_offset);
1593 return -EINVAL;
1594 }
1595 }
Zhen Kongf4948192013-11-25 13:05:35 -08001596 req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1597 (uint32_t)req.cmd_req_buf);
1598 req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
1599 (uint32_t)req.resp_buf);
1600
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001601 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001602 if (ret)
1603 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001604 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001605 if (ret)
1606 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001607 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001608 if (ret)
1609 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001610
Mona Hossain2892b6b2012-02-17 13:53:11 -08001611 return ret;
1612}
1613
1614static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1615 struct qseecom_registered_listener_list *svc)
1616{
1617 int ret;
1618 ret = (svc->rcv_req_flag != 0);
1619 return ret || data->abort;
1620}
1621
1622static int qseecom_receive_req(struct qseecom_dev_handle *data)
1623{
1624 int ret = 0;
1625 struct qseecom_registered_listener_list *this_lstnr;
1626
1627 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301628 if (!this_lstnr) {
1629 pr_err("Invalid listener ID\n");
1630 return -ENODATA;
1631 }
1632
Mona Hossain2892b6b2012-02-17 13:53:11 -08001633 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001634 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001635 __qseecom_listener_has_rcvd_req(data,
1636 this_lstnr))) {
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05301637 pr_debug("Interrupted: exiting Listener Service = %d\n",
Mona Hossain17a4faf2013-03-22 16:40:56 -07001638 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001639 /* woken up for different reason */
1640 return -ERESTARTSYS;
1641 }
1642
1643 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001644 pr_err("Aborting Listener Service = %d\n",
1645 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001646 return -ENODEV;
1647 }
1648 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001649 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001650 }
1651 return ret;
1652}
1653
Mona Hossaind44a3842012-10-15 09:41:35 -07001654static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1655{
1656 struct elf32_hdr *ehdr;
1657
1658 if (fw_entry->size < sizeof(*ehdr)) {
1659 pr_err("%s: Not big enough to be an elf header\n",
1660 qseecom.pdev->init_name);
1661 return false;
1662 }
1663 ehdr = (struct elf32_hdr *)fw_entry->data;
1664 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1665 pr_err("%s: Not an elf header\n",
1666 qseecom.pdev->init_name);
1667 return false;
1668 }
1669
1670 if (ehdr->e_phnum == 0) {
1671 pr_err("%s: No loadable segments\n",
1672 qseecom.pdev->init_name);
1673 return false;
1674 }
1675 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1676 sizeof(struct elf32_hdr) > fw_entry->size) {
1677 pr_err("%s: Program headers not within mdt\n",
1678 qseecom.pdev->init_name);
1679 return false;
1680 }
1681 return true;
1682}
1683
1684static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1685{
1686 int ret = -1;
1687 int i = 0, rc = 0;
1688 const struct firmware *fw_entry = NULL;
1689 struct elf32_phdr *phdr;
1690 char fw_name[MAX_APP_NAME_SIZE];
1691 struct elf32_hdr *ehdr;
1692 int num_images = 0;
1693
1694 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1695 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1696 if (rc) {
1697 pr_err("error with request_firmware\n");
1698 ret = -EIO;
1699 goto err;
1700 }
1701 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1702 ret = -EIO;
1703 goto err;
1704 }
1705 *fw_size = fw_entry->size;
1706 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1707 ehdr = (struct elf32_hdr *)fw_entry->data;
1708 num_images = ehdr->e_phnum;
1709 release_firmware(fw_entry);
1710 for (i = 0; i < num_images; i++, phdr++) {
1711 memset(fw_name, 0, sizeof(fw_name));
1712 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1713 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1714 if (ret)
1715 goto err;
1716 *fw_size += fw_entry->size;
1717 release_firmware(fw_entry);
1718 }
1719 return ret;
1720err:
1721 if (fw_entry)
1722 release_firmware(fw_entry);
1723 *fw_size = 0;
1724 return ret;
1725}
1726
1727static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1728 struct qseecom_load_app_ireq *load_req)
1729{
1730 int ret = -1;
1731 int i = 0, rc = 0;
1732 const struct firmware *fw_entry = NULL;
1733 char fw_name[MAX_APP_NAME_SIZE];
1734 u8 *img_data_ptr = img_data;
1735 struct elf32_hdr *ehdr;
1736 int num_images = 0;
1737
1738 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1739 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1740 if (rc) {
1741 ret = -EIO;
1742 goto err;
1743 }
1744 load_req->img_len = fw_entry->size;
1745 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1746 img_data_ptr = img_data_ptr + fw_entry->size;
1747 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1748 ehdr = (struct elf32_hdr *)fw_entry->data;
1749 num_images = ehdr->e_phnum;
1750 release_firmware(fw_entry);
1751 for (i = 0; i < num_images; i++) {
1752 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1753 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1754 if (ret) {
1755 pr_err("Failed to locate blob %s\n", fw_name);
1756 goto err;
1757 }
1758 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1759 img_data_ptr = img_data_ptr + fw_entry->size;
1760 load_req->img_len += fw_entry->size;
1761 release_firmware(fw_entry);
1762 }
1763 load_req->phy_addr = virt_to_phys(img_data);
1764 return ret;
1765err:
1766 release_firmware(fw_entry);
1767 return ret;
1768}
1769
1770static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1771{
1772 int ret = -1;
1773 uint32_t fw_size = 0;
1774 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1775 struct qseecom_command_scm_resp resp;
1776 u8 *img_data = NULL;
1777
1778 if (__qseecom_get_fw_size(appname, &fw_size))
1779 return -EIO;
1780
1781 img_data = kzalloc(fw_size, GFP_KERNEL);
1782 if (!img_data) {
1783 pr_err("Failied to allocate memory for copying image data\n");
1784 return -ENOMEM;
1785 }
1786 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1787 if (ret) {
1788 kzfree(img_data);
1789 return -EIO;
1790 }
1791
1792 /* Populate the remaining parameters */
1793 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1794 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001795
1796 if (qseecom.support_bus_scaling) {
1797 mutex_lock(&qsee_bw_mutex);
1798 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
1799 mutex_unlock(&qsee_bw_mutex);
1800 if (ret) {
1801 kzfree(img_data);
1802 return ret;
1803 }
1804 }
1805
Zhen Kong2edf90d2013-08-27 12:05:06 -07001806 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001807 if (ret) {
1808 kzfree(img_data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001809 ret = -EIO;
1810 goto loadfw_err;
Mona Hossain60f9fb02012-11-05 13:51:50 -08001811 }
1812
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001813 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001814 /* SCM_CALL to load the image */
1815 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1816 sizeof(struct qseecom_load_app_ireq),
1817 &resp, sizeof(resp));
1818 kzfree(img_data);
1819 if (ret) {
1820 pr_err("scm_call to load failed : ret %d\n", ret);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001821 ret = -EIO;
1822 goto loadfw_err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001823 }
1824
1825 switch (resp.result) {
1826 case QSEOS_RESULT_SUCCESS:
1827 ret = resp.data;
1828 break;
1829 case QSEOS_RESULT_INCOMPLETE:
1830 ret = __qseecom_process_incomplete_cmd(data, &resp);
1831 if (ret)
1832 pr_err("process_incomplete_cmd FAILED\n");
1833 else
1834 ret = resp.data;
1835 break;
1836 case QSEOS_RESULT_FAILURE:
1837 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1838 break;
1839 default:
1840 pr_err("scm call return unknown response %d\n", resp.result);
1841 ret = -EINVAL;
1842 break;
1843 }
Mona Hossain60f9fb02012-11-05 13:51:50 -08001844
Zhen Kong4bead3c2014-04-14 15:07:13 -07001845loadfw_err:
1846 __qseecom_disable_clk_scale_down(data);
1847 if (qseecom.support_bus_scaling) {
1848 mutex_lock(&qsee_bw_mutex);
1849 qseecom_unregister_bus_bandwidth_needs(data);
1850 mutex_unlock(&qsee_bw_mutex);
1851 }
Mona Hossaind44a3842012-10-15 09:41:35 -07001852 return ret;
1853}
1854
Mona Hossain9498f5e2013-01-23 18:08:45 -08001855static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001856{
Zhen Kongc46b5842013-12-12 13:09:16 +05301857 int ret = 0;
Zhen Kongfd64c982013-12-19 16:35:43 -08001858 int len = 0;
Mona Hossain05c73562012-10-29 17:49:01 -07001859 uint32_t fw_size = 0;
1860 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1861 struct qseecom_command_scm_resp resp;
1862 u8 *img_data = NULL;
Zhen Kongfd64c982013-12-19 16:35:43 -08001863 ion_phys_addr_t pa;
Mona Hossain05c73562012-10-29 17:49:01 -07001864
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001865 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001866 return -EIO;
1867
Zhen Kongc46b5842013-12-12 13:09:16 +05301868 qseecom.cmnlib_ion_handle = ion_alloc(qseecom.ion_clnt, fw_size,
1869 SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1870 if (IS_ERR_OR_NULL(qseecom.cmnlib_ion_handle)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08001871 pr_err("ION alloc failed\n");
Mona Hossain05c73562012-10-29 17:49:01 -07001872 return -ENOMEM;
1873 }
Zhen Kongc46b5842013-12-12 13:09:16 +05301874
1875 img_data = (u8 *)ion_map_kernel(qseecom.ion_clnt,
1876 qseecom.cmnlib_ion_handle);
1877 if (IS_ERR_OR_NULL(img_data)) {
Zhen Kongfd64c982013-12-19 16:35:43 -08001878 pr_err("ION memory mapping for cmnlib failed\n");
Zhen Kongc46b5842013-12-12 13:09:16 +05301879 ret = -ENOMEM;
1880 goto exit_ion_free;
1881 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001882 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001883 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05301884 ret = -EIO;
1885 goto exit_ion_unmap_kernel;
Mona Hossain05c73562012-10-29 17:49:01 -07001886 }
Zhen Kongfd64c982013-12-19 16:35:43 -08001887 /* Get the physical address of the ION BUF */
1888 ret = ion_phys(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
1889 &pa, &len);
1890 load_req.phy_addr = (s32)pa;
1891 if (ret) {
1892 pr_err("physical memory retrieval failure\n");
1893 ret = -EIO;
1894 goto exit_ion_unmap_kernel;
1895 }
Mona Hossain05c73562012-10-29 17:49:01 -07001896 /* Populate the remaining parameters */
1897 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Zhen Kong4bead3c2014-04-14 15:07:13 -07001898
1899 if (qseecom.support_bus_scaling) {
1900 mutex_lock(&qsee_bw_mutex);
1901 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
1902 mutex_unlock(&qsee_bw_mutex);
1903 if (ret) {
1904 ret = -EIO;
1905 goto exit_ion_unmap_kernel;
1906 }
1907 }
1908
Mona Hossain6311d572013-03-01 15:54:02 -08001909 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07001910 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08001911 if (ret) {
Zhen Kongc46b5842013-12-12 13:09:16 +05301912 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07001913 goto exit_unregister_bus_bw_need;
Mona Hossain6311d572013-03-01 15:54:02 -08001914 }
1915
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001916 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001917 /* SCM_CALL to load the image */
1918 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1919 sizeof(struct qseecom_load_lib_image_ireq),
1920 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001921 if (ret) {
1922 pr_err("scm_call to load failed : ret %d\n", ret);
1923 ret = -EIO;
Zhen Kongc46b5842013-12-12 13:09:16 +05301924 goto exit_disable_clk_vote;
Mona Hossain05c73562012-10-29 17:49:01 -07001925 }
Zhen Kongc46b5842013-12-12 13:09:16 +05301926
1927 switch (resp.result) {
1928 case QSEOS_RESULT_SUCCESS:
1929 break;
1930 case QSEOS_RESULT_FAILURE:
1931 pr_err("scm call failed w/response result%d\n", resp.result);
1932 ret = -EINVAL;
1933 goto exit_disable_clk_vote;
1934 case QSEOS_RESULT_INCOMPLETE:
1935 ret = __qseecom_process_incomplete_cmd(data, &resp);
1936 if (ret) {
1937 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1938 goto exit_disable_clk_vote;
1939 }
1940 break;
1941 default:
1942 pr_err("scm call return unknown response %d\n", resp.result);
1943 ret = -EINVAL;
1944 goto exit_disable_clk_vote;
1945 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07001946 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07001947 if (qseecom.support_bus_scaling) {
1948 mutex_lock(&qsee_bw_mutex);
1949 qseecom_unregister_bus_bandwidth_needs(data);
1950 mutex_unlock(&qsee_bw_mutex);
1951 }
Mona Hossain05c73562012-10-29 17:49:01 -07001952 return ret;
Zhen Kongc46b5842013-12-12 13:09:16 +05301953
1954exit_disable_clk_vote:
1955 __qseecom_disable_clk_scale_down(data);
1956
Zhen Kong4bead3c2014-04-14 15:07:13 -07001957exit_unregister_bus_bw_need:
1958 if (qseecom.support_bus_scaling) {
1959 mutex_lock(&qsee_bw_mutex);
1960 qseecom_unregister_bus_bandwidth_needs(data);
1961 mutex_unlock(&qsee_bw_mutex);
1962 }
1963
Zhen Kongc46b5842013-12-12 13:09:16 +05301964exit_ion_unmap_kernel:
1965 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1966
1967exit_ion_free:
1968 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
1969 qseecom.cmnlib_ion_handle = NULL;
1970 return ret;
Mona Hossain05c73562012-10-29 17:49:01 -07001971}
1972
1973static int qseecom_unload_commonlib_image(void)
1974{
1975 int ret = -EINVAL;
1976 struct qseecom_unload_lib_image_ireq unload_req = {0};
1977 struct qseecom_command_scm_resp resp;
1978
1979 /* Populate the remaining parameters */
1980 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1981 /* SCM_CALL to load the image */
1982 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1983 sizeof(struct qseecom_unload_lib_image_ireq),
1984 &resp, sizeof(resp));
1985 if (ret) {
1986 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1987 ret = -EIO;
1988 } else {
1989 switch (resp.result) {
1990 case QSEOS_RESULT_SUCCESS:
1991 break;
1992 case QSEOS_RESULT_FAILURE:
1993 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1994 break;
1995 default:
1996 pr_err("scm call return unknown response %d\n",
1997 resp.result);
1998 ret = -EINVAL;
1999 break;
2000 }
2001 }
Zhen Kongc46b5842013-12-12 13:09:16 +05302002
2003 ion_unmap_kernel(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2004 ion_free(qseecom.ion_clnt, qseecom.cmnlib_ion_handle);
2005 qseecom.cmnlib_ion_handle = NULL;
2006
Mona Hossain05c73562012-10-29 17:49:01 -07002007 return ret;
2008}
2009
Mona Hossaind44a3842012-10-15 09:41:35 -07002010int qseecom_start_app(struct qseecom_handle **handle,
2011 char *app_name, uint32_t size)
2012{
Mona Hossain05c73562012-10-29 17:49:01 -07002013 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07002014 unsigned long flags = 0;
2015 struct qseecom_dev_handle *data = NULL;
2016 struct qseecom_check_app_ireq app_ireq;
2017 struct qseecom_registered_app_list *entry = NULL;
2018 struct qseecom_registered_kclient_list *kclient_entry = NULL;
2019 bool found_app = false;
2020 uint32_t len;
2021 ion_phys_addr_t pa;
2022
Mona Hossain823f9882012-11-23 14:42:20 -08002023 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
2024 if (!(*handle)) {
2025 pr_err("failed to allocate memory for kernel client handle\n");
2026 return -ENOMEM;
2027 }
2028
Mona Hossaind44a3842012-10-15 09:41:35 -07002029 data = kzalloc(sizeof(*data), GFP_KERNEL);
2030 if (!data) {
2031 pr_err("kmalloc failed\n");
2032 if (ret == 0) {
2033 kfree(*handle);
2034 *handle = NULL;
2035 }
2036 return -ENOMEM;
2037 }
2038 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08002039 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07002040 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07002041 data->client.sb_length = size;
2042 data->client.user_virt_sb_base = 0;
2043 data->client.ihandle = NULL;
2044
2045 init_waitqueue_head(&data->abort_wq);
2046 atomic_set(&data->ioctl_count, 0);
2047
2048 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
2049 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
2050 if (IS_ERR_OR_NULL(data->client.ihandle)) {
2051 pr_err("Ion client could not retrieve the handle\n");
2052 kfree(data);
2053 kfree(*handle);
2054 *handle = NULL;
2055 return -EINVAL;
2056 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002057 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08002058 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002059 if (qseecom.commonlib_loaded == false) {
2060 ret = qseecom_load_commonlib_image(data);
2061 if (ret == 0)
2062 qseecom.commonlib_loaded = true;
2063 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002064 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08002065 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002066 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002067 ret = -EIO;
2068 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08002069 }
2070
2071 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
2072 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
2073 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002074 if (ret < 0)
2075 goto err;
2076
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07002077 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002078 if (ret > 0) {
2079 pr_warn("App id %d for [%s] app exists\n", ret,
2080 (char *)app_ireq.app_name);
2081 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2082 list_for_each_entry(entry,
2083 &qseecom.registered_app_list_head, list){
2084 if (entry->app_id == ret) {
2085 entry->ref_cnt++;
2086 found_app = true;
2087 break;
2088 }
2089 }
2090 spin_unlock_irqrestore(
2091 &qseecom.registered_app_list_lock, flags);
2092 if (!found_app)
2093 pr_warn("App_id %d [%s] was loaded but not registered\n",
2094 ret, (char *)app_ireq.app_name);
2095 } else {
2096 /* load the app and get the app_id */
2097 pr_debug("%s: Loading app for the first time'\n",
2098 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07002099 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002100 if (ret < 0)
2101 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002102 data->client.app_id = ret;
2103 }
2104 if (!found_app) {
2105 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2106 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002107 pr_err("kmalloc for app entry failed\n");
2108 ret = -ENOMEM;
2109 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002110 }
2111 entry->app_id = ret;
2112 entry->ref_cnt = 1;
2113
2114 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2115 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
2116 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
2117 flags);
2118 }
2119
2120 /* Get the physical address of the ION BUF */
2121 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002122 if (ret) {
2123 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2124 ret);
2125 goto err;
2126 }
2127
Mona Hossaind44a3842012-10-15 09:41:35 -07002128 /* Populate the structure for sending scm call to load image */
2129 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
2130 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08002131 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07002132 data->client.sb_phys = pa;
2133 (*handle)->dev = (void *)data;
2134 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
2135 (*handle)->sbuf_len = data->client.sb_length;
2136
2137 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
2138 if (!kclient_entry) {
2139 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002140 ret = -ENOMEM;
2141 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07002142 }
2143 kclient_entry->handle = *handle;
2144
2145 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2146 list_add_tail(&kclient_entry->list,
2147 &qseecom.registered_kclient_list_head);
2148 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2149
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002150 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07002151 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07002152
2153err:
2154 kfree(data);
2155 kfree(*handle);
2156 *handle = NULL;
2157 mutex_unlock(&app_access_lock);
2158 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07002159}
2160EXPORT_SYMBOL(qseecom_start_app);
2161
2162int qseecom_shutdown_app(struct qseecom_handle **handle)
2163{
2164 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08002165 struct qseecom_dev_handle *data;
2166
Mona Hossaind44a3842012-10-15 09:41:35 -07002167 struct qseecom_registered_kclient_list *kclient = NULL;
2168 unsigned long flags = 0;
2169 bool found_handle = false;
2170
Mona Hossain33824022013-02-25 09:32:33 -08002171 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07002172 pr_err("Handle is not initialized\n");
2173 return -EINVAL;
2174 }
Mona Hossain33824022013-02-25 09:32:33 -08002175 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07002176 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
2177 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
2178 list) {
2179 if (kclient->handle == (*handle)) {
2180 list_del(&kclient->list);
2181 found_handle = true;
2182 break;
2183 }
2184 }
2185 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
2186 if (!found_handle)
2187 pr_err("Unable to find the handle, exiting\n");
2188 else
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07002189 ret = qseecom_unload_app(data, false);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002190
2191 if (qseecom.support_bus_scaling) {
2192 mutex_lock(&qsee_bw_mutex);
2193 if (data->mode != INACTIVE) {
2194 qseecom_unregister_bus_bandwidth_needs(data);
2195 if (qseecom.cumulative_mode == INACTIVE) {
2196 ret = __qseecom_set_msm_bus_request(INACTIVE);
2197 if (ret)
2198 pr_err("Fail to scale down bus\n");
2199 }
2200 }
2201 mutex_unlock(&qsee_bw_mutex);
2202 } else {
2203 if (data->fast_load_enabled == true)
2204 qsee_disable_clock_vote(data, CLK_SFPB);
2205 if (data->perf_enabled == true)
2206 qsee_disable_clock_vote(data, CLK_DFAB);
2207 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002208 if (ret == 0) {
2209 kzfree(data);
2210 kzfree(*handle);
2211 kzfree(kclient);
2212 *handle = NULL;
2213 }
2214 return ret;
2215}
2216EXPORT_SYMBOL(qseecom_shutdown_app);
2217
2218int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
2219 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
2220{
2221 int ret = 0;
2222 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
2223 struct qseecom_dev_handle *data;
2224
Mona Hossaind44a3842012-10-15 09:41:35 -07002225 if (handle == NULL) {
2226 pr_err("Handle is not initialized\n");
2227 return -EINVAL;
2228 }
2229 data = handle->dev;
2230
2231 req.cmd_req_len = sbuf_len;
2232 req.resp_len = rbuf_len;
2233 req.cmd_req_buf = send_buf;
2234 req.resp_buf = resp_buf;
2235
2236 mutex_lock(&app_access_lock);
2237 atomic_inc(&data->ioctl_count);
Zhen Kongca4c2d52014-03-12 13:22:46 -07002238 if (qseecom.support_bus_scaling) {
2239 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
2240 if (ret) {
2241 pr_err("Failed to set bw.\n");
2242 atomic_dec(&data->ioctl_count);
2243 mutex_unlock(&app_access_lock);
2244 return ret;
2245 }
2246 }
Mona Hossaind44a3842012-10-15 09:41:35 -07002247 ret = __qseecom_send_cmd(data, &req);
Zhen Kongaf950192014-02-05 17:36:23 -08002248 if (qseecom.support_bus_scaling)
2249 __qseecom_add_bw_scale_down_timer(
2250 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossaind44a3842012-10-15 09:41:35 -07002251
2252 atomic_dec(&data->ioctl_count);
2253 mutex_unlock(&app_access_lock);
2254
2255 if (ret)
2256 return ret;
2257
2258 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
2259 req.resp_len, req.resp_buf);
2260 return ret;
2261}
2262EXPORT_SYMBOL(qseecom_send_command);
2263
Mona Hossain91a8fc92012-11-07 19:58:30 -08002264int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
2265{
Mona Hossainfca6f422013-01-12 13:00:35 -08002266 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002267 if ((handle == NULL) || (handle->dev == NULL)) {
2268 pr_err("No valid kernel client\n");
2269 return -EINVAL;
2270 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002271 if (high) {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002272 if (qseecom.support_bus_scaling) {
2273 mutex_lock(&qsee_bw_mutex);
2274 __qseecom_register_bus_bandwidth_needs(handle->dev,
2275 HIGH);
2276 mutex_unlock(&qsee_bw_mutex);
2277 if (ret)
2278 pr_err("Failed to scale bus (med) %d\n", ret);
2279 } else {
2280 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
2281 if (ret)
2282 pr_err("Failed to vote for DFAB clock%d\n",
2283 ret);
2284 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
2285 if (ret) {
2286 pr_err("Failed to vote for SFPB clock%d\n",
2287 ret);
2288 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2289 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002290 }
2291 } else {
Zhen Kong2edf90d2013-08-27 12:05:06 -07002292 if (!qseecom.support_bus_scaling) {
2293 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
2294 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07002295 } else {
2296 mutex_lock(&qsee_bw_mutex);
2297 qseecom_unregister_bus_bandwidth_needs(handle->dev);
2298 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07002299 }
Mona Hossain91a8fc92012-11-07 19:58:30 -08002300 }
Mona Hossainfca6f422013-01-12 13:00:35 -08002301 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08002302}
2303EXPORT_SYMBOL(qseecom_set_bandwidth);
2304
Mona Hossain2892b6b2012-02-17 13:53:11 -08002305static int qseecom_send_resp(void)
2306{
2307 qseecom.send_resp_flag = 1;
2308 wake_up_interruptible(&qseecom.send_resp_wq);
2309 return 0;
2310}
2311
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002312
2313static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
2314 void __user *argp)
2315{
2316 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07002317 int i;
Zhen Kongf4948192013-11-25 13:05:35 -08002318 struct qseecom_registered_listener_list *this_lstnr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002319
2320 if (copy_from_user(&resp, argp, sizeof(resp))) {
2321 pr_err("copy_from_user failed");
2322 return -EINVAL;
2323 }
Zhen Kongf4948192013-11-25 13:05:35 -08002324 this_lstnr = __qseecom_find_svc(data->listener.id);
2325 if (this_lstnr == NULL)
2326 return -EINVAL;
2327
2328 if (resp.resp_buf_ptr == NULL) {
2329 pr_err("Invalid resp_buf_ptr\n");
2330 return -EINVAL;
2331 }
Mona Hossaindddf4442013-10-01 14:08:20 -07002332 /* validate offsets */
2333 for (i = 0; i < MAX_ION_FD; i++) {
2334 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
2335 pr_err("Invalid offset %d = 0x%x\n",
2336 i, resp.ifd_data[i].cmd_buf_offset);
2337 return -EINVAL;
2338 }
2339 }
Zhen Kongf4948192013-11-25 13:05:35 -08002340
2341 if (((uint32_t)resp.resp_buf_ptr <
2342 this_lstnr->user_virt_sb_base)
2343 || ((uint32_t)resp.resp_buf_ptr >=
2344 (this_lstnr->user_virt_sb_base +
2345 this_lstnr->sb_length))) {
2346 pr_err("resp_buf_ptr address not within shared buffer\n");
2347 return -EINVAL;
2348 }
2349 resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
2350 (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07002351 __qseecom_update_cmd_buf(&resp, false, data, true);
2352 qseecom.send_resp_flag = 1;
2353 wake_up_interruptible(&qseecom.send_resp_wq);
2354 return 0;
2355}
2356
2357
Mona Hossain2892b6b2012-02-17 13:53:11 -08002358static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
2359 void __user *argp)
2360{
2361 struct qseecom_qseos_version_req req;
2362
2363 if (copy_from_user(&req, argp, sizeof(req))) {
2364 pr_err("copy_from_user failed");
2365 return -EINVAL;
2366 }
2367 req.qseos_version = qseecom.qseos_version;
2368 if (copy_to_user(argp, &req, sizeof(req))) {
2369 pr_err("copy_to_user failed");
2370 return -EINVAL;
2371 }
2372 return 0;
2373}
2374
Mona Hossainc92629e2013-04-01 13:37:46 -07002375static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002376{
2377 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002378 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08002379
Mona Hossainc92629e2013-04-01 13:37:46 -07002380 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002381 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07002382 else
2383 qclk = &qseecom.ce_drv;
2384
2385 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002386
2387 if (qclk->clk_access_cnt == ULONG_MAX)
2388 goto err;
2389
Mona Hossainc92629e2013-04-01 13:37:46 -07002390 if (qclk->clk_access_cnt > 0) {
2391 qclk->clk_access_cnt++;
2392 mutex_unlock(&clk_access_lock);
2393 return rc;
2394 }
2395
Mona Hossain6311d572013-03-01 15:54:02 -08002396 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07002397 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002398 if (rc) {
2399 pr_err("Unable to enable/prepare CE core clk\n");
2400 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002401 }
2402 /* Enable CE clk */
2403 rc = clk_prepare_enable(qclk->ce_clk);
2404 if (rc) {
2405 pr_err("Unable to enable/prepare CE iface clk\n");
2406 goto ce_clk_err;
2407 }
2408 /* Enable AXI clk */
2409 rc = clk_prepare_enable(qclk->ce_bus_clk);
2410 if (rc) {
2411 pr_err("Unable to enable/prepare CE bus clk\n");
2412 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08002413 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002414 qclk->clk_access_cnt++;
2415 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002416 return 0;
2417
2418ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002419 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002420ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07002421 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08002422err:
Mona Hossainc92629e2013-04-01 13:37:46 -07002423 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002424 return -EIO;
2425}
2426
Mona Hossainc92629e2013-04-01 13:37:46 -07002427static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08002428{
Mona Hossain17a4faf2013-03-22 16:40:56 -07002429 struct qseecom_clk *qclk;
2430
Mona Hossainc92629e2013-04-01 13:37:46 -07002431 if (ce == CLK_QSEE)
2432 qclk = &qseecom.qsee;
2433 else
2434 qclk = &qseecom.ce_drv;
2435
2436 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07002437
2438 if (qclk->clk_access_cnt == 0) {
2439 mutex_unlock(&clk_access_lock);
2440 return;
2441 }
2442
Mona Hossainc92629e2013-04-01 13:37:46 -07002443 if (qclk->clk_access_cnt == 1) {
2444 if (qclk->ce_clk != NULL)
2445 clk_disable_unprepare(qclk->ce_clk);
2446 if (qclk->ce_core_clk != NULL)
2447 clk_disable_unprepare(qclk->ce_core_clk);
2448 if (qclk->ce_bus_clk != NULL)
2449 clk_disable_unprepare(qclk->ce_bus_clk);
2450 }
2451 qclk->clk_access_cnt--;
2452 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08002453}
2454
Mona Hossain04d3fac2012-12-03 10:10:37 -08002455static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
2456 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002457{
2458 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002459 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002460
Mona Hossain17a4faf2013-03-22 16:40:56 -07002461 qclk = &qseecom.qsee;
2462 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002463 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002464
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002465 switch (clk_type) {
2466 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002467 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002468 if (!qseecom.qsee_bw_count) {
2469 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002470 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002471 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002472 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002473 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002474 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002475 if (!ret) {
2476 ret =
2477 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002478 qseecom.qsee_perf_client, 1);
2479 if ((ret) &&
2480 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002481 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002482 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002483 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002484 if (ret)
2485 pr_err("DFAB Bandwidth req failed (%d)\n",
2486 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002487 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002488 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002489 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002490 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002491 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002492 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002493 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002494 }
2495 mutex_unlock(&qsee_bw_mutex);
2496 break;
2497 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002498 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002499 if (!qseecom.qsee_sfpb_bw_count) {
2500 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002501 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002502 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002503 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002504 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002505 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002506 if (!ret) {
2507 ret =
2508 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002509 qseecom.qsee_perf_client, 2);
2510 if ((ret) &&
2511 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002512 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002513 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002514 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002515
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002516 if (ret)
2517 pr_err("SFPB Bandwidth req failed (%d)\n",
2518 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002519 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002520 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002521 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002522 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002523 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002524 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002525 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002526 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002527 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002528 break;
2529 default:
2530 pr_err("Clock type not defined\n");
2531 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002532 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002533 return ret;
2534}
2535
Mona Hossain04d3fac2012-12-03 10:10:37 -08002536static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2537 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002538{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002539 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002540 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002541
Mona Hossain17a4faf2013-03-22 16:40:56 -07002542 qclk = &qseecom.qsee;
2543 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002544 return;
2545
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002546 switch (clk_type) {
2547 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002548 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002549 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002550 pr_err("Client error.Extra call to disable DFAB clk\n");
2551 mutex_unlock(&qsee_bw_mutex);
2552 return;
2553 }
2554
Mona Hossain17a4faf2013-03-22 16:40:56 -07002555 if (qseecom.qsee_bw_count == 1) {
2556 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002557 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002558 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002559 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002560 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002561 qseecom.qsee_perf_client, 0);
2562 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002563 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002564 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002565 if (ret)
2566 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002567 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002568 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002569 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002570 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002571 }
2572 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002573 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002574 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002575 }
2576 mutex_unlock(&qsee_bw_mutex);
2577 break;
2578 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002579 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002580 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002581 pr_err("Client error.Extra call to disable SFPB clk\n");
2582 mutex_unlock(&qsee_bw_mutex);
2583 return;
2584 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002585 if (qseecom.qsee_sfpb_bw_count == 1) {
2586 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002587 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002588 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002589 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002590 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002591 qseecom.qsee_perf_client, 0);
2592 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002593 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002594 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002595 if (ret)
2596 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002597 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002598 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002599 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002600 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002601 }
2602 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002603 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002604 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002605 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002606 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002607 break;
2608 default:
2609 pr_err("Clock type not defined\n");
2610 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002611 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002612
Mona Hossain2892b6b2012-02-17 13:53:11 -08002613}
2614
Mona Hossain5ab9d772012-04-11 21:00:40 -07002615static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2616 void __user *argp)
2617{
2618 struct ion_handle *ihandle; /* Ion handle */
2619 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002620 int ret;
2621 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002622 ion_phys_addr_t pa = 0;
2623 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002624 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002625 struct qseecom_load_app_ireq load_req;
2626 struct qseecom_command_scm_resp resp;
2627
2628 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002629 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002630 (void __user *)argp,
2631 sizeof(struct qseecom_load_img_req))) {
2632 pr_err("copy_from_user failed\n");
2633 return -EFAULT;
2634 }
2635
2636 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002637 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002638 load_img_req.ifd_data_fd);
2639 if (IS_ERR_OR_NULL(ihandle)) {
2640 pr_err("Ion client could not retrieve the handle\n");
2641 return -ENOMEM;
2642 }
2643
2644 /* Get the physical address of the ION BUF */
2645 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Zhen Kong05ed4462014-01-28 18:21:30 -08002646 if (ret) {
2647 pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
2648 ret);
2649 return ret;
2650 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002651 /* Populate the structure for sending scm call to load image */
2652 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2653 load_req.mdt_len = load_img_req.mdt_len;
2654 load_req.img_len = load_img_req.img_len;
2655 load_req.phy_addr = pa;
2656
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002657 /* SCM_CALL tied to Core0 */
2658 mask = CPU_MASK_CPU0;
2659 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2660 if (set_cpu_ret) {
2661 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2662 set_cpu_ret);
2663 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302664 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002665 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302666
Zhen Kong4bead3c2014-04-14 15:07:13 -07002667 if (qseecom.support_bus_scaling) {
2668 mutex_lock(&qsee_bw_mutex);
2669 ret = __qseecom_register_bus_bandwidth_needs(data, MEDIUM);
2670 mutex_unlock(&qsee_bw_mutex);
2671 if (ret) {
2672 ret = -EIO;
2673 goto exit_cpu_restore;
2674 }
2675 }
2676
Mona Hossain6311d572013-03-01 15:54:02 -08002677 /* Vote for the SFPB clock */
Zhen Kong2edf90d2013-08-27 12:05:06 -07002678 ret = __qseecom_enable_clk_scale_up(data);
Mona Hossain6311d572013-03-01 15:54:02 -08002679 if (ret) {
Mona Hossain6311d572013-03-01 15:54:02 -08002680 ret = -EIO;
Zhen Kong4bead3c2014-04-14 15:07:13 -07002681 goto exit_register_bus_bandwidth_needs;
Mona Hossain6311d572013-03-01 15:54:02 -08002682 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002683 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2684 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002685 /* SCM_CALL to load the external elf */
2686 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2687 sizeof(struct qseecom_load_app_ireq),
2688 &resp, sizeof(resp));
2689 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002690 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002691 ret);
2692 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302693 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002694 }
2695
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302696 switch (resp.result) {
2697 case QSEOS_RESULT_SUCCESS:
2698 break;
2699 case QSEOS_RESULT_INCOMPLETE:
2700 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002701 ret = __qseecom_process_incomplete_cmd(data, &resp);
2702 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302703 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2704 break;
2705 case QSEOS_RESULT_FAILURE:
2706 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2707 ret = -EFAULT;
2708 break;
2709 default:
2710 pr_err("scm_call response result %d not supported\n",
2711 resp.result);
2712 ret = -EFAULT;
2713 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002714 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002715
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302716exit_disable_clock:
Zhen Kong2edf90d2013-08-27 12:05:06 -07002717 __qseecom_disable_clk_scale_down(data);
Zhen Kong4bead3c2014-04-14 15:07:13 -07002718
2719exit_register_bus_bandwidth_needs:
2720 if (qseecom.support_bus_scaling) {
2721 mutex_lock(&qsee_bw_mutex);
2722 ret = qseecom_unregister_bus_bandwidth_needs(data);
2723 mutex_unlock(&qsee_bw_mutex);
2724 }
2725
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302726exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002727 /* Restore the CPU mask */
2728 mask = CPU_MASK_ALL;
2729 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2730 if (set_cpu_ret) {
2731 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2732 set_cpu_ret);
2733 ret = -EFAULT;
2734 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302735exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002736 /* Deallocate the handle */
2737 if (!IS_ERR_OR_NULL(ihandle))
2738 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002739 return ret;
2740}
2741
2742static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2743{
2744 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002745 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002746 struct qseecom_command_scm_resp resp;
2747 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002748 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002749
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302750 /* unavailable client app */
2751 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2752
Mona Hossain5ab9d772012-04-11 21:00:40 -07002753 /* Populate the structure for sending scm call to unload image */
2754 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002755
2756 /* SCM_CALL tied to Core0 */
2757 mask = CPU_MASK_CPU0;
2758 ret = set_cpus_allowed_ptr(current, &mask);
2759 if (ret) {
2760 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2761 ret);
2762 return -EFAULT;
2763 }
2764
Mona Hossain5ab9d772012-04-11 21:00:40 -07002765 /* SCM_CALL to unload the external elf */
2766 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2767 sizeof(struct qseecom_unload_app_ireq),
2768 &resp, sizeof(resp));
2769 if (ret) {
2770 pr_err("scm_call to unload failed : ret %d\n",
2771 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002772 ret = -EFAULT;
2773 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002774 }
2775 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2776 ret = __qseecom_process_incomplete_cmd(data, &resp);
2777 if (ret)
2778 pr_err("process_incomplete_cmd fail err: %d\n",
2779 ret);
2780 } else {
2781 if (resp.result != QSEOS_RESULT_SUCCESS) {
2782 pr_err("scm_call to unload image failed resp.result =%d\n",
2783 resp.result);
2784 ret = -EFAULT;
2785 }
2786 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002787
2788qseecom_unload_external_elf_scm_err:
2789 /* Restore the CPU mask */
2790 mask = CPU_MASK_ALL;
2791 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2792 if (set_cpu_ret) {
2793 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2794 set_cpu_ret);
2795 ret = -EFAULT;
2796 }
2797
Mona Hossain5ab9d772012-04-11 21:00:40 -07002798 return ret;
2799}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002800
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002801static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2802 void __user *argp)
2803{
2804
2805 int32_t ret;
2806 struct qseecom_qseos_app_load_query query_req;
2807 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002808 struct qseecom_registered_app_list *entry = NULL;
2809 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002810
2811 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002812 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002813 (void __user *)argp,
2814 sizeof(struct qseecom_qseos_app_load_query))) {
2815 pr_err("copy_from_user failed\n");
2816 return -EFAULT;
2817 }
2818
2819 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002820 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002821 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2822
2823 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002824
2825 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002826 pr_err(" scm call to check if app is loaded failed");
2827 return ret; /* scm call failed */
2828 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002829 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002830 (char *)(req.app_name));
2831 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2832 list_for_each_entry(entry,
2833 &qseecom.registered_app_list_head, list){
2834 if (entry->app_id == ret) {
2835 entry->ref_cnt++;
2836 break;
2837 }
2838 }
2839 spin_unlock_irqrestore(
2840 &qseecom.registered_app_list_lock, flags);
2841 data->client.app_id = ret;
2842 query_req.app_id = ret;
2843
2844 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2845 pr_err("copy_to_user failed\n");
2846 return -EFAULT;
2847 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002848 return -EEXIST; /* app already loaded */
2849 } else {
2850 return 0; /* app not loaded */
2851 }
2852}
2853
Mona Hossain4cf78a92013-02-14 12:06:41 -08002854static int __qseecom_get_ce_pipe_info(
2855 enum qseecom_key_management_usage_type usage,
2856 uint32_t *pipe, uint32_t *ce_hw)
2857{
2858 int ret;
2859 switch (usage) {
2860 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
Zhen Kong4ffeacf2014-02-27 17:21:08 -08002861 if (qseecom.support_fde) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002862 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2863 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2864 ret = 0;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08002865
2866 } else {
2867 pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
2868 qseecom.ce_info.disk_encrypt_pipe,
2869 qseecom.ce_info.hlos_ce_hw_instance);
2870 ret = -EINVAL;
2871 }
2872 break;
2873 case QSEOS_KM_USAGE_FILE_ENCRYPTION:
2874 if (qseecom.support_pfe) {
2875 *pipe = qseecom.ce_info.file_encrypt_pipe;
2876 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2877 ret = 0;
2878 } else {
2879 pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
2880 qseecom.ce_info.file_encrypt_pipe,
2881 qseecom.ce_info.hlos_ce_hw_instance);
2882 ret = -EINVAL;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002883 }
2884 break;
2885 default:
2886 ret = -EINVAL;
2887 break;
2888 }
2889 return ret;
2890}
2891
2892static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2893 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002894 struct qseecom_key_generate_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002895{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002896 struct qseecom_command_scm_resp resp;
2897 int ret;
2898
Zhen Kong9730ddf2013-12-17 16:49:43 -08002899 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
2900 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08002901 pr_err("Error:: unsupported usage %d\n", usage);
2902 return -EFAULT;
2903 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002904 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002905
2906 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002907 ireq, sizeof(struct qseecom_key_generate_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002908 &resp, sizeof(resp));
2909 if (ret) {
2910 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002911 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002912 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002913 }
2914
2915 switch (resp.result) {
2916 case QSEOS_RESULT_SUCCESS:
2917 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002918 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongba69dfe2014-02-28 15:19:53 -08002919 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002920 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002921 case QSEOS_RESULT_INCOMPLETE:
2922 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002923 if (ret) {
2924 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongba69dfe2014-02-28 15:19:53 -08002925 pr_debug("Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002926 ret = 0;
2927 } else {
2928 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2929 resp.result);
2930 }
2931 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002932 break;
2933 case QSEOS_RESULT_FAILURE:
2934 default:
2935 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2936 ret = -EINVAL;
2937 break;
2938 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002939 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002940 return ret;
2941}
2942
2943static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2944 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002945 struct qseecom_key_delete_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002946{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002947 struct qseecom_command_scm_resp resp;
2948 int ret;
2949
2950 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2951 pr_err("Error:: unsupported usage %d\n", usage);
2952 return -EFAULT;
2953 }
2954
Mona Hossainc92629e2013-04-01 13:37:46 -07002955 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002956
2957 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002958 ireq, sizeof(struct qseecom_key_delete_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08002959 &resp, sizeof(struct qseecom_command_scm_resp));
2960 if (ret) {
2961 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002962 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08002963 return -EFAULT;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002964 }
2965
2966 switch (resp.result) {
2967 case QSEOS_RESULT_SUCCESS:
2968 break;
2969 case QSEOS_RESULT_INCOMPLETE:
2970 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08002971 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002972 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2973 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08002974 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
2975 pr_debug("Max attempts to input password reached.\n");
2976 ret = -ERANGE;
2977 }
2978 }
2979 break;
2980 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
2981 pr_debug("Max attempts to input password reached.\n");
2982 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002983 break;
2984 case QSEOS_RESULT_FAILURE:
2985 default:
2986 pr_err("Delete key scm call failed resp.result %d\n",
2987 resp.result);
2988 ret = -EINVAL;
2989 break;
2990 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002991 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002992 return ret;
2993}
2994
2995static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2996 enum qseecom_key_management_usage_type usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08002997 struct qseecom_key_select_ireq *ireq)
Mona Hossain4cf78a92013-02-14 12:06:41 -08002998{
Mona Hossain4cf78a92013-02-14 12:06:41 -08002999 struct qseecom_command_scm_resp resp;
3000 int ret;
3001
Zhen Kong9730ddf2013-12-17 16:49:43 -08003002 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3003 usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003004 pr_err("Error:: unsupported usage %d\n", usage);
3005 return -EFAULT;
3006 }
Mona Hossainc92629e2013-04-01 13:37:46 -07003007
Zhen Kongdb2bf742013-05-13 23:55:42 -07003008 __qseecom_enable_clk(CLK_QSEE);
3009 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003010 __qseecom_enable_clk(CLK_CE_DRV);
3011
Zhen Kong336636e2013-04-15 11:04:54 -07003012 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003013 ireq, sizeof(struct qseecom_key_select_ireq),
Mona Hossain4cf78a92013-02-14 12:06:41 -08003014 &resp, sizeof(struct qseecom_command_scm_resp));
3015 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003016 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07003017 __qseecom_disable_clk(CLK_QSEE);
3018 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3019 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kongca39e442013-12-25 22:57:08 -08003020 return -EFAULT;
Zhen Kong336636e2013-04-15 11:04:54 -07003021 }
3022
Mona Hossain4cf78a92013-02-14 12:06:41 -08003023 switch (resp.result) {
3024 case QSEOS_RESULT_SUCCESS:
3025 break;
3026 case QSEOS_RESULT_INCOMPLETE:
3027 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kongca39e442013-12-25 22:57:08 -08003028 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07003029 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3030 resp.result);
Zhen Kongca39e442013-12-25 22:57:08 -08003031 if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
3032 pr_debug("Max attempts to input password reached.\n");
3033 ret = -ERANGE;
3034 }
3035 }
3036 break;
3037 case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
3038 pr_debug("Max attempts to input password reached.\n");
3039 ret = -ERANGE;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003040 break;
3041 case QSEOS_RESULT_FAILURE:
3042 default:
3043 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3044 ret = -EINVAL;
3045 break;
3046 }
3047
Zhen Kongdb2bf742013-05-13 23:55:42 -07003048 __qseecom_disable_clk(CLK_QSEE);
3049 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07003050 __qseecom_disable_clk(CLK_CE_DRV);
3051
Mona Hossain4cf78a92013-02-14 12:06:41 -08003052 return ret;
3053}
3054
Zhen Kong9730ddf2013-12-17 16:49:43 -08003055static int __qseecom_update_current_key_user_info(
3056 struct qseecom_dev_handle *data,
3057 enum qseecom_key_management_usage_type usage,
3058 struct qseecom_key_userinfo_update_ireq *ireq)
3059{
3060 struct qseecom_command_scm_resp resp;
3061 int ret;
3062
3063 if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3064 usage >= QSEOS_KM_USAGE_MAX) {
3065 pr_err("Error:: unsupported usage %d\n", usage);
3066 return -EFAULT;
3067 }
3068
3069 __qseecom_enable_clk(CLK_QSEE);
3070
3071 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
3072 ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
3073 &resp, sizeof(struct qseecom_command_scm_resp));
3074 if (ret) {
3075 pr_err("scm call to update key userinfo failed : %d\n", ret);
3076 __qseecom_disable_clk(CLK_QSEE);
Zhen Kongca39e442013-12-25 22:57:08 -08003077 return -EFAULT;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003078 }
3079
3080 switch (resp.result) {
3081 case QSEOS_RESULT_SUCCESS:
3082 break;
3083 case QSEOS_RESULT_INCOMPLETE:
3084 ret = __qseecom_process_incomplete_cmd(data, &resp);
3085 if (ret)
3086 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
3087 resp.result);
3088 break;
3089 case QSEOS_RESULT_FAILURE:
3090 default:
3091 pr_err("Set key scm call failed resp.result %d\n", resp.result);
3092 ret = -EINVAL;
3093 break;
3094 }
3095
3096 __qseecom_disable_clk(CLK_QSEE);
3097 return ret;
3098}
3099
Mona Hossain4cf78a92013-02-14 12:06:41 -08003100static int qseecom_create_key(struct qseecom_dev_handle *data,
3101 void __user *argp)
3102{
3103 uint32_t ce_hw = 0;
3104 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003105 int ret = 0;
3106 uint32_t flags = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003107 struct qseecom_create_key_req create_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003108 struct qseecom_key_generate_ireq generate_key_ireq;
3109 struct qseecom_key_select_ireq set_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003110
3111 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
3112 if (ret) {
3113 pr_err("copy_from_user failed\n");
3114 return ret;
3115 }
3116
Zhen Kong9730ddf2013-12-17 16:49:43 -08003117 if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3118 create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003119 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
3120 return -EFAULT;
3121 }
3122
3123 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
3124 if (ret) {
3125 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3126 return -EINVAL;
3127 }
3128
Zhen Kong9730ddf2013-12-17 16:49:43 -08003129 generate_key_ireq.flags = flags;
3130 generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
3131 memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3132 memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3133 memcpy((void *)generate_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003134 (void *)key_id_array[create_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003135 QSEECOM_KEY_ID_SIZE);
3136 memcpy((void *)generate_key_ireq.hash32,
3137 (void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
3138
Mona Hossain4cf78a92013-02-14 12:06:41 -08003139 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003140 &generate_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003141 if (ret) {
3142 pr_err("Failed to generate key on storage: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003143 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003144 }
3145
Zhen Kong9730ddf2013-12-17 16:49:43 -08003146 set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3147 set_key_ireq.ce = ce_hw;
3148 set_key_ireq.pipe = pipe;
3149 set_key_ireq.flags = flags;
3150
3151 /* set both PIPE_ENC and PIPE_ENC_XTS*/
3152 set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
3153 memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3154 memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3155 memcpy((void *)set_key_ireq.key_id,
Zhen Kongba69dfe2014-02-28 15:19:53 -08003156 (void *)key_id_array[create_key_req.usage].desc,
3157 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003158 memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
Mona Hossain4cf78a92013-02-14 12:06:41 -08003159 QSEECOM_HASH_SIZE);
3160
3161 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003162 &set_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003163 if (ret) {
3164 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
3165 pipe, ce_hw, ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003166 return ret;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003167 }
3168
3169 return ret;
3170}
3171
3172static int qseecom_wipe_key(struct qseecom_dev_handle *data,
3173 void __user *argp)
3174{
3175 uint32_t ce_hw = 0;
3176 uint32_t pipe = 0;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003177 int ret = 0;
3178 uint32_t flags = 0;
3179 int i;
3180 struct qseecom_wipe_key_req wipe_key_req;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003181 struct qseecom_key_delete_ireq delete_key_ireq;
3182 struct qseecom_key_select_ireq clear_key_ireq;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003183
3184 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
3185 if (ret) {
3186 pr_err("copy_from_user failed\n");
3187 return ret;
3188 }
3189
Zhen Kong9730ddf2013-12-17 16:49:43 -08003190 if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3191 wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
Mona Hossain4cf78a92013-02-14 12:06:41 -08003192 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
3193 return -EFAULT;
3194 }
3195
3196 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
3197 if (ret) {
3198 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
3199 return -EINVAL;
3200 }
3201
Zhen Kongba69dfe2014-02-28 15:19:53 -08003202 if (wipe_key_req.wipe_key_flag) {
3203 delete_key_ireq.flags = flags;
3204 delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
3205 memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3206 memcpy((void *)delete_key_ireq.key_id,
3207 (void *)key_id_array[wipe_key_req.usage].desc,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003208 QSEECOM_KEY_ID_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003209 memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003210
Zhen Kongba69dfe2014-02-28 15:19:53 -08003211 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003212 &delete_key_ireq);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003213 if (ret) {
3214 pr_err("Failed to delete key from ssd storage: %d\n",
3215 ret);
3216 return -EFAULT;
3217 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003218 }
3219
Zhen Kong9730ddf2013-12-17 16:49:43 -08003220 clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
3221 clear_key_ireq.ce = ce_hw;
3222 clear_key_ireq.pipe = pipe;
3223 clear_key_ireq.flags = flags;
3224 clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003225 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
Zhen Kongba69dfe2014-02-28 15:19:53 -08003226 clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003227 memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
3228
Mona Hossain4cf78a92013-02-14 12:06:41 -08003229 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
Zhen Kong9730ddf2013-12-17 16:49:43 -08003230 &clear_key_ireq);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003231 if (ret) {
3232 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
3233 pipe, ce_hw, ret);
3234 return -EFAULT;
3235 }
3236
3237 return ret;
3238}
3239
Zhen Kong9730ddf2013-12-17 16:49:43 -08003240static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
3241 void __user *argp)
3242{
3243 int ret = 0;
3244 uint32_t flags = 0;
3245 struct qseecom_update_key_userinfo_req update_key_req;
3246 struct qseecom_key_userinfo_update_ireq ireq;
3247
3248 ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
3249 if (ret) {
3250 pr_err("copy_from_user failed\n");
3251 return ret;
3252 }
3253
3254 if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
3255 update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
3256 pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
3257 return -EFAULT;
3258 }
3259
3260 ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
3261 ireq.flags = flags;
3262 memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
3263 memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
3264 memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
Zhen Kongba69dfe2014-02-28 15:19:53 -08003265 memcpy((void *)ireq.key_id,
3266 (void *)key_id_array[update_key_req.usage].desc,
3267 QSEECOM_KEY_ID_SIZE);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003268 memcpy((void *)ireq.current_hash32,
3269 (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
3270 memcpy((void *)ireq.new_hash32,
3271 (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
3272
3273 ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
3274 &ireq);
3275 if (ret) {
3276 pr_err("Failed to update key info: %d\n", ret);
Zhen Kongca39e442013-12-25 22:57:08 -08003277 return ret;
Zhen Kong9730ddf2013-12-17 16:49:43 -08003278 }
3279 return ret;
3280
3281}
3282
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003283static int qseecom_is_es_activated(void __user *argp)
3284{
3285 struct qseecom_is_es_activated_req req;
3286 int ret;
3287 int resp_buf;
3288
3289 if (qseecom.qsee_version < QSEE_VERSION_04) {
3290 pr_err("invalid qsee version");
3291 return -ENODEV;
3292 }
3293
3294 if (argp == NULL) {
3295 pr_err("arg is null");
3296 return -EINVAL;
3297 }
3298
3299 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
3300 (void *) &resp_buf, sizeof(resp_buf));
3301 if (ret) {
3302 pr_err("scm_call failed");
3303 return ret;
3304 }
3305
3306 req.is_activated = resp_buf;
3307 ret = copy_to_user(argp, &req, sizeof(req));
3308 if (ret) {
3309 pr_err("copy_to_user failed");
3310 return ret;
3311 }
3312
3313 return 0;
3314}
3315
3316static int qseecom_save_partition_hash(void __user *argp)
3317{
3318 struct qseecom_save_partition_hash_req req;
3319 int ret;
3320
3321 if (qseecom.qsee_version < QSEE_VERSION_04) {
3322 pr_err("invalid qsee version ");
3323 return -ENODEV;
3324 }
3325
3326 if (argp == NULL) {
3327 pr_err("arg is null");
3328 return -EINVAL;
3329 }
3330
3331 ret = copy_from_user(&req, argp, sizeof(req));
3332 if (ret) {
3333 pr_err("copy_from_user failed");
3334 return ret;
3335 }
3336
3337 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
3338 (void *) &req, sizeof(req), NULL, 0);
3339 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07003340 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003341 return ret;
3342 }
3343
3344 return 0;
3345}
3346
Mona Hossain2892b6b2012-02-17 13:53:11 -08003347static long qseecom_ioctl(struct file *file, unsigned cmd,
3348 unsigned long arg)
3349{
3350 int ret = 0;
3351 struct qseecom_dev_handle *data = file->private_data;
3352 void __user *argp = (void __user *) arg;
3353
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05303354 if (!data) {
3355 pr_err("Invalid/uninitialized device handle\n");
3356 return -EINVAL;
3357 }
3358
Mona Hossain2892b6b2012-02-17 13:53:11 -08003359 if (data->abort) {
3360 pr_err("Aborting qseecom driver\n");
3361 return -ENODEV;
3362 }
3363
3364 switch (cmd) {
3365 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003366 if (data->type != QSEECOM_GENERIC) {
3367 pr_err("reg lstnr req: invalid handle (%d)\n",
3368 data->type);
3369 ret = -EINVAL;
3370 break;
3371 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003372 pr_debug("ioctl register_listener_req()\n");
3373 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003374 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003375 ret = qseecom_register_listener(data, argp);
3376 atomic_dec(&data->ioctl_count);
3377 wake_up_all(&data->abort_wq);
3378 if (ret)
3379 pr_err("failed qseecom_register_listener: %d\n", ret);
3380 break;
3381 }
3382 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003383 if ((data->listener.id == 0) ||
3384 (data->type != QSEECOM_LISTENER_SERVICE)) {
3385 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
3386 data->type, data->listener.id);
3387 ret = -EINVAL;
3388 break;
3389 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003390 pr_debug("ioctl unregister_listener_req()\n");
3391 atomic_inc(&data->ioctl_count);
3392 ret = qseecom_unregister_listener(data);
3393 atomic_dec(&data->ioctl_count);
3394 wake_up_all(&data->abort_wq);
3395 if (ret)
3396 pr_err("failed qseecom_unregister_listener: %d\n", ret);
3397 break;
3398 }
3399 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003400 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003401 if ((data->client.app_id == 0) ||
3402 (data->type != QSEECOM_CLIENT_APP)) {
3403 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
3404 data->type, data->client.app_id);
3405 ret = -EINVAL;
3406 break;
3407 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003408 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003409 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003410 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003411 /* register bus bw in case the client doesn't do it */
3412 if (!data->mode) {
3413 mutex_lock(&qsee_bw_mutex);
3414 __qseecom_register_bus_bandwidth_needs(
3415 data, HIGH);
3416 mutex_unlock(&qsee_bw_mutex);
3417 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003418 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3419 if (ret) {
3420 pr_err("Failed to set bw.\n");
3421 ret = -EINVAL;
3422 mutex_unlock(&app_access_lock);
3423 break;
3424 }
3425 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003426 atomic_inc(&data->ioctl_count);
3427 ret = qseecom_send_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003428 if (qseecom.support_bus_scaling)
3429 __qseecom_add_bw_scale_down_timer(
3430 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003431 atomic_dec(&data->ioctl_count);
3432 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003433 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003434 if (ret)
3435 pr_err("failed qseecom_send_cmd: %d\n", ret);
3436 break;
3437 }
3438 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Zhen Kong2edf90d2013-08-27 12:05:06 -07003439 pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
Mona Hossaina1124de2013-10-01 13:41:09 -07003440 if ((data->client.app_id == 0) ||
3441 (data->type != QSEECOM_CLIENT_APP)) {
3442 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
3443 data->type, data->client.app_id);
3444 ret = -EINVAL;
3445 break;
3446 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003447 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003448 mutex_lock(&app_access_lock);
Zhen Kongca4c2d52014-03-12 13:22:46 -07003449 if (qseecom.support_bus_scaling) {
Zhen Konge5b434e2014-04-17 16:47:06 -07003450 if (!data->mode) {
3451 mutex_lock(&qsee_bw_mutex);
3452 __qseecom_register_bus_bandwidth_needs(
3453 data, HIGH);
3454 mutex_unlock(&qsee_bw_mutex);
3455 }
Zhen Kongca4c2d52014-03-12 13:22:46 -07003456 ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
3457 if (ret) {
3458 pr_err("Failed to set bw.\n");
3459 mutex_unlock(&app_access_lock);
3460 ret = -EINVAL;
3461 break;
3462 }
3463 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003464 atomic_inc(&data->ioctl_count);
3465 ret = qseecom_send_modfd_cmd(data, argp);
Zhen Kongaf950192014-02-05 17:36:23 -08003466 if (qseecom.support_bus_scaling)
3467 __qseecom_add_bw_scale_down_timer(
3468 QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge8a02082014-03-11 17:36:50 -07003469 atomic_dec(&data->ioctl_count);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003470 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07003471 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003472 if (ret)
3473 pr_err("failed qseecom_send_cmd: %d\n", ret);
3474 break;
3475 }
3476 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003477 if ((data->listener.id == 0) ||
3478 (data->type != QSEECOM_LISTENER_SERVICE)) {
3479 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3480 data->type, data->listener.id);
3481 ret = -EINVAL;
3482 break;
3483 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003484 atomic_inc(&data->ioctl_count);
3485 ret = qseecom_receive_req(data);
3486 atomic_dec(&data->ioctl_count);
3487 wake_up_all(&data->abort_wq);
Hariprasad Dhalinarasimhaf44cbd22013-07-20 04:49:34 +05303488 if (ret && (ret != -ERESTARTSYS))
Mona Hossain2892b6b2012-02-17 13:53:11 -08003489 pr_err("failed qseecom_receive_req: %d\n", ret);
3490 break;
3491 }
3492 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003493 if ((data->listener.id == 0) ||
3494 (data->type != QSEECOM_LISTENER_SERVICE)) {
3495 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
3496 data->type, data->listener.id);
3497 ret = -EINVAL;
3498 break;
3499 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003500 atomic_inc(&data->ioctl_count);
3501 ret = qseecom_send_resp();
3502 atomic_dec(&data->ioctl_count);
3503 wake_up_all(&data->abort_wq);
3504 if (ret)
3505 pr_err("failed qseecom_send_resp: %d\n", ret);
3506 break;
3507 }
3508 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003509 if ((data->type != QSEECOM_CLIENT_APP) &&
3510 (data->type != QSEECOM_GENERIC) &&
3511 (data->type != QSEECOM_SECURE_SERVICE)) {
3512 pr_err("set mem param req: invalid handle (%d)\n",
3513 data->type);
3514 ret = -EINVAL;
3515 break;
3516 }
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003517 data->type = QSEECOM_CLIENT_APP;
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003518 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003519 ret = qseecom_set_client_mem_param(data, argp);
3520 if (ret)
3521 pr_err("failed Qqseecom_set_mem_param request: %d\n",
3522 ret);
3523 break;
3524 }
3525 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003526 if ((data->type != QSEECOM_GENERIC) &&
3527 (data->type != QSEECOM_CLIENT_APP)) {
3528 pr_err("load app req: invalid handle (%d)\n",
3529 data->type);
3530 ret = -EINVAL;
3531 break;
3532 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003533 data->type = QSEECOM_CLIENT_APP;
3534 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003535 mutex_lock(&app_access_lock);
3536 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07003537 if (qseecom.qsee_version > QSEEE_VERSION_00) {
3538 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08003539 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07003540 if (ret == 0)
3541 qseecom.commonlib_loaded = true;
3542 }
3543 }
3544 if (ret == 0)
3545 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003546 atomic_dec(&data->ioctl_count);
3547 mutex_unlock(&app_access_lock);
3548 if (ret)
3549 pr_err("failed load_app request: %d\n", ret);
3550 break;
3551 }
3552 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003553 if ((data->client.app_id == 0) ||
3554 (data->type != QSEECOM_CLIENT_APP)) {
3555 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
3556 data->type, data->client.app_id);
3557 ret = -EINVAL;
3558 break;
3559 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003560 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003561 mutex_lock(&app_access_lock);
3562 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07003563 ret = qseecom_unload_app(data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003564 atomic_dec(&data->ioctl_count);
3565 mutex_unlock(&app_access_lock);
3566 if (ret)
3567 pr_err("failed unload_app request: %d\n", ret);
3568 break;
3569 }
3570 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
3571 atomic_inc(&data->ioctl_count);
3572 ret = qseecom_get_qseos_version(data, argp);
3573 if (ret)
3574 pr_err("qseecom_get_qseos_version: %d\n", ret);
3575 atomic_dec(&data->ioctl_count);
3576 break;
3577 }
3578 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003579 if ((data->type != QSEECOM_GENERIC) &&
3580 (data->type != QSEECOM_CLIENT_APP)) {
3581 pr_err("perf enable req: invalid handle (%d)\n",
3582 data->type);
3583 ret = -EINVAL;
3584 break;
3585 }
3586 if ((data->type == QSEECOM_CLIENT_APP) &&
3587 (data->client.app_id == 0)) {
3588 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
3589 data->type, data->client.app_id);
3590 ret = -EINVAL;
3591 break;
3592 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003593 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003594 if (qseecom.support_bus_scaling) {
3595 mutex_lock(&qsee_bw_mutex);
3596 __qseecom_register_bus_bandwidth_needs(data, HIGH);
3597 mutex_unlock(&qsee_bw_mutex);
3598 } else {
3599 ret = qsee_vote_for_clock(data, CLK_DFAB);
3600 if (ret)
3601 pr_err("Fail to vote for DFAB clock%d\n", ret);
3602 ret = qsee_vote_for_clock(data, CLK_SFPB);
3603 if (ret)
3604 pr_err("Fail to vote for SFPB clock%d\n", ret);
3605 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003606 atomic_dec(&data->ioctl_count);
3607 break;
3608 }
3609 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07003610 if ((data->type != QSEECOM_SECURE_SERVICE) &&
3611 (data->type != QSEECOM_CLIENT_APP)) {
3612 pr_err("perf disable req: invalid handle (%d)\n",
3613 data->type);
3614 ret = -EINVAL;
3615 break;
3616 }
3617 if ((data->type == QSEECOM_CLIENT_APP) &&
3618 (data->client.app_id == 0)) {
3619 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
3620 data->type, data->client.app_id);
3621 ret = -EINVAL;
3622 break;
3623 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003624 atomic_inc(&data->ioctl_count);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003625 if (!qseecom.support_bus_scaling) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003626 qsee_disable_clock_vote(data, CLK_DFAB);
3627 qsee_disable_clock_vote(data, CLK_SFPB);
Zhen Konge5b434e2014-04-17 16:47:06 -07003628 } else {
3629 mutex_lock(&qsee_bw_mutex);
3630 qseecom_unregister_bus_bandwidth_needs(data);
3631 mutex_unlock(&qsee_bw_mutex);
Zhen Kong2edf90d2013-08-27 12:05:06 -07003632 }
3633 atomic_dec(&data->ioctl_count);
3634 break;
3635 }
3636
3637 case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
3638 if ((data->client.app_id == 0) ||
3639 (data->type != QSEECOM_CLIENT_APP)) {
3640 pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
3641 data->type, data->client.app_id);
3642 ret = -EINVAL;
3643 break;
3644 }
3645 atomic_inc(&data->ioctl_count);
3646 ret = qseecom_scale_bus_bandwidth(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003647 atomic_dec(&data->ioctl_count);
3648 break;
3649 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003650 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003651 if (data->type != QSEECOM_GENERIC) {
3652 pr_err("load ext elf req: invalid client handle (%d)\n",
3653 data->type);
3654 ret = -EINVAL;
3655 break;
3656 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003657 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003658 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003659 mutex_lock(&app_access_lock);
3660 atomic_inc(&data->ioctl_count);
3661 ret = qseecom_load_external_elf(data, argp);
3662 atomic_dec(&data->ioctl_count);
3663 mutex_unlock(&app_access_lock);
3664 if (ret)
3665 pr_err("failed load_external_elf request: %d\n", ret);
3666 break;
3667 }
3668 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003669 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3670 pr_err("unload ext elf req: invalid handle (%d)\n",
3671 data->type);
3672 ret = -EINVAL;
3673 break;
3674 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003675 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003676 mutex_lock(&app_access_lock);
3677 atomic_inc(&data->ioctl_count);
3678 ret = qseecom_unload_external_elf(data);
3679 atomic_dec(&data->ioctl_count);
3680 mutex_unlock(&app_access_lock);
3681 if (ret)
3682 pr_err("failed unload_app request: %d\n", ret);
3683 break;
3684 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003685 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003686 data->type = QSEECOM_CLIENT_APP;
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003687 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003688 mutex_lock(&app_access_lock);
3689 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003690 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003691 ret = qseecom_query_app_loaded(data, argp);
3692 atomic_dec(&data->ioctl_count);
3693 mutex_unlock(&app_access_lock);
3694 break;
3695 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003696 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003697 if (data->type != QSEECOM_GENERIC) {
3698 pr_err("send cmd svc req: invalid handle (%d)\n",
3699 data->type);
3700 ret = -EINVAL;
3701 break;
3702 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003703 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003704 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003705 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003706 qseecom.qsee_version);
3707 return -EINVAL;
3708 }
3709 mutex_lock(&app_access_lock);
3710 atomic_inc(&data->ioctl_count);
3711 ret = qseecom_send_service_cmd(data, argp);
3712 atomic_dec(&data->ioctl_count);
3713 mutex_unlock(&app_access_lock);
3714 break;
3715 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003716 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003717 if (!(qseecom.support_pfe || qseecom.support_fde))
3718 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07003719 if (data->type != QSEECOM_GENERIC) {
3720 pr_err("create key req: invalid handle (%d)\n",
3721 data->type);
3722 ret = -EINVAL;
3723 break;
3724 }
Zhen Kong336636e2013-04-15 11:04:54 -07003725 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003726 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003727 qseecom.qsee_version);
3728 return -EINVAL;
3729 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003730 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003731 atomic_inc(&data->ioctl_count);
3732 ret = qseecom_create_key(data, argp);
3733 if (ret)
3734 pr_err("failed to create encryption key: %d\n", ret);
3735
3736 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003737 break;
3738 }
3739 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003740 if (!(qseecom.support_pfe || qseecom.support_fde))
3741 pr_err("Features requiring key init not supported\n");
Mona Hossaina1124de2013-10-01 13:41:09 -07003742 if (data->type != QSEECOM_GENERIC) {
3743 pr_err("wipe key req: invalid handle (%d)\n",
3744 data->type);
3745 ret = -EINVAL;
3746 break;
3747 }
Zhen Kong336636e2013-04-15 11:04:54 -07003748 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003749 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003750 qseecom.qsee_version);
3751 return -EINVAL;
3752 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003753 data->released = true;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003754 atomic_inc(&data->ioctl_count);
3755 ret = qseecom_wipe_key(data, argp);
3756 if (ret)
3757 pr_err("failed to wipe encryption key: %d\n", ret);
3758 atomic_dec(&data->ioctl_count);
Zhen Kong9730ddf2013-12-17 16:49:43 -08003759 break;
3760 }
3761 case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
Zhen Konga10dcab2014-03-19 10:32:27 -07003762 if (!(qseecom.support_pfe || qseecom.support_fde))
3763 pr_err("Features requiring key init not supported\n");
Zhen Kong9730ddf2013-12-17 16:49:43 -08003764 if (data->type != QSEECOM_GENERIC) {
3765 pr_err("update key req: invalid handle (%d)\n",
3766 data->type);
3767 ret = -EINVAL;
3768 break;
3769 }
3770 if (qseecom.qsee_version < QSEE_VERSION_05) {
3771 pr_err("Update Key feature unsupported in qsee ver %u\n",
3772 qseecom.qsee_version);
3773 return -EINVAL;
3774 }
3775 data->released = true;
3776 atomic_inc(&data->ioctl_count);
3777 ret = qseecom_update_key_user_info(data, argp);
3778 if (ret)
3779 pr_err("failed to update key user info: %d\n", ret);
3780 atomic_dec(&data->ioctl_count);
Mona Hossain4cf78a92013-02-14 12:06:41 -08003781 break;
3782 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003783 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003784 if (data->type != QSEECOM_GENERIC) {
3785 pr_err("save part hash req: invalid handle (%d)\n",
3786 data->type);
3787 ret = -EINVAL;
3788 break;
3789 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003790 data->released = true;
3791 mutex_lock(&app_access_lock);
3792 atomic_inc(&data->ioctl_count);
3793 ret = qseecom_save_partition_hash(argp);
3794 atomic_dec(&data->ioctl_count);
3795 mutex_unlock(&app_access_lock);
3796 break;
3797 }
3798 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003799 if (data->type != QSEECOM_GENERIC) {
3800 pr_err("ES activated req: invalid handle (%d)\n",
3801 data->type);
3802 ret = -EINVAL;
3803 break;
3804 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003805 data->released = true;
3806 mutex_lock(&app_access_lock);
3807 atomic_inc(&data->ioctl_count);
3808 ret = qseecom_is_es_activated(argp);
3809 atomic_dec(&data->ioctl_count);
3810 mutex_unlock(&app_access_lock);
3811 break;
3812 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003813 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003814 if ((data->listener.id == 0) ||
3815 (data->type != QSEECOM_LISTENER_SERVICE)) {
3816 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3817 data->type, data->listener.id);
3818 ret = -EINVAL;
3819 break;
3820 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003821 /* Only one client allowed here at a time */
3822 atomic_inc(&data->ioctl_count);
3823 ret = qseecom_send_modfd_resp(data, argp);
3824 atomic_dec(&data->ioctl_count);
3825 wake_up_all(&data->abort_wq);
3826 if (ret)
3827 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3828 break;
3829 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003830 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003831 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003832 return -EINVAL;
3833 }
3834 return ret;
3835}
3836
3837static int qseecom_open(struct inode *inode, struct file *file)
3838{
3839 int ret = 0;
3840 struct qseecom_dev_handle *data;
3841
3842 data = kzalloc(sizeof(*data), GFP_KERNEL);
3843 if (!data) {
3844 pr_err("kmalloc failed\n");
3845 return -ENOMEM;
3846 }
3847 file->private_data = data;
3848 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003849 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003850 data->released = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07003851 data->mode = INACTIVE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003852 init_waitqueue_head(&data->abort_wq);
3853 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003854
Mona Hossain2892b6b2012-02-17 13:53:11 -08003855 return ret;
3856}
3857
3858static int qseecom_release(struct inode *inode, struct file *file)
3859{
3860 struct qseecom_dev_handle *data = file->private_data;
3861 int ret = 0;
3862
3863 if (data->released == false) {
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003864 pr_warn("data: released = false, type = %d, data = 0x%x\n",
3865 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003866 switch (data->type) {
3867 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003868 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003869 break;
3870 case QSEECOM_CLIENT_APP:
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07003871 ret = qseecom_unload_app(data, true);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003872 break;
3873 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003874 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003875 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003876 if (ret)
Hariprasad Dhalinarasimhaba306142013-08-19 12:45:18 -07003877 pr_err("Ion Unmap failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003878 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303879 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3880 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003881 default:
3882 pr_err("Unsupported clnt_handle_type %d",
3883 data->type);
3884 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003885 }
3886 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003887
Zhen Kong2edf90d2013-08-27 12:05:06 -07003888 if (qseecom.support_bus_scaling) {
3889 mutex_lock(&qsee_bw_mutex);
3890 if (data->mode != INACTIVE) {
3891 qseecom_unregister_bus_bandwidth_needs(data);
3892 if (qseecom.cumulative_mode == INACTIVE) {
3893 ret = __qseecom_set_msm_bus_request(INACTIVE);
3894 if (ret)
3895 pr_err("Fail to scale down bus\n");
3896 }
3897 }
3898 mutex_unlock(&qsee_bw_mutex);
3899 } else {
3900 if (data->fast_load_enabled == true)
3901 qsee_disable_clock_vote(data, CLK_SFPB);
3902 if (data->perf_enabled == true)
3903 qsee_disable_clock_vote(data, CLK_DFAB);
3904 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003905 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003906
Mona Hossain2892b6b2012-02-17 13:53:11 -08003907 return ret;
3908}
3909
Mona Hossain2892b6b2012-02-17 13:53:11 -08003910static const struct file_operations qseecom_fops = {
3911 .owner = THIS_MODULE,
3912 .unlocked_ioctl = qseecom_ioctl,
3913 .open = qseecom_open,
3914 .release = qseecom_release
3915};
3916
Mona Hossainc92629e2013-04-01 13:37:46 -07003917static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003918{
3919 int rc = 0;
3920 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003921 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003922 char *core_clk_src = NULL;
3923 char *core_clk = NULL;
3924 char *iface_clk = NULL;
3925 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003926
Mona Hossainc92629e2013-04-01 13:37:46 -07003927 switch (ce) {
3928 case CLK_QSEE: {
3929 core_clk_src = "core_clk_src";
3930 core_clk = "core_clk";
3931 iface_clk = "iface_clk";
3932 bus_clk = "bus_clk";
3933 qclk = &qseecom.qsee;
3934 qclk->instance = CLK_QSEE;
3935 break;
3936 };
3937 case CLK_CE_DRV: {
3938 core_clk_src = "ce_drv_core_clk_src";
3939 core_clk = "ce_drv_core_clk";
3940 iface_clk = "ce_drv_iface_clk";
3941 bus_clk = "ce_drv_bus_clk";
3942 qclk = &qseecom.ce_drv;
3943 qclk->instance = CLK_CE_DRV;
3944 break;
3945 };
3946 default:
3947 pr_err("Invalid ce hw instance: %d!\n", ce);
3948 return -EIO;
3949 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003950 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003951
Mona Hossainc92629e2013-04-01 13:37:46 -07003952 /* Get CE3 src core clk. */
3953 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003954 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003955 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003956 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003957 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003958 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003959 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003960 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003961 }
3962 } else {
3963 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003964 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003965 }
3966
3967 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003968 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003969 if (IS_ERR(qclk->ce_core_clk)) {
3970 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003971 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003972 if (qclk->ce_core_src_clk != NULL)
3973 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003974 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003975 }
3976
3977 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003978 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003979 if (IS_ERR(qclk->ce_clk)) {
3980 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003981 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003982 if (qclk->ce_core_src_clk != NULL)
3983 clk_put(qclk->ce_core_src_clk);
3984 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003985 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003986 }
3987
3988 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003989 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003990 if (IS_ERR(qclk->ce_bus_clk)) {
3991 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003992 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003993 if (qclk->ce_core_src_clk != NULL)
3994 clk_put(qclk->ce_core_src_clk);
3995 clk_put(qclk->ce_core_clk);
3996 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003997 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003998 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003999 return rc;
4000}
4001
Mona Hossainc92629e2013-04-01 13:37:46 -07004002static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004003{
Mona Hossain17a4faf2013-03-22 16:40:56 -07004004 struct qseecom_clk *qclk;
4005
Mona Hossainc92629e2013-04-01 13:37:46 -07004006 if (ce == CLK_QSEE)
4007 qclk = &qseecom.qsee;
4008 else
4009 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004010
4011 if (qclk->ce_clk != NULL) {
4012 clk_put(qclk->ce_clk);
4013 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004014 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004015 if (qclk->ce_core_clk != NULL) {
4016 clk_put(qclk->ce_core_clk);
4017 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004018 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004019 if (qclk->ce_bus_clk != NULL) {
4020 clk_put(qclk->ce_bus_clk);
4021 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004022 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07004023 if (qclk->ce_core_src_clk != NULL) {
4024 clk_put(qclk->ce_core_src_clk);
4025 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004026 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004027}
4028
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004029static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004030{
4031 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004032 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004033 struct device *class_dev;
4034 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07004035 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004036 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
4037
Mona Hossain17a4faf2013-03-22 16:40:56 -07004038 qseecom.qsee_bw_count = 0;
4039 qseecom.qsee_perf_client = 0;
4040 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08004041
Mona Hossain17a4faf2013-03-22 16:40:56 -07004042 qseecom.qsee.ce_core_clk = NULL;
4043 qseecom.qsee.ce_clk = NULL;
4044 qseecom.qsee.ce_core_src_clk = NULL;
4045 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07004046
Zhen Kong2edf90d2013-08-27 12:05:06 -07004047 qseecom.cumulative_mode = 0;
4048 qseecom.current_mode = INACTIVE;
4049 qseecom.support_bus_scaling = false;
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004050 qseecom.support_fde = false;
4051 qseecom.support_pfe = false;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004052
Mona Hossainc92629e2013-04-01 13:37:46 -07004053 qseecom.ce_drv.ce_core_clk = NULL;
4054 qseecom.ce_drv.ce_clk = NULL;
4055 qseecom.ce_drv.ce_core_src_clk = NULL;
4056 qseecom.ce_drv.ce_bus_clk = NULL;
4057
Mona Hossain2892b6b2012-02-17 13:53:11 -08004058 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
4059 if (rc < 0) {
4060 pr_err("alloc_chrdev_region failed %d\n", rc);
4061 return rc;
4062 }
4063
4064 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
4065 if (IS_ERR(driver_class)) {
4066 rc = -ENOMEM;
4067 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304068 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004069 }
4070
4071 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
4072 QSEECOM_DEV);
4073 if (!class_dev) {
4074 pr_err("class_device_create failed %d\n", rc);
4075 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304076 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004077 }
4078
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304079 cdev_init(&qseecom.cdev, &qseecom_fops);
4080 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004081
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304082 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004083 if (rc < 0) {
4084 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304085 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004086 }
4087
4088 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
4089 spin_lock_init(&qseecom.registered_listener_list_lock);
4090 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
4091 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07004092 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
4093 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004094 init_waitqueue_head(&qseecom.send_resp_wq);
4095 qseecom.send_resp_flag = 0;
4096
4097 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
4098 &qsee_not_legacy, sizeof(qsee_not_legacy));
4099 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07004100 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304101 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004102 }
Mona Hossain05c73562012-10-29 17:49:01 -07004103 if (qsee_not_legacy) {
4104 uint32_t feature = 10;
4105
4106 qseecom.qsee_version = QSEEE_VERSION_00;
4107 rc = scm_call(6, 3, &feature, sizeof(feature),
4108 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
4109 if (rc) {
4110 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304111 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07004112 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08004113 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07004114 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07004115 pr_err("QSEE legacy version is not supported:");
4116 pr_err("Support for TZ1.3 and earlier is deprecated\n");
4117 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304118 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004119 }
Mona Hossain05c73562012-10-29 17:49:01 -07004120 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004121 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004122 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07004123 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08004124 if (qseecom.ion_clnt == NULL) {
4125 pr_err("Ion client cannot be created\n");
4126 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304127 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004128 }
4129
4130 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004131 if (pdev->dev.of_node) {
AnilKumar Chimatabb512722014-01-29 00:12:35 +05304132 qseecom.pdev->of_node = pdev->dev.of_node;
Zhen Kong2edf90d2013-08-27 12:05:06 -07004133 qseecom.support_bus_scaling =
4134 of_property_read_bool((&pdev->dev)->of_node,
4135 "qcom,support-bus-scaling");
4136 pr_warn("support_bus_scaling=0x%x",
4137 qseecom.support_bus_scaling);
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004138 qseecom.support_fde =
4139 of_property_read_bool((&pdev->dev)->of_node,
4140 "qcom,support-fde");
4141 if (qseecom.support_fde) {
4142 if (of_property_read_u32((&pdev->dev)->of_node,
Mona Hossain4cf78a92013-02-14 12:06:41 -08004143 "qcom,disk-encrypt-pipe-pair",
4144 &qseecom.ce_info.disk_encrypt_pipe)) {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004145 pr_err("Fail to get FDE pipe information.\n");
4146 rc = -EINVAL;
4147 goto exit_destroy_ion_client;
4148 } else {
4149 pr_warn("disk-encrypt-pipe-pair=0x%x",
4150 qseecom.ce_info.disk_encrypt_pipe);
4151 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08004152 } else {
Zhen Kong4ffeacf2014-02-27 17:21:08 -08004153 pr_warn("Device does not support FDE");
4154 qseecom.ce_info.disk_encrypt_pipe = 0xff;
4155 }
4156 qseecom.support_pfe =
4157 of_property_read_bool((&pdev->dev)->of_node,
4158 "qcom,support-pfe");
4159 if (qseecom.support_pfe) {
4160 if (of_property_read_u32((&pdev->dev)->of_node,
4161 "qcom,file-encrypt-pipe-pair",
4162 &qseecom.ce_info.disk_encrypt_pipe)) {
4163 pr_err("Fail to get PFE pipe information.\n");
4164 rc = -EINVAL;
4165 goto exit_destroy_ion_client;
4166 } else {
4167 pr_warn("file-encrypt-pipe-pair=0x%x",
4168 qseecom.ce_info.file_encrypt_pipe);
4169 }
4170 } else {
4171 pr_warn("Device does not support PFE");
4172 qseecom.ce_info.file_encrypt_pipe = 0xff;
4173 }
4174 if (qseecom.support_pfe || qseecom.support_fde) {
4175 if (of_property_read_u32((&pdev->dev)->of_node,
4176 "qcom,hlos-ce-hw-instance",
4177 &qseecom.ce_info.hlos_ce_hw_instance)) {
4178 pr_err("Fail: get hlos ce hw instanc info\n");
4179 rc = -EINVAL;
4180 goto exit_destroy_ion_client;
4181 } else {
4182 pr_warn("hlos-ce-hw-instance=0x%x",
4183 qseecom.ce_info.hlos_ce_hw_instance);
4184 }
4185 } else {
4186 pr_warn("Device does not support PFE/FDE");
4187 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004188 }
4189
4190 if (of_property_read_u32((&pdev->dev)->of_node,
4191 "qcom,qsee-ce-hw-instance",
4192 &qseecom.ce_info.qsee_ce_hw_instance)) {
4193 pr_err("Fail to get qsee ce hw instance information.\n");
Mona Hossain4cf78a92013-02-14 12:06:41 -08004194 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304195 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08004196 } else {
4197 pr_warn("qsee-ce-hw-instance=0x%x",
4198 qseecom.ce_info.qsee_ce_hw_instance);
4199 }
4200
Mona Hossainc92629e2013-04-01 13:37:46 -07004201 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
4202 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
4203
4204 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004205 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304206 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08004207
Zhen Konga10dcab2014-03-19 10:32:27 -07004208 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4209 (qseecom.support_pfe || qseecom.support_fde)) {
Mona Hossainc92629e2013-04-01 13:37:46 -07004210 ret = __qseecom_init_clk(CLK_CE_DRV);
4211 if (ret) {
4212 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304213 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07004214 }
4215 } else {
4216 struct qseecom_clk *qclk;
4217
4218 qclk = &qseecom.qsee;
4219 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
4220 qseecom.ce_drv.ce_clk = qclk->ce_clk;
4221 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
4222 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
4223 }
4224
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004225 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4226 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08004227 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
4228 struct resource *resource = NULL;
4229 struct qsee_apps_region_info_ireq req;
4230 struct qseecom_command_scm_resp resp;
4231
4232 resource = platform_get_resource_byname(pdev,
4233 IORESOURCE_MEM, "secapp-region");
4234 if (resource) {
4235 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
4236 req.addr = resource->start;
4237 req.size = resource_size(resource);
4238 pr_warn("secure app region addr=0x%x size=0x%x",
4239 req.addr, req.size);
4240 } else {
4241 pr_err("Fail to get secure app region info\n");
4242 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304243 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004244 }
4245 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
4246 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07004247 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
4248 pr_err("send secapp reg fail %d resp.res %d\n",
4249 rc, resp.result);
4250 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304251 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08004252 }
4253 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004254 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004255 qseecom_platform_support = (struct msm_bus_scale_pdata *)
4256 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08004257 }
Zhen Kong2edf90d2013-08-27 12:05:06 -07004258 if (qseecom.support_bus_scaling) {
4259 init_timer(&(qseecom.bw_scale_down_timer));
4260 INIT_WORK(&qseecom.bw_inactive_req_ws,
4261 qseecom_bw_inactive_req_work);
4262 qseecom.bw_scale_down_timer.function =
4263 qseecom_scale_bus_bandwidth_timer_callback;
4264 }
Zhen Kongea5d4bb2014-02-18 14:59:53 -08004265 qseecom.timer_running = false;
Mona Hossain17a4faf2013-03-22 16:40:56 -07004266 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004267 qseecom_platform_support);
4268
Mona Hossain17a4faf2013-03-22 16:40:56 -07004269 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07004270 pr_err("Unable to register bus client\n");
4271 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304272
4273exit_destroy_ion_client:
4274 ion_client_destroy(qseecom.ion_clnt);
4275exit_del_cdev:
4276 cdev_del(&qseecom.cdev);
4277exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004278 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304279exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004280 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304281exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08004282 unregister_chrdev_region(qseecom_device_no, 1);
4283 return rc;
4284}
4285
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004286static int __devinit qseecom_remove(struct platform_device *pdev)
4287{
Mona Hossaind44a3842012-10-15 09:41:35 -07004288 struct qseecom_registered_kclient_list *kclient = NULL;
4289 unsigned long flags = 0;
4290 int ret = 0;
4291
Mona Hossaind44a3842012-10-15 09:41:35 -07004292 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304293
Mona Hossaind44a3842012-10-15 09:41:35 -07004294 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304295 list) {
4296 if (!kclient)
4297 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07004298
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304299 /* Break the loop if client handle is NULL */
4300 if (!kclient->handle)
4301 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07004302
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304303 if (list_empty(&kclient->list))
4304 goto exit_free_kc_handle;
4305
4306 list_del(&kclient->list);
Hariprasad Dhalinarasimhabd0c5452013-06-21 18:40:50 -07004307 ret = qseecom_unload_app(kclient->handle->dev, false);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304308 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07004309 kzfree(kclient->handle->dev);
4310 kzfree(kclient->handle);
4311 kzfree(kclient);
4312 }
Mona Hossaind44a3842012-10-15 09:41:35 -07004313 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304314
4315exit_free_kc_handle:
4316 kzfree(kclient->handle);
4317exit_free_kclient:
4318 kzfree(kclient);
4319exit_irqrestore:
4320 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
4321
4322 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07004323 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08004324
Mona Hossain17a4faf2013-03-22 16:40:56 -07004325 if (qseecom.qsee_perf_client)
4326 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
4327 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304328 if (pdev->dev.platform_data != NULL)
4329 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
4330
Zhen Kong2edf90d2013-08-27 12:05:06 -07004331 if (qseecom.support_bus_scaling) {
4332 cancel_work_sync(&qseecom.bw_inactive_req_ws);
4333 del_timer_sync(&qseecom.bw_scale_down_timer);
4334 }
4335
Mona Hossaind39e33b2012-11-05 13:36:40 -08004336 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07004337 if (pdev->dev.of_node) {
4338 __qseecom_deinit_clk(CLK_QSEE);
Zhen Konga10dcab2014-03-19 10:32:27 -07004339 if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
4340 (qseecom.support_pfe || qseecom.support_fde))
Mona Hossainc92629e2013-04-01 13:37:46 -07004341 __qseecom_deinit_clk(CLK_CE_DRV);
4342 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304343
4344 ion_client_destroy(qseecom.ion_clnt);
4345
4346 cdev_del(&qseecom.cdev);
4347
4348 device_destroy(driver_class, qseecom_device_no);
4349
4350 class_destroy(driver_class);
4351
4352 unregister_chrdev_region(qseecom_device_no, 1);
4353
Mona Hossaind44a3842012-10-15 09:41:35 -07004354 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304355}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004356
Zhen Konga0944b82013-11-06 17:02:00 -08004357static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
4358{
4359 int ret = 0;
4360 struct qseecom_clk *qclk;
4361 qclk = &qseecom.qsee;
4362
Zhen Konge5b434e2014-04-17 16:47:06 -07004363 mutex_lock(&qsee_bw_mutex);
4364 mutex_lock(&clk_access_lock);
4365
4366 if (qseecom.cumulative_mode != INACTIVE &&
4367 qseecom.current_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004368 ret = msm_bus_scale_client_update_request(
4369 qseecom.qsee_perf_client, INACTIVE);
Zhen Konga0944b82013-11-06 17:02:00 -08004370 if (ret)
4371 pr_err("Fail to scale down bus\n");
Zhen Konge5b434e2014-04-17 16:47:06 -07004372 else
4373 qseecom.current_mode = INACTIVE;
Zhen Konga0944b82013-11-06 17:02:00 -08004374 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004375
Zhen Konga0944b82013-11-06 17:02:00 -08004376 if (qclk->clk_access_cnt) {
4377 if (qclk->ce_clk != NULL)
4378 clk_disable_unprepare(qclk->ce_clk);
4379 if (qclk->ce_core_clk != NULL)
4380 clk_disable_unprepare(qclk->ce_core_clk);
4381 if (qclk->ce_bus_clk != NULL)
4382 clk_disable_unprepare(qclk->ce_bus_clk);
4383 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004384
4385 del_timer_sync(&(qseecom.bw_scale_down_timer));
4386 qseecom.timer_running = false;
4387
Zhen Konga0944b82013-11-06 17:02:00 -08004388 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004389 mutex_unlock(&qsee_bw_mutex);
4390
Zhen Konga0944b82013-11-06 17:02:00 -08004391 return 0;
4392}
4393
4394static int qseecom_resume(struct platform_device *pdev)
4395{
4396 int mode = 0;
4397 int ret = 0;
4398 struct qseecom_clk *qclk;
4399 qclk = &qseecom.qsee;
4400
Zhen Konge5b434e2014-04-17 16:47:06 -07004401 mutex_lock(&qsee_bw_mutex);
4402 mutex_lock(&clk_access_lock);
Zhen Konga0944b82013-11-06 17:02:00 -08004403 if (qseecom.cumulative_mode >= HIGH)
4404 mode = HIGH;
4405 else
4406 mode = qseecom.cumulative_mode;
4407
4408 if (qseecom.cumulative_mode != INACTIVE) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004409 ret = msm_bus_scale_client_update_request(
Zhen Kong98b0e512014-04-04 10:12:24 -07004410 qseecom.qsee_perf_client, mode);
Zhen Konga0944b82013-11-06 17:02:00 -08004411 if (ret)
Zhen Kong98b0e512014-04-04 10:12:24 -07004412 pr_err("Fail to scale up bus to %d\n", mode);
Zhen Konge5b434e2014-04-17 16:47:06 -07004413 else
4414 qseecom.current_mode = mode;
Zhen Konga0944b82013-11-06 17:02:00 -08004415 }
4416
Zhen Konga0944b82013-11-06 17:02:00 -08004417 if (qclk->clk_access_cnt) {
4418
4419 ret = clk_prepare_enable(qclk->ce_core_clk);
4420 if (ret) {
4421 pr_err("Unable to enable/prepare CE core clk\n");
4422 qclk->clk_access_cnt = 0;
4423 goto err;
4424 }
4425
4426 ret = clk_prepare_enable(qclk->ce_clk);
4427 if (ret) {
4428 pr_err("Unable to enable/prepare CE iface clk\n");
4429 qclk->clk_access_cnt = 0;
4430 goto ce_clk_err;
4431 }
4432
4433 ret = clk_prepare_enable(qclk->ce_bus_clk);
4434 if (ret) {
4435 pr_err("Unable to enable/prepare CE bus clk\n");
4436 qclk->clk_access_cnt = 0;
4437 goto ce_bus_clk_err;
4438 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004439 }
4440
4441 if (qclk->clk_access_cnt || qseecom.cumulative_mode) {
Zhen Kongca4c2d52014-03-12 13:22:46 -07004442 qseecom.bw_scale_down_timer.expires = jiffies +
4443 msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
Zhen Konge5b434e2014-04-17 16:47:06 -07004444 mod_timer(&(qseecom.bw_scale_down_timer),
4445 qseecom.bw_scale_down_timer.expires);
Zhen Kongca4c2d52014-03-12 13:22:46 -07004446 qseecom.timer_running = true;
Zhen Konga0944b82013-11-06 17:02:00 -08004447 }
Zhen Konge5b434e2014-04-17 16:47:06 -07004448
Zhen Konga0944b82013-11-06 17:02:00 -08004449 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004450 mutex_unlock(&qsee_bw_mutex);
4451
4452
Zhen Konga0944b82013-11-06 17:02:00 -08004453 return 0;
4454
4455ce_bus_clk_err:
4456 clk_disable_unprepare(qclk->ce_clk);
4457ce_clk_err:
4458 clk_disable_unprepare(qclk->ce_core_clk);
4459err:
4460 mutex_unlock(&clk_access_lock);
Zhen Konge5b434e2014-04-17 16:47:06 -07004461 mutex_unlock(&qsee_bw_mutex);
Zhen Konga0944b82013-11-06 17:02:00 -08004462 return -EIO;
4463}
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004464static struct of_device_id qseecom_match[] = {
4465 {
4466 .compatible = "qcom,qseecom",
4467 },
4468 {}
4469};
4470
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004471static struct platform_driver qseecom_plat_driver = {
4472 .probe = qseecom_probe,
4473 .remove = qseecom_remove,
Zhen Konga0944b82013-11-06 17:02:00 -08004474 .suspend = qseecom_suspend,
4475 .resume = qseecom_resume,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004476 .driver = {
4477 .name = "qseecom",
4478 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07004479 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07004480 },
4481};
4482
4483static int __devinit qseecom_init(void)
4484{
4485 return platform_driver_register(&qseecom_plat_driver);
4486}
4487
4488static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08004489{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05304490 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08004491}
4492
4493MODULE_LICENSE("GPL v2");
4494MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
4495
4496module_init(qseecom_init);
4497module_exit(qseecom_exit);