blob: e4c31527176f3114f5a48764cfc26ddd1c0ee3c9 [file] [log] [blame]
Mona Hossain2892b6b2012-02-17 13:53:11 -08001/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
2 *
3 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
4 *
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>
29#include <linux/ion.h>
30#include <linux/types.h>
31#include <linux/clk.h>
32#include <linux/qseecom.h>
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#include <mach/scm.h>
36#include <mach/peripheral-loader.h>
37#include "qseecom_legacy.h"
38
39#define QSEECOM_DEV "qseecom"
40#define QSEOS_VERSION_13 0x13
41#define QSEOS_VERSION_14 0x14
42#define QSEOS_CHECK_VERSION_CMD 0x00001803;
43
44enum qseecom_command_scm_resp_type {
45 QSEOS_APP_ID = 0xEE01,
46 QSEOS_LISTENER_ID
47};
48
49enum qseecom_qceos_cmd_id {
50 QSEOS_APP_START_COMMAND = 0x01,
51 QSEOS_APP_SHUTDOWN_COMMAND,
52 QSEOS_APP_LOOKUP_COMMAND,
53 QSEOS_REGISTER_LISTENER,
54 QSEOS_DEREGISTER_LISTENER,
55 QSEOS_CLIENT_SEND_DATA_COMMAND,
56 QSEOS_LISTENER_DATA_RSP_COMMAND,
57 QSEOS_CMD_MAX = 0xEFFFFFFF
58};
59
60enum qseecom_qceos_cmd_status {
61 QSEOS_RESULT_SUCCESS = 0,
62 QSEOS_RESULT_INCOMPLETE,
63 QSEOS_RESULT_FAILURE = 0xFFFFFFFF
64};
65
66__packed struct qseecom_check_app_ireq {
67 uint32_t qsee_cmd_id;
68 char app_name[MAX_APP_NAME_SIZE];
69};
70
71__packed struct qseecom_load_app_ireq {
72 uint32_t qsee_cmd_id;
73 uint32_t mdt_len; /* Length of the mdt file */
74 uint32_t img_len; /* Length of .bxx and .mdt files */
75 uint32_t phy_addr; /* phy addr of the start of image */
76 char app_name[MAX_APP_NAME_SIZE]; /* application name*/
77};
78
79__packed struct qseecom_unload_app_ireq {
80 uint32_t qsee_cmd_id;
81 uint32_t app_id;
82};
83
84__packed struct qseecom_register_listener_ireq {
85 uint32_t qsee_cmd_id;
86 uint32_t listener_id;
87 void *sb_ptr;
88 uint32_t sb_len;
89};
90
91__packed struct qseecom_unregister_listener_ireq {
92 uint32_t qsee_cmd_id;
93 uint32_t listener_id;
94};
95
96__packed struct qseecom_client_send_data_ireq {
97 uint32_t qsee_cmd_id;
98 uint32_t app_id;
99 void *req_ptr;
100 uint32_t req_len;
101 void *rsp_ptr; /* First 4 bytes should always be the return status */
102 uint32_t rsp_len;
103};
104
105/* send_data resp */
106__packed struct qseecom_client_listener_data_irsp {
107 uint32_t qsee_cmd_id;
108 uint32_t listener_id;
109};
110
111/*
112 * struct qseecom_command_scm_resp - qseecom response buffer
113 * @cmd_status: value from enum tz_sched_cmd_status
114 * @sb_in_rsp_addr: points to physical location of response
115 * buffer
116 * @sb_in_rsp_len: length of command response
117 */
118__packed struct qseecom_command_scm_resp {
119 uint32_t result;
120 enum qseecom_command_scm_resp_type resp_type;
121 unsigned int data;
122};
123
124static struct class *driver_class;
125static dev_t qseecom_device_no;
126static struct cdev qseecom_cdev;
127
128/* Data structures used in legacy support */
129static void *pil;
130static uint32_t pil_ref_cnt;
131static DEFINE_MUTEX(pil_access_lock);
132
133static DEFINE_MUTEX(send_msg_lock);
134static DEFINE_MUTEX(qsee_bw_mutex);
135static DEFINE_MUTEX(app_access_lock);
136
137static int qsee_bw_count;
138static struct clk *qseecom_bus_clk;
139static uint32_t qsee_perf_client;
140
141struct qseecom_registered_listener_list {
142 struct list_head list;
143 struct qseecom_register_listener_req svc;
144 u8 *sb_reg_req;
145 u8 *sb_virt;
146 s32 sb_phys;
147 size_t sb_length;
148 struct ion_handle *ihandle; /* Retrieve phy addr */
149
150 wait_queue_head_t rcv_req_wq;
151 int rcv_req_flag;
152};
153
154struct qseecom_registered_app_list {
155 struct list_head list;
156 u32 app_id;
157 u32 ref_cnt;
158};
159
160struct qseecom_control {
161 struct ion_client *ion_clnt; /* Ion client */
162 struct list_head registered_listener_list_head;
163 spinlock_t registered_listener_list_lock;
164
165 struct list_head registered_app_list_head;
166 spinlock_t registered_app_list_lock;
167
168 wait_queue_head_t send_resp_wq;
169 int send_resp_flag;
170
171 uint32_t qseos_version;
172};
173
174struct qseecom_client_handle {
175 u32 app_id;
176 u8 *sb_virt;
177 s32 sb_phys;
178 uint32_t user_virt_sb_base;
179 size_t sb_length;
180 struct ion_handle *ihandle; /* Retrieve phy addr */
181};
182
183struct qseecom_listener_handle {
184 u32 id;
185};
186
187static struct qseecom_control qseecom;
188
189struct qseecom_dev_handle {
190 bool service;
191 union {
192 struct qseecom_client_handle client;
193 struct qseecom_listener_handle listener;
194 };
195 bool released;
196 int abort;
197 wait_queue_head_t abort_wq;
198 atomic_t ioctl_count;
199};
200
201static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
202 struct qseecom_register_listener_req svc)
203{
204 struct qseecom_registered_listener_list *ptr;
205 int unique = 1;
206 unsigned long flags;
207
208 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
209 list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
210 if (ptr->svc.listener_id == svc.listener_id) {
211 pr_err("Service id: %u is already registered\n",
212 ptr->svc.listener_id);
213 unique = 0;
214 break;
215 }
216 }
217 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
218 return unique;
219}
220
221static struct qseecom_registered_listener_list *__qseecom_find_svc(
222 int32_t listener_id)
223{
224 struct qseecom_registered_listener_list *entry = NULL;
225 unsigned long flags;
226
227 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
228 list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
229 {
230 if (entry->svc.listener_id == listener_id)
231 break;
232 }
233 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
234 return entry;
235}
236
237static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
238 struct qseecom_dev_handle *handle,
239 struct qseecom_register_listener_req *listener)
240{
241 int ret = 0;
242 unsigned int flags = 0;
243 struct qseecom_register_listener_ireq req;
244 struct qseecom_command_scm_resp resp;
245 ion_phys_addr_t pa;
246
247 /* Get the handle of the shared fd */
248 svc->ihandle = ion_import_fd(qseecom.ion_clnt, listener->ifd_data_fd);
249 if (svc->ihandle == NULL) {
250 pr_err("Ion client could not retrieve the handle\n");
251 return -ENOMEM;
252 }
253
254 /* Get the physical address of the ION BUF */
255 ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
256
257 /* Populate the structure for sending scm call to load image */
258 svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
259 svc->ihandle, flags);
260 svc->sb_phys = pa;
261
262 if (qseecom.qseos_version == QSEOS_VERSION_14) {
263 req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
264 req.listener_id = svc->svc.listener_id;
265 req.sb_len = svc->sb_length;
266 req.sb_ptr = (void *)svc->sb_phys;
267
268 resp.result = QSEOS_RESULT_INCOMPLETE;
269
270 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
271 sizeof(req), &resp, sizeof(resp));
272 if (ret) {
273 pr_err("qseecom_scm_call failed with err: %d\n", ret);
274 return -EINVAL;
275 }
276
277 if (resp.result != QSEOS_RESULT_SUCCESS) {
278 pr_err("Error SB registration req: resp.result = %d\n",
279 resp.result);
280 return -EPERM;
281 }
282 } else {
283 struct qseecom_command cmd;
284 struct qseecom_response resp;
285 struct qse_pr_init_sb_req_s sb_init_req;
286 struct qse_pr_init_sb_rsp_s sb_init_rsp;
287
288 svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
289 sizeof(sb_init_rsp)), GFP_KERNEL);
290
291 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
292 sb_init_req.listener_id = svc->svc.listener_id;
293 sb_init_req.sb_len = svc->sb_length;
294 sb_init_req.sb_ptr = svc->sb_phys;
295
296 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
297
298 /* It will always be a new cmd from this method */
299 cmd.cmd_type = TZ_SCHED_CMD_NEW;
300 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
301 cmd.sb_in_cmd_len = sizeof(sb_init_req);
302
303 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
304
305 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
306 , &resp, sizeof(resp));
307
308 if (ret) {
309 pr_err("qseecom_scm_call failed with err: %d\n", ret);
310 return -EINVAL;
311 }
312
313 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
314 pr_err("SB registration fail resp.cmd_status %d\n",
315 resp.cmd_status);
316 return -EINVAL;
317 }
318 memset(svc->sb_virt, 0, svc->sb_length);
319 }
320 return 0;
321}
322
323static int qseecom_register_listener(struct qseecom_dev_handle *data,
324 void __user *argp)
325{
326 int ret = 0;
327 unsigned long flags;
328 struct qseecom_register_listener_req rcvd_lstnr;
329 struct qseecom_registered_listener_list *new_entry;
330
331 ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
332 if (ret) {
333 pr_err("copy_from_user failed\n");
334 return ret;
335 }
336
337 if (!__qseecom_is_svc_unique(data, rcvd_lstnr)) {
338 pr_err("Service is not unique and is already registered\n");
339 return ret;
340 }
341
342 ret = copy_to_user(argp, &rcvd_lstnr, sizeof(rcvd_lstnr));
343 if (ret) {
344 pr_err("copy_to_user failed\n");
345 return ret;
346 }
347
348 new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
349 if (!new_entry) {
350 pr_err("kmalloc failed\n");
351 return -ENOMEM;
352 }
353 memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
354 new_entry->rcv_req_flag = 0;
355
356 new_entry->svc.listener_id = rcvd_lstnr.listener_id;
357 new_entry->sb_length = rcvd_lstnr.sb_size;
358 if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
359 pr_err("qseecom_set_sb_memoryfailed\n");
360 kzfree(new_entry);
361 return -ENOMEM;
362 }
363 data->listener.id = rcvd_lstnr.listener_id;
364 data->service = true;
365 init_waitqueue_head(&new_entry->rcv_req_wq);
366
367 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
368 list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
369 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
370 return ret;
371}
372
373static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
374{
375 int ret = 0;
376 unsigned long flags;
377 uint32_t unmap_mem = 0;
378 struct qseecom_register_listener_ireq req;
379 struct qseecom_registered_listener_list *ptr_svc = NULL;
380 struct qseecom_command_scm_resp resp;
381 struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
382
383 if (qseecom.qseos_version == QSEOS_VERSION_14) {
384 req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
385 req.listener_id = data->listener.id;
386 resp.result = QSEOS_RESULT_INCOMPLETE;
387
388 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
389 sizeof(req), &resp, sizeof(resp));
390 if (ret) {
391 pr_err("qseecom_scm_call failed with err: %d\n", ret);
392 return ret;
393 }
394
395 if (resp.result != QSEOS_RESULT_SUCCESS) {
396 pr_err("SB deregistartion: result=%d\n", resp.result);
397 return -EPERM;
398 }
399 } else {
400 struct qse_pr_init_sb_req_s sb_init_req;
401 struct qseecom_command cmd;
402 struct qseecom_response resp;
403 struct qseecom_registered_listener_list *svc;
404
405 svc = __qseecom_find_svc(data->listener.id);
406 sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
407 sb_init_req.listener_id = data->listener.id;
408 sb_init_req.sb_len = 0;
409 sb_init_req.sb_ptr = 0;
410
411 memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
412
413 /* It will always be a new cmd from this method */
414 cmd.cmd_type = TZ_SCHED_CMD_NEW;
415 cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
416 cmd.sb_in_cmd_len = sizeof(sb_init_req);
417 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
418
419 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
420 &resp, sizeof(resp));
421 if (ret) {
422 pr_err("qseecom_scm_call failed with err: %d\n", ret);
423 return ret;
424 }
425 kzfree(svc->sb_reg_req);
426 if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
427 pr_err("Error with SB initialization\n");
428 return -EPERM;
429 }
430 }
431 data->abort = 1;
432 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
433 list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
434 list) {
435 if (ptr_svc->svc.listener_id == data->listener.id) {
436 wake_up_all(&ptr_svc->rcv_req_wq);
437 break;
438 }
439 }
440 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
441
442 while (atomic_read(&data->ioctl_count) > 1) {
443 if (wait_event_interruptible(data->abort_wq,
444 atomic_read(&data->ioctl_count) <= 1)) {
445 pr_err("Interrupted from abort\n");
446 ret = -ERESTARTSYS;
447 break;
448 }
449 }
450
451 spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
452 list_for_each_entry(ptr_svc,
453 &qseecom.registered_listener_list_head,
454 list)
455 {
456 if (ptr_svc->svc.listener_id == data->listener.id) {
457 if (ptr_svc->sb_virt) {
458 unmap_mem = 1;
459 ihandle = ptr_svc->ihandle;
460 }
461 list_del(&ptr_svc->list);
462 kzfree(ptr_svc);
463 break;
464 }
465 }
466 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
467
468 /* Unmap the memory */
469 if (unmap_mem) {
470 if (!IS_ERR_OR_NULL(ihandle)) {
471 ion_unmap_kernel(qseecom.ion_clnt, ihandle);
472 ion_free(qseecom.ion_clnt, ihandle);
473 }
474 }
475 data->released = true;
476 return ret;
477}
478
479static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
480 void __user *argp)
481{
482 ion_phys_addr_t pa;
483 int32_t ret;
484 unsigned int flags = 0;
485 struct qseecom_set_sb_mem_param_req req;
486 uint32_t len;
487
488 /* Copy the relevant information needed for loading the image */
489 if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
490 return -EFAULT;
491
492 if (qseecom.qseos_version == QSEOS_VERSION_13) {
493 long pil_error;
494 mutex_lock(&pil_access_lock);
495 if (pil_ref_cnt == 0) {
496 pil = pil_get("tzapps");
497 if (IS_ERR(pil)) {
498 pr_err("Playready PIL image load failed\n");
499 pil_error = PTR_ERR(pil);
500 pil = NULL;
501 pr_debug("tzapps image load FAILED\n");
502 mutex_unlock(&pil_access_lock);
503 return pil_error;
504 }
505 }
506 pil_ref_cnt++;
507 mutex_unlock(&pil_access_lock);
508 }
509 /* Get the handle of the shared fd */
510 data->client.ihandle = ion_import_fd(qseecom.ion_clnt, req.ifd_data_fd);
511 if (IS_ERR_OR_NULL(data->client.ihandle)) {
512 pr_err("Ion client could not retrieve the handle\n");
513 return -ENOMEM;
514 }
515 /* Get the physical address of the ION BUF */
516 ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
517 /* Populate the structure for sending scm call to load image */
518 data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
519 data->client.ihandle,
520 flags);
521 data->client.sb_phys = pa;
522 data->client.sb_length = req.sb_len;
523 data->client.user_virt_sb_base = req.virt_sb_base;
524 return 0;
525}
526
527
528static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
529{
530 int ret;
531 ret = (qseecom.send_resp_flag != 0);
532 return ret || data->abort;
533}
534
535static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
536 struct qseecom_command_scm_resp *resp)
537{
538 int ret = 0;
539 uint32_t lstnr;
540 unsigned long flags;
541 struct qseecom_client_listener_data_irsp send_data_rsp;
542 struct qseecom_registered_listener_list *ptr_svc = NULL;
543
544
545 while (resp->result == QSEOS_RESULT_INCOMPLETE) {
546 lstnr = resp->data;
547 /*
548 * Wake up blocking lsitener service with the lstnr id
549 */
550 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
551 flags);
552 list_for_each_entry(ptr_svc,
553 &qseecom.registered_listener_list_head, list) {
554 if (ptr_svc->svc.listener_id == lstnr) {
555 ptr_svc->rcv_req_flag = 1;
556 wake_up_interruptible(&ptr_svc->rcv_req_wq);
557 break;
558 }
559 }
560 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
561 flags);
562 if (ptr_svc->svc.listener_id != lstnr) {
563 pr_warning("Service requested for does on exist\n");
564 return -ERESTARTSYS;
565 }
566 pr_debug("waking up rcv_req_wq and "
567 "waiting for send_resp_wq\n");
568 if (wait_event_interruptible(qseecom.send_resp_wq,
569 __qseecom_listener_has_sent_rsp(data))) {
570 pr_warning("Interrupted: exiting send_cmd loop\n");
571 return -ERESTARTSYS;
572 }
573
574 if (data->abort) {
575 pr_err("Aborting driver\n");
576 return -ENODEV;
577 }
578 qseecom.send_resp_flag = 0;
579 send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
580 send_data_rsp.listener_id = lstnr ;
581
582 ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
583 (const void *)&send_data_rsp,
584 sizeof(send_data_rsp), resp,
585 sizeof(*resp));
586 if (ret) {
587 pr_err("qseecom_scm_call failed with err: %d\n", ret);
588 return ret;
589 }
590 }
591 return ret;
592}
593
594static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
595{
596 struct qseecom_registered_app_list *entry = NULL;
597 unsigned long flags = 0;
598 u32 app_id = 0;
599 struct ion_handle *ihandle; /* Ion handle */
600 struct qseecom_load_img_req load_img_req;
601 int32_t ret;
602 ion_phys_addr_t pa = 0;
603 uint32_t len;
604 struct qseecom_command_scm_resp resp;
605 struct qseecom_check_app_ireq req;
606 /* Copy the relevant information needed for loading the image */
607 if (__copy_from_user(&load_img_req,
608 (void __user *)argp,
609 sizeof(struct qseecom_load_img_req))) {
610 pr_err("copy_from_user failed\n");
611 return -EFAULT;
612 }
613
614 req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
615 memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
616
617 /* SCM_CALL to check if app_id for the mentioned app exists */
618 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
619 sizeof(struct qseecom_check_app_ireq),
620 &resp, sizeof(resp));
621
622 if (resp.result == QSEOS_RESULT_FAILURE)
623 app_id = 0;
624 else
625 app_id = resp.data;
626
627 if (app_id) {
628 pr_warn("App id already exists\n");
629 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
630 list_for_each_entry(entry,
631 &qseecom.registered_app_list_head, list){
632 if (entry->app_id == app_id) {
633 entry->ref_cnt++;
634 break;
635 }
636 }
637 spin_unlock_irqrestore(
638 &qseecom.registered_app_list_lock, flags);
639 } else {
640 struct qseecom_load_app_ireq load_req;
641
642 pr_warn("App id does not exist\n");
643 /* Get the handle of the shared fd */
644 ihandle = ion_import_fd(qseecom.ion_clnt,
645 load_img_req.ifd_data_fd);
646 if (IS_ERR_OR_NULL(ihandle)) {
647 pr_err("Ion client could not retrieve the handle\n");
648 return -ENOMEM;
649 }
650
651 /* Get the physical address of the ION BUF */
652 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
653
654 /* Populate the structure for sending scm call to load image */
655 load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
656 load_req.mdt_len = load_img_req.mdt_len;
657 load_req.img_len = load_img_req.img_len;
658 load_req.phy_addr = pa;
659
660 /* SCM_CALL to load the app and get the app_id back */
661 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
662 sizeof(struct qseecom_load_app_ireq),
663 &resp, sizeof(resp));
664
665 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
666 ret = __qseecom_process_incomplete_cmd(data, &resp);
667 if (ret) {
668 pr_err("process_incomplete_cmd failed err: %d\n",
669 ret);
670 if (!IS_ERR_OR_NULL(ihandle))
671 ion_free(qseecom.ion_clnt, ihandle);
672 return ret;
673 }
674 }
675 if (resp.result != QSEOS_RESULT_SUCCESS) {
676 pr_err("scm_call failed resp.result != QSEOS_RESULT_SUCCESS\n");
677 if (!IS_ERR_OR_NULL(ihandle))
678 ion_free(qseecom.ion_clnt, ihandle);
679 return -EFAULT;
680 }
681
682 app_id = resp.data;
683
684 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
685 if (!entry) {
686 pr_err("kmalloc failed\n");
687 return -ENOMEM;
688 }
689 entry->app_id = app_id;
690 entry->ref_cnt = 1;
691
692 /* Deallocate the handle */
693 if (!IS_ERR_OR_NULL(ihandle))
694 ion_free(qseecom.ion_clnt, ihandle);
695
696 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
697 list_add_tail(&entry->list, &qseecom.registered_app_list_head);
698 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
699 flags);
700 }
701 data->client.app_id = app_id;
702 load_img_req.app_id = app_id;
703 if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
704 pr_err("copy_to_user failed\n");
705 kzfree(entry);
706 return -EFAULT;
707 }
708 return 0;
709}
710
711static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
712{
713 wake_up_all(&qseecom.send_resp_wq);
714 while (atomic_read(&data->ioctl_count) > 1) {
715 if (wait_event_interruptible(data->abort_wq,
716 atomic_read(&data->ioctl_count) <= 1)) {
717 pr_err("Interrupted from abort\n");
718 return -ERESTARTSYS;
719 break;
720 }
721 }
722 /* Set unload app */
723 return 1;
724}
725
726static int qseecom_unload_app(struct qseecom_dev_handle *data)
727{
728 unsigned long flags;
729 int ret = 0;
730 struct qseecom_command_scm_resp resp;
731 struct qseecom_registered_app_list *ptr_app;
732 uint32_t unload = 0;
733
734 if (qseecom.qseos_version == QSEOS_VERSION_14) {
735 spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
736 list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
737 list) {
738 if (ptr_app->app_id == data->client.app_id) {
739 if (ptr_app->ref_cnt == 1) {
740 unload = __qseecom_cleanup_app(data);
741 list_del(&ptr_app->list);
742 kzfree(ptr_app);
743 break;
744 } else {
745 ptr_app->ref_cnt--;
746 break;
747 }
748 }
749 }
750 spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
751 flags);
752 }
753 if (!IS_ERR_OR_NULL(data->client.ihandle)) {
754 ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
755 ion_free(qseecom.ion_clnt, data->client.ihandle);
756 }
757
758 if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
759 struct qseecom_unload_app_ireq req;
760
761 /* Populate the structure for sending scm call to load image */
762 req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
763 req.app_id = data->client.app_id;
764
765 /* SCM_CALL to unload the app */
766 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
767 sizeof(struct qseecom_unload_app_ireq),
768 &resp, sizeof(resp));
769 if (ret) {
770 pr_err("Fail to unload APP\n");
771 return -EFAULT;
772 }
773 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
774 ret = __qseecom_process_incomplete_cmd(data, &resp);
775 if (ret) {
776 pr_err("process_incomplete_cmd fail err: %d\n",
777 ret);
778 return ret;
779 }
780 }
781 }
782
783 if (qseecom.qseos_version == QSEOS_VERSION_13) {
784 data->abort = 1;
785 wake_up_all(&qseecom.send_resp_wq);
786 while (atomic_read(&data->ioctl_count) > 0) {
787 if (wait_event_interruptible(data->abort_wq,
788 atomic_read(&data->ioctl_count) <= 0)) {
789 pr_err("Interrupted from abort\n");
790 ret = -ERESTARTSYS;
791 break;
792 }
793 }
794 mutex_lock(&pil_access_lock);
795 if (pil_ref_cnt == 1)
796 pil_put(pil);
797 pil_ref_cnt--;
798 mutex_unlock(&pil_access_lock);
799 }
800 data->released = true;
801 return ret;
802}
803
804static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
805 uint32_t virt)
806{
807 return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
808}
809
810static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
811 struct qseecom_send_cmd_req *req)
812{
813 int ret = 0;
814 unsigned long flags;
815 u32 reqd_len_sb_in = 0;
816 struct qseecom_command cmd;
817 struct qseecom_response resp;
818
819
820 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
821 pr_err("cmd buffer or response buffer is null\n");
822 return -EINVAL;
823 }
824
825 if (req->cmd_req_len <= 0 ||
826 req->resp_len <= 0 ||
827 req->cmd_req_len > data->client.sb_length ||
828 req->resp_len > data->client.sb_length) {
829 pr_err("cmd buffer length or "
830 "response buffer length not valid\n");
831 return -EINVAL;
832 }
833
834 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
835 if (reqd_len_sb_in > data->client.sb_length) {
836 pr_debug("Not enough memory to fit cmd_buf and "
837 "resp_buf. Required: %u, Available: %u\n",
838 reqd_len_sb_in, data->client.sb_length);
839 return -ENOMEM;
840 }
841 cmd.cmd_type = TZ_SCHED_CMD_NEW;
842 cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
843 cmd.sb_in_cmd_len = req->cmd_req_len;
844
845 resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
846 resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
847 resp.sb_in_rsp_len = req->resp_len;
848
849 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
850 sizeof(cmd), &resp, sizeof(resp));
851
852 if (ret) {
853 pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
854 return ret;
855 }
856
857 while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
858 /*
859 * If cmd is incomplete, get the callback cmd out from SB out
860 * and put it on the list
861 */
862 struct qseecom_registered_listener_list *ptr_svc = NULL;
863 /*
864 * We don't know which service can handle the command. so we
865 * wake up all blocking services and let them figure out if
866 * they can handle the given command.
867 */
868 spin_lock_irqsave(&qseecom.registered_listener_list_lock,
869 flags);
870 list_for_each_entry(ptr_svc,
871 &qseecom.registered_listener_list_head, list) {
872 ptr_svc->rcv_req_flag = 1;
873 wake_up_interruptible(&ptr_svc->rcv_req_wq);
874 }
875 spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
876 flags);
877
878 pr_debug("waking up rcv_req_wq and "
879 "waiting for send_resp_wq\n");
880 if (wait_event_interruptible(qseecom.send_resp_wq,
881 __qseecom_listener_has_sent_rsp(data))) {
882 pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
883 return -ERESTARTSYS;
884 }
885
886 if (data->abort) {
887 pr_err("Aborting driver\n");
888 return -ENODEV;
889 }
890 qseecom.send_resp_flag = 0;
891 cmd.cmd_type = TZ_SCHED_CMD_PENDING;
892 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
893 sizeof(cmd), &resp, sizeof(resp));
894 if (ret) {
895 pr_err("qseecom_scm_call failed with err: %d\n", ret);
896 return ret;
897 }
898 }
899 return ret;
900}
901
902static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
903 struct qseecom_send_cmd_req *req)
904{
905 int ret = 0;
906 u32 reqd_len_sb_in = 0;
907 struct qseecom_client_send_data_ireq send_data_req;
908 struct qseecom_command_scm_resp resp;
909
910 if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
911 pr_err("cmd buffer or response buffer is null\n");
912 return -EINVAL;
913 }
914
915 if (req->cmd_req_len <= 0 ||
916 req->resp_len <= 0 ||
917 req->cmd_req_len > data->client.sb_length ||
918 req->resp_len > data->client.sb_length) {
919 pr_err("cmd buffer length or "
920 "response buffer length not valid\n");
921 return -EINVAL;
922 }
923
924 reqd_len_sb_in = req->cmd_req_len + req->resp_len;
925 if (reqd_len_sb_in > data->client.sb_length) {
926 pr_debug("Not enough memory to fit cmd_buf and "
927 "resp_buf. Required: %u, Available: %u\n",
928 reqd_len_sb_in, data->client.sb_length);
929 return -ENOMEM;
930 }
931
932 send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
933 send_data_req.app_id = data->client.app_id;
934 send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
935 (uint32_t)req->cmd_req_buf));
936 send_data_req.req_len = req->cmd_req_len;
937 send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
938 (uint32_t)req->resp_buf));
939 send_data_req.rsp_len = req->resp_len;
940
941 ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
942 sizeof(send_data_req),
943 &resp, sizeof(resp));
944 if (ret) {
945 pr_err("qseecom_scm_call failed with err: %d\n", ret);
946 return ret;
947 }
948
949 if (resp.result == QSEOS_RESULT_INCOMPLETE) {
950 ret = __qseecom_process_incomplete_cmd(data, &resp);
951 if (ret) {
952 pr_err("process_incomplete_cmd failed err: %d\n", ret);
953 return ret;
954 }
955 }
956 return ret;
957}
958
959
960static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
961{
962 int ret = 0;
963 struct qseecom_send_cmd_req req;
964
965 ret = copy_from_user(&req, argp, sizeof(req));
966 if (ret) {
967 pr_err("copy_from_user failed\n");
968 return ret;
969 }
970 if (qseecom.qseos_version == QSEOS_VERSION_14)
971 ret = __qseecom_send_cmd(data, &req);
972 else
973 ret = __qseecom_send_cmd_legacy(data, &req);
974 if (ret)
975 return ret;
976
977 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
978 req.resp_len, req.resp_buf);
979 return ret;
980}
981
982static int __qseecom_send_cmd_req_clean_up(
983 struct qseecom_send_modfd_cmd_req *req)
984{
985 char *field;
986 uint32_t *update;
987 int ret = 0;
988 int i = 0;
989
990 for (i = 0; i < MAX_ION_FD; i++) {
991 if (req->ifd_data[i].fd != 0) {
992 field = (char *)req->cmd_req_buf +
993 req->ifd_data[i].cmd_buf_offset;
994 update = (uint32_t *) field;
995 *update = 0;
996 }
997 }
998 return ret;
999}
1000
1001static int __qseecom_update_with_phy_addr(
1002 struct qseecom_send_modfd_cmd_req *req)
1003{
1004 struct ion_handle *ihandle;
1005 char *field;
1006 uint32_t *update;
1007 ion_phys_addr_t pa;
1008 int ret = 0;
1009 int i = 0;
1010 uint32_t length;
1011
1012 for (i = 0; i < MAX_ION_FD; i++) {
1013 if (req->ifd_data[i].fd != 0) {
1014 /* Get the handle of the shared fd */
1015 ihandle = ion_import_fd(qseecom.ion_clnt,
1016 req->ifd_data[i].fd);
1017 if (IS_ERR_OR_NULL(ihandle)) {
1018 pr_err("Ion client can't retrieve the handle\n");
1019 return -ENOMEM;
1020 }
1021 field = (char *) req->cmd_req_buf +
1022 req->ifd_data[i].cmd_buf_offset;
1023 update = (uint32_t *) field;
1024
1025 /* Populate the cmd data structure with the phys_addr */
1026 ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &length);
1027 if (ret)
1028 return -ENOMEM;
1029
1030 *update = (uint32_t)pa;
1031 /* Deallocate the handle */
1032 if (!IS_ERR_OR_NULL(ihandle))
1033 ion_free(qseecom.ion_clnt, ihandle);
1034 }
1035 }
1036 return ret;
1037}
1038
1039static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
1040 void __user *argp)
1041{
1042 int ret = 0;
1043 struct qseecom_send_modfd_cmd_req req;
1044 struct qseecom_send_cmd_req send_cmd_req;
1045
1046 ret = copy_from_user(&req, argp, sizeof(req));
1047 if (ret) {
1048 pr_err("copy_from_user failed\n");
1049 return ret;
1050 }
1051 send_cmd_req.cmd_req_buf = req.cmd_req_buf;
1052 send_cmd_req.cmd_req_len = req.cmd_req_len;
1053 send_cmd_req.resp_buf = req.resp_buf;
1054 send_cmd_req.resp_len = req.resp_len;
1055
1056 ret = __qseecom_update_with_phy_addr(&req);
1057 if (ret)
1058 return ret;
1059 if (qseecom.qseos_version == QSEOS_VERSION_14)
1060 ret = __qseecom_send_cmd(data, &send_cmd_req);
1061 else
1062 ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
1063 __qseecom_send_cmd_req_clean_up(&req);
1064
1065 if (ret)
1066 return ret;
1067
1068 pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
1069 req.resp_len, req.resp_buf);
1070 return ret;
1071}
1072
1073static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
1074 struct qseecom_registered_listener_list *svc)
1075{
1076 int ret;
1077 ret = (svc->rcv_req_flag != 0);
1078 return ret || data->abort;
1079}
1080
1081static int qseecom_receive_req(struct qseecom_dev_handle *data)
1082{
1083 int ret = 0;
1084 struct qseecom_registered_listener_list *this_lstnr;
1085
1086 this_lstnr = __qseecom_find_svc(data->listener.id);
1087 while (1) {
1088 if (wait_event_interruptible(this_lstnr->rcv_req_wq,
1089 __qseecom_listener_has_rcvd_req(data,
1090 this_lstnr))) {
1091 pr_warning("Interrupted: exiting wait_rcv_req loop\n");
1092 /* woken up for different reason */
1093 return -ERESTARTSYS;
1094 }
1095
1096 if (data->abort) {
1097 pr_err("Aborting driver!\n");
1098 return -ENODEV;
1099 }
1100 this_lstnr->rcv_req_flag = 0;
1101 if (qseecom.qseos_version == QSEOS_VERSION_13) {
1102 if (*((uint32_t *)this_lstnr->sb_virt) != 0)
1103 break;
1104 } else {
1105 break;
1106 }
1107 }
1108 return ret;
1109}
1110
1111static int qseecom_send_resp(void)
1112{
1113 qseecom.send_resp_flag = 1;
1114 wake_up_interruptible(&qseecom.send_resp_wq);
1115 return 0;
1116}
1117
1118static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
1119 void __user *argp)
1120{
1121 struct qseecom_qseos_version_req req;
1122
1123 if (copy_from_user(&req, argp, sizeof(req))) {
1124 pr_err("copy_from_user failed");
1125 return -EINVAL;
1126 }
1127 req.qseos_version = qseecom.qseos_version;
1128 if (copy_to_user(argp, &req, sizeof(req))) {
1129 pr_err("copy_to_user failed");
1130 return -EINVAL;
1131 }
1132 return 0;
1133}
1134
1135static int qsee_vote_for_clock(void)
1136{
1137 int ret = 0;
1138
1139 if (!qsee_perf_client)
1140 return -EINVAL;
1141
1142 mutex_lock(&qsee_bw_mutex);
1143 if (!qsee_bw_count) {
1144 ret = msm_bus_scale_client_update_request(
1145 qsee_perf_client, 1);
1146 if (ret) {
1147 pr_err("Bandwidth request failed (%d)\n", ret);
1148 } else {
1149 ret = clk_enable(qseecom_bus_clk);
1150 if (ret)
1151 pr_err("Clock enable failed\n");
1152 }
1153 }
1154 if (ret)
1155 msm_bus_scale_client_update_request(qsee_perf_client, 0);
1156 else
1157 qsee_bw_count++;
1158
1159 mutex_unlock(&qsee_bw_mutex);
1160 return ret;
1161}
1162
1163static void qsee_disable_clock_vote(void)
1164{
1165 if (!qsee_perf_client)
1166 return ;
1167
1168 mutex_lock(&qsee_bw_mutex);
1169 if (qsee_bw_count > 0) {
1170 if (qsee_bw_count-- == 1) {
1171 msm_bus_scale_client_update_request(qsee_perf_client,
1172 0);
1173 clk_disable(qseecom_bus_clk);
1174 }
1175 }
1176 mutex_unlock(&qsee_bw_mutex);
1177}
1178
1179
1180static long qseecom_ioctl(struct file *file, unsigned cmd,
1181 unsigned long arg)
1182{
1183 int ret = 0;
1184 struct qseecom_dev_handle *data = file->private_data;
1185 void __user *argp = (void __user *) arg;
1186
1187 if (data->abort) {
1188 pr_err("Aborting qseecom driver\n");
1189 return -ENODEV;
1190 }
1191
1192 switch (cmd) {
1193 case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
1194 pr_debug("ioctl register_listener_req()\n");
1195 atomic_inc(&data->ioctl_count);
1196 ret = qseecom_register_listener(data, argp);
1197 atomic_dec(&data->ioctl_count);
1198 wake_up_all(&data->abort_wq);
1199 if (ret)
1200 pr_err("failed qseecom_register_listener: %d\n", ret);
1201 break;
1202 }
1203 case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
1204 pr_debug("ioctl unregister_listener_req()\n");
1205 atomic_inc(&data->ioctl_count);
1206 ret = qseecom_unregister_listener(data);
1207 atomic_dec(&data->ioctl_count);
1208 wake_up_all(&data->abort_wq);
1209 if (ret)
1210 pr_err("failed qseecom_unregister_listener: %d\n", ret);
1211 break;
1212 }
1213 case QSEECOM_IOCTL_SEND_CMD_REQ: {
1214 /* Only one client allowed here at a time */
1215 mutex_lock(&send_msg_lock);
1216 atomic_inc(&data->ioctl_count);
1217 ret = qseecom_send_cmd(data, argp);
1218 atomic_dec(&data->ioctl_count);
1219 wake_up_all(&data->abort_wq);
1220 mutex_unlock(&send_msg_lock);
1221 if (ret)
1222 pr_err("failed qseecom_send_cmd: %d\n", ret);
1223 break;
1224 }
1225 case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
1226 /* Only one client allowed here at a time */
1227 mutex_lock(&send_msg_lock);
1228 atomic_inc(&data->ioctl_count);
1229 ret = qseecom_send_modfd_cmd(data, argp);
1230 atomic_dec(&data->ioctl_count);
1231 wake_up_all(&data->abort_wq);
1232 mutex_unlock(&send_msg_lock);
1233 if (ret)
1234 pr_err("failed qseecom_send_cmd: %d\n", ret);
1235 break;
1236 }
1237 case QSEECOM_IOCTL_RECEIVE_REQ: {
1238 atomic_inc(&data->ioctl_count);
1239 ret = qseecom_receive_req(data);
1240 atomic_dec(&data->ioctl_count);
1241 wake_up_all(&data->abort_wq);
1242 if (ret)
1243 pr_err("failed qseecom_receive_req: %d\n", ret);
1244 break;
1245 }
1246 case QSEECOM_IOCTL_SEND_RESP_REQ: {
1247 atomic_inc(&data->ioctl_count);
1248 ret = qseecom_send_resp();
1249 atomic_dec(&data->ioctl_count);
1250 wake_up_all(&data->abort_wq);
1251 if (ret)
1252 pr_err("failed qseecom_send_resp: %d\n", ret);
1253 break;
1254 }
1255 case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
1256 ret = qseecom_set_client_mem_param(data, argp);
1257 if (ret)
1258 pr_err("failed Qqseecom_set_mem_param request: %d\n",
1259 ret);
1260 break;
1261 }
1262 case QSEECOM_IOCTL_LOAD_APP_REQ: {
1263 mutex_lock(&app_access_lock);
1264 atomic_inc(&data->ioctl_count);
1265 ret = qseecom_load_app(data, argp);
1266 atomic_dec(&data->ioctl_count);
1267 mutex_unlock(&app_access_lock);
1268 if (ret)
1269 pr_err("failed load_app request: %d\n", ret);
1270 break;
1271 }
1272 case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
1273 mutex_lock(&app_access_lock);
1274 atomic_inc(&data->ioctl_count);
1275 ret = qseecom_unload_app(data);
1276 atomic_dec(&data->ioctl_count);
1277 mutex_unlock(&app_access_lock);
1278 if (ret)
1279 pr_err("failed unload_app request: %d\n", ret);
1280 break;
1281 }
1282 case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
1283 atomic_inc(&data->ioctl_count);
1284 ret = qseecom_get_qseos_version(data, argp);
1285 if (ret)
1286 pr_err("qseecom_get_qseos_version: %d\n", ret);
1287 atomic_dec(&data->ioctl_count);
1288 break;
1289 }
1290 case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
1291 atomic_inc(&data->ioctl_count);
1292 ret = qsee_vote_for_clock();
1293 if (ret)
1294 pr_err("Failed to vote for clock%d\n", ret);
1295 atomic_dec(&data->ioctl_count);
1296 break;
1297 }
1298 case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
1299 atomic_inc(&data->ioctl_count);
1300 qsee_disable_clock_vote();
1301 atomic_dec(&data->ioctl_count);
1302 break;
1303 }
1304 default:
1305 return -EINVAL;
1306 }
1307 return ret;
1308}
1309
1310static int qseecom_open(struct inode *inode, struct file *file)
1311{
1312 int ret = 0;
1313 struct qseecom_dev_handle *data;
1314
1315 data = kzalloc(sizeof(*data), GFP_KERNEL);
1316 if (!data) {
1317 pr_err("kmalloc failed\n");
1318 return -ENOMEM;
1319 }
1320 file->private_data = data;
1321 data->abort = 0;
1322 data->service = false;
1323 data->released = false;
1324 init_waitqueue_head(&data->abort_wq);
1325 atomic_set(&data->ioctl_count, 0);
1326 return ret;
1327}
1328
1329static int qseecom_release(struct inode *inode, struct file *file)
1330{
1331 struct qseecom_dev_handle *data = file->private_data;
1332 int ret = 0;
1333
1334 if (data->released == false) {
1335 pr_warn("data->released == false\n");
1336 if (data->service)
1337 ret = qseecom_unregister_listener(data);
1338 else
1339 ret = qseecom_unload_app(data);
1340 if (ret) {
1341 pr_err("Close failed\n");
1342 return ret;
1343 }
1344 }
1345 kfree(data);
1346 return ret;
1347}
1348
1349/* qseecom bus scaling */
1350static struct msm_bus_paths qsee_bw_table[] = {
1351 {
1352 .vectors = (struct msm_bus_vectors[]){
1353 {
1354 .src = MSM_BUS_MASTER_SPS,
1355 .dst = MSM_BUS_SLAVE_EBI_CH0,
1356 },
1357 },
1358 .num_paths = 1,
1359 },
1360 {
1361 .vectors = (struct msm_bus_vectors[]){
1362 {
1363 .src = MSM_BUS_MASTER_SPS,
1364 .dst = MSM_BUS_SLAVE_EBI_CH0,
1365 .ib = (492 * 8) * 1000000UL,
1366 .ab = (492 * 8) * 100000UL,
1367 },
1368 },
1369 .num_paths = 1,
1370 },
1371};
1372
1373static struct msm_bus_scale_pdata qsee_bus_pdata = {
1374 .usecase = qsee_bw_table,
1375 .num_usecases = ARRAY_SIZE(qsee_bw_table),
1376 .name = "qsee",
1377};
1378
1379static const struct file_operations qseecom_fops = {
1380 .owner = THIS_MODULE,
1381 .unlocked_ioctl = qseecom_ioctl,
1382 .open = qseecom_open,
1383 .release = qseecom_release
1384};
1385
1386static int __init qseecom_init(void)
1387{
1388 int rc;
1389 int ret = 0;
1390 struct device *class_dev;
1391 char qsee_not_legacy = 0;
1392 uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
1393
1394 rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
1395 if (rc < 0) {
1396 pr_err("alloc_chrdev_region failed %d\n", rc);
1397 return rc;
1398 }
1399
1400 driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
1401 if (IS_ERR(driver_class)) {
1402 rc = -ENOMEM;
1403 pr_err("class_create failed %d\n", rc);
1404 goto unregister_chrdev_region;
1405 }
1406
1407 class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
1408 QSEECOM_DEV);
1409 if (!class_dev) {
1410 pr_err("class_device_create failed %d\n", rc);
1411 rc = -ENOMEM;
1412 goto class_destroy;
1413 }
1414
1415 cdev_init(&qseecom_cdev, &qseecom_fops);
1416 qseecom_cdev.owner = THIS_MODULE;
1417
1418 rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
1419 if (rc < 0) {
1420 pr_err("cdev_add failed %d\n", rc);
1421 goto err;
1422 }
1423
1424 INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
1425 spin_lock_init(&qseecom.registered_listener_list_lock);
1426 INIT_LIST_HEAD(&qseecom.registered_app_list_head);
1427 spin_lock_init(&qseecom.registered_app_list_lock);
1428 init_waitqueue_head(&qseecom.send_resp_wq);
1429 qseecom.send_resp_flag = 0;
1430
1431 rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
1432 &qsee_not_legacy, sizeof(qsee_not_legacy));
1433 if (rc) {
1434 pr_err("Failed to retrieve QSEE version information %d\n", rc);
1435 goto err;
1436 }
1437 if (qsee_not_legacy)
1438 qseecom.qseos_version = QSEOS_VERSION_14;
1439 else {
1440 qseecom.qseos_version = QSEOS_VERSION_13;
1441 pil = NULL;
1442 pil_ref_cnt = 0;
1443 }
1444 /* Create ION msm client */
1445 qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
1446 if (qseecom.ion_clnt == NULL) {
1447 pr_err("Ion client cannot be created\n");
1448 rc = -ENOMEM;
1449 goto err;
1450 }
1451
1452 /* register client for bus scaling */
1453 qsee_perf_client = msm_bus_scale_register_client(&qsee_bus_pdata);
1454 if (!qsee_perf_client)
1455 pr_err("Unable to register bus client\n");
1456
1457 qseecom_bus_clk = clk_get_sys("scm", "bus_clk");
1458 if (!IS_ERR(qseecom_bus_clk)) {
1459 ret = clk_set_rate(qseecom_bus_clk, 64000000);
1460 if (ret) {
1461 qseecom_bus_clk = NULL;
1462 pr_err("Unable to set clock rate\n");
1463 }
1464 } else {
1465 qseecom_bus_clk = NULL;
1466 pr_warn("Unable to get bus clk\n");
1467 }
1468 return 0;
1469err:
1470 device_destroy(driver_class, qseecom_device_no);
1471class_destroy:
1472 class_destroy(driver_class);
1473unregister_chrdev_region:
1474 unregister_chrdev_region(qseecom_device_no, 1);
1475 return rc;
1476}
1477
1478static void __exit qseecom_exit(void)
1479{
1480 device_destroy(driver_class, qseecom_device_no);
1481 class_destroy(driver_class);
1482 unregister_chrdev_region(qseecom_device_no, 1);
1483 ion_client_destroy(qseecom.ion_clnt);
1484}
1485
1486MODULE_LICENSE("GPL v2");
1487MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
1488
1489module_init(qseecom_init);
1490module_exit(qseecom_exit);