@@ -39,9 +39,29 @@ struct optee_shm_arg_entry {
3939 DECLARE_BITMAP (map , MAX_ARG_COUNT_PER_ENTRY );
4040};
4141
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+
4257void optee_cq_wait_init (struct optee_call_queue * cq ,
4358 struct optee_call_waiter * w , bool sys_thread )
4459{
60+ unsigned int free_thread_threshold ;
61+ bool need_wait = false;
62+
63+ memset (w , 0 , sizeof (* w ));
64+
4565 /*
4666 * We're preparing to make a call to secure world. In case we can't
4767 * 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,
6080 */
6181 init_completion (& w -> c );
6282 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+ }
6396
6497 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+ }
65115}
66116
67117void 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)
83133{
84134 struct optee_call_waiter * w ;
85135
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+
86144 list_for_each_entry (w , & cq -> waiters , list_node ) {
87145 if (!completion_done (& w -> c )) {
88146 complete (& w -> c );
@@ -104,6 +162,8 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
104162 /* Get out of the list */
105163 list_del (& w -> list_node );
106164
165+ cq -> free_thread_count ++ ;
166+
107167 /* Wake up one eventual waiting task */
108168 optee_cq_complete_one (cq );
109169
@@ -119,6 +179,28 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
119179 mutex_unlock (& cq -> mutex );
120180}
121181
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+
122204/* Requires the filpstate mutex to be held */
123205static struct optee_session * find_session (struct optee_context_data * ctxdata ,
124206 u32 session_id )
@@ -361,6 +443,27 @@ int optee_open_session(struct tee_context *ctx,
361443 return rc ;
362444}
363445
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+
364467int optee_close_session_helper (struct tee_context * ctx , u32 session ,
365468 bool system_thread )
366469{
@@ -380,6 +483,9 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session,
380483
381484 optee_free_msg_arg (ctx , entry , offs );
382485
486+ if (system_thread )
487+ optee_cq_decr_sys_thread_count (& optee -> call_queue );
488+
383489 return 0 ;
384490}
385491
0 commit comments