@@ -39,9 +39,29 @@ struct optee_shm_arg_entry {
39
39
DECLARE_BITMAP (map , MAX_ARG_COUNT_PER_ENTRY );
40
40
};
41
41
42
+ void optee_cq_init (struct optee_call_queue * cq , int thread_count )
43
+ {
44
+ mutex_init (& cq -> mutex );
45
+ INIT_LIST_HEAD (& cq -> waiters );
46
+
47
+ /*
48
+ * If cq->total_thread_count is 0 then we're not trying to keep
49
+ * track of how many free threads we have, instead we're relying on
50
+ * the secure world to tell us when we're out of thread and have to
51
+ * wait for another thread to become available.
52
+ */
53
+ cq -> total_thread_count = thread_count ;
54
+ cq -> free_thread_count = thread_count ;
55
+ }
56
+
42
57
void optee_cq_wait_init (struct optee_call_queue * cq ,
43
58
struct optee_call_waiter * w , bool sys_thread )
44
59
{
60
+ unsigned int free_thread_threshold ;
61
+ bool need_wait = false;
62
+
63
+ memset (w , 0 , sizeof (* w ));
64
+
45
65
/*
46
66
* We're preparing to make a call to secure world. In case we can't
47
67
* allocate a thread in secure world we'll end up waiting in
@@ -60,8 +80,38 @@ void optee_cq_wait_init(struct optee_call_queue *cq,
60
80
*/
61
81
init_completion (& w -> c );
62
82
list_add_tail (& w -> list_node , & cq -> waiters );
83
+ w -> sys_thread = sys_thread ;
84
+
85
+ if (cq -> total_thread_count ) {
86
+ if (sys_thread || !cq -> sys_thread_req_count )
87
+ free_thread_threshold = 0 ;
88
+ else
89
+ free_thread_threshold = 1 ;
90
+
91
+ if (cq -> free_thread_count > free_thread_threshold )
92
+ cq -> free_thread_count -- ;
93
+ else
94
+ need_wait = true;
95
+ }
63
96
64
97
mutex_unlock (& cq -> mutex );
98
+
99
+ while (need_wait ) {
100
+ optee_cq_wait_for_completion (cq , w );
101
+ mutex_lock (& cq -> mutex );
102
+
103
+ if (sys_thread || !cq -> sys_thread_req_count )
104
+ free_thread_threshold = 0 ;
105
+ else
106
+ free_thread_threshold = 1 ;
107
+
108
+ if (cq -> free_thread_count > free_thread_threshold ) {
109
+ cq -> free_thread_count -- ;
110
+ need_wait = false;
111
+ }
112
+
113
+ mutex_unlock (& cq -> mutex );
114
+ }
65
115
}
66
116
67
117
void optee_cq_wait_for_completion (struct optee_call_queue * cq ,
@@ -83,6 +133,14 @@ static void optee_cq_complete_one(struct optee_call_queue *cq)
83
133
{
84
134
struct optee_call_waiter * w ;
85
135
136
+ /* Wake a waiting system session if any, prior to a normal session */
137
+ list_for_each_entry (w , & cq -> waiters , list_node ) {
138
+ if (w -> sys_thread && !completion_done (& w -> c )) {
139
+ complete (& w -> c );
140
+ return ;
141
+ }
142
+ }
143
+
86
144
list_for_each_entry (w , & cq -> waiters , list_node ) {
87
145
if (!completion_done (& w -> c )) {
88
146
complete (& w -> c );
@@ -104,6 +162,8 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
104
162
/* Get out of the list */
105
163
list_del (& w -> list_node );
106
164
165
+ cq -> free_thread_count ++ ;
166
+
107
167
/* Wake up one eventual waiting task */
108
168
optee_cq_complete_one (cq );
109
169
@@ -119,6 +179,28 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
119
179
mutex_unlock (& cq -> mutex );
120
180
}
121
181
182
+ /* Count registered system sessions to reserved a system thread or not */
183
+ static bool optee_cq_incr_sys_thread_count (struct optee_call_queue * cq )
184
+ {
185
+ if (cq -> total_thread_count <= 1 )
186
+ return false;
187
+
188
+ mutex_lock (& cq -> mutex );
189
+ cq -> sys_thread_req_count ++ ;
190
+ mutex_unlock (& cq -> mutex );
191
+
192
+ return true;
193
+ }
194
+
195
+ static void optee_cq_decr_sys_thread_count (struct optee_call_queue * cq )
196
+ {
197
+ mutex_lock (& cq -> mutex );
198
+ cq -> sys_thread_req_count -- ;
199
+ /* If there's someone waiting, let it resume */
200
+ optee_cq_complete_one (cq );
201
+ mutex_unlock (& cq -> mutex );
202
+ }
203
+
122
204
/* Requires the filpstate mutex to be held */
123
205
static struct optee_session * find_session (struct optee_context_data * ctxdata ,
124
206
u32 session_id )
@@ -361,6 +443,27 @@ int optee_open_session(struct tee_context *ctx,
361
443
return rc ;
362
444
}
363
445
446
+ int optee_system_session (struct tee_context * ctx , u32 session )
447
+ {
448
+ struct optee * optee = tee_get_drvdata (ctx -> teedev );
449
+ struct optee_context_data * ctxdata = ctx -> data ;
450
+ struct optee_session * sess ;
451
+ int rc = - EINVAL ;
452
+
453
+ mutex_lock (& ctxdata -> mutex );
454
+
455
+ sess = find_session (ctxdata , session );
456
+ if (sess && (sess -> use_sys_thread ||
457
+ optee_cq_incr_sys_thread_count (& optee -> call_queue ))) {
458
+ sess -> use_sys_thread = true;
459
+ rc = 0 ;
460
+ }
461
+
462
+ mutex_unlock (& ctxdata -> mutex );
463
+
464
+ return rc ;
465
+ }
466
+
364
467
int optee_close_session_helper (struct tee_context * ctx , u32 session ,
365
468
bool system_thread )
366
469
{
@@ -380,6 +483,9 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session,
380
483
381
484
optee_free_msg_arg (ctx , entry , offs );
382
485
486
+ if (system_thread )
487
+ optee_cq_decr_sys_thread_count (& optee -> call_queue );
488
+
383
489
return 0 ;
384
490
}
385
491
0 commit comments