Skip to content

Commit

Permalink
optee: refactor call queue code
Browse files Browse the repository at this point in the history
Move the call queue handling logic off to a new file to allow for its use
in other translation units cleanly.

Signed-off-by: Hernan Gatta <[email protected]>
Acked-by: Etienne Carriere <[email protected]>
[etienne: picked commit from linaro-swg/linux#72]
Signed-off-by: Etienne Carriere <[email protected]>
Change-Id: Ifbd281a8be32921d8273ba8683c53d5b19334b66
  • Loading branch information
etienne-lms authored and fourmone committed Mar 25, 2022
1 parent 0cca4d0 commit 2aa2627
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 85 deletions.
1 change: 1 addition & 0 deletions drivers/tee/optee/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_OPTEE) += optee.o
optee-objs += core.o
optee-objs += call_queue.o
optee-objs += call.o
optee-objs += rpc.o
optee-objs += supp.o
Expand Down
85 changes: 0 additions & 85 deletions drivers/tee/optee/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,91 +17,6 @@
#define CREATE_TRACE_POINTS
#include "optee_trace.h"

struct optee_call_waiter {
struct list_head list_node;
struct completion c;
};

static void optee_cq_wait_init(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
/*
* We're preparing to make a call to secure world. In case we can't
* allocate a thread in secure world we'll end up waiting in
* optee_cq_wait_for_completion().
*
* Normally if there's no contention in secure world the call will
* complete and we can cleanup directly with optee_cq_wait_final().
*/
mutex_lock(&cq->mutex);

/*
* We add ourselves to the queue, but we don't wait. This
* guarantees that we don't lose a completion if secure world
* returns busy and another thread just exited and try to complete
* someone.
*/
init_completion(&w->c);
list_add_tail(&w->list_node, &cq->waiters);

mutex_unlock(&cq->mutex);
}

static void optee_cq_wait_for_completion(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
wait_for_completion(&w->c);

mutex_lock(&cq->mutex);

/* Move to end of list to get out of the way for other waiters */
list_del(&w->list_node);
reinit_completion(&w->c);
list_add_tail(&w->list_node, &cq->waiters);

mutex_unlock(&cq->mutex);
}

static void optee_cq_complete_one(struct optee_call_queue *cq)
{
struct optee_call_waiter *w;

list_for_each_entry(w, &cq->waiters, list_node) {
if (!completion_done(&w->c)) {
complete(&w->c);
break;
}
}
}

static void optee_cq_wait_final(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
/*
* We're done with the call to secure world. The thread in secure
* world that was used for this call is now available for some
* other task to use.
*/
mutex_lock(&cq->mutex);

/* Get out of the list */
list_del(&w->list_node);

/* Wake up one eventual waiting task */
optee_cq_complete_one(cq);

/*
* If we're completed we've got a completion from another task that
* was just done with its call to secure world. Since yet another
* thread now is available in secure world wake up another eventual
* waiting task.
*/
if (completion_done(&w->c))
optee_cq_complete_one(cq);

mutex_unlock(&cq->mutex);
}

/* Requires the filpstate mutex to be held */
static struct optee_session *find_session(struct optee_context_data *ctxdata,
u32 session_id)
Expand Down
86 changes: 86 additions & 0 deletions drivers/tee/optee/call_queue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015, Linaro Limited
*/

#include "optee_private.h"

void optee_cq_wait_init(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
/*
* We're preparing to make a call to secure world. In case we can't
* allocate a thread in secure world we'll end up waiting in
* optee_cq_wait_for_completion().
*
* Normally if there's no contention in secure world the call will
* complete and we can cleanup directly with optee_cq_wait_final().
*/
mutex_lock(&cq->mutex);

/*
* We add ourselves to the queue, but we don't wait. This
* guarantees that we don't lose a completion if secure world
* returns busy and another thread just exited and try to complete
* someone.
*/
init_completion(&w->c);
list_add_tail(&w->list_node, &cq->waiters);

mutex_unlock(&cq->mutex);
}

void optee_cq_wait_for_completion(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
wait_for_completion(&w->c);

mutex_lock(&cq->mutex);

/* Move to end of list to get out of the way for other waiters */
list_del(&w->list_node);
reinit_completion(&w->c);
list_add_tail(&w->list_node, &cq->waiters);

mutex_unlock(&cq->mutex);
}

void optee_cq_complete_one(struct optee_call_queue *cq)
{
struct optee_call_waiter *w;

list_for_each_entry(w, &cq->waiters, list_node) {
if (!completion_done(&w->c)) {
complete(&w->c);
break;
}
}
}

void optee_cq_wait_final(struct optee_call_queue *cq,
struct optee_call_waiter *w)
{
/*
* We're done with the call to secure world. The thread in secure
* world that was used for this call is now available for some
* other task to use.
*/
mutex_lock(&cq->mutex);

/* Get out of the list */
list_del(&w->list_node);

/* Wake up one eventual waiting task */
optee_cq_complete_one(cq);

/*
* If we're completed we've got a completion from another task that
* was just done with its call to secure world. Since yet another
* thread now is available in secure world wake up another eventual
* waiting task.
*/
if (completion_done(&w->c))
optee_cq_complete_one(cq);

mutex_unlock(&cq->mutex);
}
13 changes: 13 additions & 0 deletions drivers/tee/optee/optee_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ struct optee_rpc_param {
u32 a7;
};

struct optee_call_waiter {
struct list_head list_node;
struct completion c;
};

/* Holds context that is preserved during one STD call */
struct optee_call_ctx {
/* information about pages list used in last allocation */
Expand Down Expand Up @@ -186,6 +191,14 @@ void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
int optee_enumerate_devices(u32 func);
void optee_unregister_devices(void);

void optee_cq_wait_init(struct optee_call_queue *cq,
struct optee_call_waiter *w);
void optee_cq_wait_for_completion(struct optee_call_queue *cq,
struct optee_call_waiter *w);
void optee_cq_complete_one(struct optee_call_queue *cq);
void optee_cq_wait_final(struct optee_call_queue *cq,
struct optee_call_waiter *w);

/*
* Small helpers
*/
Expand Down

0 comments on commit 2aa2627

Please sign in to comment.