blob: 071fffce88647e849ae50bfa6a12134a27b09a36 [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
877 if (((uint32_t)req_ptr->cmd_req_buf <
878 data_ptr->client.user_virt_sb_base)
879 || ((uint32_t)req_ptr->cmd_req_buf >=
880 (data_ptr->client.user_virt_sb_base +
881 data_ptr->client.sb_length))) {
882 pr_err("cmd buffer address not within shared bufffer\n");
883 return -EINVAL;
884 }
885
886
887 if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
888 || ((uint32_t)req_ptr->resp_buf >=
889 (data_ptr->client.user_virt_sb_base +
890 data_ptr->client.sb_length))){
891 pr_err("response buffer address not within shared bufffer\n");
892 return -EINVAL;
893 }
894
895 req_buf = data_ptr->client.sb_virt;
896
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800897 send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
898 send_svc_ireq_ptr->key_type =
Hariprasad Dhalinarasimhafd86ecd2013-09-27 18:38:53 -0700899 ((struct qseecom_rpmb_provision_key *)req_buf)->key_type;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800900 send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
901 send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
902 (uint32_t)req_ptr->resp_buf));
903 send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
904
905 pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
906 ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
907 return ret;
908}
909
910static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
911 void __user *argp)
912{
913 int ret = 0;
914 struct qseecom_client_send_service_ireq send_svc_ireq;
915 struct qseecom_command_scm_resp resp;
916 struct qseecom_send_svc_cmd_req req;
917 /*struct qseecom_command_scm_resp resp;*/
918
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -0700919 if (copy_from_user(&req,
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800920 (void __user *)argp,
921 sizeof(req))) {
922 pr_err("copy_from_user failed\n");
923 return -EFAULT;
924 }
925
926 if (req.resp_buf == NULL) {
927 pr_err("cmd buffer or response buffer is null\n");
928 return -EINVAL;
929 }
930
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800931 switch (req.cmd_id) {
Hariprasad Dhalinarasimhab3832242013-07-23 15:35:26 -0700932 case QSEOS_RPMB_PROVISION_KEY_COMMAND:
933 case QSEOS_RPMB_ERASE_COMMAND:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800934 if (__qseecom_process_rpmb_svc_cmd(data, &req,
935 &send_svc_ireq))
936 return -EINVAL;
937 break;
938 default:
939 pr_err("Unsupported cmd_id %d\n", req.cmd_id);
940 return -EINVAL;
941 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530942
943 ret = qsee_vote_for_clock(data, CLK_DFAB);
944 if (ret) {
945 pr_err("Failed to vote for DFAB clock%d\n", ret);
946 return ret;
947 }
948 ret = qsee_vote_for_clock(data, CLK_SFPB);
949 if (ret) {
950 pr_err("Failed to vote for SFPB clock%d\n", ret);
951 goto exit_reset_dfab_freq;
952 }
953
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700954 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
955 data->client.sb_virt, data->client.sb_length,
956 ION_IOC_CLEAN_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800957 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
958 sizeof(send_svc_ireq),
959 &resp, sizeof(resp));
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -0700960 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
961 data->client.sb_virt, data->client.sb_length,
962 ION_IOC_INV_CACHES);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800963 if (ret) {
964 pr_err("qseecom_scm_call failed with err: %d\n", ret);
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530965 goto exit_reset_sdfab_freq;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800966 }
967
968 switch (resp.result) {
969 case QSEOS_RESULT_SUCCESS:
970 break;
971 case QSEOS_RESULT_INCOMPLETE:
972 pr_err("qseos_result_incomplete\n");
973 ret = __qseecom_process_incomplete_cmd(data, &resp);
974 if (ret) {
975 pr_err("process_incomplete_cmd fail: err: %d\n",
976 ret);
977 }
978 break;
979 case QSEOS_RESULT_FAILURE:
980 pr_err("process_incomplete_cmd failed err: %d\n", ret);
981 break;
982 default:
983 pr_err("Response result %d not supported\n",
984 resp.result);
985 ret = -EINVAL;
986 break;
987 }
AnilKumar Chimata80f1d1b2013-08-03 05:16:14 +0530988exit_reset_sdfab_freq:
989 qsee_disable_clock_vote(data, CLK_SFPB);
990exit_reset_dfab_freq:
991 qsee_disable_clock_vote(data, CLK_DFAB);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800992 return ret;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -0800993}
994
Mona Hossain2892b6b2012-02-17 13:53:11 -0800995static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
996 struct qseecom_send_cmd_req *req)
997{
998 int ret = 0;
999 u32 reqd_len_sb_in = 0;
1000 struct qseecom_client_send_data_ireq send_data_req;
1001 struct qseecom_command_scm_resp resp;
1002
1003 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
1004 pr_err("cmd buffer or response buffer is null\n");
1005 return -EINVAL;
1006 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001007 if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
1008 ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
1009 data->client.sb_length))) {
1010 pr_err("cmd buffer address not within shared bufffer\n");
1011 return -EINVAL;
1012 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001013
Mona Hossaindddf4442013-10-01 14:08:20 -07001014
1015 if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
1016 ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
1017 data->client.sb_length))){
1018 pr_err("response buffer address not within shared bufffer\n");
1019 return -EINVAL;
1020 }
1021
1022 if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
Mona Hossain2892b6b2012-02-17 13:53:11 -08001023 req->cmd_req_len > data->client.sb_length ||
1024 req->resp_len > data->client.sb_length) {
1025 pr_err("cmd buffer length or "
1026 "response buffer length not valid\n");
1027 return -EINVAL;
1028 }
1029
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001030 if (req->cmd_req_len > UINT_MAX - req->resp_len) {
1031 pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
1032 return -EINVAL;
1033 }
1034
Mona Hossain2892b6b2012-02-17 13:53:11 -08001035 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
1036 if (reqd_len_sb_in > data->client.sb_length) {
1037 pr_debug("Not enough memory to fit cmd_buf and "
1038 "resp_buf. Required: %u, Available: %u\n",
1039 reqd_len_sb_in, data->client.sb_length);
1040 return -ENOMEM;
1041 }
1042
1043 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
1044 send_data_req.app_id = data->client.app_id;
1045 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1046 (uint32_t)req->cmd_req_buf));
1047 send_data_req.req_len = req->cmd_req_len;
1048 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
1049 (uint32_t)req->resp_buf));
1050 send_data_req.rsp_len = req->resp_len;
1051
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001052 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1053 data->client.sb_virt,
Hariprasad Dhalinarasimha528400a2013-10-03 16:43:39 -07001054 reqd_len_sb_in,
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001055 ION_IOC_CLEAN_INV_CACHES);
1056
Mona Hossain2892b6b2012-02-17 13:53:11 -08001057 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
1058 sizeof(send_data_req),
1059 &resp, sizeof(resp));
1060 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001061 pr_err("scm_call() failed with err: %d (app_id = %d)\n",
1062 ret, data->client.app_id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001063 return ret;
1064 }
1065
1066 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
1067 ret = __qseecom_process_incomplete_cmd(data, &resp);
1068 if (ret) {
1069 pr_err("process_incomplete_cmd failed err: %d\n", ret);
1070 return ret;
1071 }
Mona Hossainbb0bca12012-04-12 11:47:45 -07001072 } else {
1073 if (resp.result != QSEOS_RESULT_SUCCESS) {
1074 pr_err("Response result %d not supported\n",
1075 resp.result);
1076 ret = -EINVAL;
1077 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001078 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001079 msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
1080 data->client.sb_virt, data->client.sb_length,
1081 ION_IOC_INV_CACHES);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001082 return ret;
1083}
1084
Mona Hossain2892b6b2012-02-17 13:53:11 -08001085static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
1086{
1087 int ret = 0;
1088 struct qseecom_send_cmd_req req;
1089
1090 ret = copy_from_user(&req, argp, sizeof(req));
1091 if (ret) {
1092 pr_err("copy_from_user failed\n");
1093 return ret;
1094 }
Mona Hossaind4613de2013-05-15 16:49:29 -07001095 ret = __qseecom_send_cmd(data, &req);
1096
Mona Hossain2892b6b2012-02-17 13:53:11 -08001097 if (ret)
1098 return ret;
1099
Mona Hossain2892b6b2012-02-17 13:53:11 -08001100 return ret;
1101}
1102
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001103static int qseecom_unprotect_buffer(void __user *argp)
1104{
1105 int ret = 0;
1106 struct ion_handle *ihandle;
1107 int32_t ion_fd;
1108
1109 ret = copy_from_user(&ion_fd, argp, sizeof(ion_fd));
1110 if (ret) {
1111 pr_err("copy_from_user failed");
1112 return ret;
1113 }
1114
1115 ihandle = ion_import_dma_buf(qseecom.ion_clnt, ion_fd);
1116
1117 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt, ihandle);
1118 if (ret)
1119 return -EINVAL;
1120 return 0;
1121}
1122
1123static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
1124 struct qseecom_dev_handle *data,
1125 bool listener_svc)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001126{
1127 struct ion_handle *ihandle;
1128 char *field;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001129 int ret = 0;
1130 int i = 0;
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001131 uint32_t len = 0;
1132 struct scatterlist *sg;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001133 struct qseecom_send_modfd_cmd_req *cmd_req = NULL;
1134 struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
1135 struct qseecom_registered_listener_list *this_lstnr = NULL;
1136
1137 if (msg == NULL) {
1138 pr_err("Invalid address\n");
1139 return -EINVAL;
1140 }
1141 if (listener_svc) {
1142 lstnr_resp = (struct qseecom_send_modfd_listener_resp *)msg;
1143 this_lstnr = __qseecom_find_svc(data->listener.id);
1144 if (IS_ERR_OR_NULL(this_lstnr)) {
1145 pr_err("Invalid listener ID\n");
1146 return -ENOMEM;
1147 }
1148 } else {
1149 cmd_req = (struct qseecom_send_modfd_cmd_req *)msg;
1150 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08001151
1152 for (i = 0; i < MAX_ION_FD; i++) {
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001153 struct sg_table *sg_ptr = NULL;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001154 if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
Laura Abbottb14ed962012-01-30 14:18:08 -08001155 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001156 cmd_req->ifd_data[i].fd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001157 if (IS_ERR_OR_NULL(ihandle)) {
1158 pr_err("Ion client can't retrieve the handle\n");
1159 return -ENOMEM;
1160 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001161 field = (char *) cmd_req->cmd_req_buf +
1162 cmd_req->ifd_data[i].cmd_buf_offset;
1163 } else if ((listener_svc) &&
1164 (lstnr_resp->ifd_data[i].fd > 0)) {
1165 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
1166 lstnr_resp->ifd_data[i].fd);
1167 if (IS_ERR_OR_NULL(ihandle)) {
1168 pr_err("Ion client can't retrieve the handle\n");
1169 return -ENOMEM;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001170 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001171 switch (lstnr_resp->protection_mode) {
1172 case QSEOS_PROTECT_BUFFER:
1173 ret = msm_ion_secure_buffer(qseecom.ion_clnt,
1174 ihandle,
1175 VIDEO_PIXEL,
1176 0);
1177 break;
1178 case QSEOS_UNPROTECT_PROTECTED_BUFFER:
1179 ret = msm_ion_unsecure_buffer(qseecom.ion_clnt,
1180 ihandle);
1181 break;
1182 case QSEOS_UNPROTECTED_BUFFER:
1183 default:
1184 break;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001185 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001186 field = lstnr_resp->resp_buf_ptr +
1187 lstnr_resp->ifd_data[i].cmd_buf_offset;
1188 } else {
1189 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001190 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001191 /* Populate the cmd data structure with the phys_addr */
1192 sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
1193 if (sg_ptr == NULL) {
1194 pr_err("IOn client could not retrieve sg table\n");
1195 goto err;
1196 }
1197 if (sg_ptr->nents == 0) {
1198 pr_err("Num of scattered entries is 0\n");
1199 goto err;
1200 }
1201 if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
1202 pr_err("Num of scattered entries");
1203 pr_err(" (%d) is greater than max supported %d\n",
1204 sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
1205 goto err;
1206 }
1207 sg = sg_ptr->sgl;
1208 if (sg_ptr->nents == 1) {
1209 uint32_t *update;
1210 update = (uint32_t *) field;
1211 if (cleanup)
1212 *update = 0;
1213 else
1214 *update = (uint32_t)sg_dma_address(
1215 sg_ptr->sgl);
1216 len += (uint32_t)sg->length;
1217 } else {
1218 struct qseecom_sg_entry *update;
1219 int j = 0;
1220 update = (struct qseecom_sg_entry *) field;
1221 for (j = 0; j < sg_ptr->nents; j++) {
1222 if (cleanup) {
1223 update->phys_addr = 0;
1224 update->len = 0;
1225 } else {
1226 update->phys_addr = (uint32_t)
1227 sg_dma_address(sg);
1228 update->len = sg->length;
1229 }
1230 len += sg->length;
1231 update++;
1232 sg = sg_next(sg);
1233 }
1234 }
1235 if (cleanup)
1236 msm_ion_do_cache_op(qseecom.ion_clnt,
1237 ihandle, NULL, len,
1238 ION_IOC_INV_CACHES);
1239 else
1240 msm_ion_do_cache_op(qseecom.ion_clnt,
1241 ihandle, NULL, len,
1242 ION_IOC_CLEAN_INV_CACHES);
1243 /* Deallocate the handle */
1244 if (!IS_ERR_OR_NULL(ihandle))
1245 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001246 }
1247 return ret;
Mona Hossainf1f2ed62012-11-15 19:51:33 -08001248err:
1249 if (!IS_ERR_OR_NULL(ihandle))
1250 ion_free(qseecom.ion_clnt, ihandle);
1251 return -ENOMEM;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001252}
1253
1254static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1255 void __user *argp)
1256{
1257 int ret = 0;
Mona Hossaindddf4442013-10-01 14:08:20 -07001258 int i;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001259 struct qseecom_send_modfd_cmd_req req;
1260 struct qseecom_send_cmd_req send_cmd_req;
1261
1262 ret = copy_from_user(&req, argp, sizeof(req));
1263 if (ret) {
1264 pr_err("copy_from_user failed\n");
1265 return ret;
1266 }
1267 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1268 send_cmd_req.cmd_req_len = req.cmd_req_len;
1269 send_cmd_req.resp_buf = req.resp_buf;
1270 send_cmd_req.resp_len = req.resp_len;
1271
Mona Hossaindddf4442013-10-01 14:08:20 -07001272 /* validate offsets */
1273 for (i = 0; i < MAX_ION_FD; i++) {
1274 if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
1275 pr_err("Invalid offset %d = 0x%x\n",
1276 i, req.ifd_data[i].cmd_buf_offset);
1277 return -EINVAL;
1278 }
1279 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001280 ret = __qseecom_update_cmd_buf(&req, false, data, false);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001281 if (ret)
1282 return ret;
Mona Hossaind4613de2013-05-15 16:49:29 -07001283 ret = __qseecom_send_cmd(data, &send_cmd_req);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001284 if (ret)
1285 return ret;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001286 ret = __qseecom_update_cmd_buf(&req, true, data, false);
Mona Hossainc56584d2013-05-28 09:06:26 -07001287 if (ret)
1288 return ret;
Zhen Kong04f65b82013-10-03 13:58:45 -07001289
Mona Hossain2892b6b2012-02-17 13:53:11 -08001290 return ret;
1291}
1292
1293static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1294 struct qseecom_registered_listener_list *svc)
1295{
1296 int ret;
1297 ret = (svc->rcv_req_flag != 0);
1298 return ret || data->abort;
1299}
1300
1301static int qseecom_receive_req(struct qseecom_dev_handle *data)
1302{
1303 int ret = 0;
1304 struct qseecom_registered_listener_list *this_lstnr;
1305
1306 this_lstnr = __qseecom_find_svc(data->listener.id);
AnilKumar Chimata69b857a2013-07-23 23:03:26 +05301307 if (!this_lstnr) {
1308 pr_err("Invalid listener ID\n");
1309 return -ENODATA;
1310 }
1311
Mona Hossain2892b6b2012-02-17 13:53:11 -08001312 while (1) {
Mona Hossainacea1022012-04-09 13:37:27 -07001313 if (wait_event_freezable(this_lstnr->rcv_req_wq,
Mona Hossain2892b6b2012-02-17 13:53:11 -08001314 __qseecom_listener_has_rcvd_req(data,
1315 this_lstnr))) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001316 pr_warning("Interrupted: exiting Listener Service = %d\n",
1317 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001318 /* woken up for different reason */
1319 return -ERESTARTSYS;
1320 }
1321
1322 if (data->abort) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001323 pr_err("Aborting Listener Service = %d\n",
1324 (uint32_t)data->listener.id);
Mona Hossain2892b6b2012-02-17 13:53:11 -08001325 return -ENODEV;
1326 }
1327 this_lstnr->rcv_req_flag = 0;
Mona Hossaind4613de2013-05-15 16:49:29 -07001328 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001329 }
1330 return ret;
1331}
1332
Mona Hossaind44a3842012-10-15 09:41:35 -07001333static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
1334{
1335 struct elf32_hdr *ehdr;
1336
1337 if (fw_entry->size < sizeof(*ehdr)) {
1338 pr_err("%s: Not big enough to be an elf header\n",
1339 qseecom.pdev->init_name);
1340 return false;
1341 }
1342 ehdr = (struct elf32_hdr *)fw_entry->data;
1343 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
1344 pr_err("%s: Not an elf header\n",
1345 qseecom.pdev->init_name);
1346 return false;
1347 }
1348
1349 if (ehdr->e_phnum == 0) {
1350 pr_err("%s: No loadable segments\n",
1351 qseecom.pdev->init_name);
1352 return false;
1353 }
1354 if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
1355 sizeof(struct elf32_hdr) > fw_entry->size) {
1356 pr_err("%s: Program headers not within mdt\n",
1357 qseecom.pdev->init_name);
1358 return false;
1359 }
1360 return true;
1361}
1362
1363static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
1364{
1365 int ret = -1;
1366 int i = 0, rc = 0;
1367 const struct firmware *fw_entry = NULL;
1368 struct elf32_phdr *phdr;
1369 char fw_name[MAX_APP_NAME_SIZE];
1370 struct elf32_hdr *ehdr;
1371 int num_images = 0;
1372
1373 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1374 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1375 if (rc) {
1376 pr_err("error with request_firmware\n");
1377 ret = -EIO;
1378 goto err;
1379 }
1380 if (!__qseecom_is_fw_image_valid(fw_entry)) {
1381 ret = -EIO;
1382 goto err;
1383 }
1384 *fw_size = fw_entry->size;
1385 phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
1386 ehdr = (struct elf32_hdr *)fw_entry->data;
1387 num_images = ehdr->e_phnum;
1388 release_firmware(fw_entry);
1389 for (i = 0; i < num_images; i++, phdr++) {
1390 memset(fw_name, 0, sizeof(fw_name));
1391 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1392 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1393 if (ret)
1394 goto err;
1395 *fw_size += fw_entry->size;
1396 release_firmware(fw_entry);
1397 }
1398 return ret;
1399err:
1400 if (fw_entry)
1401 release_firmware(fw_entry);
1402 *fw_size = 0;
1403 return ret;
1404}
1405
1406static int __qseecom_get_fw_data(char *appname, u8 *img_data,
1407 struct qseecom_load_app_ireq *load_req)
1408{
1409 int ret = -1;
1410 int i = 0, rc = 0;
1411 const struct firmware *fw_entry = NULL;
1412 char fw_name[MAX_APP_NAME_SIZE];
1413 u8 *img_data_ptr = img_data;
1414 struct elf32_hdr *ehdr;
1415 int num_images = 0;
1416
1417 snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
1418 rc = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1419 if (rc) {
1420 ret = -EIO;
1421 goto err;
1422 }
1423 load_req->img_len = fw_entry->size;
1424 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1425 img_data_ptr = img_data_ptr + fw_entry->size;
1426 load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
1427 ehdr = (struct elf32_hdr *)fw_entry->data;
1428 num_images = ehdr->e_phnum;
1429 release_firmware(fw_entry);
1430 for (i = 0; i < num_images; i++) {
1431 snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
1432 ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
1433 if (ret) {
1434 pr_err("Failed to locate blob %s\n", fw_name);
1435 goto err;
1436 }
1437 memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
1438 img_data_ptr = img_data_ptr + fw_entry->size;
1439 load_req->img_len += fw_entry->size;
1440 release_firmware(fw_entry);
1441 }
1442 load_req->phy_addr = virt_to_phys(img_data);
1443 return ret;
1444err:
1445 release_firmware(fw_entry);
1446 return ret;
1447}
1448
1449static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
1450{
1451 int ret = -1;
1452 uint32_t fw_size = 0;
1453 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1454 struct qseecom_command_scm_resp resp;
1455 u8 *img_data = NULL;
1456
1457 if (__qseecom_get_fw_size(appname, &fw_size))
1458 return -EIO;
1459
1460 img_data = kzalloc(fw_size, GFP_KERNEL);
1461 if (!img_data) {
1462 pr_err("Failied to allocate memory for copying image data\n");
1463 return -ENOMEM;
1464 }
1465 ret = __qseecom_get_fw_data(appname, img_data, &load_req);
1466 if (ret) {
1467 kzfree(img_data);
1468 return -EIO;
1469 }
1470
1471 /* Populate the remaining parameters */
1472 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
1473 memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001474 ret = qsee_vote_for_clock(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001475 if (ret) {
1476 kzfree(img_data);
1477 pr_warning("Unable to vote for SFPB clock");
Mona Hossain60f9fb02012-11-05 13:51:50 -08001478 return -EIO;
1479 }
1480
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001481 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossaind44a3842012-10-15 09:41:35 -07001482 /* SCM_CALL to load the image */
1483 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1484 sizeof(struct qseecom_load_app_ireq),
1485 &resp, sizeof(resp));
1486 kzfree(img_data);
1487 if (ret) {
1488 pr_err("scm_call to load failed : ret %d\n", ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08001489 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001490 return -EIO;
1491 }
1492
1493 switch (resp.result) {
1494 case QSEOS_RESULT_SUCCESS:
1495 ret = resp.data;
1496 break;
1497 case QSEOS_RESULT_INCOMPLETE:
1498 ret = __qseecom_process_incomplete_cmd(data, &resp);
1499 if (ret)
1500 pr_err("process_incomplete_cmd FAILED\n");
1501 else
1502 ret = resp.data;
1503 break;
1504 case QSEOS_RESULT_FAILURE:
1505 pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
1506 break;
1507 default:
1508 pr_err("scm call return unknown response %d\n", resp.result);
1509 ret = -EINVAL;
1510 break;
1511 }
Mona Hossain04d3fac2012-12-03 10:10:37 -08001512 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain60f9fb02012-11-05 13:51:50 -08001513
Mona Hossaind44a3842012-10-15 09:41:35 -07001514 return ret;
1515}
1516
Mona Hossain9498f5e2013-01-23 18:08:45 -08001517static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data)
Mona Hossain05c73562012-10-29 17:49:01 -07001518{
1519 int32_t ret = 0;
1520 uint32_t fw_size = 0;
1521 struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
1522 struct qseecom_command_scm_resp resp;
1523 u8 *img_data = NULL;
1524
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001525 if (__qseecom_get_fw_size("cmnlib", &fw_size))
Mona Hossain05c73562012-10-29 17:49:01 -07001526 return -EIO;
1527
1528 img_data = kzalloc(fw_size, GFP_KERNEL);
1529 if (!img_data) {
1530 pr_err("Mem allocation for lib image data failed\n");
1531 return -ENOMEM;
1532 }
Hariprasad Dhalinarasimhaa3b96442013-01-02 10:40:40 -08001533 ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
Mona Hossain05c73562012-10-29 17:49:01 -07001534 if (ret) {
1535 kzfree(img_data);
1536 return -EIO;
1537 }
1538 /* Populate the remaining parameters */
1539 load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
Mona Hossain6311d572013-03-01 15:54:02 -08001540 /* Vote for the SFPB clock */
1541 ret = qsee_vote_for_clock(data, CLK_SFPB);
1542 if (ret) {
1543 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
1544 kzfree(img_data);
1545 return -EIO;
1546 }
1547
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07001548 __cpuc_flush_dcache_area((void *)img_data, fw_size);
Mona Hossain05c73562012-10-29 17:49:01 -07001549 /* SCM_CALL to load the image */
1550 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
1551 sizeof(struct qseecom_load_lib_image_ireq),
1552 &resp, sizeof(resp));
Mona Hossain05c73562012-10-29 17:49:01 -07001553 if (ret) {
1554 pr_err("scm_call to load failed : ret %d\n", ret);
1555 ret = -EIO;
1556 } else {
1557 switch (resp.result) {
1558 case QSEOS_RESULT_SUCCESS:
1559 break;
1560 case QSEOS_RESULT_FAILURE:
1561 pr_err("scm call failed w/response result%d\n",
1562 resp.result);
1563 ret = -EINVAL;
1564 break;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001565 case QSEOS_RESULT_INCOMPLETE:
1566 ret = __qseecom_process_incomplete_cmd(data, &resp);
1567 if (ret)
1568 pr_err("process_incomplete_cmd failed err: %d\n",
1569 ret);
1570 break;
Mona Hossain05c73562012-10-29 17:49:01 -07001571 default:
1572 pr_err("scm call return unknown response %d\n",
1573 resp.result);
1574 ret = -EINVAL;
1575 break;
1576 }
1577 }
Hariprasad Dhalinarasimha1a81ca32013-01-31 18:32:32 -08001578 kzfree(img_data);
Mona Hossain6311d572013-03-01 15:54:02 -08001579 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain05c73562012-10-29 17:49:01 -07001580 return ret;
1581}
1582
1583static int qseecom_unload_commonlib_image(void)
1584{
1585 int ret = -EINVAL;
1586 struct qseecom_unload_lib_image_ireq unload_req = {0};
1587 struct qseecom_command_scm_resp resp;
1588
1589 /* Populate the remaining parameters */
1590 unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
1591 /* SCM_CALL to load the image */
1592 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
1593 sizeof(struct qseecom_unload_lib_image_ireq),
1594 &resp, sizeof(resp));
1595 if (ret) {
1596 pr_err("scm_call to unload lib failed : ret %d\n", ret);
1597 ret = -EIO;
1598 } else {
1599 switch (resp.result) {
1600 case QSEOS_RESULT_SUCCESS:
1601 break;
1602 case QSEOS_RESULT_FAILURE:
1603 pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
1604 break;
1605 default:
1606 pr_err("scm call return unknown response %d\n",
1607 resp.result);
1608 ret = -EINVAL;
1609 break;
1610 }
1611 }
1612 return ret;
1613}
1614
Mona Hossaind44a3842012-10-15 09:41:35 -07001615int qseecom_start_app(struct qseecom_handle **handle,
1616 char *app_name, uint32_t size)
1617{
Mona Hossain05c73562012-10-29 17:49:01 -07001618 int32_t ret = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07001619 unsigned long flags = 0;
1620 struct qseecom_dev_handle *data = NULL;
1621 struct qseecom_check_app_ireq app_ireq;
1622 struct qseecom_registered_app_list *entry = NULL;
1623 struct qseecom_registered_kclient_list *kclient_entry = NULL;
1624 bool found_app = false;
1625 uint32_t len;
1626 ion_phys_addr_t pa;
1627
Mona Hossain823f9882012-11-23 14:42:20 -08001628 *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
1629 if (!(*handle)) {
1630 pr_err("failed to allocate memory for kernel client handle\n");
1631 return -ENOMEM;
1632 }
1633
Mona Hossaind44a3842012-10-15 09:41:35 -07001634 data = kzalloc(sizeof(*data), GFP_KERNEL);
1635 if (!data) {
1636 pr_err("kmalloc failed\n");
1637 if (ret == 0) {
1638 kfree(*handle);
1639 *handle = NULL;
1640 }
1641 return -ENOMEM;
1642 }
1643 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08001644 data->type = QSEECOM_CLIENT_APP;
Mona Hossaind44a3842012-10-15 09:41:35 -07001645 data->released = false;
Mona Hossaind44a3842012-10-15 09:41:35 -07001646 data->client.sb_length = size;
1647 data->client.user_virt_sb_base = 0;
1648 data->client.ihandle = NULL;
1649
1650 init_waitqueue_head(&data->abort_wq);
1651 atomic_set(&data->ioctl_count, 0);
1652
1653 data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
1654 ION_HEAP(ION_QSECOM_HEAP_ID), 0);
1655 if (IS_ERR_OR_NULL(data->client.ihandle)) {
1656 pr_err("Ion client could not retrieve the handle\n");
1657 kfree(data);
1658 kfree(*handle);
1659 *handle = NULL;
1660 return -EINVAL;
1661 }
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001662 mutex_lock(&app_access_lock);
Mona Hossain9498f5e2013-01-23 18:08:45 -08001663 if (qseecom.qsee_version > QSEEE_VERSION_00) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08001664 if (qseecom.commonlib_loaded == false) {
1665 ret = qseecom_load_commonlib_image(data);
1666 if (ret == 0)
1667 qseecom.commonlib_loaded = true;
1668 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001669 }
Mona Hossain9498f5e2013-01-23 18:08:45 -08001670 if (ret) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07001671 pr_err("Failed to load commonlib image\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001672 ret = -EIO;
1673 goto err;
Mona Hossain9498f5e2013-01-23 18:08:45 -08001674 }
1675
1676 app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
1677 memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
1678 ret = __qseecom_check_app_exists(app_ireq);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001679 if (ret < 0)
1680 goto err;
1681
Hariprasad Dhalinarasimhaefecbfd2013-04-10 15:13:03 -07001682 data->client.app_id = ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001683 if (ret > 0) {
1684 pr_warn("App id %d for [%s] app exists\n", ret,
1685 (char *)app_ireq.app_name);
1686 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1687 list_for_each_entry(entry,
1688 &qseecom.registered_app_list_head, list){
1689 if (entry->app_id == ret) {
1690 entry->ref_cnt++;
1691 found_app = true;
1692 break;
1693 }
1694 }
1695 spin_unlock_irqrestore(
1696 &qseecom.registered_app_list_lock, flags);
1697 if (!found_app)
1698 pr_warn("App_id %d [%s] was loaded but not registered\n",
1699 ret, (char *)app_ireq.app_name);
1700 } else {
1701 /* load the app and get the app_id */
1702 pr_debug("%s: Loading app for the first time'\n",
1703 qseecom.pdev->init_name);
Mona Hossaind44a3842012-10-15 09:41:35 -07001704 ret = __qseecom_load_fw(data, app_name);
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001705 if (ret < 0)
1706 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001707 data->client.app_id = ret;
1708 }
1709 if (!found_app) {
1710 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1711 if (!entry) {
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001712 pr_err("kmalloc for app entry failed\n");
1713 ret = -ENOMEM;
1714 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001715 }
1716 entry->app_id = ret;
1717 entry->ref_cnt = 1;
1718
1719 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
1720 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
1721 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
1722 flags);
1723 }
1724
1725 /* Get the physical address of the ION BUF */
1726 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
1727 /* Populate the structure for sending scm call to load image */
1728 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
1729 data->client.ihandle);
Hariprasad Dhalinarasimhaacfb09c2013-01-10 13:16:15 -08001730 data->client.user_virt_sb_base = (uint32_t)data->client.sb_virt;
Mona Hossaind44a3842012-10-15 09:41:35 -07001731 data->client.sb_phys = pa;
1732 (*handle)->dev = (void *)data;
1733 (*handle)->sbuf = (unsigned char *)data->client.sb_virt;
1734 (*handle)->sbuf_len = data->client.sb_length;
1735
1736 kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
1737 if (!kclient_entry) {
1738 pr_err("kmalloc failed\n");
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001739 ret = -ENOMEM;
1740 goto err;
Mona Hossaind44a3842012-10-15 09:41:35 -07001741 }
1742 kclient_entry->handle = *handle;
1743
1744 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1745 list_add_tail(&kclient_entry->list,
1746 &qseecom.registered_kclient_list_head);
1747 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1748
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001749 mutex_unlock(&app_access_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07001750 return 0;
Mona Hossainb2dc0f82013-05-22 09:26:50 -07001751
1752err:
1753 kfree(data);
1754 kfree(*handle);
1755 *handle = NULL;
1756 mutex_unlock(&app_access_lock);
1757 return ret;
Mona Hossaind44a3842012-10-15 09:41:35 -07001758}
1759EXPORT_SYMBOL(qseecom_start_app);
1760
1761int qseecom_shutdown_app(struct qseecom_handle **handle)
1762{
1763 int ret = -EINVAL;
Mona Hossain33824022013-02-25 09:32:33 -08001764 struct qseecom_dev_handle *data;
1765
Mona Hossaind44a3842012-10-15 09:41:35 -07001766 struct qseecom_registered_kclient_list *kclient = NULL;
1767 unsigned long flags = 0;
1768 bool found_handle = false;
1769
Mona Hossain33824022013-02-25 09:32:33 -08001770 if ((handle == NULL) || (*handle == NULL)) {
Mona Hossaind44a3842012-10-15 09:41:35 -07001771 pr_err("Handle is not initialized\n");
1772 return -EINVAL;
1773 }
Mona Hossain33824022013-02-25 09:32:33 -08001774 data = (struct qseecom_dev_handle *) ((*handle)->dev);
Mona Hossaind44a3842012-10-15 09:41:35 -07001775 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
1776 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
1777 list) {
1778 if (kclient->handle == (*handle)) {
1779 list_del(&kclient->list);
1780 found_handle = true;
1781 break;
1782 }
1783 }
1784 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
1785 if (!found_handle)
1786 pr_err("Unable to find the handle, exiting\n");
1787 else
1788 ret = qseecom_unload_app(data);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001789 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001790 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07001791 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08001792 qsee_disable_clock_vote(data, CLK_DFAB);
Mona Hossaind44a3842012-10-15 09:41:35 -07001793 if (ret == 0) {
1794 kzfree(data);
1795 kzfree(*handle);
1796 kzfree(kclient);
1797 *handle = NULL;
1798 }
1799 return ret;
1800}
1801EXPORT_SYMBOL(qseecom_shutdown_app);
1802
1803int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
1804 uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
1805{
1806 int ret = 0;
1807 struct qseecom_send_cmd_req req = {0, 0, 0, 0};
1808 struct qseecom_dev_handle *data;
1809
Mona Hossaind44a3842012-10-15 09:41:35 -07001810 if (handle == NULL) {
1811 pr_err("Handle is not initialized\n");
1812 return -EINVAL;
1813 }
1814 data = handle->dev;
1815
1816 req.cmd_req_len = sbuf_len;
1817 req.resp_len = rbuf_len;
1818 req.cmd_req_buf = send_buf;
1819 req.resp_buf = resp_buf;
1820
1821 mutex_lock(&app_access_lock);
1822 atomic_inc(&data->ioctl_count);
1823
1824 ret = __qseecom_send_cmd(data, &req);
1825
1826 atomic_dec(&data->ioctl_count);
1827 mutex_unlock(&app_access_lock);
1828
1829 if (ret)
1830 return ret;
1831
1832 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1833 req.resp_len, req.resp_buf);
1834 return ret;
1835}
1836EXPORT_SYMBOL(qseecom_send_command);
1837
Mona Hossain91a8fc92012-11-07 19:58:30 -08001838int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
1839{
Mona Hossainfca6f422013-01-12 13:00:35 -08001840 int ret = 0;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001841 if ((handle == NULL) || (handle->dev == NULL)) {
1842 pr_err("No valid kernel client\n");
1843 return -EINVAL;
1844 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001845 if (high) {
1846 ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
1847 if (ret)
1848 pr_err("Failed to vote for DFAB clock%d\n", ret);
1849 ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
1850 if (ret) {
1851 pr_err("Failed to vote for SFPB clock%d\n", ret);
1852 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
1853 }
1854 } else {
Mona Hossain04d3fac2012-12-03 10:10:37 -08001855 qsee_disable_clock_vote(handle->dev, CLK_DFAB);
Mona Hossainfca6f422013-01-12 13:00:35 -08001856 qsee_disable_clock_vote(handle->dev, CLK_SFPB);
Mona Hossain91a8fc92012-11-07 19:58:30 -08001857 }
Mona Hossainfca6f422013-01-12 13:00:35 -08001858 return ret;
Mona Hossain91a8fc92012-11-07 19:58:30 -08001859}
1860EXPORT_SYMBOL(qseecom_set_bandwidth);
1861
Mona Hossain2892b6b2012-02-17 13:53:11 -08001862static int qseecom_send_resp(void)
1863{
1864 qseecom.send_resp_flag = 1;
1865 wake_up_interruptible(&qseecom.send_resp_wq);
1866 return 0;
1867}
1868
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001869
1870static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
1871 void __user *argp)
1872{
1873 struct qseecom_send_modfd_listener_resp resp;
Mona Hossaindddf4442013-10-01 14:08:20 -07001874 int i;
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001875
1876 if (copy_from_user(&resp, argp, sizeof(resp))) {
1877 pr_err("copy_from_user failed");
1878 return -EINVAL;
1879 }
Mona Hossaindddf4442013-10-01 14:08:20 -07001880 /* validate offsets */
1881 for (i = 0; i < MAX_ION_FD; i++) {
1882 if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
1883 pr_err("Invalid offset %d = 0x%x\n",
1884 i, resp.ifd_data[i].cmd_buf_offset);
1885 return -EINVAL;
1886 }
1887 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07001888 __qseecom_update_cmd_buf(&resp, false, data, true);
1889 qseecom.send_resp_flag = 1;
1890 wake_up_interruptible(&qseecom.send_resp_wq);
1891 return 0;
1892}
1893
1894
Mona Hossain2892b6b2012-02-17 13:53:11 -08001895static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1896 void __user *argp)
1897{
1898 struct qseecom_qseos_version_req req;
1899
1900 if (copy_from_user(&req, argp, sizeof(req))) {
1901 pr_err("copy_from_user failed");
1902 return -EINVAL;
1903 }
1904 req.qseos_version = qseecom.qseos_version;
1905 if (copy_to_user(argp, &req, sizeof(req))) {
1906 pr_err("copy_to_user failed");
1907 return -EINVAL;
1908 }
1909 return 0;
1910}
1911
Mona Hossainc92629e2013-04-01 13:37:46 -07001912static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001913{
1914 int rc = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001915 struct qseecom_clk *qclk;
Mona Hossain6311d572013-03-01 15:54:02 -08001916
Mona Hossainc92629e2013-04-01 13:37:46 -07001917 if (ce == CLK_QSEE)
Mona Hossain4cf78a92013-02-14 12:06:41 -08001918 qclk = &qseecom.qsee;
Mona Hossainc92629e2013-04-01 13:37:46 -07001919 else
1920 qclk = &qseecom.ce_drv;
1921
1922 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001923
1924 if (qclk->clk_access_cnt == ULONG_MAX)
1925 goto err;
1926
Mona Hossainc92629e2013-04-01 13:37:46 -07001927 if (qclk->clk_access_cnt > 0) {
1928 qclk->clk_access_cnt++;
1929 mutex_unlock(&clk_access_lock);
1930 return rc;
1931 }
1932
Mona Hossain6311d572013-03-01 15:54:02 -08001933 /* Enable CE core clk */
Mona Hossain17a4faf2013-03-22 16:40:56 -07001934 rc = clk_prepare_enable(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001935 if (rc) {
1936 pr_err("Unable to enable/prepare CE core clk\n");
1937 goto err;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001938 }
1939 /* Enable CE clk */
1940 rc = clk_prepare_enable(qclk->ce_clk);
1941 if (rc) {
1942 pr_err("Unable to enable/prepare CE iface clk\n");
1943 goto ce_clk_err;
1944 }
1945 /* Enable AXI clk */
1946 rc = clk_prepare_enable(qclk->ce_bus_clk);
1947 if (rc) {
1948 pr_err("Unable to enable/prepare CE bus clk\n");
1949 goto ce_bus_clk_err;
Mona Hossain6311d572013-03-01 15:54:02 -08001950 }
Mona Hossainc92629e2013-04-01 13:37:46 -07001951 qclk->clk_access_cnt++;
1952 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001953 return 0;
1954
1955ce_bus_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001956 clk_disable_unprepare(qclk->ce_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001957ce_clk_err:
Mona Hossain17a4faf2013-03-22 16:40:56 -07001958 clk_disable_unprepare(qclk->ce_core_clk);
Mona Hossain6311d572013-03-01 15:54:02 -08001959err:
Mona Hossainc92629e2013-04-01 13:37:46 -07001960 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001961 return -EIO;
1962}
1963
Mona Hossainc92629e2013-04-01 13:37:46 -07001964static void __qseecom_disable_clk(enum qseecom_ce_hw_instance ce)
Mona Hossain6311d572013-03-01 15:54:02 -08001965{
Mona Hossain17a4faf2013-03-22 16:40:56 -07001966 struct qseecom_clk *qclk;
1967
Mona Hossainc92629e2013-04-01 13:37:46 -07001968 if (ce == CLK_QSEE)
1969 qclk = &qseecom.qsee;
1970 else
1971 qclk = &qseecom.ce_drv;
1972
1973 mutex_lock(&clk_access_lock);
Zhen Kong1f09c7692013-05-03 17:50:32 -07001974
1975 if (qclk->clk_access_cnt == 0) {
1976 mutex_unlock(&clk_access_lock);
1977 return;
1978 }
1979
Mona Hossainc92629e2013-04-01 13:37:46 -07001980 if (qclk->clk_access_cnt == 1) {
1981 if (qclk->ce_clk != NULL)
1982 clk_disable_unprepare(qclk->ce_clk);
1983 if (qclk->ce_core_clk != NULL)
1984 clk_disable_unprepare(qclk->ce_core_clk);
1985 if (qclk->ce_bus_clk != NULL)
1986 clk_disable_unprepare(qclk->ce_bus_clk);
1987 }
1988 qclk->clk_access_cnt--;
1989 mutex_unlock(&clk_access_lock);
Mona Hossain6311d572013-03-01 15:54:02 -08001990}
1991
Mona Hossain04d3fac2012-12-03 10:10:37 -08001992static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
1993 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08001994{
1995 int ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07001996 struct qseecom_clk *qclk;
Mona Hossain2892b6b2012-02-17 13:53:11 -08001997
Mona Hossain17a4faf2013-03-22 16:40:56 -07001998 qclk = &qseecom.qsee;
1999 if (!qseecom.qsee_perf_client)
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002000 return ret;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002001
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002002 switch (clk_type) {
2003 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002004 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002005 if (!qseecom.qsee_bw_count) {
2006 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002007 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002008 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002009 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002010 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002011 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002012 if (!ret) {
2013 ret =
2014 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002015 qseecom.qsee_perf_client, 1);
2016 if ((ret) &&
2017 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002018 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002019 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002020 }
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002021 if (ret)
2022 pr_err("DFAB Bandwidth req failed (%d)\n",
2023 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002024 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002025 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002026 data->perf_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002027 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002028 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002029 qseecom.qsee_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002030 data->perf_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002031 }
2032 mutex_unlock(&qsee_bw_mutex);
2033 break;
2034 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002035 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002036 if (!qseecom.qsee_sfpb_bw_count) {
2037 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002038 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002039 qseecom.qsee_perf_client, 3);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002040 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002041 if (qclk->ce_core_src_clk != NULL)
Mona Hossainc92629e2013-04-01 13:37:46 -07002042 ret = __qseecom_enable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002043 if (!ret) {
2044 ret =
2045 msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002046 qseecom.qsee_perf_client, 2);
2047 if ((ret) &&
2048 (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002049 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain6311d572013-03-01 15:54:02 -08002050 }
Mona Hossaind39e33b2012-11-05 13:36:40 -08002051 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002052
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002053 if (ret)
2054 pr_err("SFPB Bandwidth req failed (%d)\n",
2055 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002056 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002057 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002058 data->fast_load_enabled = true;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002059 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002060 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002061 qseecom.qsee_sfpb_bw_count++;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002062 data->fast_load_enabled = true;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002063 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002064 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002065 break;
2066 default:
2067 pr_err("Clock type not defined\n");
2068 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002069 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002070 return ret;
2071}
2072
Mona Hossain04d3fac2012-12-03 10:10:37 -08002073static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
2074 int32_t clk_type)
Mona Hossain2892b6b2012-02-17 13:53:11 -08002075{
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002076 int32_t ret = 0;
Mona Hossain17a4faf2013-03-22 16:40:56 -07002077 struct qseecom_clk *qclk;
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002078
Mona Hossain17a4faf2013-03-22 16:40:56 -07002079 qclk = &qseecom.qsee;
2080 if (!qseecom.qsee_perf_client)
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08002081 return;
2082
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002083 switch (clk_type) {
2084 case CLK_DFAB:
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002085 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002086 if (qseecom.qsee_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002087 pr_err("Client error.Extra call to disable DFAB clk\n");
2088 mutex_unlock(&qsee_bw_mutex);
2089 return;
2090 }
2091
Mona Hossain17a4faf2013-03-22 16:40:56 -07002092 if (qseecom.qsee_bw_count == 1) {
2093 if (qseecom.qsee_sfpb_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002094 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002095 qseecom.qsee_perf_client, 2);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002096 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002097 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002098 qseecom.qsee_perf_client, 0);
2099 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002100 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002101 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002102 if (ret)
2103 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002104 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002105 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002106 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002107 data->perf_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002108 }
2109 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002110 qseecom.qsee_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002111 data->perf_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002112 }
2113 mutex_unlock(&qsee_bw_mutex);
2114 break;
2115 case CLK_SFPB:
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002116 mutex_lock(&qsee_bw_mutex);
Mona Hossain17a4faf2013-03-22 16:40:56 -07002117 if (qseecom.qsee_sfpb_bw_count == 0) {
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002118 pr_err("Client error.Extra call to disable SFPB clk\n");
2119 mutex_unlock(&qsee_bw_mutex);
2120 return;
2121 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07002122 if (qseecom.qsee_sfpb_bw_count == 1) {
2123 if (qseecom.qsee_bw_count > 0)
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002124 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002125 qseecom.qsee_perf_client, 1);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002126 else {
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002127 ret = msm_bus_scale_client_update_request(
Mona Hossain17a4faf2013-03-22 16:40:56 -07002128 qseecom.qsee_perf_client, 0);
2129 if ((!ret) && (qclk->ce_core_src_clk != NULL))
Mona Hossainc92629e2013-04-01 13:37:46 -07002130 __qseecom_disable_clk(CLK_QSEE);
Mona Hossaind39e33b2012-11-05 13:36:40 -08002131 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002132 if (ret)
2133 pr_err("SFPB Bandwidth req fail (%d)\n",
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002134 ret);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002135 else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002136 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002137 data->fast_load_enabled = false;
Mona Hossain04d3fac2012-12-03 10:10:37 -08002138 }
2139 } else {
Mona Hossain17a4faf2013-03-22 16:40:56 -07002140 qseecom.qsee_sfpb_bw_count--;
Mona Hossainc9c83c72013-04-11 12:43:48 -07002141 data->fast_load_enabled = false;
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002142 }
Ramesh Masavarapu8d756582012-10-03 10:18:06 -07002143 mutex_unlock(&qsee_bw_mutex);
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002144 break;
2145 default:
2146 pr_err("Clock type not defined\n");
2147 break;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07002148 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002149
Mona Hossain2892b6b2012-02-17 13:53:11 -08002150}
2151
Mona Hossain5ab9d772012-04-11 21:00:40 -07002152static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
2153 void __user *argp)
2154{
2155 struct ion_handle *ihandle; /* Ion handle */
2156 struct qseecom_load_img_req load_img_req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002157 int ret;
2158 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002159 ion_phys_addr_t pa = 0;
2160 uint32_t len;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002161 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002162 struct qseecom_load_app_ireq load_req;
2163 struct qseecom_command_scm_resp resp;
2164
2165 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002166 if (copy_from_user(&load_img_req,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002167 (void __user *)argp,
2168 sizeof(struct qseecom_load_img_req))) {
2169 pr_err("copy_from_user failed\n");
2170 return -EFAULT;
2171 }
2172
2173 /* Get the handle of the shared fd */
Laura Abbottb14ed962012-01-30 14:18:08 -08002174 ihandle = ion_import_dma_buf(qseecom.ion_clnt,
Mona Hossain5ab9d772012-04-11 21:00:40 -07002175 load_img_req.ifd_data_fd);
2176 if (IS_ERR_OR_NULL(ihandle)) {
2177 pr_err("Ion client could not retrieve the handle\n");
2178 return -ENOMEM;
2179 }
2180
2181 /* Get the physical address of the ION BUF */
2182 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
2183
2184 /* Populate the structure for sending scm call to load image */
2185 load_req.qsee_cmd_id = QSEOS_LOAD_EXTERNAL_ELF_COMMAND;
2186 load_req.mdt_len = load_img_req.mdt_len;
2187 load_req.img_len = load_img_req.img_len;
2188 load_req.phy_addr = pa;
2189
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002190 /* SCM_CALL tied to Core0 */
2191 mask = CPU_MASK_CPU0;
2192 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2193 if (set_cpu_ret) {
2194 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2195 set_cpu_ret);
2196 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302197 goto exit_ion_free;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002198 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302199
Mona Hossain6311d572013-03-01 15:54:02 -08002200 /* Vote for the SFPB clock */
2201 ret = qsee_vote_for_clock(data, CLK_SFPB);
2202 if (ret) {
2203 pr_err("Unable to vote for SFPB clock: ret = %d", ret);
2204 ret = -EIO;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302205 goto exit_cpu_restore;
Mona Hossain6311d572013-03-01 15:54:02 -08002206 }
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002207 msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
2208 ION_IOC_CLEAN_INV_CACHES);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002209 /* SCM_CALL to load the external elf */
2210 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
2211 sizeof(struct qseecom_load_app_ireq),
2212 &resp, sizeof(resp));
2213 if (ret) {
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002214 pr_err("scm_call to load failed : ret %d\n",
Mona Hossain5ab9d772012-04-11 21:00:40 -07002215 ret);
2216 ret = -EFAULT;
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302217 goto exit_disable_clock;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002218 }
2219
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302220 switch (resp.result) {
2221 case QSEOS_RESULT_SUCCESS:
2222 break;
2223 case QSEOS_RESULT_INCOMPLETE:
2224 pr_err("%s: qseos result incomplete\n", __func__);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002225 ret = __qseecom_process_incomplete_cmd(data, &resp);
2226 if (ret)
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302227 pr_err("process_incomplete_cmd failed: err: %d\n", ret);
2228 break;
2229 case QSEOS_RESULT_FAILURE:
2230 pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
2231 ret = -EFAULT;
2232 break;
2233 default:
2234 pr_err("scm_call response result %d not supported\n",
2235 resp.result);
2236 ret = -EFAULT;
2237 break;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002238 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002239
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302240exit_disable_clock:
2241 qsee_disable_clock_vote(data, CLK_SFPB);
2242exit_cpu_restore:
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002243 /* Restore the CPU mask */
2244 mask = CPU_MASK_ALL;
2245 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2246 if (set_cpu_ret) {
2247 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2248 set_cpu_ret);
2249 ret = -EFAULT;
2250 }
AnilKumar Chimatac470bc92013-06-12 13:08:37 +05302251exit_ion_free:
Mona Hossain5ab9d772012-04-11 21:00:40 -07002252 /* Deallocate the handle */
2253 if (!IS_ERR_OR_NULL(ihandle))
2254 ion_free(qseecom.ion_clnt, ihandle);
Mona Hossain5ab9d772012-04-11 21:00:40 -07002255 return ret;
2256}
2257
2258static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
2259{
2260 int ret = 0;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002261 int set_cpu_ret = 0;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002262 struct qseecom_command_scm_resp resp;
2263 struct qseecom_unload_app_ireq req;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002264 struct cpumask mask;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002265
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05302266 /* unavailable client app */
2267 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
2268
Mona Hossain5ab9d772012-04-11 21:00:40 -07002269 /* Populate the structure for sending scm call to unload image */
2270 req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002271
2272 /* SCM_CALL tied to Core0 */
2273 mask = CPU_MASK_CPU0;
2274 ret = set_cpus_allowed_ptr(current, &mask);
2275 if (ret) {
2276 pr_err("set_cpus_allowed_ptr failed : ret %d\n",
2277 ret);
2278 return -EFAULT;
2279 }
2280
Mona Hossain5ab9d772012-04-11 21:00:40 -07002281 /* SCM_CALL to unload the external elf */
2282 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
2283 sizeof(struct qseecom_unload_app_ireq),
2284 &resp, sizeof(resp));
2285 if (ret) {
2286 pr_err("scm_call to unload failed : ret %d\n",
2287 ret);
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002288 ret = -EFAULT;
2289 goto qseecom_unload_external_elf_scm_err;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002290 }
2291 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
2292 ret = __qseecom_process_incomplete_cmd(data, &resp);
2293 if (ret)
2294 pr_err("process_incomplete_cmd fail err: %d\n",
2295 ret);
2296 } else {
2297 if (resp.result != QSEOS_RESULT_SUCCESS) {
2298 pr_err("scm_call to unload image failed resp.result =%d\n",
2299 resp.result);
2300 ret = -EFAULT;
2301 }
2302 }
Ramesh Masavarapu41af8ab2012-05-21 11:08:00 -07002303
2304qseecom_unload_external_elf_scm_err:
2305 /* Restore the CPU mask */
2306 mask = CPU_MASK_ALL;
2307 set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
2308 if (set_cpu_ret) {
2309 pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
2310 set_cpu_ret);
2311 ret = -EFAULT;
2312 }
2313
Mona Hossain5ab9d772012-04-11 21:00:40 -07002314 return ret;
2315}
Mona Hossain2892b6b2012-02-17 13:53:11 -08002316
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002317static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
2318 void __user *argp)
2319{
2320
2321 int32_t ret;
2322 struct qseecom_qseos_app_load_query query_req;
2323 struct qseecom_check_app_ireq req;
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002324 struct qseecom_registered_app_list *entry = NULL;
2325 unsigned long flags = 0;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002326
2327 /* Copy the relevant information needed for loading the image */
Hariprasad Dhalinarasimhae2014952013-10-01 18:25:21 -07002328 if (copy_from_user(&query_req,
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002329 (void __user *)argp,
2330 sizeof(struct qseecom_qseos_app_load_query))) {
2331 pr_err("copy_from_user failed\n");
2332 return -EFAULT;
2333 }
2334
2335 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
Hariprasad Dhalinarasimha7a018822013-10-03 16:52:16 -07002336 query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002337 memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
2338
2339 ret = __qseecom_check_app_exists(req);
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002340
2341 if ((ret == -EINVAL) || (ret == -ENODEV)) {
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002342 pr_err(" scm call to check if app is loaded failed");
2343 return ret; /* scm call failed */
2344 } else if (ret > 0) {
Mona Hossain7c443202013-04-18 12:08:58 -07002345 pr_debug("App id %d (%s) already exists\n", ret,
Ramesh Masavarapu13d99672012-07-17 11:05:15 -07002346 (char *)(req.app_name));
2347 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
2348 list_for_each_entry(entry,
2349 &qseecom.registered_app_list_head, list){
2350 if (entry->app_id == ret) {
2351 entry->ref_cnt++;
2352 break;
2353 }
2354 }
2355 spin_unlock_irqrestore(
2356 &qseecom.registered_app_list_lock, flags);
2357 data->client.app_id = ret;
2358 query_req.app_id = ret;
2359
2360 if (copy_to_user(argp, &query_req, sizeof(query_req))) {
2361 pr_err("copy_to_user failed\n");
2362 return -EFAULT;
2363 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07002364 return -EEXIST; /* app already loaded */
2365 } else {
2366 return 0; /* app not loaded */
2367 }
2368}
2369
Mona Hossain4cf78a92013-02-14 12:06:41 -08002370static int __qseecom_get_ce_pipe_info(
2371 enum qseecom_key_management_usage_type usage,
2372 uint32_t *pipe, uint32_t *ce_hw)
2373{
2374 int ret;
2375 switch (usage) {
2376 case QSEOS_KM_USAGE_DISK_ENCRYPTION:
2377 if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
2378 qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
2379 pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
2380 qseecom.ce_info.disk_encrypt_pipe,
2381 qseecom.ce_info.hlos_ce_hw_instance);
2382 ret = -EINVAL;
2383 } else {
2384 *pipe = qseecom.ce_info.disk_encrypt_pipe;
2385 *ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
2386 ret = 0;
2387 }
2388 break;
2389 default:
2390 ret = -EINVAL;
2391 break;
2392 }
2393 return ret;
2394}
2395
2396static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
2397 enum qseecom_key_management_usage_type usage,
2398 uint8_t *key_id, uint32_t flags)
2399{
2400 struct qseecom_key_generate_ireq ireq;
2401 struct qseecom_command_scm_resp resp;
2402 int ret;
2403
2404 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2405 pr_err("Error:: unsupported usage %d\n", usage);
2406 return -EFAULT;
2407 }
2408
2409 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2410 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002411 ireq.qsee_command_id = QSEOS_GENERATE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002412
Mona Hossainc92629e2013-04-01 13:37:46 -07002413 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002414
2415 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002416 &ireq, sizeof(struct qseecom_key_generate_ireq),
2417 &resp, sizeof(resp));
2418 if (ret) {
2419 pr_err("scm call to generate key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002420 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002421 return ret;
2422 }
2423
2424 switch (resp.result) {
2425 case QSEOS_RESULT_SUCCESS:
2426 break;
Zhen Kong336636e2013-04-15 11:04:54 -07002427 case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
Zhen Kongdb2bf742013-05-13 23:55:42 -07002428 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002429 break;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002430 case QSEOS_RESULT_INCOMPLETE:
2431 ret = __qseecom_process_incomplete_cmd(data, &resp);
Zhen Kong336636e2013-04-15 11:04:54 -07002432 if (ret) {
2433 if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
Zhen Kongdb2bf742013-05-13 23:55:42 -07002434 pr_debug("process_incomplete_cmd return Key ID exists.\n");
Zhen Kong336636e2013-04-15 11:04:54 -07002435 ret = 0;
2436 } else {
2437 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2438 resp.result);
2439 }
2440 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08002441 break;
2442 case QSEOS_RESULT_FAILURE:
2443 default:
2444 pr_err("gen key scm call failed resp.result %d\n", resp.result);
2445 ret = -EINVAL;
2446 break;
2447 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002448 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002449 return ret;
2450}
2451
2452static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
2453 enum qseecom_key_management_usage_type usage,
2454 uint8_t *key_id, uint32_t flags)
2455{
2456 struct qseecom_key_delete_ireq ireq;
2457 struct qseecom_command_scm_resp resp;
2458 int ret;
2459
2460 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2461 pr_err("Error:: unsupported usage %d\n", usage);
2462 return -EFAULT;
2463 }
2464
2465 memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2466 ireq.flags = flags;
Zhen Kong336636e2013-04-15 11:04:54 -07002467 ireq.qsee_command_id = QSEOS_DELETE_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002468
Mona Hossainc92629e2013-04-01 13:37:46 -07002469 __qseecom_enable_clk(CLK_QSEE);
Zhen Kong336636e2013-04-15 11:04:54 -07002470
2471 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002472 &ireq, sizeof(struct qseecom_key_delete_ireq),
2473 &resp, sizeof(struct qseecom_command_scm_resp));
2474 if (ret) {
2475 pr_err("scm call to delete key failed : %d\n", ret);
Mona Hossainc92629e2013-04-01 13:37:46 -07002476 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002477 return ret;
2478 }
2479
2480 switch (resp.result) {
2481 case QSEOS_RESULT_SUCCESS:
2482 break;
2483 case QSEOS_RESULT_INCOMPLETE:
2484 ret = __qseecom_process_incomplete_cmd(data, &resp);
2485 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002486 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2487 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002488 break;
2489 case QSEOS_RESULT_FAILURE:
2490 default:
2491 pr_err("Delete key scm call failed resp.result %d\n",
2492 resp.result);
2493 ret = -EINVAL;
2494 break;
2495 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002496 __qseecom_disable_clk(CLK_QSEE);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002497 return ret;
2498}
2499
2500static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
2501 enum qseecom_key_management_usage_type usage,
2502 struct qseecom_set_key_parameter *set_key_para)
2503{
2504 struct qseecom_key_select_ireq ireq;
2505 struct qseecom_command_scm_resp resp;
2506 int ret;
2507
2508 if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2509 pr_err("Error:: unsupported usage %d\n", usage);
2510 return -EFAULT;
2511 }
Mona Hossainc92629e2013-04-01 13:37:46 -07002512
Zhen Kongdb2bf742013-05-13 23:55:42 -07002513 __qseecom_enable_clk(CLK_QSEE);
2514 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002515 __qseecom_enable_clk(CLK_CE_DRV);
2516
Mona Hossain4cf78a92013-02-14 12:06:41 -08002517 memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
Zhen Kong336636e2013-04-15 11:04:54 -07002518 ireq.qsee_command_id = QSEOS_SET_KEY;
Mona Hossain4cf78a92013-02-14 12:06:41 -08002519 ireq.ce = set_key_para->ce_hw;
2520 ireq.pipe = set_key_para->pipe;
2521 ireq.flags = set_key_para->flags;
2522
Zhen Kong1f09c7692013-05-03 17:50:32 -07002523 /* set both PIPE_ENC and PIPE_ENC_XTS*/
2524 ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
Zhen Kong336636e2013-04-15 11:04:54 -07002525
Mona Hossain4cf78a92013-02-14 12:06:41 -08002526 if (set_key_para->set_clear_key_flag ==
2527 QSEECOM_SET_CE_KEY_CMD)
2528 memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
2529 QSEECOM_HASH_SIZE);
2530 else
2531 memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
2532
Zhen Kong336636e2013-04-15 11:04:54 -07002533 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
Mona Hossain4cf78a92013-02-14 12:06:41 -08002534 &ireq, sizeof(struct qseecom_key_select_ireq),
2535 &resp, sizeof(struct qseecom_command_scm_resp));
2536 if (ret) {
Zhen Kong336636e2013-04-15 11:04:54 -07002537 pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
Zhen Kongdb2bf742013-05-13 23:55:42 -07002538 __qseecom_disable_clk(CLK_QSEE);
2539 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
2540 __qseecom_disable_clk(CLK_CE_DRV);
Zhen Kong336636e2013-04-15 11:04:54 -07002541 return ret;
2542 }
2543
Mona Hossain4cf78a92013-02-14 12:06:41 -08002544 switch (resp.result) {
2545 case QSEOS_RESULT_SUCCESS:
2546 break;
2547 case QSEOS_RESULT_INCOMPLETE:
2548 ret = __qseecom_process_incomplete_cmd(data, &resp);
2549 if (ret)
Zhen Kong336636e2013-04-15 11:04:54 -07002550 pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
2551 resp.result);
Mona Hossain4cf78a92013-02-14 12:06:41 -08002552 break;
2553 case QSEOS_RESULT_FAILURE:
2554 default:
2555 pr_err("Set key scm call failed resp.result %d\n", resp.result);
2556 ret = -EINVAL;
2557 break;
2558 }
2559
Zhen Kongdb2bf742013-05-13 23:55:42 -07002560 __qseecom_disable_clk(CLK_QSEE);
2561 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
Mona Hossainc92629e2013-04-01 13:37:46 -07002562 __qseecom_disable_clk(CLK_CE_DRV);
2563
Mona Hossain4cf78a92013-02-14 12:06:41 -08002564 return ret;
2565}
2566
2567static int qseecom_create_key(struct qseecom_dev_handle *data,
2568 void __user *argp)
2569{
2570 uint32_t ce_hw = 0;
2571 uint32_t pipe = 0;
2572 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2573 int ret = 0;
2574 uint32_t flags = 0;
2575 struct qseecom_set_key_parameter set_key_para;
2576 struct qseecom_create_key_req create_key_req;
2577
2578 ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
2579 if (ret) {
2580 pr_err("copy_from_user failed\n");
2581 return ret;
2582 }
2583
2584 if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2585 pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
2586 return -EFAULT;
2587 }
2588
2589 ret = __qseecom_get_ce_pipe_info(create_key_req.usage, &pipe, &ce_hw);
2590 if (ret) {
2591 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2592 return -EINVAL;
2593 }
2594
2595 ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
2596 key_id, flags);
2597 if (ret) {
2598 pr_err("Failed to generate key on storage: %d\n", ret);
2599 return -EFAULT;
2600 }
2601
2602 set_key_para.ce_hw = ce_hw;
2603 set_key_para.pipe = pipe;
2604 memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
2605 set_key_para.flags = flags;
2606 set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
2607 memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
2608 QSEECOM_HASH_SIZE);
2609
2610 ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
2611 &set_key_para);
2612 if (ret) {
2613 pr_err("Failed to create key: pipe %d, ce %d: %d\n",
2614 pipe, ce_hw, ret);
2615 return -EFAULT;
2616 }
2617
2618 return ret;
2619}
2620
2621static int qseecom_wipe_key(struct qseecom_dev_handle *data,
2622 void __user *argp)
2623{
2624 uint32_t ce_hw = 0;
2625 uint32_t pipe = 0;
2626 uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
2627 int ret = 0;
2628 uint32_t flags = 0;
2629 int i;
2630 struct qseecom_wipe_key_req wipe_key_req;
2631 struct qseecom_set_key_parameter clear_key_para;
2632
2633 ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
2634 if (ret) {
2635 pr_err("copy_from_user failed\n");
2636 return ret;
2637 }
2638
2639 if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
2640 pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
2641 return -EFAULT;
2642 }
2643
2644 ret = __qseecom_get_ce_pipe_info(wipe_key_req.usage, &pipe, &ce_hw);
2645 if (ret) {
2646 pr_err("Failed to retrieve pipe/ce_hw info: %d\n", ret);
2647 return -EINVAL;
2648 }
2649
2650 ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
2651 flags);
2652 if (ret) {
2653 pr_err("Failed to delete key from ssd storage: %d\n", ret);
2654 return -EFAULT;
2655 }
2656
2657 /* an invalid key_id 0xff is used to indicate clear key*/
2658 for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
2659 clear_key_para.key_id[i] = 0xff;
2660 clear_key_para.ce_hw = ce_hw;
2661 clear_key_para.pipe = pipe;
2662 clear_key_para.flags = flags;
2663 clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
2664 ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
2665 &clear_key_para);
2666 if (ret) {
2667 pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
2668 pipe, ce_hw, ret);
2669 return -EFAULT;
2670 }
2671
2672 return ret;
2673}
2674
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002675static int qseecom_is_es_activated(void __user *argp)
2676{
2677 struct qseecom_is_es_activated_req req;
2678 int ret;
2679 int resp_buf;
2680
2681 if (qseecom.qsee_version < QSEE_VERSION_04) {
2682 pr_err("invalid qsee version");
2683 return -ENODEV;
2684 }
2685
2686 if (argp == NULL) {
2687 pr_err("arg is null");
2688 return -EINVAL;
2689 }
2690
2691 ret = scm_call(SCM_SVC_ES, SCM_IS_ACTIVATED_ID, NULL, 0,
2692 (void *) &resp_buf, sizeof(resp_buf));
2693 if (ret) {
2694 pr_err("scm_call failed");
2695 return ret;
2696 }
2697
2698 req.is_activated = resp_buf;
2699 ret = copy_to_user(argp, &req, sizeof(req));
2700 if (ret) {
2701 pr_err("copy_to_user failed");
2702 return ret;
2703 }
2704
2705 return 0;
2706}
2707
2708static int qseecom_save_partition_hash(void __user *argp)
2709{
2710 struct qseecom_save_partition_hash_req req;
2711 int ret;
2712
2713 if (qseecom.qsee_version < QSEE_VERSION_04) {
2714 pr_err("invalid qsee version ");
2715 return -ENODEV;
2716 }
2717
2718 if (argp == NULL) {
2719 pr_err("arg is null");
2720 return -EINVAL;
2721 }
2722
2723 ret = copy_from_user(&req, argp, sizeof(req));
2724 if (ret) {
2725 pr_err("copy_from_user failed");
2726 return ret;
2727 }
2728
2729 ret = scm_call(SCM_SVC_ES, SCM_SAVE_PARTITION_HASH_ID,
2730 (void *) &req, sizeof(req), NULL, 0);
2731 if (ret) {
Hariprasad Dhalinarasimha682d1c32013-05-19 21:22:10 -07002732 pr_err("qseecom_scm_call failed");
Amir Samuelovd1fc7412013-03-10 16:56:13 +02002733 return ret;
2734 }
2735
2736 return 0;
2737}
2738
Mona Hossain2892b6b2012-02-17 13:53:11 -08002739static long qseecom_ioctl(struct file *file, unsigned cmd,
2740 unsigned long arg)
2741{
2742 int ret = 0;
2743 struct qseecom_dev_handle *data = file->private_data;
2744 void __user *argp = (void __user *) arg;
2745
AnilKumar Chimata11e1f522013-07-23 06:02:23 +05302746 if (!data) {
2747 pr_err("Invalid/uninitialized device handle\n");
2748 return -EINVAL;
2749 }
2750
Mona Hossain2892b6b2012-02-17 13:53:11 -08002751 if (data->abort) {
2752 pr_err("Aborting qseecom driver\n");
2753 return -ENODEV;
2754 }
2755
2756 switch (cmd) {
2757 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002758 if (data->type != QSEECOM_GENERIC) {
2759 pr_err("reg lstnr req: invalid handle (%d)\n",
2760 data->type);
2761 ret = -EINVAL;
2762 break;
2763 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002764 pr_debug("ioctl register_listener_req()\n");
2765 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002766 data->type = QSEECOM_LISTENER_SERVICE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08002767 ret = qseecom_register_listener(data, argp);
2768 atomic_dec(&data->ioctl_count);
2769 wake_up_all(&data->abort_wq);
2770 if (ret)
2771 pr_err("failed qseecom_register_listener: %d\n", ret);
2772 break;
2773 }
2774 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002775 if ((data->listener.id == 0) ||
2776 (data->type != QSEECOM_LISTENER_SERVICE)) {
2777 pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
2778 data->type, data->listener.id);
2779 ret = -EINVAL;
2780 break;
2781 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002782 pr_debug("ioctl unregister_listener_req()\n");
2783 atomic_inc(&data->ioctl_count);
2784 ret = qseecom_unregister_listener(data);
2785 atomic_dec(&data->ioctl_count);
2786 wake_up_all(&data->abort_wq);
2787 if (ret)
2788 pr_err("failed qseecom_unregister_listener: %d\n", ret);
2789 break;
2790 }
2791 case QSEECOM_IOCTL_SEND_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002792 if ((data->client.app_id == 0) ||
2793 (data->type != QSEECOM_CLIENT_APP)) {
2794 pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
2795 data->type, data->client.app_id);
2796 ret = -EINVAL;
2797 break;
2798 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002799 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002800 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002801 atomic_inc(&data->ioctl_count);
2802 ret = qseecom_send_cmd(data, argp);
2803 atomic_dec(&data->ioctl_count);
2804 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002805 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002806 if (ret)
2807 pr_err("failed qseecom_send_cmd: %d\n", ret);
2808 break;
2809 }
2810 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002811 if ((data->client.app_id == 0) ||
2812 (data->type != QSEECOM_CLIENT_APP)) {
2813 pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
2814 data->type, data->client.app_id);
2815 ret = -EINVAL;
2816 break;
2817 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002818 /* Only one client allowed here at a time */
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002819 mutex_lock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002820 atomic_inc(&data->ioctl_count);
2821 ret = qseecom_send_modfd_cmd(data, argp);
2822 atomic_dec(&data->ioctl_count);
2823 wake_up_all(&data->abort_wq);
Ramesh Masavarapud8610112012-06-26 15:32:52 -07002824 mutex_unlock(&app_access_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002825 if (ret)
2826 pr_err("failed qseecom_send_cmd: %d\n", ret);
2827 break;
2828 }
2829 case QSEECOM_IOCTL_RECEIVE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002830 if ((data->listener.id == 0) ||
2831 (data->type != QSEECOM_LISTENER_SERVICE)) {
2832 pr_err("receive req: invalid handle (%d), lid(%d)\n",
2833 data->type, data->listener.id);
2834 ret = -EINVAL;
2835 break;
2836 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002837 atomic_inc(&data->ioctl_count);
2838 ret = qseecom_receive_req(data);
2839 atomic_dec(&data->ioctl_count);
2840 wake_up_all(&data->abort_wq);
2841 if (ret)
2842 pr_err("failed qseecom_receive_req: %d\n", ret);
2843 break;
2844 }
2845 case QSEECOM_IOCTL_SEND_RESP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002846 if ((data->listener.id == 0) ||
2847 (data->type != QSEECOM_LISTENER_SERVICE)) {
2848 pr_err("send resp req: invalid handle (%d), lid(%d)\n",
2849 data->type, data->listener.id);
2850 ret = -EINVAL;
2851 break;
2852 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002853 atomic_inc(&data->ioctl_count);
2854 ret = qseecom_send_resp();
2855 atomic_dec(&data->ioctl_count);
2856 wake_up_all(&data->abort_wq);
2857 if (ret)
2858 pr_err("failed qseecom_send_resp: %d\n", ret);
2859 break;
2860 }
2861 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002862 if ((data->type != QSEECOM_CLIENT_APP) &&
2863 (data->type != QSEECOM_GENERIC) &&
2864 (data->type != QSEECOM_SECURE_SERVICE)) {
2865 pr_err("set mem param req: invalid handle (%d)\n",
2866 data->type);
2867 ret = -EINVAL;
2868 break;
2869 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002870 pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002871 ret = qseecom_set_client_mem_param(data, argp);
2872 if (ret)
2873 pr_err("failed Qqseecom_set_mem_param request: %d\n",
2874 ret);
2875 break;
2876 }
2877 case QSEECOM_IOCTL_LOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002878 if ((data->type != QSEECOM_GENERIC) &&
2879 (data->type != QSEECOM_CLIENT_APP)) {
2880 pr_err("load app req: invalid handle (%d)\n",
2881 data->type);
2882 ret = -EINVAL;
2883 break;
2884 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002885 data->type = QSEECOM_CLIENT_APP;
2886 pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002887 mutex_lock(&app_access_lock);
2888 atomic_inc(&data->ioctl_count);
Mona Hossain05c73562012-10-29 17:49:01 -07002889 if (qseecom.qsee_version > QSEEE_VERSION_00) {
2890 if (qseecom.commonlib_loaded == false) {
Mona Hossain9498f5e2013-01-23 18:08:45 -08002891 ret = qseecom_load_commonlib_image(data);
Mona Hossain05c73562012-10-29 17:49:01 -07002892 if (ret == 0)
2893 qseecom.commonlib_loaded = true;
2894 }
2895 }
2896 if (ret == 0)
2897 ret = qseecom_load_app(data, argp);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002898 atomic_dec(&data->ioctl_count);
2899 mutex_unlock(&app_access_lock);
2900 if (ret)
2901 pr_err("failed load_app request: %d\n", ret);
2902 break;
2903 }
2904 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002905 if ((data->client.app_id == 0) ||
2906 (data->type != QSEECOM_CLIENT_APP)) {
2907 pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
2908 data->type, data->client.app_id);
2909 ret = -EINVAL;
2910 break;
2911 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002912 pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002913 mutex_lock(&app_access_lock);
2914 atomic_inc(&data->ioctl_count);
2915 ret = qseecom_unload_app(data);
2916 atomic_dec(&data->ioctl_count);
2917 mutex_unlock(&app_access_lock);
2918 if (ret)
2919 pr_err("failed unload_app request: %d\n", ret);
2920 break;
2921 }
2922 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
2923 atomic_inc(&data->ioctl_count);
2924 ret = qseecom_get_qseos_version(data, argp);
2925 if (ret)
2926 pr_err("qseecom_get_qseos_version: %d\n", ret);
2927 atomic_dec(&data->ioctl_count);
2928 break;
2929 }
2930 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002931 if ((data->type != QSEECOM_GENERIC) &&
2932 (data->type != QSEECOM_CLIENT_APP)) {
2933 pr_err("perf enable req: invalid handle (%d)\n",
2934 data->type);
2935 ret = -EINVAL;
2936 break;
2937 }
2938 if ((data->type == QSEECOM_CLIENT_APP) &&
2939 (data->client.app_id == 0)) {
2940 pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
2941 data->type, data->client.app_id);
2942 ret = -EINVAL;
2943 break;
2944 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002945 atomic_inc(&data->ioctl_count);
Mona Hossain04d3fac2012-12-03 10:10:37 -08002946 ret = qsee_vote_for_clock(data, CLK_DFAB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002947 if (ret)
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07002948 pr_err("Failed to vote for DFAB clock%d\n", ret);
Mona Hossain8e2d73a2013-01-10 04:30:04 -08002949 ret = qsee_vote_for_clock(data, CLK_SFPB);
2950 if (ret)
2951 pr_err("Failed to vote for SFPB clock%d\n", ret);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002952 atomic_dec(&data->ioctl_count);
2953 break;
2954 }
2955 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
Mona Hossaina1124de2013-10-01 13:41:09 -07002956 if ((data->type != QSEECOM_SECURE_SERVICE) &&
2957 (data->type != QSEECOM_CLIENT_APP)) {
2958 pr_err("perf disable req: invalid handle (%d)\n",
2959 data->type);
2960 ret = -EINVAL;
2961 break;
2962 }
2963 if ((data->type == QSEECOM_CLIENT_APP) &&
2964 (data->client.app_id == 0)) {
2965 pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
2966 data->type, data->client.app_id);
2967 ret = -EINVAL;
2968 break;
2969 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08002970 atomic_inc(&data->ioctl_count);
Mona Hossaina1124de2013-10-01 13:41:09 -07002971 qsee_disable_clock_vote(data, CLK_DFAB);
2972 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossain2892b6b2012-02-17 13:53:11 -08002973 atomic_dec(&data->ioctl_count);
2974 break;
2975 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07002976 case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002977 if (data->type != QSEECOM_GENERIC) {
2978 pr_err("load ext elf req: invalid client handle (%d)\n",
2979 data->type);
2980 ret = -EINVAL;
2981 break;
2982 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07002983 data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002984 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07002985 mutex_lock(&app_access_lock);
2986 atomic_inc(&data->ioctl_count);
2987 ret = qseecom_load_external_elf(data, argp);
2988 atomic_dec(&data->ioctl_count);
2989 mutex_unlock(&app_access_lock);
2990 if (ret)
2991 pr_err("failed load_external_elf request: %d\n", ret);
2992 break;
2993 }
2994 case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07002995 if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
2996 pr_err("unload ext elf req: invalid handle (%d)\n",
2997 data->type);
2998 ret = -EINVAL;
2999 break;
3000 }
Mona Hossain5ab9d772012-04-11 21:00:40 -07003001 data->released = true;
Mona Hossain5ab9d772012-04-11 21:00:40 -07003002 mutex_lock(&app_access_lock);
3003 atomic_inc(&data->ioctl_count);
3004 ret = qseecom_unload_external_elf(data);
3005 atomic_dec(&data->ioctl_count);
3006 mutex_unlock(&app_access_lock);
3007 if (ret)
3008 pr_err("failed unload_app request: %d\n", ret);
3009 break;
3010 }
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003011 case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003012 data->type = QSEECOM_CLIENT_APP;
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003013 mutex_lock(&app_access_lock);
3014 atomic_inc(&data->ioctl_count);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003015 pr_debug("APP_LOAD_QUERY: qseecom_addr = 0x%x\n", (u32)data);
Ramesh Masavarapu1ee4ac82012-06-22 15:38:34 -07003016 ret = qseecom_query_app_loaded(data, argp);
3017 atomic_dec(&data->ioctl_count);
3018 mutex_unlock(&app_access_lock);
3019 break;
3020 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003021 case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003022 if (data->type != QSEECOM_GENERIC) {
3023 pr_err("send cmd svc req: invalid handle (%d)\n",
3024 data->type);
3025 ret = -EINVAL;
3026 break;
3027 }
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003028 data->type = QSEECOM_SECURE_SERVICE;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003029 if (qseecom.qsee_version < QSEE_VERSION_03) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003030 pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003031 qseecom.qsee_version);
3032 return -EINVAL;
3033 }
3034 mutex_lock(&app_access_lock);
3035 atomic_inc(&data->ioctl_count);
3036 ret = qseecom_send_service_cmd(data, argp);
3037 atomic_dec(&data->ioctl_count);
3038 mutex_unlock(&app_access_lock);
3039 break;
3040 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003041 case QSEECOM_IOCTL_CREATE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003042 if (data->type != QSEECOM_GENERIC) {
3043 pr_err("create key req: invalid handle (%d)\n",
3044 data->type);
3045 ret = -EINVAL;
3046 break;
3047 }
Zhen Kong336636e2013-04-15 11:04:54 -07003048 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003049 pr_err("Create Key feature unsupported: qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003050 qseecom.qsee_version);
3051 return -EINVAL;
3052 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003053 data->released = true;
3054 mutex_lock(&app_access_lock);
3055 atomic_inc(&data->ioctl_count);
3056 ret = qseecom_create_key(data, argp);
3057 if (ret)
3058 pr_err("failed to create encryption key: %d\n", ret);
3059
3060 atomic_dec(&data->ioctl_count);
3061 mutex_unlock(&app_access_lock);
3062 break;
3063 }
3064 case QSEECOM_IOCTL_WIPE_KEY_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003065 if (data->type != QSEECOM_GENERIC) {
3066 pr_err("wipe key req: invalid handle (%d)\n",
3067 data->type);
3068 ret = -EINVAL;
3069 break;
3070 }
Zhen Kong336636e2013-04-15 11:04:54 -07003071 if (qseecom.qsee_version < QSEE_VERSION_05) {
Mona Hossaina1124de2013-10-01 13:41:09 -07003072 pr_err("Wipe Key feature unsupported in qsee ver %u\n",
Zhen Kong336636e2013-04-15 11:04:54 -07003073 qseecom.qsee_version);
3074 return -EINVAL;
3075 }
Mona Hossain4cf78a92013-02-14 12:06:41 -08003076 data->released = true;
3077 mutex_lock(&app_access_lock);
3078 atomic_inc(&data->ioctl_count);
3079 ret = qseecom_wipe_key(data, argp);
3080 if (ret)
3081 pr_err("failed to wipe encryption key: %d\n", ret);
3082 atomic_dec(&data->ioctl_count);
3083 mutex_unlock(&app_access_lock);
3084 break;
3085 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003086 case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003087 if (data->type != QSEECOM_GENERIC) {
3088 pr_err("save part hash req: invalid handle (%d)\n",
3089 data->type);
3090 ret = -EINVAL;
3091 break;
3092 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003093 data->released = true;
3094 mutex_lock(&app_access_lock);
3095 atomic_inc(&data->ioctl_count);
3096 ret = qseecom_save_partition_hash(argp);
3097 atomic_dec(&data->ioctl_count);
3098 mutex_unlock(&app_access_lock);
3099 break;
3100 }
3101 case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003102 if (data->type != QSEECOM_GENERIC) {
3103 pr_err("ES activated req: invalid handle (%d)\n",
3104 data->type);
3105 ret = -EINVAL;
3106 break;
3107 }
Amir Samuelovd1fc7412013-03-10 16:56:13 +02003108 data->released = true;
3109 mutex_lock(&app_access_lock);
3110 atomic_inc(&data->ioctl_count);
3111 ret = qseecom_is_es_activated(argp);
3112 atomic_dec(&data->ioctl_count);
3113 mutex_unlock(&app_access_lock);
3114 break;
3115 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003116 case QSEECOM_IOCTL_SEND_MODFD_RESP: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003117 if ((data->listener.id == 0) ||
3118 (data->type != QSEECOM_LISTENER_SERVICE)) {
3119 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3120 data->type, data->listener.id);
3121 ret = -EINVAL;
3122 break;
3123 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003124 /* Only one client allowed here at a time */
3125 atomic_inc(&data->ioctl_count);
3126 ret = qseecom_send_modfd_resp(data, argp);
3127 atomic_dec(&data->ioctl_count);
3128 wake_up_all(&data->abort_wq);
3129 if (ret)
3130 pr_err("failed qseecom_send_mod_resp: %d\n", ret);
3131 break;
3132 }
3133 case QSEECOM_IOCTL_UNPROTECT_BUF: {
Mona Hossaina1124de2013-10-01 13:41:09 -07003134 if ((data->listener.id == 0) ||
3135 (data->type != QSEECOM_LISTENER_SERVICE)) {
3136 pr_err("receive req: invalid handle (%d), lid(%d)\n",
3137 data->type, data->listener.id);
3138 ret = -EINVAL;
3139 break;
3140 }
Hariprasad Dhalinarasimha23fdcd92013-05-01 14:51:09 -07003141 /* Only one client allowed here at a time */
3142 atomic_inc(&data->ioctl_count);
3143 ret = qseecom_unprotect_buffer(argp);
3144 atomic_dec(&data->ioctl_count);
3145 wake_up_all(&data->abort_wq);
3146 if (ret)
3147 pr_err("failed qseecom_unprotect: %d\n", ret);
3148 break;
3149 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003150 default:
Mona Hossaina1124de2013-10-01 13:41:09 -07003151 pr_err("Invalid IOCTL: %d\n", cmd);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003152 return -EINVAL;
3153 }
3154 return ret;
3155}
3156
3157static int qseecom_open(struct inode *inode, struct file *file)
3158{
3159 int ret = 0;
3160 struct qseecom_dev_handle *data;
3161
3162 data = kzalloc(sizeof(*data), GFP_KERNEL);
3163 if (!data) {
3164 pr_err("kmalloc failed\n");
3165 return -ENOMEM;
3166 }
3167 file->private_data = data;
3168 data->abort = 0;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003169 data->type = QSEECOM_GENERIC;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003170 data->released = false;
3171 init_waitqueue_head(&data->abort_wq);
3172 atomic_set(&data->ioctl_count, 0);
Mona Hossaind4613de2013-05-15 16:49:29 -07003173
Mona Hossain2892b6b2012-02-17 13:53:11 -08003174 return ret;
3175}
3176
3177static int qseecom_release(struct inode *inode, struct file *file)
3178{
3179 struct qseecom_dev_handle *data = file->private_data;
3180 int ret = 0;
3181
3182 if (data->released == false) {
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003183 pr_warn("data: released = false, type = %d, data = 0x%x\n",
3184 data->type, (u32)data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003185 switch (data->type) {
3186 case QSEECOM_LISTENER_SERVICE:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003187 ret = qseecom_unregister_listener(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003188 break;
3189 case QSEECOM_CLIENT_APP:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003190 ret = qseecom_unload_app(data);
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003191 break;
3192 case QSEECOM_SECURE_SERVICE:
Mona Hossaind4b705732013-04-05 21:56:28 -07003193 case QSEECOM_GENERIC:
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003194 ret = qseecom_unmap_ion_allocated_memory(data);
Hariprasad Dhalinarasimha492530f2013-08-19 12:45:18 -07003195 if (ret)
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003196 pr_err("Close failed\n");
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003197 break;
AnilKumar Chimataf732bbe2013-07-24 00:44:09 +05303198 case QSEECOM_UNAVAILABLE_CLIENT_APP:
3199 break;
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003200 default:
3201 pr_err("Unsupported clnt_handle_type %d",
3202 data->type);
3203 break;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003204 }
3205 }
Hariprasad Dhalinarasimhaadf27a82013-02-11 15:07:59 -08003206
Mona Hossainc9c83c72013-04-11 12:43:48 -07003207 if (data->fast_load_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003208 qsee_disable_clock_vote(data, CLK_SFPB);
Mona Hossainc9c83c72013-04-11 12:43:48 -07003209 if (data->perf_enabled == true)
Mona Hossain04d3fac2012-12-03 10:10:37 -08003210 qsee_disable_clock_vote(data, CLK_DFAB);
3211
Mona Hossain2892b6b2012-02-17 13:53:11 -08003212 kfree(data);
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003213
Mona Hossain2892b6b2012-02-17 13:53:11 -08003214 return ret;
3215}
3216
Mona Hossain2892b6b2012-02-17 13:53:11 -08003217static const struct file_operations qseecom_fops = {
3218 .owner = THIS_MODULE,
3219 .unlocked_ioctl = qseecom_ioctl,
3220 .open = qseecom_open,
3221 .release = qseecom_release
3222};
3223
Mona Hossainc92629e2013-04-01 13:37:46 -07003224static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003225{
3226 int rc = 0;
3227 struct device *pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003228 struct qseecom_clk *qclk;
Mona Hossainc92629e2013-04-01 13:37:46 -07003229 char *core_clk_src = NULL;
3230 char *core_clk = NULL;
3231 char *iface_clk = NULL;
3232 char *bus_clk = NULL;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003233
Mona Hossainc92629e2013-04-01 13:37:46 -07003234 switch (ce) {
3235 case CLK_QSEE: {
3236 core_clk_src = "core_clk_src";
3237 core_clk = "core_clk";
3238 iface_clk = "iface_clk";
3239 bus_clk = "bus_clk";
3240 qclk = &qseecom.qsee;
3241 qclk->instance = CLK_QSEE;
3242 break;
3243 };
3244 case CLK_CE_DRV: {
3245 core_clk_src = "ce_drv_core_clk_src";
3246 core_clk = "ce_drv_core_clk";
3247 iface_clk = "ce_drv_iface_clk";
3248 bus_clk = "ce_drv_bus_clk";
3249 qclk = &qseecom.ce_drv;
3250 qclk->instance = CLK_CE_DRV;
3251 break;
3252 };
3253 default:
3254 pr_err("Invalid ce hw instance: %d!\n", ce);
3255 return -EIO;
3256 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003257 pdev = qseecom.pdev;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003258
Mona Hossainc92629e2013-04-01 13:37:46 -07003259 /* Get CE3 src core clk. */
3260 qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003261 if (!IS_ERR(qclk->ce_core_src_clk)) {
Mona Hossain6311d572013-03-01 15:54:02 -08003262 /* Set the core src clk @100Mhz */
Mona Hossain17a4faf2013-03-22 16:40:56 -07003263 rc = clk_set_rate(qclk->ce_core_src_clk, QSEE_CE_CLK_100MHZ);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003264 if (rc) {
Mona Hossain17a4faf2013-03-22 16:40:56 -07003265 clk_put(qclk->ce_core_src_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003266 pr_err("Unable to set the core src clk @100Mhz.\n");
Mona Hossaind39e33b2012-11-05 13:36:40 -08003267 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003268 }
3269 } else {
3270 pr_warn("Unable to get CE core src clk, set to NULL\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003271 qclk->ce_core_src_clk = NULL;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003272 }
3273
3274 /* Get CE core clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003275 qclk->ce_core_clk = clk_get(pdev, core_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003276 if (IS_ERR(qclk->ce_core_clk)) {
3277 rc = PTR_ERR(qclk->ce_core_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003278 pr_err("Unable to get CE core clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003279 if (qclk->ce_core_src_clk != NULL)
3280 clk_put(qclk->ce_core_src_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003281 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003282 }
3283
3284 /* Get CE Interface clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003285 qclk->ce_clk = clk_get(pdev, iface_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003286 if (IS_ERR(qclk->ce_clk)) {
3287 rc = PTR_ERR(qclk->ce_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003288 pr_err("Unable to get CE interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003289 if (qclk->ce_core_src_clk != NULL)
3290 clk_put(qclk->ce_core_src_clk);
3291 clk_put(qclk->ce_core_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003292 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003293 }
3294
3295 /* Get CE AXI clk */
Mona Hossainc92629e2013-04-01 13:37:46 -07003296 qclk->ce_bus_clk = clk_get(pdev, bus_clk);
Mona Hossain17a4faf2013-03-22 16:40:56 -07003297 if (IS_ERR(qclk->ce_bus_clk)) {
3298 rc = PTR_ERR(qclk->ce_bus_clk);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003299 pr_err("Unable to get CE BUS interface clk\n");
Mona Hossain17a4faf2013-03-22 16:40:56 -07003300 if (qclk->ce_core_src_clk != NULL)
3301 clk_put(qclk->ce_core_src_clk);
3302 clk_put(qclk->ce_core_clk);
3303 clk_put(qclk->ce_clk);
Mona Hossaind39e33b2012-11-05 13:36:40 -08003304 return -EIO;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003305 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003306 return rc;
3307}
3308
Mona Hossainc92629e2013-04-01 13:37:46 -07003309static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003310{
Mona Hossain17a4faf2013-03-22 16:40:56 -07003311 struct qseecom_clk *qclk;
3312
Mona Hossainc92629e2013-04-01 13:37:46 -07003313 if (ce == CLK_QSEE)
3314 qclk = &qseecom.qsee;
3315 else
3316 qclk = &qseecom.ce_drv;
Mona Hossain17a4faf2013-03-22 16:40:56 -07003317
3318 if (qclk->ce_clk != NULL) {
3319 clk_put(qclk->ce_clk);
3320 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003321 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003322 if (qclk->ce_core_clk != NULL) {
3323 clk_put(qclk->ce_core_clk);
3324 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003325 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003326 if (qclk->ce_bus_clk != NULL) {
3327 clk_put(qclk->ce_bus_clk);
3328 qclk->ce_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003329 }
Mona Hossain17a4faf2013-03-22 16:40:56 -07003330 if (qclk->ce_core_src_clk != NULL) {
3331 clk_put(qclk->ce_core_src_clk);
3332 qclk->ce_core_src_clk = NULL;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003333 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003334}
3335
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003336static int __devinit qseecom_probe(struct platform_device *pdev)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003337{
3338 int rc;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003339 int ret = 0;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003340 struct device *class_dev;
3341 char qsee_not_legacy = 0;
Mona Hossaind44a3842012-10-15 09:41:35 -07003342 struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003343 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
3344
Mona Hossain17a4faf2013-03-22 16:40:56 -07003345 qseecom.qsee_bw_count = 0;
3346 qseecom.qsee_perf_client = 0;
3347 qseecom.qsee_sfpb_bw_count = 0;
Mona Hossaind39e33b2012-11-05 13:36:40 -08003348
Mona Hossain17a4faf2013-03-22 16:40:56 -07003349 qseecom.qsee.ce_core_clk = NULL;
3350 qseecom.qsee.ce_clk = NULL;
3351 qseecom.qsee.ce_core_src_clk = NULL;
3352 qseecom.qsee.ce_bus_clk = NULL;
Ramesh Masavarapue640e842012-04-03 11:21:54 -07003353
Mona Hossainc92629e2013-04-01 13:37:46 -07003354 qseecom.ce_drv.ce_core_clk = NULL;
3355 qseecom.ce_drv.ce_clk = NULL;
3356 qseecom.ce_drv.ce_core_src_clk = NULL;
3357 qseecom.ce_drv.ce_bus_clk = NULL;
3358
Mona Hossain2892b6b2012-02-17 13:53:11 -08003359 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
3360 if (rc < 0) {
3361 pr_err("alloc_chrdev_region failed %d\n", rc);
3362 return rc;
3363 }
3364
3365 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
3366 if (IS_ERR(driver_class)) {
3367 rc = -ENOMEM;
3368 pr_err("class_create failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303369 goto exit_unreg_chrdev_region;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003370 }
3371
3372 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
3373 QSEECOM_DEV);
3374 if (!class_dev) {
3375 pr_err("class_device_create failed %d\n", rc);
3376 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303377 goto exit_destroy_class;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003378 }
3379
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303380 cdev_init(&qseecom.cdev, &qseecom_fops);
3381 qseecom.cdev.owner = THIS_MODULE;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003382
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303383 rc = cdev_add(&qseecom.cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003384 if (rc < 0) {
3385 pr_err("cdev_add failed %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303386 goto exit_destroy_device;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003387 }
3388
3389 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
3390 spin_lock_init(&qseecom.registered_listener_list_lock);
3391 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
3392 spin_lock_init(&qseecom.registered_app_list_lock);
Mona Hossaind44a3842012-10-15 09:41:35 -07003393 INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
3394 spin_lock_init(&qseecom.registered_kclient_list_lock);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003395 init_waitqueue_head(&qseecom.send_resp_wq);
3396 qseecom.send_resp_flag = 0;
3397
3398 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
3399 &qsee_not_legacy, sizeof(qsee_not_legacy));
3400 if (rc) {
Mona Hossain05c73562012-10-29 17:49:01 -07003401 pr_err("Failed to retrieve QSEOS version information %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303402 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003403 }
Mona Hossain05c73562012-10-29 17:49:01 -07003404 if (qsee_not_legacy) {
3405 uint32_t feature = 10;
3406
3407 qseecom.qsee_version = QSEEE_VERSION_00;
3408 rc = scm_call(6, 3, &feature, sizeof(feature),
3409 &qseecom.qsee_version, sizeof(qseecom.qsee_version));
3410 if (rc) {
3411 pr_err("Failed to get QSEE version info %d\n", rc);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303412 goto exit_del_cdev;
Mona Hossain05c73562012-10-29 17:49:01 -07003413 }
Mona Hossain2892b6b2012-02-17 13:53:11 -08003414 qseecom.qseos_version = QSEOS_VERSION_14;
Mona Hossain05c73562012-10-29 17:49:01 -07003415 } else {
Mona Hossain9c1f6c52013-05-19 21:27:26 -07003416 pr_err("QSEE legacy version is not supported:");
3417 pr_err("Support for TZ1.3 and earlier is deprecated\n");
3418 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303419 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003420 }
Mona Hossain05c73562012-10-29 17:49:01 -07003421 qseecom.commonlib_loaded = false;
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003422 qseecom.pdev = class_dev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003423 /* Create ION msm client */
Mona Hossaind44a3842012-10-15 09:41:35 -07003424 qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
Mona Hossain2892b6b2012-02-17 13:53:11 -08003425 if (qseecom.ion_clnt == NULL) {
3426 pr_err("Ion client cannot be created\n");
3427 rc = -ENOMEM;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303428 goto exit_del_cdev;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003429 }
3430
3431 /* register client for bus scaling */
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003432 if (pdev->dev.of_node) {
Mona Hossainc92629e2013-04-01 13:37:46 -07003433
Mona Hossain4cf78a92013-02-14 12:06:41 -08003434 if (of_property_read_u32((&pdev->dev)->of_node,
3435 "qcom,disk-encrypt-pipe-pair",
3436 &qseecom.ce_info.disk_encrypt_pipe)) {
3437 pr_err("Fail to get disk-encrypt pipe pair information.\n");
3438 qseecom.ce_info.disk_encrypt_pipe = 0xff;
3439 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303440 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003441 } else {
3442 pr_warn("bam_pipe_pair=0x%x",
3443 qseecom.ce_info.disk_encrypt_pipe);
3444 }
3445
3446 if (of_property_read_u32((&pdev->dev)->of_node,
3447 "qcom,qsee-ce-hw-instance",
3448 &qseecom.ce_info.qsee_ce_hw_instance)) {
3449 pr_err("Fail to get qsee ce hw instance information.\n");
3450 qseecom.ce_info.qsee_ce_hw_instance = 0xff;
3451 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303452 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003453 } else {
3454 pr_warn("qsee-ce-hw-instance=0x%x",
3455 qseecom.ce_info.qsee_ce_hw_instance);
3456 }
3457
3458 if (of_property_read_u32((&pdev->dev)->of_node,
3459 "qcom,hlos-ce-hw-instance",
3460 &qseecom.ce_info.hlos_ce_hw_instance)) {
3461 pr_err("Fail to get hlos ce hw instance information.\n");
3462 qseecom.ce_info.hlos_ce_hw_instance = 0xff;
3463 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303464 goto exit_destroy_ion_client;
Mona Hossain4cf78a92013-02-14 12:06:41 -08003465 } else {
3466 pr_warn("hlos-ce-hw-instance=0x%x",
3467 qseecom.ce_info.hlos_ce_hw_instance);
3468 }
3469
Mona Hossainc92629e2013-04-01 13:37:46 -07003470 qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
3471 qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
3472
3473 ret = __qseecom_init_clk(CLK_QSEE);
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003474 if (ret)
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303475 goto exit_destroy_ion_client;
Mona Hossain6311d572013-03-01 15:54:02 -08003476
Mona Hossainc92629e2013-04-01 13:37:46 -07003477 if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
3478 ret = __qseecom_init_clk(CLK_CE_DRV);
3479 if (ret) {
3480 __qseecom_deinit_clk(CLK_QSEE);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303481 goto exit_destroy_ion_client;
Mona Hossainc92629e2013-04-01 13:37:46 -07003482 }
3483 } else {
3484 struct qseecom_clk *qclk;
3485
3486 qclk = &qseecom.qsee;
3487 qseecom.ce_drv.ce_core_clk = qclk->ce_core_clk;
3488 qseecom.ce_drv.ce_clk = qclk->ce_clk;
3489 qseecom.ce_drv.ce_core_src_clk = qclk->ce_core_src_clk;
3490 qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk;
3491 }
3492
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003493 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3494 msm_bus_cl_get_pdata(pdev);
Mona Hossain5b76a622012-11-15 20:09:08 -08003495 if (qseecom.qsee_version >= (QSEE_VERSION_02)) {
3496 struct resource *resource = NULL;
3497 struct qsee_apps_region_info_ireq req;
3498 struct qseecom_command_scm_resp resp;
3499
3500 resource = platform_get_resource_byname(pdev,
3501 IORESOURCE_MEM, "secapp-region");
3502 if (resource) {
3503 req.qsee_cmd_id = QSEOS_APP_REGION_NOTIFICATION;
3504 req.addr = resource->start;
3505 req.size = resource_size(resource);
3506 pr_warn("secure app region addr=0x%x size=0x%x",
3507 req.addr, req.size);
3508 } else {
3509 pr_err("Fail to get secure app region info\n");
3510 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303511 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003512 }
3513 rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
3514 &resp, sizeof(resp));
Mona Hossain32deb982013-08-06 16:25:44 -07003515 if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
3516 pr_err("send secapp reg fail %d resp.res %d\n",
3517 rc, resp.result);
3518 rc = -EINVAL;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303519 goto exit_destroy_ion_client;
Mona Hossain5b76a622012-11-15 20:09:08 -08003520 }
3521 }
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003522 } else {
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003523 qseecom_platform_support = (struct msm_bus_scale_pdata *)
3524 pdev->dev.platform_data;
Mona Hossain2892b6b2012-02-17 13:53:11 -08003525 }
Ramesh Masavarapua1bc0e42012-03-05 07:42:48 -08003526
Mona Hossain17a4faf2013-03-22 16:40:56 -07003527 qseecom.qsee_perf_client = msm_bus_scale_register_client(
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003528 qseecom_platform_support);
3529
Mona Hossain17a4faf2013-03-22 16:40:56 -07003530 if (!qseecom.qsee_perf_client)
Ramesh Masavarapuff377032012-09-14 12:11:32 -07003531 pr_err("Unable to register bus client\n");
3532 return 0;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303533
3534exit_destroy_ion_client:
3535 ion_client_destroy(qseecom.ion_clnt);
3536exit_del_cdev:
3537 cdev_del(&qseecom.cdev);
3538exit_destroy_device:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003539 device_destroy(driver_class, qseecom_device_no);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303540exit_destroy_class:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003541 class_destroy(driver_class);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303542exit_unreg_chrdev_region:
Mona Hossain2892b6b2012-02-17 13:53:11 -08003543 unregister_chrdev_region(qseecom_device_no, 1);
3544 return rc;
3545}
3546
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003547static int __devinit qseecom_remove(struct platform_device *pdev)
3548{
Mona Hossaind44a3842012-10-15 09:41:35 -07003549 struct qseecom_registered_kclient_list *kclient = NULL;
3550 unsigned long flags = 0;
3551 int ret = 0;
3552
Mona Hossaind44a3842012-10-15 09:41:35 -07003553 spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303554
Mona Hossaind44a3842012-10-15 09:41:35 -07003555 list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303556 list) {
3557 if (!kclient)
3558 goto exit_irqrestore;
Mona Hossaind44a3842012-10-15 09:41:35 -07003559
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303560 /* Break the loop if client handle is NULL */
3561 if (!kclient->handle)
3562 goto exit_free_kclient;
Mona Hossaind44a3842012-10-15 09:41:35 -07003563
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303564 if (list_empty(&kclient->list))
3565 goto exit_free_kc_handle;
3566
3567 list_del(&kclient->list);
Mona Hossaind44a3842012-10-15 09:41:35 -07003568 ret = qseecom_unload_app(kclient->handle->dev);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303569 if (!ret) {
Mona Hossaind44a3842012-10-15 09:41:35 -07003570 kzfree(kclient->handle->dev);
3571 kzfree(kclient->handle);
3572 kzfree(kclient);
3573 }
Mona Hossaind44a3842012-10-15 09:41:35 -07003574 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303575
3576exit_free_kc_handle:
3577 kzfree(kclient->handle);
3578exit_free_kclient:
3579 kzfree(kclient);
3580exit_irqrestore:
3581 spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
3582
3583 if (qseecom.qseos_version > QSEEE_VERSION_00)
Mona Hossain05c73562012-10-29 17:49:01 -07003584 qseecom_unload_commonlib_image();
Mona Hossaind39e33b2012-11-05 13:36:40 -08003585
Mona Hossain17a4faf2013-03-22 16:40:56 -07003586 if (qseecom.qsee_perf_client)
3587 msm_bus_scale_client_update_request(qseecom.qsee_perf_client,
3588 0);
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303589 if (pdev->dev.platform_data != NULL)
3590 msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
3591
Mona Hossaind39e33b2012-11-05 13:36:40 -08003592 /* register client for bus scaling */
Mona Hossainc92629e2013-04-01 13:37:46 -07003593 if (pdev->dev.of_node) {
3594 __qseecom_deinit_clk(CLK_QSEE);
3595 if (qseecom.qsee.instance != qseecom.ce_drv.instance)
3596 __qseecom_deinit_clk(CLK_CE_DRV);
3597 }
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303598
3599 ion_client_destroy(qseecom.ion_clnt);
3600
3601 cdev_del(&qseecom.cdev);
3602
3603 device_destroy(driver_class, qseecom_device_no);
3604
3605 class_destroy(driver_class);
3606
3607 unregister_chrdev_region(qseecom_device_no, 1);
3608
Mona Hossaind44a3842012-10-15 09:41:35 -07003609 return ret;
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303610}
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003611
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003612static struct of_device_id qseecom_match[] = {
3613 {
3614 .compatible = "qcom,qseecom",
3615 },
3616 {}
3617};
3618
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003619static struct platform_driver qseecom_plat_driver = {
3620 .probe = qseecom_probe,
3621 .remove = qseecom_remove,
3622 .driver = {
3623 .name = "qseecom",
3624 .owner = THIS_MODULE,
Ramesh Masavarapufb1f01e2012-06-14 09:40:40 -07003625 .of_match_table = qseecom_match,
Ramesh Masavarapua26cce72012-04-09 12:32:25 -07003626 },
3627};
3628
3629static int __devinit qseecom_init(void)
3630{
3631 return platform_driver_register(&qseecom_plat_driver);
3632}
3633
3634static void __devexit qseecom_exit(void)
Mona Hossain2892b6b2012-02-17 13:53:11 -08003635{
AnilKumar Chimataa253a032013-10-04 18:53:42 +05303636 platform_driver_unregister(&qseecom_plat_driver);
Mona Hossain2892b6b2012-02-17 13:53:11 -08003637}
3638
3639MODULE_LICENSE("GPL v2");
3640MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
3641
3642module_init(qseecom_init);
3643module_exit(qseecom_exit);