drivers/tee/optee/call.c

Source file repositories/reference/linux-study-clean/drivers/tee/optee/call.c

File Facts

System
Linux kernel
Corpus path
drivers/tee/optee/call.c
Extension
.c
Size
17374 bytes
Lines
673
Domain
Driver Families
Bucket
drivers/tee
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct optee_shm_arg_entry {
	struct list_head list_node;
	struct tee_shm *shm;
	DECLARE_BITMAP(map, MAX_ARG_COUNT_PER_ENTRY);
};

void optee_cq_init(struct optee_call_queue *cq, int thread_count)
{
	mutex_init(&cq->mutex);
	INIT_LIST_HEAD(&cq->waiters);

	/*
	 * If cq->total_thread_count is 0 then we're not trying to keep
	 * track of how many free threads we have, instead we're relying on
	 * the secure world to tell us when we're out of thread and have to
	 * wait for another thread to become available.
	 */
	cq->total_thread_count = thread_count;
	cq->free_thread_count = thread_count;
}

void optee_cq_wait_init(struct optee_call_queue *cq,
			struct optee_call_waiter *w, bool sys_thread)
{
	unsigned int free_thread_threshold;
	bool need_wait = false;

	memset(w, 0, sizeof(*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);
	w->sys_thread = sys_thread;

	if (cq->total_thread_count) {
		if (sys_thread || !cq->sys_thread_req_count)
			free_thread_threshold = 0;
		else
			free_thread_threshold = 1;

		if (cq->free_thread_count > free_thread_threshold)
			cq->free_thread_count--;
		else
			need_wait = true;
	}

	mutex_unlock(&cq->mutex);

	while (need_wait) {
		optee_cq_wait_for_completion(cq, w);
		mutex_lock(&cq->mutex);

		if (sys_thread || !cq->sys_thread_req_count)
			free_thread_threshold = 0;
		else
			free_thread_threshold = 1;

		if (cq->free_thread_count > free_thread_threshold) {
			cq->free_thread_count--;
			need_wait = false;
		}

		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);

Annotation

Implementation Notes