blob: 0bc18fbeba9aec5b66616d75da0972649ed3ecc8 [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 *
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08003 * Copyright (c) 2012-2013, 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
Mona Hossain4cf78a92013-02-14 12:06:41 -080064#define QSEECOM_DISK_ENCRYTPION_KEY_ID 0
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
Ramesh Masavarapua26cce72012-04-09 12:32:25 -070074enum qseecom_clk_definitions {
75 CLK_DFAB = 0,
76 CLK_SFPB,
77};
78
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080079enum qseecom_client_handle_type {
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053080 QSEECOM_CLIENT_APP = 1,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080081 QSEECOM_LISTENER_SERVICE,
82 QSEECOM_SECURE_SERVICE,
83 QSEECOM_GENERIC,
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +053084 QSEECOM_UNAVAILABLE_CLIENT_APP,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -080085};
86
Mona Hossainc92629e2013-04-01 13:37:46 -070087enum qseecom_ce_hw_instance {
88 CLK_QSEE = 0,
89 CLK_CE_DRV,
90};
91
Mona Hossain2892b6b2012-02-17 13:53:11 -080092static struct class *driver_class;
93static dev_t qseecom_device_no;
Mona Hossain2892b6b2012-02-17 13:53:11 -080094
Mona Hossain2892b6b2012-02-17 13:53:11 -080095static DEFINE_MUTEX(qsee_bw_mutex);
96static DEFINE_MUTEX(app_access_lock);
Mona Hossainc92629e2013-04-01 13:37:46 -070097static DEFINE_MUTEX(clk_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -080098
Mona Hossain2892b6b2012-02-17 13:53:11 -080099struct qseecom_registered_listener_list {
100 struct list_head list;
101 struct qseecom_register_listener_req svc;
102 u8 *sb_reg_req;
103 u8 *sb_virt;
104 s32 sb_phys;
105 size_t sb_length;
106 struct ion_handle *ihandle; /* Retrieve phy addr */
107
108 wait_queue_head_t rcv_req_wq;
109 int rcv_req_flag;
110};
111
112struct qseecom_registered_app_list {
113 struct list_head list;
114 u32 app_id;
115 u32 ref_cnt;
116};
117
Mona Hossaind44a3842012-10-15 09:41:35 -0700118struct qseecom_registered_kclient_list {
119 struct list_head list;
120 struct qseecom_handle *handle;
121};
122
Mona Hossain4cf78a92013-02-14 12:06:41 -0800123struct ce_hw_usage_info {
124 uint32_t qsee_ce_hw_instance;
125 uint32_t hlos_ce_hw_instance;
126 uint32_t disk_encrypt_pipe;
127};
128
Mona Hossain17a4faf2013-03-22 16:40:56 -0700129struct qseecom_clk {
Mona Hossainc92629e2013-04-01 13:37:46 -0700130 enum qseecom_ce_hw_instance instance;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700131 struct clk *ce_core_clk;
132 struct clk *ce_clk;
133 struct clk *ce_core_src_clk;
134 struct clk *ce_bus_clk;
Mona Hossainc92629e2013-04-01 13:37:46 -0700135 uint32_t clk_access_cnt;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700136};
137
Mona Hossain2892b6b2012-02-17 13:53:11 -0800138struct qseecom_control {
139 struct ion_client *ion_clnt; /* Ion client */
140 struct list_head registered_listener_list_head;
141 spinlock_t registered_listener_list_lock;
142
143 struct list_head registered_app_list_head;
144 spinlock_t registered_app_list_lock;
145
Mona Hossaind44a3842012-10-15 09:41:35 -0700146 struct list_head registered_kclient_list_head;
147 spinlock_t registered_kclient_list_lock;
148
Mona Hossain2892b6b2012-02-17 13:53:11 -0800149 wait_queue_head_t send_resp_wq;
150 int send_resp_flag;
151
152 uint32_t qseos_version;
Mona Hossain05c73562012-10-29 17:49:01 -0700153 uint32_t qsee_version;
Ramesh Masavarapuff377032012-09-14 12:11:32 -0700154 struct device *pdev;
Mona Hossain05c73562012-10-29 17:49:01 -0700155 bool commonlib_loaded;
Mona Hossain4cf78a92013-02-14 12:06:41 -0800156 struct ce_hw_usage_info ce_info;
Mona Hossain17a4faf2013-03-22 16:40:56 -0700157
158 int qsee_bw_count;
159 int qsee_sfpb_bw_count;
160
161 uint32_t qsee_perf_client;
162 struct qseecom_clk qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -0700163 struct qseecom_clk ce_drv;
AnilKumar Chimataa253a032013-10-04 18:53:42 +0530164 struct cdev cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800165};
166
167struct qseecom_client_handle {
168 u32 app_id;
169 u8 *sb_virt;
170 s32 sb_phys;
171 uint32_t user_virt_sb_base;
172 size_t sb_length;
173 struct ion_handle *ihandle; /* Retrieve phy addr */
174};
175
176struct qseecom_listener_handle {
177 u32 id;
178};
179
180static struct qseecom_control qseecom;
181
182struct qseecom_dev_handle {
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800183 enum qseecom_client_handle_type type;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800184 union {
185 struct qseecom_client_handle client;
186 struct qseecom_listener_handle listener;
187 };
188 bool released;
189 int abort;
190 wait_queue_head_t abort_wq;
191 atomic_t ioctl_count;
Mona Hossainc9c83c72013-04-11 12:43:48 -0700192 bool perf_enabled;
193 bool fast_load_enabled;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800194};
195
Mona Hossain4cf78a92013-02-14 12:06:41 -0800196enum qseecom_set_clear_key_flag {
197 QSEECOM_CLEAR_CE_KEY_CMD = 0,
198 QSEECOM_SET_CE_KEY_CMD,
199};
200
201struct qseecom_set_key_parameter {
202 uint32_t ce_hw;
203 uint32_t pipe;
204 uint32_t flags;
205 uint8_t key_id[QSEECOM_KEY_ID_SIZE];
206 unsigned char hash32[QSEECOM_HASH_SIZE];
207 enum qseecom_set_clear_key_flag set_clear_key_flag;
208};
209
Mona Hossainf1f2ed62012-11-15 19:51:33 -0800210struct qseecom_sg_entry {
211 uint32_t phys_addr;
212 uint32_t len;
213};
214
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700215/* Function proto types */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800216static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
217static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
Zhen Kong7812dc12013-07-09 17:12:55 -0700218static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce);
219static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700220
Mona Hossain2892b6b2012-02-17 13:53:11 -0800221static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
Mona Hossain0af10ab2012-02-28 18:26:41 -0800222 struct qseecom_register_listener_req *svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -0800223{
224 struct qseecom_registered_listener_list *ptr;
225 int unique = 1;
226 unsigned long flags;
227
228 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
229 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
Mona Hossain0af10ab2012-02-28 18:26:41 -0800230 if (ptr->svc.listener_id == svc->listener_id) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800231 pr_err("Service id: %u is already registered\n",
232 ptr->svc.listener_id);
233 unique = 0;
234 break;
235 }
236 }
237 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
238 return unique;
239}
240
241static struct qseecom_registered_listener_list *__qseecom_find_svc(
242 int32_t listener_id)
243{
244 struct qseecom_registered_listener_list *entry = NULL;
245 unsigned long flags;
246
247 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
248 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
249 {
250 if (entry->svc.listener_id == listener_id)
251 break;
252 }
253 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +0530254
255 if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
256 pr_err("Service id: %u is not found\n", listener_id);
257 return NULL;
258 }
259
Mona Hossain2892b6b2012-02-17 13:53:11 -0800260 return entry;
261}
262
263static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
264 struct qseecom_dev_handle *handle,
265 struct qseecom_register_listener_req *listener)
266{
267 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800268 struct qseecom_register_listener_ireq req;
269 struct qseecom_command_scm_resp resp;
270 ion_phys_addr_t pa;
271
272 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800273 svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
274 listener->ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800275 if (svc->ihandle == NULL) {
276 pr_err("Ion client could not retrieve the handle\n");
277 return -ENOMEM;
278 }
279
280 /* Get the physical address of the ION BUF */
281 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
282
283 /* Populate the structure for sending scm call to load image */
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700284 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800285 svc->sb_phys = pa;
286
Mona Hossaind4613de2013-05-15 16:49:29 -0700287 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
288 req.listener_id = svc->svc.listener_id;
289 req.sb_len = svc->sb_length;
290 req.sb_ptr = (void *)svc->sb_phys;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800291
Mona Hossaind4613de2013-05-15 16:49:29 -0700292 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800293
Mona Hossaind4613de2013-05-15 16:49:29 -0700294 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800295 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700296 if (ret) {
297 pr_err("qseecom_scm_call failed with err: %d\n", ret);
298 return -EINVAL;
299 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800300
Mona Hossaind4613de2013-05-15 16:49:29 -0700301 if (resp.result != QSEOS_RESULT_SUCCESS) {
302 pr_err("Error SB registration req: resp.result = %d\n",
303 resp.result);
304 return -EPERM;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800305 }
306 return 0;
307}
308
309static int qseecom_register_listener(struct qseecom_dev_handle *data,
310 void __user *argp)
311{
312 int ret = 0;
313 unsigned long flags;
314 struct qseecom_register_listener_req rcvd_lstnr;
315 struct qseecom_registered_listener_list *new_entry;
316
317 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
318 if (ret) {
319 pr_err("copy_from_user failed\n");
320 return ret;
321 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800322 data->listener.id = 0;
Mona Hossain0af10ab2012-02-28 18:26:41 -0800323 if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800324 pr_err("Service is not unique and is already registered\n");
Mona Hossain0af10ab2012-02-28 18:26:41 -0800325 data->released = true;
326 return -EBUSY;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800327 }
328
329 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
330 if (!new_entry) {
331 pr_err("kmalloc failed\n");
332 return -ENOMEM;
333 }
334 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
335 new_entry->rcv_req_flag = 0;
336
337 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
338 new_entry->sb_length = rcvd_lstnr.sb_size;
339 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
340 pr_err("qseecom_set_sb_memoryfailed\n");
341 kzfree(new_entry);
342 return -ENOMEM;
343 }
Mona Hossain0af10ab2012-02-28 18:26:41 -0800344
Mona Hossain2892b6b2012-02-17 13:53:11 -0800345 data->listener.id = rcvd_lstnr.listener_id;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800346 init_waitqueue_head(&new_entry->rcv_req_wq);
347
348 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
349 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
350 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
Mona Hossain0af10ab2012-02-28 18:26:41 -0800351
Mona Hossain2892b6b2012-02-17 13:53:11 -0800352 return ret;
353}
354
355static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
356{
357 int ret = 0;
358 unsigned long flags;
359 uint32_t unmap_mem = 0;
360 struct qseecom_register_listener_ireq req;
361 struct qseecom_registered_listener_list *ptr_svc = NULL;
362 struct qseecom_command_scm_resp resp;
363 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
364
Mona Hossaind4613de2013-05-15 16:49:29 -0700365 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
366 req.listener_id = data->listener.id;
367 resp.result = QSEOS_RESULT_INCOMPLETE;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800368
Mona Hossaind4613de2013-05-15 16:49:29 -0700369 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800370 sizeof(req), &resp, sizeof(resp));
Mona Hossaind4613de2013-05-15 16:49:29 -0700371 if (ret) {
372 pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
373 ret, data->listener.id);
374 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800375 }
Mona Hossaind4613de2013-05-15 16:49:29 -0700376
377 if (resp.result != QSEOS_RESULT_SUCCESS) {
378 pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
379 resp.result, data->listener.id);
380 return -EPERM;
381 }
382
Mona Hossain2892b6b2012-02-17 13:53:11 -0800383 data->abort = 1;
384 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
385 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
386 list) {
387 if (ptr_svc->svc.listener_id == data->listener.id) {
388 wake_up_all(&ptr_svc->rcv_req_wq);
389 break;
390 }
391 }
392 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
393
394 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700395 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800396 atomic_read(&data->ioctl_count) <= 1)) {
397 pr_err("Interrupted from abort\n");
398 ret = -ERESTARTSYS;
399 break;
400 }
401 }
402
403 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
404 list_for_each_entry(ptr_svc,
405 &qseecom.registered_listener_list_head,
406 list)
407 {
408 if (ptr_svc->svc.listener_id == data->listener.id) {
409 if (ptr_svc->sb_virt) {
410 unmap_mem = 1;
411 ihandle = ptr_svc->ihandle;
412 }
413 list_del(&ptr_svc->list);
414 kzfree(ptr_svc);
415 break;
416 }
417 }
418 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
419
420 /* Unmap the memory */
421 if (unmap_mem) {
422 if (!IS_ERR_OR_NULL(ihandle)) {
423 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
424 ion_free(qseecom.ion_clnt, ihandle);
425 }
426 }
427 data->released = true;
428 return ret;
429}
430
431static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
432 void __user *argp)
433{
434 ion_phys_addr_t pa;
435 int32_t ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800436 struct qseecom_set_sb_mem_param_req req;
437 uint32_t len;
438
439 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700440 if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
Mona Hossain2892b6b2012-02-17 13:53:11 -0800441 return -EFAULT;
442
Mona Hossaina1124de2013-10-01 13:41:09 -0700443 if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
444 (req.sb_len == 0)) {
445 pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
446 req.ifd_data_fd, req.sb_len, req.virt_sb_base);
447 return -EFAULT;
448 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800449 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -0800450 data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
451 req.ifd_data_fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800452 if (IS_ERR_OR_NULL(data->client.ihandle)) {
453 pr_err("Ion client could not retrieve the handle\n");
454 return -ENOMEM;
455 }
456 /* Get the physical address of the ION BUF */
457 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
458 /* Populate the structure for sending scm call to load image */
459 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700460 data->client.ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800461 data->client.sb_phys = pa;
462 data->client.sb_length = req.sb_len;
463 data->client.user_virt_sb_base = req.virt_sb_base;
464 return 0;
465}
466
Mona Hossain2892b6b2012-02-17 13:53:11 -0800467static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
468{
469 int ret;
470 ret = (qseecom.send_resp_flag != 0);
471 return ret || data->abort;
472}
473
474static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
475 struct qseecom_command_scm_resp *resp)
476{
477 int ret = 0;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800478 int rc = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800479 uint32_t lstnr;
480 unsigned long flags;
481 struct qseecom_client_listener_data_irsp send_data_rsp;
482 struct qseecom_registered_listener_list *ptr_svc = NULL;
Mona Hossain91da2c52013-03-29 17:28:31 -0700483 sigset_t new_sigset;
484 sigset_t old_sigset;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800485
Mona Hossain2892b6b2012-02-17 13:53:11 -0800486 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
487 lstnr = resp->data;
488 /*
489 * Wake up blocking lsitener service with the lstnr id
490 */
491 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
492 flags);
493 list_for_each_entry(ptr_svc,
494 &qseecom.registered_listener_list_head, list) {
495 if (ptr_svc->svc.listener_id == lstnr) {
496 ptr_svc->rcv_req_flag = 1;
497 wake_up_interruptible(&ptr_svc->rcv_req_wq);
498 break;
499 }
500 }
501 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
502 flags);
Zhen Kongc4d49512013-10-03 13:47:23 -0700503
504 if (ptr_svc == NULL) {
505 pr_err("Listener Svc %d does not exist\n", lstnr);
506 return -EINVAL;
507 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800508 if (ptr_svc->svc.listener_id != lstnr) {
509 pr_warning("Service requested for does on exist\n");
510 return -ERESTARTSYS;
511 }
512 pr_debug("waking up rcv_req_wq and "
513 "waiting for send_resp_wq\n");
Mona Hossain2892b6b2012-02-17 13:53:11 -0800514
Mona Hossain91da2c52013-03-29 17:28:31 -0700515 /* initialize the new signal mask with all signals*/
516 sigfillset(&new_sigset);
517 /* block all signals */
518 sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
519
520 do {
521 if (!wait_event_freezable(qseecom.send_resp_wq,
522 __qseecom_listener_has_sent_rsp(data)))
523 break;
524 } while (1);
525
526 /* restore signal mask */
527 sigprocmask(SIG_SETMASK, &old_sigset, NULL);
528 if (data->abort) {
Mona Hossaineaa69b72013-04-15 17:20:15 -0700529 pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
530 data->client.app_id, lstnr, ret);
Mona Hossain91da2c52013-03-29 17:28:31 -0700531 rc = -ENODEV;
Mona Hossain0b3a2792013-02-05 17:38:55 -0800532 send_data_rsp.status = QSEOS_RESULT_FAILURE;
533 } else {
534 send_data_rsp.status = QSEOS_RESULT_SUCCESS;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800535 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800536
Mona Hossain2892b6b2012-02-17 13:53:11 -0800537 qseecom.send_resp_flag = 0;
538 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
539 send_data_rsp.listener_id = lstnr ;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700540 if (ptr_svc)
541 msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
542 ptr_svc->sb_virt, ptr_svc->sb_length,
543 ION_IOC_CLEAN_INV_CACHES);
Zhen Kong7812dc12013-07-09 17:12:55 -0700544
545 if (lstnr == RPMB_SERVICE)
546 __qseecom_enable_clk(CLK_QSEE);
547
Mona Hossain2892b6b2012-02-17 13:53:11 -0800548 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
549 (const void *)&send_data_rsp,
550 sizeof(send_data_rsp), resp,
551 sizeof(*resp));
552 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -0700553 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800554 ret, data->client.app_id);
Zhen Kong7812dc12013-07-09 17:12:55 -0700555 if (lstnr == RPMB_SERVICE)
556 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800557 return ret;
558 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800559 if ((resp->result != QSEOS_RESULT_SUCCESS) &&
560 (resp->result != QSEOS_RESULT_INCOMPLETE)) {
561 pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
562 resp->result, data->client.app_id, lstnr);
563 ret = -EINVAL;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700564 }
Zhen Kong7812dc12013-07-09 17:12:55 -0700565 if (lstnr == RPMB_SERVICE)
566 __qseecom_disable_clk(CLK_QSEE);
567
Mona Hossain2892b6b2012-02-17 13:53:11 -0800568 }
Mona Hossain0b3a2792013-02-05 17:38:55 -0800569 if (rc)
570 return rc;
571
Mona Hossain2892b6b2012-02-17 13:53:11 -0800572 return ret;
573}
574
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700575static int __qseecom_check_app_exists(struct qseecom_check_app_ireq req)
576{
577 int32_t ret;
578 struct qseecom_command_scm_resp resp;
579
580 /* SCM_CALL to check if app_id for the mentioned app exists */
581 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
582 sizeof(struct qseecom_check_app_ireq),
583 &resp, sizeof(resp));
584 if (ret) {
585 pr_err("scm_call to check if app is already loaded failed\n");
586 return -EINVAL;
587 }
588
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700589 if (resp.result == QSEOS_RESULT_FAILURE) {
590 return 0;
591 } else {
592 switch (resp.resp_type) {
593 /*qsee returned listener type response */
594 case QSEOS_LISTENER_ID:
595 pr_err("resp type is of listener type instead of app");
596 return -EINVAL;
597 break;
598 case QSEOS_APP_ID:
599 return resp.data;
600 default:
601 pr_err("invalid resp type (%d) from qsee",
602 resp.resp_type);
603 return -ENODEV;
604 break;
605 }
606 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -0700607}
608
Mona Hossain2892b6b2012-02-17 13:53:11 -0800609static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
610{
611 struct qseecom_registered_app_list *entry = NULL;
612 unsigned long flags = 0;
613 u32 app_id = 0;
614 struct ion_handle *ihandle; /* Ion handle */
615 struct qseecom_load_img_req load_img_req;
616 int32_t ret;
617 ion_phys_addr_t pa = 0;
618 uint32_t len;
619 struct qseecom_command_scm_resp resp;
Mona Hossain436b75f2012-11-20 17:10:40 -0800620 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700621 struct qseecom_load_app_ireq load_req;
622
Mona Hossain2892b6b2012-02-17 13:53:11 -0800623 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700624 if (copy_from_user(&load_img_req,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800625 (void __user *)argp,
626 sizeof(struct qseecom_load_img_req))) {
627 pr_err("copy_from_user failed\n");
628 return -EFAULT;
629 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700630 /* Vote for the SFPB clock */
Mona Hossain04d3fac2012-12-03 10:10:37 -0800631 ret = qsee_vote_for_clock(data, CLK_SFPB);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -0700632 if (ret)
633 pr_warning("Unable to vote for SFPB clock");
Mona Hossain436b75f2012-11-20 17:10:40 -0800634 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -0700635 load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
Mona Hossain436b75f2012-11-20 17:10:40 -0800636 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800637
Mona Hossain436b75f2012-11-20 17:10:40 -0800638 ret = __qseecom_check_app_exists(req);
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530639 if (ret < 0) {
640 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800641 return ret;
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530642 }
Mona Hossain436b75f2012-11-20 17:10:40 -0800643
AnilKumar Chimata5370c7a2013-06-12 12:43:55 +0530644 app_id = ret;
Mona Hossain436b75f2012-11-20 17:10:40 -0800645 if (app_id) {
Mona Hossain7c443202013-04-18 12:08:58 -0700646 pr_debug("App id %d (%s) already exists\n", app_id,
Mona Hossain436b75f2012-11-20 17:10:40 -0800647 (char *)(req.app_name));
648 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
649 list_for_each_entry(entry,
650 &qseecom.registered_app_list_head, list){
651 if (entry->app_id == app_id) {
652 entry->ref_cnt++;
653 break;
654 }
655 }
656 spin_unlock_irqrestore(
657 &qseecom.registered_app_list_lock, flags);
658 } else {
659 pr_warn("App (%s) does'nt exist, loading apps for first time\n",
Mona Hossaind44a3842012-10-15 09:41:35 -0700660 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800661 /* Get the handle of the shared fd */
662 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800663 load_img_req.ifd_data_fd);
Mona Hossain436b75f2012-11-20 17:10:40 -0800664 if (IS_ERR_OR_NULL(ihandle)) {
665 pr_err("Ion client could not retrieve the handle\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800666 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800667 return -ENOMEM;
668 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800669
Mona Hossain436b75f2012-11-20 17:10:40 -0800670 /* Get the physical address of the ION BUF */
671 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800672
Mona Hossain436b75f2012-11-20 17:10:40 -0800673 /* Populate the structure for sending scm call to load image */
674 memcpy(load_req.app_name, load_img_req.img_name,
675 MAX_APP_NAME_SIZE);
676 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
677 load_req.mdt_len = load_img_req.mdt_len;
678 load_req.img_len = load_img_req.img_len;
679 load_req.phy_addr = pa;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700680 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
681 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800682
Mona Hossain436b75f2012-11-20 17:10:40 -0800683 /* SCM_CALL to load the app and get the app_id back */
684 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700685 sizeof(struct qseecom_load_app_ireq),
686 &resp, sizeof(resp));
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700687 if (ret) {
Mona Hossain436b75f2012-11-20 17:10:40 -0800688 pr_err("scm_call to load app failed\n");
Hariprasad Dhalinarasimha56d35122013-02-28 17:55:51 -0800689 if (!IS_ERR_OR_NULL(ihandle))
690 ion_free(qseecom.ion_clnt, ihandle);
691 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800692 return -EINVAL;
693 }
694
695 if (resp.result == QSEOS_RESULT_FAILURE) {
696 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700697 if (!IS_ERR_OR_NULL(ihandle))
698 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800699 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800700 return -EFAULT;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700701 }
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700702
Mona Hossain436b75f2012-11-20 17:10:40 -0800703 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
704 ret = __qseecom_process_incomplete_cmd(data, &resp);
705 if (ret) {
706 pr_err("process_incomplete_cmd failed err: %d\n",
707 ret);
708 if (!IS_ERR_OR_NULL(ihandle))
709 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800710 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800711 return ret;
712 }
713 }
714
715 if (resp.result != QSEOS_RESULT_SUCCESS) {
716 pr_err("scm_call failed resp.result unknown, %d\n",
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700717 resp.result);
Mona Hossain436b75f2012-11-20 17:10:40 -0800718 if (!IS_ERR_OR_NULL(ihandle))
719 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800720 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800721 return -EFAULT;
722 }
723
724 app_id = resp.data;
725
726 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
727 if (!entry) {
728 pr_err("kmalloc failed\n");
Mona Hossain04d3fac2012-12-03 10:10:37 -0800729 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain436b75f2012-11-20 17:10:40 -0800730 return -ENOMEM;
731 }
732 entry->app_id = app_id;
733 entry->ref_cnt = 1;
734
735 /* Deallocate the handle */
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700736 if (!IS_ERR_OR_NULL(ihandle))
737 ion_free(qseecom.ion_clnt, ihandle);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700738
Mona Hossain436b75f2012-11-20 17:10:40 -0800739 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
740 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
741 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
742 flags);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -0700743
Mona Hossain436b75f2012-11-20 17:10:40 -0800744 pr_warn("App with id %d (%s) now loaded\n", app_id,
Mona Hossaind44a3842012-10-15 09:41:35 -0700745 (char *)(load_img_req.img_name));
Mona Hossain436b75f2012-11-20 17:10:40 -0800746 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800747 data->client.app_id = app_id;
748 load_img_req.app_id = app_id;
749 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
750 pr_err("copy_to_user failed\n");
751 kzfree(entry);
Mona Hossain04d3fac2012-12-03 10:10:37 -0800752 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800753 return -EFAULT;
754 }
Mona Hossain04d3fac2012-12-03 10:10:37 -0800755 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800756 return 0;
757}
758
759static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
760{
761 wake_up_all(&qseecom.send_resp_wq);
762 while (atomic_read(&data->ioctl_count) > 1) {
Mona Hossainacea1022012-04-09 13:37:27 -0700763 if (wait_event_freezable(data->abort_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -0800764 atomic_read(&data->ioctl_count) <= 1)) {
765 pr_err("Interrupted from abort\n");
766 return -ERESTARTSYS;
767 break;
768 }
769 }
770 /* Set unload app */
771 return 1;
772}
773
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800774static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
775{
776 int ret = 0;
777 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
778 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
779 ion_free(qseecom.ion_clnt, data->client.ihandle);
780 data->client.ihandle = NULL;
781 }
782 return ret;
783}
784
Mona Hossain2892b6b2012-02-17 13:53:11 -0800785static int qseecom_unload_app(struct qseecom_dev_handle *data)
786{
787 unsigned long flags;
788 int ret = 0;
789 struct qseecom_command_scm_resp resp;
790 struct qseecom_registered_app_list *ptr_app;
Mona Hossain340dba82012-08-07 19:54:46 -0700791 bool unload = false;
792 bool found_app = false;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800793
Mona Hossaind4613de2013-05-15 16:49:29 -0700794 if (data->client.app_id > 0) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800795 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
796 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
797 list) {
798 if (ptr_app->app_id == data->client.app_id) {
Mona Hossain340dba82012-08-07 19:54:46 -0700799 found_app = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800800 if (ptr_app->ref_cnt == 1) {
Mona Hossain340dba82012-08-07 19:54:46 -0700801 unload = true;
Mona Hossain2892b6b2012-02-17 13:53:11 -0800802 break;
803 } else {
804 ptr_app->ref_cnt--;
Mona Hossain7c443202013-04-18 12:08:58 -0700805 pr_debug("Can't unload app(%d) inuse\n",
Mona Hossaina5f1aab2012-03-29 10:18:07 -0700806 ptr_app->app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800807 break;
808 }
809 }
810 }
811 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
812 flags);
Mona Hossain1fb538f2012-08-30 16:19:38 -0700813 if (found_app == false) {
814 pr_err("Cannot find app with id = %d\n",
815 data->client.app_id);
816 return -EINVAL;
817 }
Mona Hossain2892b6b2012-02-17 13:53:11 -0800818 }
819
Mona Hossaind4613de2013-05-15 16:49:29 -0700820 if (unload) {
Mona Hossain2892b6b2012-02-17 13:53:11 -0800821 struct qseecom_unload_app_ireq req;
822
Mona Hossain340dba82012-08-07 19:54:46 -0700823 __qseecom_cleanup_app(data);
824 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
825 list_del(&ptr_app->list);
826 kzfree(ptr_app);
827 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
828 flags);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800829 /* Populate the structure for sending scm call to load image */
830 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
831 req.app_id = data->client.app_id;
832
833 /* SCM_CALL to unload the app */
834 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
835 sizeof(struct qseecom_unload_app_ireq),
836 &resp, sizeof(resp));
837 if (ret) {
Mona Hossainbb0bca12012-04-12 11:47:45 -0700838 pr_err("scm_call to unload app (id = %d) failed\n",
839 req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800840 return -EFAULT;
Mona Hossainbb0bca12012-04-12 11:47:45 -0700841 } else {
842 pr_warn("App id %d now unloaded\n", req.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800843 }
844 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
845 ret = __qseecom_process_incomplete_cmd(data, &resp);
846 if (ret) {
847 pr_err("process_incomplete_cmd fail err: %d\n",
848 ret);
849 return ret;
850 }
851 }
852 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800853 qseecom_unmap_ion_allocated_memory(data);
Mona Hossain2892b6b2012-02-17 13:53:11 -0800854 data->released = true;
855 return ret;
856}
857
858static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
859 uint32_t virt)
860{
861 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
862}
863
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800864int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
865 struct qseecom_send_svc_cmd_req *req_ptr,
866 struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
867{
868 int ret = 0;
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -0700869 void *req_buf = NULL;
870
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800871 if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
872 pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
873 req_ptr, send_svc_ireq_ptr);
874 return -EINVAL;
875 }
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -0700876
Hariprasad Dhalinarasimha10aed742013-11-18 11:54:03 -0800877 if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
878 pr_err("Invalid req/resp buffer, exiting\n");
879 return -EINVAL;
880 }
881
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -0700882 if (((uint32_t)req_ptr->cmd_req_buf <
883 data_ptr->client.user_virt_sb_base)
884 || ((uint32_t)req_ptr->cmd_req_buf >=
885 (data_ptr->client.user_virt_sb_base +
886 data_ptr->client.sb_length))) {
887 pr_err("cmd buffer address not within shared bufffer\n");
888 return -EINVAL;
889 }
890
891
892 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
893 || ((uint32_t)req_ptr->resp_buf >=
894 (data_ptr->client.user_virt_sb_base +
895 data_ptr->client.sb_length))){
896 pr_err("response buffer address not within shared bufffer\n");
897 return -EINVAL;
898 }
899
900 req_buf = data_ptr->client.sb_virt;
901
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800902 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
903 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -0700904 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800905 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
906 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
907 (uint32_t)req_ptr->resp_buf));
908 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
909
910 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
911 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
912 return ret;
913}
914
915static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
916 void __user *argp)
917{
918 int ret = 0;
919 struct qseecom_client_send_service_ireq send_svc_ireq;
920 struct qseecom_command_scm_resp resp;
921 struct qseecom_send_svc_cmd_req req;
922 /*struct qseecom_command_scm_resp resp;*/
923
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700924 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800925 (void __user *)argp,
926 sizeof(req))) {
927 pr_err("copy_from_user failed\n");
928 return -EFAULT;
929 }
930
931 if (req.resp_buf == NULL) {
932 pr_err("cmd buffer or response buffer is null\n");
933 return -EINVAL;
934 }
935
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800936 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -0700937 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
938 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800939 if (__qseecom_process_rpmb_svc_cmd(data, &req,
940 &send_svc_ireq))
941 return -EINVAL;
942 break;
943 default:
944 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
945 return -EINVAL;
946 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530947
948 ret = qsee_vote_for_clock(data, CLK_DFAB);
949 if (ret) {
950 pr_err("Failed to vote for DFAB clock%d\n", ret);
951 return ret;
952 }
953 ret = qsee_vote_for_clock(data, CLK_SFPB);
954 if (ret) {
955 pr_err("Failed to vote for SFPB clock%d\n", ret);
956 goto exit_reset_dfab_freq;
957 }
958
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700959 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
960 data->client.sb_virt, data->client.sb_length,
961 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800962 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
963 sizeof(send_svc_ireq),
964 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700965 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
966 data->client.sb_virt, data->client.sb_length,
967 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800968 if (ret) {
969 pr_err("qseecom_scm_call failed with err: %d\n", ret);
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530970 goto exit_reset_sdfab_freq;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800971 }
972
973 switch (resp.result) {
974 case QSEOS_RESULT_SUCCESS:
975 break;
976 case QSEOS_RESULT_INCOMPLETE:
977 pr_err("qseos_result_incomplete\n");
978 ret = __qseecom_process_incomplete_cmd(data, &resp);
979 if (ret) {
980 pr_err("process_incomplete_cmd fail: err: %d\n",
981 ret);
982 }
983 break;
984 case QSEOS_RESULT_FAILURE:
985 pr_err("process_incomplete_cmd failed err: %d\n", ret);
986 break;
987 default:
988 pr_err("Response result %d not supported\n",
989 resp.result);
990 ret = -EINVAL;
991 break;
992 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530993exit_reset_sdfab_freq:
994 qsee_disable_clock_vote(data, CLK_SFPB);
995exit_reset_dfab_freq:
996 qsee_disable_clock_vote(data, CLK_DFAB);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800997 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800998}
999
Mona Hossain2892b6b2012-02-17 13:53:11 -08001000static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
1001 struct qseecom_send_cmd_req *req)
1002{
1003 int ret = 0;
1004 u32 reqd_len_sb_in = 0;
1005 struct qseecom_client_send_data_ireq send_data_req;
1006 struct qseecom_command_scm_resp resp;
1007
1008 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1009 pr_err("cmd buffer or response buffer is null\n");
1010 return -EINVAL;
1011 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001012 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1013 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1014 data->client.sb_length))) {
1015 pr_err("cmd buffer address not within shared bufffer\n");
1016 return -EINVAL;
1017 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001018
Mona Hossaindddf4442013-10-01 14:08:20 -07001019
1020 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1021 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1022 data->client.sb_length))){
1023 pr_err("response buffer address not within shared bufffer\n");
1024 return -EINVAL;
1025 }
1026
1027 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001028 req->cmd_req_len > data->client.sb_length ||
1029 req->resp_len > data->client.sb_length) {
1030 pr_err("cmd buffer length or "
1031 "response buffer length not valid\n");
1032 return -EINVAL;
1033 }
1034
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001035 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1036 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1037 return -EINVAL;
1038 }
1039
Mona Hossain2892b6b2012-02-17 13:53:11 -08001040 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1041 if (reqd_len_sb_in > data->client.sb_length) {
1042 pr_debug("Not enough memory to fit cmd_buf and "
1043 "resp_buf. Required: %u, Available: %u\n",
1044 reqd_len_sb_in, data->client.sb_length);
1045 return -ENOMEM;
1046 }
1047
1048 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1049 send_data_req.app_id = data->client.app_id;
1050 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1051 (uint32_t)req->cmd_req_buf));
1052 send_data_req.req_len = req->cmd_req_len;
1053 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1054 (uint32_t)req->resp_buf));
1055 send_data_req.rsp_len = req->resp_len;
1056
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001057 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1058 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001059 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001060 ION_IOC_CLEAN_INV_CACHES);
1061
Mona Hossain2892b6b2012-02-17 13:53:11 -08001062 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1063 sizeof(send_data_req),
1064 &resp, sizeof(resp));
1065 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001066 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1067 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001068 return ret;
1069 }
1070
1071 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1072 ret = __qseecom_process_incomplete_cmd(data, &resp);
1073 if (ret) {
1074 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1075 return ret;
1076 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001077 } else {
1078 if (resp.result != QSEOS_RESULT_SUCCESS) {
1079 pr_err("Response result %d not supported\n",
1080 resp.result);
1081 ret = -EINVAL;
1082 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001083 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001084 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1085 data->client.sb_virt, data->client.sb_length,
1086 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001087 return ret;
1088}
1089
Mona Hossain2892b6b2012-02-17 13:53:11 -08001090static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1091{
1092 int ret = 0;
1093 struct qseecom_send_cmd_req req;
1094
1095 ret = copy_from_user(&req, argp, sizeof(req));
1096 if (ret) {
1097 pr_err("copy_from_user failed\n");
1098 return ret;
1099 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001100 ret = __qseecom_send_cmd(data, &req);
1101
Mona Hossain2892b6b2012-02-17 13:53:11 -08001102 if (ret)
1103 return ret;
1104
Mona Hossain2892b6b2012-02-17 13:53:11 -08001105 return ret;
1106}
1107
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001108static int qseecom_unprotect_buffer(void __user *argp)
1109{
1110 int ret = 0;
1111 struct ion_handle *ihandle;
1112 int32_t ion_fd;
1113
1114 ret = copy_from_user(&ion_fd, argp, sizeof(ion_fd));
1115 if (ret) {
1116 pr_err("copy_from_user failed");
1117 return ret;
1118 }
1119
1120 ihandle = ion_import_dma_buf(qseecom.ion_clnt, ion_fd);
1121
1122 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt, ihandle);
1123 if (ret)
1124 return -EINVAL;
1125 return 0;
1126}
1127
1128static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1129 struct qseecom_dev_handle *data,
1130 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001131{
1132 struct ion_handle *ihandle;
1133 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001134 int ret = 0;
1135 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001136 uint32_t len = 0;
1137 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001138 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1139 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1140 struct qseecom_registered_listener_list *this_lstnr = NULL;
1141
1142 if (msg == NULL) {
1143 pr_err("Invalid address\n");
1144 return -EINVAL;
1145 }
1146 if (listener_svc) {
1147 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1148 this_lstnr = __qseecom_find_svc(data->listener.id);
1149 if (IS_ERR_OR_NULL(this_lstnr)) {
1150 pr_err("Invalid listener ID\n");
1151 return -ENOMEM;
1152 }
1153 } else {
1154 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1155 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001156
1157 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001158 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001159 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001160 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001161 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001162 if (IS_ERR_OR_NULL(ihandle)) {
1163 pr_err("Ion client can't retrieve the handle\n");
1164 return -ENOMEM;
1165 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001166 field = (char *) cmd_req->cmd_req_buf +
1167 cmd_req->ifd_data[i].cmd_buf_offset;
1168 } else if ((listener_svc) &&
1169 (lstnr_resp->ifd_data[i].fd > 0)) {
1170 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1171 lstnr_resp->ifd_data[i].fd);
1172 if (IS_ERR_OR_NULL(ihandle)) {
1173 pr_err("Ion client can't retrieve the handle\n");
1174 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001175 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001176 switch (lstnr_resp->protection_mode) {
1177 case QSEOS_PROTECT_BUFFER:
1178 ret = msm_ion_secure_buffer(qseecom.ion_clnt,
1179 ihandle,
1180 VIDEO_PIXEL,
1181 0);
1182 break;
1183 case QSEOS_UNPROTECT_PROTECTED_BUFFER:
1184 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt,
1185 ihandle);
1186 break;
1187 case QSEOS_UNPROTECTED_BUFFER:
1188 default:
1189 break;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001190 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001191 field = lstnr_resp->resp_buf_ptr +
1192 lstnr_resp->ifd_data[i].cmd_buf_offset;
1193 } else {
1194 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001195 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001196 /* Populate the cmd data structure with the phys_addr */
1197 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1198 if (sg_ptr == NULL) {
1199 pr_err("IOn client could not retrieve sg table\n");
1200 goto err;
1201 }
1202 if (sg_ptr->nents == 0) {
1203 pr_err("Num of scattered entries is 0\n");
1204 goto err;
1205 }
1206 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1207 pr_err("Num of scattered entries");
1208 pr_err(" (%d) is greater than max supported %d\n",
1209 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1210 goto err;
1211 }
1212 sg = sg_ptr->sgl;
1213 if (sg_ptr->nents == 1) {
1214 uint32_t *update;
1215 update = (uint32_t *) field;
1216 if (cleanup)
1217 *update = 0;
1218 else
1219 *update = (uint32_t)sg_dma_address(
1220 sg_ptr->sgl);
1221 len += (uint32_t)sg->length;
1222 } else {
1223 struct qseecom_sg_entry *update;
1224 int j = 0;
1225 update = (struct qseecom_sg_entry *) field;
1226 for (j = 0; j < sg_ptr->nents; j++) {
1227 if (cleanup) {
1228 update->phys_addr = 0;
1229 update->len = 0;
1230 } else {
1231 update->phys_addr = (uint32_t)
1232 sg_dma_address(sg);
1233 update->len = sg->length;
1234 }
1235 len += sg->length;
1236 update++;
1237 sg = sg_next(sg);
1238 }
1239 }
1240 if (cleanup)
1241 msm_ion_do_cache_op(qseecom.ion_clnt,
1242 ihandle, NULL, len,
1243 ION_IOC_INV_CACHES);
1244 else
1245 msm_ion_do_cache_op(qseecom.ion_clnt,
1246 ihandle, NULL, len,
1247 ION_IOC_CLEAN_INV_CACHES);
1248 /* Deallocate the handle */
1249 if (!IS_ERR_OR_NULL(ihandle))
1250 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001251 }
1252 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001253err:
1254 if (!IS_ERR_OR_NULL(ihandle))
1255 ion_free(qseecom.ion_clnt, ihandle);
1256 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001257}
1258
1259static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1260 void __user *argp)
1261{
1262 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001263 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001264 struct qseecom_send_modfd_cmd_req req;
1265 struct qseecom_send_cmd_req send_cmd_req;
1266
1267 ret = copy_from_user(&req, argp, sizeof(req));
1268 if (ret) {
1269 pr_err("copy_from_user failed\n");
1270 return ret;
1271 }
1272 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1273 send_cmd_req.cmd_req_len = req.cmd_req_len;
1274 send_cmd_req.resp_buf = req.resp_buf;
1275 send_cmd_req.resp_len = req.resp_len;
1276
Mona Hossaindddf4442013-10-01 14:08:20 -07001277 /* validate offsets */
1278 for (i = 0; i < MAX_ION_FD; i++) {
1279 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1280 pr_err("Invalid offset %d = 0x%x\n",
1281 i, req.ifd_data[i].cmd_buf_offset);
1282 return -EINVAL;
1283 }
1284 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001285 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001286 if (ret)
1287 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001288 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001289 if (ret)
1290 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001291 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001292 if (ret)
1293 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001294
Mona Hossain2892b6b2012-02-17 13:53:11 -08001295 return ret;
1296}
1297
1298static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1299 struct qseecom_registered_listener_list *svc)
1300{
1301 int ret;
1302 ret = (svc->rcv_req_flag != 0);
1303 return ret || data->abort;
1304}
1305
1306static int qseecom_receive_req(struct qseecom_dev_handle *data)
1307{
1308 int ret = 0;
1309 struct qseecom_registered_listener_list *this_lstnr;
1310
1311 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301312 if (!this_lstnr) {
1313 pr_err("Invalid listener ID\n");
1314 return -ENODATA;
1315 }
1316
Mona Hossain2892b6b2012-02-17 13:53:11 -08001317 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001318 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001319 __qseecom_listener_has_rcvd_req(data,
1320 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001321 pr_warning("Interrupted: exiting Listener Service = %d\n",
1322 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001323 /* woken up for different reason */
1324 return -ERESTARTSYS;
1325 }
1326
1327 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001328 pr_err("Aborting Listener Service = %d\n",
1329 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001330 return -ENODEV;
1331 }
1332 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001333 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001334 }
1335 return ret;
1336}
1337
Mona Hossaind44a3842012-10-15 09:41:35 -07001338static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1339{
1340 struct elf32_hdr *ehdr;
1341
1342 if (fw_entry->size < sizeof(*ehdr)) {
1343 pr_err("%s: Not big enough to be an elf header\n",
1344 qseecom.pdev->init_name);
1345 return false;
1346 }
1347 ehdr = (struct elf32_hdr *)fw_entry->data;
1348 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1349 pr_err("%s: Not an elf header\n",
1350 qseecom.pdev->init_name);
1351 return false;
1352 }
1353
1354 if (ehdr->e_phnum == 0) {
1355 pr_err("%s: No loadable segments\n",
1356 qseecom.pdev->init_name);
1357 return false;
1358 }
1359 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1360 sizeof(struct elf32_hdr) > fw_entry->size) {
1361 pr_err("%s: Program headers not within mdt\n",
1362 qseecom.pdev->init_name);
1363 return false;
1364 }
1365 return true;
1366}
1367
1368static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1369{
1370 int ret = -1;
1371 int i = 0, rc = 0;
1372 const struct firmware *fw_entry = NULL;
1373 struct elf32_phdr *phdr;
1374 char fw_name[MAX_APP_NAME_SIZE];
1375 struct elf32_hdr *ehdr;
1376 int num_images = 0;
1377
1378 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1379 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1380 if (rc) {
1381 pr_err("error with request_firmware\n");
1382 ret = -EIO;
1383 goto err;
1384 }
1385 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1386 ret = -EIO;
1387 goto err;
1388 }
1389 *fw_size = fw_entry->size;
1390 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1391 ehdr = (struct elf32_hdr *)fw_entry->data;
1392 num_images = ehdr->e_phnum;
1393 release_firmware(fw_entry);
1394 for (i = 0; i < num_images; i++, phdr++) {
1395 memset(fw_name, 0, sizeof(fw_name));
1396 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1397 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1398 if (ret)
1399 goto err;
1400 *fw_size += fw_entry->size;
1401 release_firmware(fw_entry);
1402 }
1403 return ret;
1404err:
1405 if (fw_entry)
1406 release_firmware(fw_entry);
1407 *fw_size = 0;
1408 return ret;
1409}
1410
1411static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1412 struct qseecom_load_app_ireq *load_req)
1413{
1414 int ret = -1;
1415 int i = 0, rc = 0;
1416 const struct firmware *fw_entry = NULL;
1417 char fw_name[MAX_APP_NAME_SIZE];
1418 u8 *img_data_ptr = img_data;
1419 struct elf32_hdr *ehdr;
1420 int num_images = 0;
1421
1422 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1423 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1424 if (rc) {
1425 ret = -EIO;
1426 goto err;
1427 }
1428 load_req->img_len = fw_entry->size;
1429 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1430 img_data_ptr = img_data_ptr + fw_entry->size;
1431 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1432 ehdr = (struct elf32_hdr *)fw_entry->data;
1433 num_images = ehdr->e_phnum;
1434 release_firmware(fw_entry);
1435 for (i = 0; i < num_images; i++) {
1436 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1437 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1438 if (ret) {
1439 pr_err("Failed to locate blob %s\n", fw_name);
1440 goto err;
1441 }
1442 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1443 img_data_ptr = img_data_ptr + fw_entry->size;
1444 load_req->img_len += fw_entry->size;
1445 release_firmware(fw_entry);
1446 }
1447 load_req->phy_addr = virt_to_phys(img_data);
1448 return ret;
1449err:
1450 release_firmware(fw_entry);
1451 return ret;
1452}
1453
1454static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1455{
1456 int ret = -1;
1457 uint32_t fw_size = 0;
1458 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1459 struct qseecom_command_scm_resp resp;
1460 u8 *img_data = NULL;
1461
1462 if (__qseecom_get_fw_size(appname, &fw_size))
1463 return -EIO;
1464
1465 img_data = kzalloc(fw_size, GFP_KERNEL);
1466 if (!img_data) {
1467 pr_err("Failied to allocate memory for copying image data\n");
1468 return -ENOMEM;
1469 }
1470 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1471 if (ret) {
1472 kzfree(img_data);
1473 return -EIO;
1474 }
1475
1476 /* Populate the remaining parameters */
1477 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1478 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001479 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001480 if (ret) {
1481 kzfree(img_data);
1482 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001483 return -EIO;
1484 }
1485
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001486 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001487 /* SCM_CALL to load the image */
1488 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1489 sizeof(struct qseecom_load_app_ireq),
1490 &resp, sizeof(resp));
1491 kzfree(img_data);
1492 if (ret) {
1493 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001494 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001495 return -EIO;
1496 }
1497
1498 switch (resp.result) {
1499 case QSEOS_RESULT_SUCCESS:
1500 ret = resp.data;
1501 break;
1502 case QSEOS_RESULT_INCOMPLETE:
1503 ret = __qseecom_process_incomplete_cmd(data, &resp);
1504 if (ret)
1505 pr_err("process_incomplete_cmd FAILED\n");
1506 else
1507 ret = resp.data;
1508 break;
1509 case QSEOS_RESULT_FAILURE:
1510 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1511 break;
1512 default:
1513 pr_err("scm call return unknown response %d\n", resp.result);
1514 ret = -EINVAL;
1515 break;
1516 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001517 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001518
Mona Hossaind44a3842012-10-15 09:41:35 -07001519 return ret;
1520}
1521
Mona Hossain9498f5e2013-01-23 18:08:45 -08001522static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001523{
1524 int32_t ret = 0;
1525 uint32_t fw_size = 0;
1526 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1527 struct qseecom_command_scm_resp resp;
1528 u8 *img_data = NULL;
1529
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001530 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001531 return -EIO;
1532
1533 img_data = kzalloc(fw_size, GFP_KERNEL);
1534 if (!img_data) {
1535 pr_err("Mem allocation for lib image data failed\n");
1536 return -ENOMEM;
1537 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001538 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001539 if (ret) {
1540 kzfree(img_data);
1541 return -EIO;
1542 }
1543 /* Populate the remaining parameters */
1544 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001545 /* Vote for the SFPB clock */
1546 ret = qsee_vote_for_clock(data, CLK_SFPB);
1547 if (ret) {
1548 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1549 kzfree(img_data);
1550 return -EIO;
1551 }
1552
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001553 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001554 /* SCM_CALL to load the image */
1555 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1556 sizeof(struct qseecom_load_lib_image_ireq),
1557 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001558 if (ret) {
1559 pr_err("scm_call to load failed : ret %d\n", ret);
1560 ret = -EIO;
1561 } else {
1562 switch (resp.result) {
1563 case QSEOS_RESULT_SUCCESS:
1564 break;
1565 case QSEOS_RESULT_FAILURE:
1566 pr_err("scm call failed w/response result%d\n",
1567 resp.result);
1568 ret = -EINVAL;
1569 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001570 case QSEOS_RESULT_INCOMPLETE:
1571 ret = __qseecom_process_incomplete_cmd(data, &resp);
1572 if (ret)
1573 pr_err("process_incomplete_cmd failed err: %d\n",
1574 ret);
1575 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001576 default:
1577 pr_err("scm call return unknown response %d\n",
1578 resp.result);
1579 ret = -EINVAL;
1580 break;
1581 }
1582 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001583 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001584 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001585 return ret;
1586}
1587
1588static int qseecom_unload_commonlib_image(void)
1589{
1590 int ret = -EINVAL;
1591 struct qseecom_unload_lib_image_ireq unload_req = {0};
1592 struct qseecom_command_scm_resp resp;
1593
1594 /* Populate the remaining parameters */
1595 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1596 /* SCM_CALL to load the image */
1597 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1598 sizeof(struct qseecom_unload_lib_image_ireq),
1599 &resp, sizeof(resp));
1600 if (ret) {
1601 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1602 ret = -EIO;
1603 } else {
1604 switch (resp.result) {
1605 case QSEOS_RESULT_SUCCESS:
1606 break;
1607 case QSEOS_RESULT_FAILURE:
1608 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1609 break;
1610 default:
1611 pr_err("scm call return unknown response %d\n",
1612 resp.result);
1613 ret = -EINVAL;
1614 break;
1615 }
1616 }
1617 return ret;
1618}
1619
Mona Hossaind44a3842012-10-15 09:41:35 -07001620int qseecom_start_app(struct qseecom_handle **handle,
1621 char *app_name, uint32_t size)
1622{
Mona Hossain05c73562012-10-29 17:49:01 -07001623 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001624 unsigned long flags = 0;
1625 struct qseecom_dev_handle *data = NULL;
1626 struct qseecom_check_app_ireq app_ireq;
1627 struct qseecom_registered_app_list *entry = NULL;
1628 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1629 bool found_app = false;
1630 uint32_t len;
1631 ion_phys_addr_t pa;
1632
Mona Hossain823f9882012-11-23 14:42:20 -08001633 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1634 if (!(*handle)) {
1635 pr_err("failed to allocate memory for kernel client handle\n");
1636 return -ENOMEM;
1637 }
1638
Mona Hossaind44a3842012-10-15 09:41:35 -07001639 data = kzalloc(sizeof(*data), GFP_KERNEL);
1640 if (!data) {
1641 pr_err("kmalloc failed\n");
1642 if (ret == 0) {
1643 kfree(*handle);
1644 *handle = NULL;
1645 }
1646 return -ENOMEM;
1647 }
1648 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001649 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001650 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001651 data->client.sb_length = size;
1652 data->client.user_virt_sb_base = 0;
1653 data->client.ihandle = NULL;
1654
1655 init_waitqueue_head(&data->abort_wq);
1656 atomic_set(&data->ioctl_count, 0);
1657
1658 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1659 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1660 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1661 pr_err("Ion client could not retrieve the handle\n");
1662 kfree(data);
1663 kfree(*handle);
1664 *handle = NULL;
1665 return -EINVAL;
1666 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001667 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001668 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001669 if (qseecom.commonlib_loaded == false) {
1670 ret = qseecom_load_commonlib_image(data);
1671 if (ret == 0)
1672 qseecom.commonlib_loaded = true;
1673 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001674 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001675 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001676 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001677 ret = -EIO;
1678 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001679 }
1680
1681 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1682 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1683 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001684 if (ret < 0)
1685 goto err;
1686
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001687 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001688 if (ret > 0) {
1689 pr_warn("App id %d for [%s] app exists\n", ret,
1690 (char *)app_ireq.app_name);
1691 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1692 list_for_each_entry(entry,
1693 &qseecom.registered_app_list_head, list){
1694 if (entry->app_id == ret) {
1695 entry->ref_cnt++;
1696 found_app = true;
1697 break;
1698 }
1699 }
1700 spin_unlock_irqrestore(
1701 &qseecom.registered_app_list_lock, flags);
1702 if (!found_app)
1703 pr_warn("App_id %d [%s] was loaded but not registered\n",
1704 ret, (char *)app_ireq.app_name);
1705 } else {
1706 /* load the app and get the app_id */
1707 pr_debug("%s: Loading app for the first time'\n",
1708 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001709 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001710 if (ret < 0)
1711 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001712 data->client.app_id = ret;
1713 }
1714 if (!found_app) {
1715 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1716 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001717 pr_err("kmalloc for app entry failed\n");
1718 ret = -ENOMEM;
1719 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001720 }
1721 entry->app_id = ret;
1722 entry->ref_cnt = 1;
1723
1724 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1725 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1726 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1727 flags);
1728 }
1729
1730 /* Get the physical address of the ION BUF */
1731 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1732 /* Populate the structure for sending scm call to load image */
1733 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1734 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001735 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001736 data->client.sb_phys = pa;
1737 (*handle)->dev = (void *)data;
1738 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1739 (*handle)->sbuf_len = data->client.sb_length;
1740
1741 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1742 if (!kclient_entry) {
1743 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001744 ret = -ENOMEM;
1745 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001746 }
1747 kclient_entry->handle = *handle;
1748
1749 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1750 list_add_tail(&kclient_entry->list,
1751 &qseecom.registered_kclient_list_head);
1752 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1753
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001754 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001755 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001756
1757err:
1758 kfree(data);
1759 kfree(*handle);
1760 *handle = NULL;
1761 mutex_unlock(&app_access_lock);
1762 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001763}
1764EXPORT_SYMBOL(qseecom_start_app);
1765
1766int qseecom_shutdown_app(struct qseecom_handle **handle)
1767{
1768 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001769 struct qseecom_dev_handle *data;
1770
Mona Hossaind44a3842012-10-15 09:41:35 -07001771 struct qseecom_registered_kclient_list *kclient = NULL;
1772 unsigned long flags = 0;
1773 bool found_handle = false;
1774
Mona Hossain33824022013-02-25 09:32:33 -08001775 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001776 pr_err("Handle is not initialized\n");
1777 return -EINVAL;
1778 }
Mona Hossain33824022013-02-25 09:32:33 -08001779 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001780 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1781 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1782 list) {
1783 if (kclient->handle == (*handle)) {
1784 list_del(&kclient->list);
1785 found_handle = true;
1786 break;
1787 }
1788 }
1789 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1790 if (!found_handle)
1791 pr_err("Unable to find the handle, exiting\n");
1792 else
1793 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001794 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001795 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001796 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001797 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001798 if (ret == 0) {
1799 kzfree(data);
1800 kzfree(*handle);
1801 kzfree(kclient);
1802 *handle = NULL;
1803 }
1804 return ret;
1805}
1806EXPORT_SYMBOL(qseecom_shutdown_app);
1807
1808int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1809 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1810{
1811 int ret = 0;
1812 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1813 struct qseecom_dev_handle *data;
1814
Mona Hossaind44a3842012-10-15 09:41:35 -07001815 if (handle == NULL) {
1816 pr_err("Handle is not initialized\n");
1817 return -EINVAL;
1818 }
1819 data = handle->dev;
1820
1821 req.cmd_req_len = sbuf_len;
1822 req.resp_len = rbuf_len;
1823 req.cmd_req_buf = send_buf;
1824 req.resp_buf = resp_buf;
1825
1826 mutex_lock(&app_access_lock);
1827 atomic_inc(&data->ioctl_count);
1828
1829 ret = __qseecom_send_cmd(data, &req);
1830
1831 atomic_dec(&data->ioctl_count);
1832 mutex_unlock(&app_access_lock);
1833
1834 if (ret)
1835 return ret;
1836
1837 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1838 req.resp_len, req.resp_buf);
1839 return ret;
1840}
1841EXPORT_SYMBOL(qseecom_send_command);
1842
Mona Hossain91a8fc92012-11-07 19:58:30 -08001843int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1844{
Mona Hossainfca6f422013-01-12 13:00:35 -08001845 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001846 if ((handle == NULL) || (handle->dev == NULL)) {
1847 pr_err("No valid kernel client\n");
1848 return -EINVAL;
1849 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001850 if (high) {
1851 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1852 if (ret)
1853 pr_err("Failed to vote for DFAB clock%d\n", ret);
1854 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1855 if (ret) {
1856 pr_err("Failed to vote for SFPB clock%d\n", ret);
1857 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1858 }
1859 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001860 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001861 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001862 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001863 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001864}
1865EXPORT_SYMBOL(qseecom_set_bandwidth);
1866
Mona Hossain2892b6b2012-02-17 13:53:11 -08001867static int qseecom_send_resp(void)
1868{
1869 qseecom.send_resp_flag = 1;
1870 wake_up_interruptible(&qseecom.send_resp_wq);
1871 return 0;
1872}
1873
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001874
1875static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
1876 void __user *argp)
1877{
1878 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07001879 int i;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001880
1881 if (copy_from_user(&resp, argp, sizeof(resp))) {
1882 pr_err("copy_from_user failed");
1883 return -EINVAL;
1884 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001885 /* validate offsets */
1886 for (i = 0; i < MAX_ION_FD; i++) {
1887 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
1888 pr_err("Invalid offset %d = 0x%x\n",
1889 i, resp.ifd_data[i].cmd_buf_offset);
1890 return -EINVAL;
1891 }
1892 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001893 __qseecom_update_cmd_buf(&resp, false, data, true);
1894 qseecom.send_resp_flag = 1;
1895 wake_up_interruptible(&qseecom.send_resp_wq);
1896 return 0;
1897}
1898
1899
Mona Hossain2892b6b2012-02-17 13:53:11 -08001900static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1901 void __user *argp)
1902{
1903 struct qseecom_qseos_version_req req;
1904
1905 if (copy_from_user(&req, argp, sizeof(req))) {
1906 pr_err("copy_from_user failed");
1907 return -EINVAL;
1908 }
1909 req.qseos_version = qseecom.qseos_version;
1910 if (copy_to_user(argp, &req, sizeof(req))) {
1911 pr_err("copy_to_user failed");
1912 return -EINVAL;
1913 }
1914 return 0;
1915}
1916
Mona Hossainc92629e2013-04-01 13:37:46 -07001917static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001918{
1919 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001920 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001921
Mona Hossainc92629e2013-04-01 13:37:46 -07001922 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001923 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001924 else
1925 qclk = &qseecom.ce_drv;
1926
1927 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001928
1929 if (qclk->clk_access_cnt == ULONG_MAX)
1930 goto err;
1931
Mona Hossainc92629e2013-04-01 13:37:46 -07001932 if (qclk->clk_access_cnt > 0) {
1933 qclk->clk_access_cnt++;
1934 mutex_unlock(&clk_access_lock);
1935 return rc;
1936 }
1937
Mona Hossain6311d572013-03-01 15:54:02 -08001938 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001939 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001940 if (rc) {
1941 pr_err("Unable to enable/prepare CE core clk\n");
1942 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001943 }
1944 /* Enable CE clk */
1945 rc = clk_prepare_enable(qclk->ce_clk);
1946 if (rc) {
1947 pr_err("Unable to enable/prepare CE iface clk\n");
1948 goto ce_clk_err;
1949 }
1950 /* Enable AXI clk */
1951 rc = clk_prepare_enable(qclk->ce_bus_clk);
1952 if (rc) {
1953 pr_err("Unable to enable/prepare CE bus clk\n");
1954 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001955 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001956 qclk->clk_access_cnt++;
1957 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001958 return 0;
1959
1960ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001961 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001962ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001963 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001964err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001965 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001966 return -EIO;
1967}
1968
Mona Hossainc92629e2013-04-01 13:37:46 -07001969static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001970{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001971 struct qseecom_clk *qclk;
1972
Mona Hossainc92629e2013-04-01 13:37:46 -07001973 if (ce == CLK_QSEE)
1974 qclk = &qseecom.qsee;
1975 else
1976 qclk = &qseecom.ce_drv;
1977
1978 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001979
1980 if (qclk->clk_access_cnt == 0) {
1981 mutex_unlock(&clk_access_lock);
1982 return;
1983 }
1984
Mona Hossainc92629e2013-04-01 13:37:46 -07001985 if (qclk->clk_access_cnt == 1) {
1986 if (qclk->ce_clk != NULL)
1987 clk_disable_unprepare(qclk->ce_clk);
1988 if (qclk->ce_core_clk != NULL)
1989 clk_disable_unprepare(qclk->ce_core_clk);
1990 if (qclk->ce_bus_clk != NULL)
1991 clk_disable_unprepare(qclk->ce_bus_clk);
1992 }
1993 qclk->clk_access_cnt--;
1994 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001995}
1996
Mona Hossain04d3fac2012-12-03 10:10:37 -08001997static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1998 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001999{
2000 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002001 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002002
Mona Hossain17a4faf2013-03-22 16:40:56 -07002003 qclk = &qseecom.qsee;
2004 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002005 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002006
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002007 switch (clk_type) {
2008 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002009 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002010 if (!qseecom.qsee_bw_count) {
2011 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002012 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002013 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002014 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002015 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002016 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002017 if (!ret) {
2018 ret =
2019 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002020 qseecom.qsee_perf_client, 1);
2021 if ((ret) &&
2022 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002023 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002024 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002025 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002026 if (ret)
2027 pr_err("DFAB Bandwidth req failed (%d)\n",
2028 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002029 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002030 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002031 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002032 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002033 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002034 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002035 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002036 }
2037 mutex_unlock(&qsee_bw_mutex);
2038 break;
2039 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002040 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002041 if (!qseecom.qsee_sfpb_bw_count) {
2042 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002043 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002044 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002045 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002046 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002047 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002048 if (!ret) {
2049 ret =
2050 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002051 qseecom.qsee_perf_client, 2);
2052 if ((ret) &&
2053 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002054 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002055 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002056 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002057
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002058 if (ret)
2059 pr_err("SFPB Bandwidth req failed (%d)\n",
2060 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002061 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002062 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002063 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002064 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002065 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002066 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002067 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002068 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002069 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002070 break;
2071 default:
2072 pr_err("Clock type not defined\n");
2073 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002074 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002075 return ret;
2076}
2077
Mona Hossain04d3fac2012-12-03 10:10:37 -08002078static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2079 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002080{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002081 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002082 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002083
Mona Hossain17a4faf2013-03-22 16:40:56 -07002084 qclk = &qseecom.qsee;
2085 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002086 return;
2087
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002088 switch (clk_type) {
2089 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002090 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002091 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002092 pr_err("Client error.Extra call to disable DFAB clk\n");
2093 mutex_unlock(&qsee_bw_mutex);
2094 return;
2095 }
2096
Mona Hossain17a4faf2013-03-22 16:40:56 -07002097 if (qseecom.qsee_bw_count == 1) {
2098 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002099 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002100 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002101 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002102 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002103 qseecom.qsee_perf_client, 0);
2104 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002105 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002106 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002107 if (ret)
2108 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002109 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002110 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002111 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002112 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002113 }
2114 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002115 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002116 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002117 }
2118 mutex_unlock(&qsee_bw_mutex);
2119 break;
2120 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002121 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002122 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002123 pr_err("Client error.Extra call to disable SFPB clk\n");
2124 mutex_unlock(&qsee_bw_mutex);
2125 return;
2126 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002127 if (qseecom.qsee_sfpb_bw_count == 1) {
2128 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002129 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002130 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002131 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002132 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002133 qseecom.qsee_perf_client, 0);
2134 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002135 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002136 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002137 if (ret)
2138 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002139 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002140 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002141 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002142 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002143 }
2144 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002145 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002146 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002147 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002148 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002149 break;
2150 default:
2151 pr_err("Clock type not defined\n");
2152 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002153 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002154
Mona Hossain2892b6b2012-02-17 13:53:11 -08002155}
2156
Mona Hossain5ab9d772012-04-11 21:00:40 -07002157static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2158 void __user *argp)
2159{
2160 struct ion_handle *ihandle; /* Ion handle */
2161 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002162 int ret;
2163 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002164 ion_phys_addr_t pa = 0;
2165 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002166 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002167 struct qseecom_load_app_ireq load_req;
2168 struct qseecom_command_scm_resp resp;
2169
2170 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002171 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002172 (void __user *)argp,
2173 sizeof(struct qseecom_load_img_req))) {
2174 pr_err("copy_from_user failed\n");
2175 return -EFAULT;
2176 }
2177
2178 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002179 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002180 load_img_req.ifd_data_fd);
2181 if (IS_ERR_OR_NULL(ihandle)) {
2182 pr_err("Ion client could not retrieve the handle\n");
2183 return -ENOMEM;
2184 }
2185
2186 /* Get the physical address of the ION BUF */
2187 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2188
2189 /* Populate the structure for sending scm call to load image */
2190 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2191 load_req.mdt_len = load_img_req.mdt_len;
2192 load_req.img_len = load_img_req.img_len;
2193 load_req.phy_addr = pa;
2194
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002195 /* SCM_CALL tied to Core0 */
2196 mask = CPU_MASK_CPU0;
2197 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2198 if (set_cpu_ret) {
2199 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2200 set_cpu_ret);
2201 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302202 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002203 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302204
Mona Hossain6311d572013-03-01 15:54:02 -08002205 /* Vote for the SFPB clock */
2206 ret = qsee_vote_for_clock(data, CLK_SFPB);
2207 if (ret) {
2208 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2209 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302210 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002211 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002212 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2213 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002214 /* SCM_CALL to load the external elf */
2215 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2216 sizeof(struct qseecom_load_app_ireq),
2217 &resp, sizeof(resp));
2218 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002219 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002220 ret);
2221 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302222 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002223 }
2224
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302225 switch (resp.result) {
2226 case QSEOS_RESULT_SUCCESS:
2227 break;
2228 case QSEOS_RESULT_INCOMPLETE:
2229 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002230 ret = __qseecom_process_incomplete_cmd(data, &resp);
2231 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302232 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2233 break;
2234 case QSEOS_RESULT_FAILURE:
2235 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2236 ret = -EFAULT;
2237 break;
2238 default:
2239 pr_err("scm_call response result %d not supported\n",
2240 resp.result);
2241 ret = -EFAULT;
2242 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002243 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002244
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302245exit_disable_clock:
2246 qsee_disable_clock_vote(data, CLK_SFPB);
2247exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002248 /* Restore the CPU mask */
2249 mask = CPU_MASK_ALL;
2250 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2251 if (set_cpu_ret) {
2252 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2253 set_cpu_ret);
2254 ret = -EFAULT;
2255 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302256exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002257 /* Deallocate the handle */
2258 if (!IS_ERR_OR_NULL(ihandle))
2259 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002260 return ret;
2261}
2262
2263static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2264{
2265 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002266 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002267 struct qseecom_command_scm_resp resp;
2268 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002269 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002270
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302271 /* unavailable client app */
2272 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2273
Mona Hossain5ab9d772012-04-11 21:00:40 -07002274 /* Populate the structure for sending scm call to unload image */
2275 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002276
2277 /* SCM_CALL tied to Core0 */
2278 mask = CPU_MASK_CPU0;
2279 ret = set_cpus_allowed_ptr(current, &mask);
2280 if (ret) {
2281 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2282 ret);
2283 return -EFAULT;
2284 }
2285
Mona Hossain5ab9d772012-04-11 21:00:40 -07002286 /* SCM_CALL to unload the external elf */
2287 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2288 sizeof(struct qseecom_unload_app_ireq),
2289 &resp, sizeof(resp));
2290 if (ret) {
2291 pr_err("scm_call to unload failed : ret %d\n",
2292 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002293 ret = -EFAULT;
2294 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002295 }
2296 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2297 ret = __qseecom_process_incomplete_cmd(data, &resp);
2298 if (ret)
2299 pr_err("process_incomplete_cmd fail err: %d\n",
2300 ret);
2301 } else {
2302 if (resp.result != QSEOS_RESULT_SUCCESS) {
2303 pr_err("scm_call to unload image failed resp.result =%d\n",
2304 resp.result);
2305 ret = -EFAULT;
2306 }
2307 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002308
2309qseecom_unload_external_elf_scm_err:
2310 /* Restore the CPU mask */
2311 mask = CPU_MASK_ALL;
2312 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2313 if (set_cpu_ret) {
2314 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2315 set_cpu_ret);
2316 ret = -EFAULT;
2317 }
2318
Mona Hossain5ab9d772012-04-11 21:00:40 -07002319 return ret;
2320}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002321
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002322static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2323 void __user *argp)
2324{
2325
2326 int32_t ret;
2327 struct qseecom_qseos_app_load_query query_req;
2328 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002329 struct qseecom_registered_app_list *entry = NULL;
2330 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002331
2332 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002333 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002334 (void __user *)argp,
2335 sizeof(struct qseecom_qseos_app_load_query))) {
2336 pr_err("copy_from_user failed\n");
2337 return -EFAULT;
2338 }
2339
2340 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002341 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002342 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2343
2344 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002345
2346 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002347 pr_err(" scm call to check if app is loaded failed");
2348 return ret; /* scm call failed */
2349 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002350 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002351 (char *)(req.app_name));
2352 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2353 list_for_each_entry(entry,
2354 &qseecom.registered_app_list_head, list){
2355 if (entry->app_id == ret) {
2356 entry->ref_cnt++;
2357 break;
2358 }
2359 }
2360 spin_unlock_irqrestore(
2361 &qseecom.registered_app_list_lock, flags);
2362 data->client.app_id = ret;
2363 query_req.app_id = ret;
2364
2365 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2366 pr_err("copy_to_user failed\n");
2367 return -EFAULT;
2368 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002369 return -EEXIST; /* app already loaded */
2370 } else {
2371 return 0; /* app not loaded */
2372 }
2373}
2374
Mona Hossain4cf78a92013-02-14 12:06:41 -08002375static int __qseecom_get_ce_pipe_info(
2376 enum qseecom_key_management_usage_type usage,
2377 uint32_t *pipe, uint32_t *ce_hw)
2378{
2379 int ret;
2380 switch (usage) {
2381 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2382 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2383 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2384 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2385 qseecom.ce_info.disk_encrypt_pipe,
2386 qseecom.ce_info.hlos_ce_hw_instance);
2387 ret = -EINVAL;
2388 } else {
2389 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2390 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2391 ret = 0;
2392 }
2393 break;
2394 default:
2395 ret = -EINVAL;
2396 break;
2397 }
2398 return ret;
2399}
2400
2401static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2402 enum qseecom_key_management_usage_type usage,
2403 uint8_t *key_id, uint32_t flags)
2404{
2405 struct qseecom_key_generate_ireq ireq;
2406 struct qseecom_command_scm_resp resp;
2407 int ret;
2408
2409 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2410 pr_err("Error:: unsupported usage %d\n", usage);
2411 return -EFAULT;
2412 }
2413
2414 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2415 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002416 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002417
Mona Hossainc92629e2013-04-01 13:37:46 -07002418 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002419
2420 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002421 &ireq, sizeof(struct qseecom_key_generate_ireq),
2422 &resp, sizeof(resp));
2423 if (ret) {
2424 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002425 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002426 return ret;
2427 }
2428
2429 switch (resp.result) {
2430 case QSEOS_RESULT_SUCCESS:
2431 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002432 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002433 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002434 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002435 case QSEOS_RESULT_INCOMPLETE:
2436 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002437 if (ret) {
2438 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002439 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002440 ret = 0;
2441 } else {
2442 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2443 resp.result);
2444 }
2445 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002446 break;
2447 case QSEOS_RESULT_FAILURE:
2448 default:
2449 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2450 ret = -EINVAL;
2451 break;
2452 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002453 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002454 return ret;
2455}
2456
2457static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2458 enum qseecom_key_management_usage_type usage,
2459 uint8_t *key_id, uint32_t flags)
2460{
2461 struct qseecom_key_delete_ireq ireq;
2462 struct qseecom_command_scm_resp resp;
2463 int ret;
2464
2465 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2466 pr_err("Error:: unsupported usage %d\n", usage);
2467 return -EFAULT;
2468 }
2469
2470 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2471 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002472 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002473
Mona Hossainc92629e2013-04-01 13:37:46 -07002474 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002475
2476 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002477 &ireq, sizeof(struct qseecom_key_delete_ireq),
2478 &resp, sizeof(struct qseecom_command_scm_resp));
2479 if (ret) {
2480 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002481 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002482 return ret;
2483 }
2484
2485 switch (resp.result) {
2486 case QSEOS_RESULT_SUCCESS:
2487 break;
2488 case QSEOS_RESULT_INCOMPLETE:
2489 ret = __qseecom_process_incomplete_cmd(data, &resp);
2490 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002491 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2492 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002493 break;
2494 case QSEOS_RESULT_FAILURE:
2495 default:
2496 pr_err("Delete key scm call failed resp.result %d\n",
2497 resp.result);
2498 ret = -EINVAL;
2499 break;
2500 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002501 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002502 return ret;
2503}
2504
2505static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2506 enum qseecom_key_management_usage_type usage,
2507 struct qseecom_set_key_parameter *set_key_para)
2508{
2509 struct qseecom_key_select_ireq ireq;
2510 struct qseecom_command_scm_resp resp;
2511 int ret;
2512
2513 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2514 pr_err("Error:: unsupported usage %d\n", usage);
2515 return -EFAULT;
2516 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002517
Zhen Kongdb2bf742013-05-13 23:55:42 -07002518 __qseecom_enable_clk(CLK_QSEE);
2519 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002520 __qseecom_enable_clk(CLK_CE_DRV);
2521
Mona Hossain4cf78a92013-02-14 12:06:41 -08002522 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002523 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002524 ireq.ce = set_key_para->ce_hw;
2525 ireq.pipe = set_key_para->pipe;
2526 ireq.flags = set_key_para->flags;
2527
Zhen Kong1f09c7692013-05-03 17:50:32 -07002528 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2529 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002530
Mona Hossain4cf78a92013-02-14 12:06:41 -08002531 if (set_key_para->set_clear_key_flag ==
2532 QSEECOM_SET_CE_KEY_CMD)
2533 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2534 QSEECOM_HASH_SIZE);
2535 else
2536 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2537
Zhen Kong336636e2013-04-15 11:04:54 -07002538 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002539 &ireq, sizeof(struct qseecom_key_select_ireq),
2540 &resp, sizeof(struct qseecom_command_scm_resp));
2541 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002542 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002543 __qseecom_disable_clk(CLK_QSEE);
2544 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2545 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kong336636e2013-04-15 11:04:54 -07002546 return ret;
2547 }
2548
Mona Hossain4cf78a92013-02-14 12:06:41 -08002549 switch (resp.result) {
2550 case QSEOS_RESULT_SUCCESS:
2551 break;
2552 case QSEOS_RESULT_INCOMPLETE:
2553 ret = __qseecom_process_incomplete_cmd(data, &resp);
2554 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002555 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2556 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002557 break;
2558 case QSEOS_RESULT_FAILURE:
2559 default:
2560 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2561 ret = -EINVAL;
2562 break;
2563 }
2564
Zhen Kongdb2bf742013-05-13 23:55:42 -07002565 __qseecom_disable_clk(CLK_QSEE);
2566 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002567 __qseecom_disable_clk(CLK_CE_DRV);
2568
Mona Hossain4cf78a92013-02-14 12:06:41 -08002569 return ret;
2570}
2571
2572static int qseecom_create_key(struct qseecom_dev_handle *data,
2573 void __user *argp)
2574{
2575 uint32_t ce_hw = 0;
2576 uint32_t pipe = 0;
2577 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2578 int ret = 0;
2579 uint32_t flags = 0;
2580 struct qseecom_set_key_parameter set_key_para;
2581 struct qseecom_create_key_req create_key_req;
2582
2583 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2584 if (ret) {
2585 pr_err("copy_from_user failed\n");
2586 return ret;
2587 }
2588
2589 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2590 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2591 return -EFAULT;
2592 }
2593
2594 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2595 if (ret) {
2596 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2597 return -EINVAL;
2598 }
2599
2600 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2601 key_id, flags);
2602 if (ret) {
2603 pr_err("Failed to generate key on storage: %d\n", ret);
2604 return -EFAULT;
2605 }
2606
2607 set_key_para.ce_hw = ce_hw;
2608 set_key_para.pipe = pipe;
2609 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2610 set_key_para.flags = flags;
2611 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2612 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2613 QSEECOM_HASH_SIZE);
2614
2615 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2616 &set_key_para);
2617 if (ret) {
2618 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2619 pipe, ce_hw, ret);
2620 return -EFAULT;
2621 }
2622
2623 return ret;
2624}
2625
2626static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2627 void __user *argp)
2628{
2629 uint32_t ce_hw = 0;
2630 uint32_t pipe = 0;
2631 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2632 int ret = 0;
2633 uint32_t flags = 0;
2634 int i;
2635 struct qseecom_wipe_key_req wipe_key_req;
2636 struct qseecom_set_key_parameter clear_key_para;
2637
2638 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2639 if (ret) {
2640 pr_err("copy_from_user failed\n");
2641 return ret;
2642 }
2643
2644 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2645 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2646 return -EFAULT;
2647 }
2648
2649 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2650 if (ret) {
2651 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2652 return -EINVAL;
2653 }
2654
2655 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2656 flags);
2657 if (ret) {
2658 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2659 return -EFAULT;
2660 }
2661
2662 /* an invalid key_id 0xff is used to indicate clear key*/
2663 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2664 clear_key_para.key_id[i] = 0xff;
2665 clear_key_para.ce_hw = ce_hw;
2666 clear_key_para.pipe = pipe;
2667 clear_key_para.flags = flags;
2668 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2669 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2670 &clear_key_para);
2671 if (ret) {
2672 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2673 pipe, ce_hw, ret);
2674 return -EFAULT;
2675 }
2676
2677 return ret;
2678}
2679
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002680static int qseecom_is_es_activated(void __user *argp)
2681{
2682 struct qseecom_is_es_activated_req req;
2683 int ret;
2684 int resp_buf;
2685
2686 if (qseecom.qsee_version < QSEE_VERSION_04) {
2687 pr_err("invalid qsee version");
2688 return -ENODEV;
2689 }
2690
2691 if (argp == NULL) {
2692 pr_err("arg is null");
2693 return -EINVAL;
2694 }
2695
2696 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2697 (void *) &resp_buf, sizeof(resp_buf));
2698 if (ret) {
2699 pr_err("scm_call failed");
2700 return ret;
2701 }
2702
2703 req.is_activated = resp_buf;
2704 ret = copy_to_user(argp, &req, sizeof(req));
2705 if (ret) {
2706 pr_err("copy_to_user failed");
2707 return ret;
2708 }
2709
2710 return 0;
2711}
2712
2713static int qseecom_save_partition_hash(void __user *argp)
2714{
2715 struct qseecom_save_partition_hash_req req;
2716 int ret;
2717
2718 if (qseecom.qsee_version < QSEE_VERSION_04) {
2719 pr_err("invalid qsee version ");
2720 return -ENODEV;
2721 }
2722
2723 if (argp == NULL) {
2724 pr_err("arg is null");
2725 return -EINVAL;
2726 }
2727
2728 ret = copy_from_user(&req, argp, sizeof(req));
2729 if (ret) {
2730 pr_err("copy_from_user failed");
2731 return ret;
2732 }
2733
2734 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2735 (void *) &req, sizeof(req), NULL, 0);
2736 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002737 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002738 return ret;
2739 }
2740
2741 return 0;
2742}
2743
Mona Hossain2892b6b2012-02-17 13:53:11 -08002744static long qseecom_ioctl(struct file *file, unsigned cmd,
2745 unsigned long arg)
2746{
2747 int ret = 0;
2748 struct qseecom_dev_handle *data = file->private_data;
2749 void __user *argp = (void __user *) arg;
2750
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05302751 if (!data) {
2752 pr_err("Invalid/uninitialized device handle\n");
2753 return -EINVAL;
2754 }
2755
Mona Hossain2892b6b2012-02-17 13:53:11 -08002756 if (data->abort) {
2757 pr_err("Aborting qseecom driver\n");
2758 return -ENODEV;
2759 }
2760
2761 switch (cmd) {
2762 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002763 if (data->type != QSEECOM_GENERIC) {
2764 pr_err("reg lstnr req: invalid handle (%d)\n",
2765 data->type);
2766 ret = -EINVAL;
2767 break;
2768 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002769 pr_debug("ioctl register_listener_req()\n");
2770 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002771 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002772 ret = qseecom_register_listener(data, argp);
2773 atomic_dec(&data->ioctl_count);
2774 wake_up_all(&data->abort_wq);
2775 if (ret)
2776 pr_err("failed qseecom_register_listener: %d\n", ret);
2777 break;
2778 }
2779 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002780 if ((data->listener.id == 0) ||
2781 (data->type != QSEECOM_LISTENER_SERVICE)) {
2782 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
2783 data->type, data->listener.id);
2784 ret = -EINVAL;
2785 break;
2786 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002787 pr_debug("ioctl unregister_listener_req()\n");
2788 atomic_inc(&data->ioctl_count);
2789 ret = qseecom_unregister_listener(data);
2790 atomic_dec(&data->ioctl_count);
2791 wake_up_all(&data->abort_wq);
2792 if (ret)
2793 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2794 break;
2795 }
2796 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002797 if ((data->client.app_id == 0) ||
2798 (data->type != QSEECOM_CLIENT_APP)) {
2799 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
2800 data->type, data->client.app_id);
2801 ret = -EINVAL;
2802 break;
2803 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002804 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002805 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002806 atomic_inc(&data->ioctl_count);
2807 ret = qseecom_send_cmd(data, argp);
2808 atomic_dec(&data->ioctl_count);
2809 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002810 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002811 if (ret)
2812 pr_err("failed qseecom_send_cmd: %d\n", ret);
2813 break;
2814 }
2815 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002816 if ((data->client.app_id == 0) ||
2817 (data->type != QSEECOM_CLIENT_APP)) {
2818 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
2819 data->type, data->client.app_id);
2820 ret = -EINVAL;
2821 break;
2822 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002823 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002824 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002825 atomic_inc(&data->ioctl_count);
2826 ret = qseecom_send_modfd_cmd(data, argp);
2827 atomic_dec(&data->ioctl_count);
2828 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002829 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002830 if (ret)
2831 pr_err("failed qseecom_send_cmd: %d\n", ret);
2832 break;
2833 }
2834 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002835 if ((data->listener.id == 0) ||
2836 (data->type != QSEECOM_LISTENER_SERVICE)) {
2837 pr_err("receive req: invalid handle (%d), lid(%d)\n",
2838 data->type, data->listener.id);
2839 ret = -EINVAL;
2840 break;
2841 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002842 atomic_inc(&data->ioctl_count);
2843 ret = qseecom_receive_req(data);
2844 atomic_dec(&data->ioctl_count);
2845 wake_up_all(&data->abort_wq);
2846 if (ret)
2847 pr_err("failed qseecom_receive_req: %d\n", ret);
2848 break;
2849 }
2850 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002851 if ((data->listener.id == 0) ||
2852 (data->type != QSEECOM_LISTENER_SERVICE)) {
2853 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
2854 data->type, data->listener.id);
2855 ret = -EINVAL;
2856 break;
2857 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002858 atomic_inc(&data->ioctl_count);
2859 ret = qseecom_send_resp();
2860 atomic_dec(&data->ioctl_count);
2861 wake_up_all(&data->abort_wq);
2862 if (ret)
2863 pr_err("failed qseecom_send_resp: %d\n", ret);
2864 break;
2865 }
2866 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002867 if ((data->type != QSEECOM_CLIENT_APP) &&
2868 (data->type != QSEECOM_GENERIC) &&
2869 (data->type != QSEECOM_SECURE_SERVICE)) {
2870 pr_err("set mem param req: invalid handle (%d)\n",
2871 data->type);
2872 ret = -EINVAL;
2873 break;
2874 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002875 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002876 ret = qseecom_set_client_mem_param(data, argp);
2877 if (ret)
2878 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2879 ret);
2880 break;
2881 }
2882 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002883 if ((data->type != QSEECOM_GENERIC) &&
2884 (data->type != QSEECOM_CLIENT_APP)) {
2885 pr_err("load app req: invalid handle (%d)\n",
2886 data->type);
2887 ret = -EINVAL;
2888 break;
2889 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002890 data->type = QSEECOM_CLIENT_APP;
2891 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002892 mutex_lock(&app_access_lock);
2893 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002894 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2895 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002896 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002897 if (ret == 0)
2898 qseecom.commonlib_loaded = true;
2899 }
2900 }
2901 if (ret == 0)
2902 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002903 atomic_dec(&data->ioctl_count);
2904 mutex_unlock(&app_access_lock);
2905 if (ret)
2906 pr_err("failed load_app request: %d\n", ret);
2907 break;
2908 }
2909 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002910 if ((data->client.app_id == 0) ||
2911 (data->type != QSEECOM_CLIENT_APP)) {
2912 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
2913 data->type, data->client.app_id);
2914 ret = -EINVAL;
2915 break;
2916 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002917 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002918 mutex_lock(&app_access_lock);
2919 atomic_inc(&data->ioctl_count);
2920 ret = qseecom_unload_app(data);
2921 atomic_dec(&data->ioctl_count);
2922 mutex_unlock(&app_access_lock);
2923 if (ret)
2924 pr_err("failed unload_app request: %d\n", ret);
2925 break;
2926 }
2927 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2928 atomic_inc(&data->ioctl_count);
2929 ret = qseecom_get_qseos_version(data, argp);
2930 if (ret)
2931 pr_err("qseecom_get_qseos_version: %d\n", ret);
2932 atomic_dec(&data->ioctl_count);
2933 break;
2934 }
2935 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002936 if ((data->type != QSEECOM_GENERIC) &&
2937 (data->type != QSEECOM_CLIENT_APP)) {
2938 pr_err("perf enable req: invalid handle (%d)\n",
2939 data->type);
2940 ret = -EINVAL;
2941 break;
2942 }
2943 if ((data->type == QSEECOM_CLIENT_APP) &&
2944 (data->client.app_id == 0)) {
2945 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
2946 data->type, data->client.app_id);
2947 ret = -EINVAL;
2948 break;
2949 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002950 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002951 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002952 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002953 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002954 ret = qsee_vote_for_clock(data, CLK_SFPB);
2955 if (ret)
2956 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002957 atomic_dec(&data->ioctl_count);
2958 break;
2959 }
2960 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002961 if ((data->type != QSEECOM_SECURE_SERVICE) &&
2962 (data->type != QSEECOM_CLIENT_APP)) {
2963 pr_err("perf disable req: invalid handle (%d)\n",
2964 data->type);
2965 ret = -EINVAL;
2966 break;
2967 }
2968 if ((data->type == QSEECOM_CLIENT_APP) &&
2969 (data->client.app_id == 0)) {
2970 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
2971 data->type, data->client.app_id);
2972 ret = -EINVAL;
2973 break;
2974 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002975 atomic_inc(&data->ioctl_count);
Mona Hossaina1124de2013-10-01 13:41:09 -07002976 qsee_disable_clock_vote(data, CLK_DFAB);
2977 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002978 atomic_dec(&data->ioctl_count);
2979 break;
2980 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002981 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002982 if (data->type != QSEECOM_GENERIC) {
2983 pr_err("load ext elf req: invalid client handle (%d)\n",
2984 data->type);
2985 ret = -EINVAL;
2986 break;
2987 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002988 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002989 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002990 mutex_lock(&app_access_lock);
2991 atomic_inc(&data->ioctl_count);
2992 ret = qseecom_load_external_elf(data, argp);
2993 atomic_dec(&data->ioctl_count);
2994 mutex_unlock(&app_access_lock);
2995 if (ret)
2996 pr_err("failed load_external_elf request: %d\n", ret);
2997 break;
2998 }
2999 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003000 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
3001 pr_err("unload ext elf req: invalid handle (%d)\n",
3002 data->type);
3003 ret = -EINVAL;
3004 break;
3005 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003006 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003007 mutex_lock(&app_access_lock);
3008 atomic_inc(&data->ioctl_count);
3009 ret = qseecom_unload_external_elf(data);
3010 atomic_dec(&data->ioctl_count);
3011 mutex_unlock(&app_access_lock);
3012 if (ret)
3013 pr_err("failed unload_app request: %d\n", ret);
3014 break;
3015 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003016 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003017 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003018 mutex_lock(&app_access_lock);
3019 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003020 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003021 ret = qseecom_query_app_loaded(data, argp);
3022 atomic_dec(&data->ioctl_count);
3023 mutex_unlock(&app_access_lock);
3024 break;
3025 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003026 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003027 if (data->type != QSEECOM_GENERIC) {
3028 pr_err("send cmd svc req: invalid handle (%d)\n",
3029 data->type);
3030 ret = -EINVAL;
3031 break;
3032 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003033 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003034 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003035 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003036 qseecom.qsee_version);
3037 return -EINVAL;
3038 }
3039 mutex_lock(&app_access_lock);
3040 atomic_inc(&data->ioctl_count);
3041 ret = qseecom_send_service_cmd(data, argp);
3042 atomic_dec(&data->ioctl_count);
3043 mutex_unlock(&app_access_lock);
3044 break;
3045 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003046 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003047 if (data->type != QSEECOM_GENERIC) {
3048 pr_err("create key req: invalid handle (%d)\n",
3049 data->type);
3050 ret = -EINVAL;
3051 break;
3052 }
Zhen Kong336636e2013-04-15 11:04:54 -07003053 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003054 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003055 qseecom.qsee_version);
3056 return -EINVAL;
3057 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003058 data->released = true;
3059 mutex_lock(&app_access_lock);
3060 atomic_inc(&data->ioctl_count);
3061 ret = qseecom_create_key(data, argp);
3062 if (ret)
3063 pr_err("failed to create encryption key: %d\n", ret);
3064
3065 atomic_dec(&data->ioctl_count);
3066 mutex_unlock(&app_access_lock);
3067 break;
3068 }
3069 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003070 if (data->type != QSEECOM_GENERIC) {
3071 pr_err("wipe key req: invalid handle (%d)\n",
3072 data->type);
3073 ret = -EINVAL;
3074 break;
3075 }
Zhen Kong336636e2013-04-15 11:04:54 -07003076 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003077 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003078 qseecom.qsee_version);
3079 return -EINVAL;
3080 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003081 data->released = true;
3082 mutex_lock(&app_access_lock);
3083 atomic_inc(&data->ioctl_count);
3084 ret = qseecom_wipe_key(data, argp);
3085 if (ret)
3086 pr_err("failed to wipe encryption key: %d\n", ret);
3087 atomic_dec(&data->ioctl_count);
3088 mutex_unlock(&app_access_lock);
3089 break;
3090 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003091 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003092 if (data->type != QSEECOM_GENERIC) {
3093 pr_err("save part hash req: invalid handle (%d)\n",
3094 data->type);
3095 ret = -EINVAL;
3096 break;
3097 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003098 data->released = true;
3099 mutex_lock(&app_access_lock);
3100 atomic_inc(&data->ioctl_count);
3101 ret = qseecom_save_partition_hash(argp);
3102 atomic_dec(&data->ioctl_count);
3103 mutex_unlock(&app_access_lock);
3104 break;
3105 }
3106 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003107 if (data->type != QSEECOM_GENERIC) {
3108 pr_err("ES activated req: invalid handle (%d)\n",
3109 data->type);
3110 ret = -EINVAL;
3111 break;
3112 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003113 data->released = true;
3114 mutex_lock(&app_access_lock);
3115 atomic_inc(&data->ioctl_count);
3116 ret = qseecom_is_es_activated(argp);
3117 atomic_dec(&data->ioctl_count);
3118 mutex_unlock(&app_access_lock);
3119 break;
3120 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003121 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003122 if ((data->listener.id == 0) ||
3123 (data->type != QSEECOM_LISTENER_SERVICE)) {
3124 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3125 data->type, data->listener.id);
3126 ret = -EINVAL;
3127 break;
3128 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003129 /* Only one client allowed here at a time */
3130 atomic_inc(&data->ioctl_count);
3131 ret = qseecom_send_modfd_resp(data, argp);
3132 atomic_dec(&data->ioctl_count);
3133 wake_up_all(&data->abort_wq);
3134 if (ret)
3135 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3136 break;
3137 }
3138 case QSEECOM_IOCTL_UNPROTECT_BUF: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003139 if ((data->listener.id == 0) ||
3140 (data->type != QSEECOM_LISTENER_SERVICE)) {
3141 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3142 data->type, data->listener.id);
3143 ret = -EINVAL;
3144 break;
3145 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003146 /* Only one client allowed here at a time */
3147 atomic_inc(&data->ioctl_count);
3148 ret = qseecom_unprotect_buffer(argp);
3149 atomic_dec(&data->ioctl_count);
3150 wake_up_all(&data->abort_wq);
3151 if (ret)
3152 pr_err("failed qseecom_unprotect: %d\n", ret);
3153 break;
3154 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003155 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003156 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003157 return -EINVAL;
3158 }
3159 return ret;
3160}
3161
3162static int qseecom_open(struct inode *inode, struct file *file)
3163{
3164 int ret = 0;
3165 struct qseecom_dev_handle *data;
3166
3167 data = kzalloc(sizeof(*data), GFP_KERNEL);
3168 if (!data) {
3169 pr_err("kmalloc failed\n");
3170 return -ENOMEM;
3171 }
3172 file->private_data = data;
3173 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003174 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003175 data->released = false;
3176 init_waitqueue_head(&data->abort_wq);
3177 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003178
Mona Hossain2892b6b2012-02-17 13:53:11 -08003179 return ret;
3180}
3181
3182static int qseecom_release(struct inode *inode, struct file *file)
3183{
3184 struct qseecom_dev_handle *data = file->private_data;
3185 int ret = 0;
3186
3187 if (data->released == false) {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003188 pr_warn("data: released = false, type = %d, data = 0x%x\n",
3189 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003190 switch (data->type) {
3191 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003192 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003193 break;
3194 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003195 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003196 break;
3197 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003198 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003199 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003200 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003201 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003202 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303203 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3204 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003205 default:
3206 pr_err("Unsupported clnt_handle_type %d",
3207 data->type);
3208 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003209 }
3210 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003211
Mona Hossainc9c83c72013-04-11 12:43:48 -07003212 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003213 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07003214 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003215 qsee_disable_clock_vote(data, CLK_DFAB);
3216
Mona Hossain2892b6b2012-02-17 13:53:11 -08003217 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003218
Mona Hossain2892b6b2012-02-17 13:53:11 -08003219 return ret;
3220}
3221
Mona Hossain2892b6b2012-02-17 13:53:11 -08003222static const struct file_operations qseecom_fops = {
3223 .owner = THIS_MODULE,
3224 .unlocked_ioctl = qseecom_ioctl,
3225 .open = qseecom_open,
3226 .release = qseecom_release
3227};
3228
Mona Hossainc92629e2013-04-01 13:37:46 -07003229static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003230{
3231 int rc = 0;
3232 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003233 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003234 char *core_clk_src = NULL;
3235 char *core_clk = NULL;
3236 char *iface_clk = NULL;
3237 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003238
Mona Hossainc92629e2013-04-01 13:37:46 -07003239 switch (ce) {
3240 case CLK_QSEE: {
3241 core_clk_src = "core_clk_src";
3242 core_clk = "core_clk";
3243 iface_clk = "iface_clk";
3244 bus_clk = "bus_clk";
3245 qclk = &qseecom.qsee;
3246 qclk->instance = CLK_QSEE;
3247 break;
3248 };
3249 case CLK_CE_DRV: {
3250 core_clk_src = "ce_drv_core_clk_src";
3251 core_clk = "ce_drv_core_clk";
3252 iface_clk = "ce_drv_iface_clk";
3253 bus_clk = "ce_drv_bus_clk";
3254 qclk = &qseecom.ce_drv;
3255 qclk->instance = CLK_CE_DRV;
3256 break;
3257 };
3258 default:
3259 pr_err("Invalid ce hw instance: %d!\n", ce);
3260 return -EIO;
3261 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003262 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003263
Mona Hossainc92629e2013-04-01 13:37:46 -07003264 /* Get CE3 src core clk. */
3265 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003266 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003267 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003268 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003269 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003270 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003271 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003272 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003273 }
3274 } else {
3275 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003276 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003277 }
3278
3279 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003280 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003281 if (IS_ERR(qclk->ce_core_clk)) {
3282 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003283 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003284 if (qclk->ce_core_src_clk != NULL)
3285 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003286 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003287 }
3288
3289 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003290 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003291 if (IS_ERR(qclk->ce_clk)) {
3292 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003293 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003294 if (qclk->ce_core_src_clk != NULL)
3295 clk_put(qclk->ce_core_src_clk);
3296 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003297 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003298 }
3299
3300 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003301 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003302 if (IS_ERR(qclk->ce_bus_clk)) {
3303 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003304 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003305 if (qclk->ce_core_src_clk != NULL)
3306 clk_put(qclk->ce_core_src_clk);
3307 clk_put(qclk->ce_core_clk);
3308 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003309 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003310 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003311 return rc;
3312}
3313
Mona Hossainc92629e2013-04-01 13:37:46 -07003314static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003315{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003316 struct qseecom_clk *qclk;
3317
Mona Hossainc92629e2013-04-01 13:37:46 -07003318 if (ce == CLK_QSEE)
3319 qclk = &qseecom.qsee;
3320 else
3321 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003322
3323 if (qclk->ce_clk != NULL) {
3324 clk_put(qclk->ce_clk);
3325 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003326 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003327 if (qclk->ce_core_clk != NULL) {
3328 clk_put(qclk->ce_core_clk);
3329 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003330 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003331 if (qclk->ce_bus_clk != NULL) {
3332 clk_put(qclk->ce_bus_clk);
3333 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003334 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003335 if (qclk->ce_core_src_clk != NULL) {
3336 clk_put(qclk->ce_core_src_clk);
3337 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003338 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003339}
3340
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003341static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003342{
3343 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003344 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003345 struct device *class_dev;
3346 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003347 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003348 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3349
Mona Hossain17a4faf2013-03-22 16:40:56 -07003350 qseecom.qsee_bw_count = 0;
3351 qseecom.qsee_perf_client = 0;
3352 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003353
Mona Hossain17a4faf2013-03-22 16:40:56 -07003354 qseecom.qsee.ce_core_clk = NULL;
3355 qseecom.qsee.ce_clk = NULL;
3356 qseecom.qsee.ce_core_src_clk = NULL;
3357 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003358
Mona Hossainc92629e2013-04-01 13:37:46 -07003359 qseecom.ce_drv.ce_core_clk = NULL;
3360 qseecom.ce_drv.ce_clk = NULL;
3361 qseecom.ce_drv.ce_core_src_clk = NULL;
3362 qseecom.ce_drv.ce_bus_clk = NULL;
3363
Mona Hossain2892b6b2012-02-17 13:53:11 -08003364 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3365 if (rc < 0) {
3366 pr_err("alloc_chrdev_region failed %d\n", rc);
3367 return rc;
3368 }
3369
3370 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3371 if (IS_ERR(driver_class)) {
3372 rc = -ENOMEM;
3373 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303374 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003375 }
3376
3377 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3378 QSEECOM_DEV);
3379 if (!class_dev) {
3380 pr_err("class_device_create failed %d\n", rc);
3381 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303382 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003383 }
3384
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303385 cdev_init(&qseecom.cdev, &qseecom_fops);
3386 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003387
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303388 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003389 if (rc < 0) {
3390 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303391 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003392 }
3393
3394 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3395 spin_lock_init(&qseecom.registered_listener_list_lock);
3396 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3397 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003398 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3399 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003400 init_waitqueue_head(&qseecom.send_resp_wq);
3401 qseecom.send_resp_flag = 0;
3402
3403 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3404 &qsee_not_legacy, sizeof(qsee_not_legacy));
3405 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003406 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303407 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003408 }
Mona Hossain05c73562012-10-29 17:49:01 -07003409 if (qsee_not_legacy) {
3410 uint32_t feature = 10;
3411
3412 qseecom.qsee_version = QSEEE_VERSION_00;
3413 rc = scm_call(6, 3, &feature, sizeof(feature),
3414 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3415 if (rc) {
3416 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303417 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003418 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003419 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003420 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003421 pr_err("QSEE legacy version is not supported:");
3422 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3423 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303424 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003425 }
Mona Hossain05c73562012-10-29 17:49:01 -07003426 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003427 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003428 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003429 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003430 if (qseecom.ion_clnt == NULL) {
3431 pr_err("Ion client cannot be created\n");
3432 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303433 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003434 }
3435
3436 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003437 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003438
Mona Hossain4cf78a92013-02-14 12:06:41 -08003439 if (of_property_read_u32((&pdev->dev)->of_node,
3440 "qcom,disk-encrypt-pipe-pair",
3441 &qseecom.ce_info.disk_encrypt_pipe)) {
3442 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3443 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3444 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303445 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003446 } else {
3447 pr_warn("bam_pipe_pair=0x%x",
3448 qseecom.ce_info.disk_encrypt_pipe);
3449 }
3450
3451 if (of_property_read_u32((&pdev->dev)->of_node,
3452 "qcom,qsee-ce-hw-instance",
3453 &qseecom.ce_info.qsee_ce_hw_instance)) {
3454 pr_err("Fail to get qsee ce hw instance information.\n");
3455 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3456 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303457 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003458 } else {
3459 pr_warn("qsee-ce-hw-instance=0x%x",
3460 qseecom.ce_info.qsee_ce_hw_instance);
3461 }
3462
3463 if (of_property_read_u32((&pdev->dev)->of_node,
3464 "qcom,hlos-ce-hw-instance",
3465 &qseecom.ce_info.hlos_ce_hw_instance)) {
3466 pr_err("Fail to get hlos ce hw instance information.\n");
3467 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3468 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303469 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003470 } else {
3471 pr_warn("hlos-ce-hw-instance=0x%x",
3472 qseecom.ce_info.hlos_ce_hw_instance);
3473 }
3474
Mona Hossainc92629e2013-04-01 13:37:46 -07003475 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3476 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3477
3478 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003479 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303480 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003481
Mona Hossainc92629e2013-04-01 13:37:46 -07003482 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3483 ret = __qseecom_init_clk(CLK_CE_DRV);
3484 if (ret) {
3485 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303486 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003487 }
3488 } else {
3489 struct qseecom_clk *qclk;
3490
3491 qclk = &qseecom.qsee;
3492 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3493 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3494 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3495 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3496 }
3497
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003498 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3499 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003500 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3501 struct resource *resource = NULL;
3502 struct qsee_apps_region_info_ireq req;
3503 struct qseecom_command_scm_resp resp;
3504
3505 resource = platform_get_resource_byname(pdev,
3506 IORESOURCE_MEM, "secapp-region");
3507 if (resource) {
3508 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3509 req.addr = resource->start;
3510 req.size = resource_size(resource);
3511 pr_warn("secure app region addr=0x%x size=0x%x",
3512 req.addr, req.size);
3513 } else {
3514 pr_err("Fail to get secure app region info\n");
3515 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303516 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003517 }
3518 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3519 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003520 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3521 pr_err("send secapp reg fail %d resp.res %d\n",
3522 rc, resp.result);
3523 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303524 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003525 }
3526 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003527 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003528 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3529 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003530 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003531
Mona Hossain17a4faf2013-03-22 16:40:56 -07003532 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003533 qseecom_platform_support);
3534
Mona Hossain17a4faf2013-03-22 16:40:56 -07003535 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003536 pr_err("Unable to register bus client\n");
3537 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303538
3539exit_destroy_ion_client:
3540 ion_client_destroy(qseecom.ion_clnt);
3541exit_del_cdev:
3542 cdev_del(&qseecom.cdev);
3543exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003544 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303545exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003546 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303547exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003548 unregister_chrdev_region(qseecom_device_no, 1);
3549 return rc;
3550}
3551
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003552static int __devinit qseecom_remove(struct platform_device *pdev)
3553{
Mona Hossaind44a3842012-10-15 09:41:35 -07003554 struct qseecom_registered_kclient_list *kclient = NULL;
3555 unsigned long flags = 0;
3556 int ret = 0;
3557
Mona Hossaind44a3842012-10-15 09:41:35 -07003558 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303559
Mona Hossaind44a3842012-10-15 09:41:35 -07003560 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303561 list) {
3562 if (!kclient)
3563 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07003564
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303565 /* Break the loop if client handle is NULL */
3566 if (!kclient->handle)
3567 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07003568
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303569 if (list_empty(&kclient->list))
3570 goto exit_free_kc_handle;
3571
3572 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07003573 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303574 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07003575 kzfree(kclient->handle->dev);
3576 kzfree(kclient->handle);
3577 kzfree(kclient);
3578 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003579 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303580
3581exit_free_kc_handle:
3582 kzfree(kclient->handle);
3583exit_free_kclient:
3584 kzfree(kclient);
3585exit_irqrestore:
3586 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3587
3588 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07003589 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003590
Mona Hossain17a4faf2013-03-22 16:40:56 -07003591 if (qseecom.qsee_perf_client)
3592 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3593 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303594 if (pdev->dev.platform_data != NULL)
3595 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
3596
Mona Hossaind39e33b2012-11-05 13:36:40 -08003597 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003598 if (pdev->dev.of_node) {
3599 __qseecom_deinit_clk(CLK_QSEE);
3600 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3601 __qseecom_deinit_clk(CLK_CE_DRV);
3602 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303603
3604 ion_client_destroy(qseecom.ion_clnt);
3605
3606 cdev_del(&qseecom.cdev);
3607
3608 device_destroy(driver_class, qseecom_device_no);
3609
3610 class_destroy(driver_class);
3611
3612 unregister_chrdev_region(qseecom_device_no, 1);
3613
Mona Hossaind44a3842012-10-15 09:41:35 -07003614 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303615}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003616
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003617static struct of_device_id qseecom_match[] = {
3618 {
3619 .compatible = "qcom,qseecom",
3620 },
3621 {}
3622};
3623
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003624static struct platform_driver qseecom_plat_driver = {
3625 .probe = qseecom_probe,
3626 .remove = qseecom_remove,
3627 .driver = {
3628 .name = "qseecom",
3629 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003630 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003631 },
3632};
3633
3634static int __devinit qseecom_init(void)
3635{
3636 return platform_driver_register(&qseecom_plat_driver);
3637}
3638
3639static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003640{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303641 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003642}
3643
3644MODULE_LICENSE("GPL v2");
3645MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3646
3647module_init(qseecom_init);
3648module_exit(qseecom_exit);