xref: /optee_os/core/kernel/notif.c (revision 94397285508204a92b4e7fa518b2c3329c4286f9)
12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
22828809eSJens Wiklander /*
32828809eSJens Wiklander  * Copyright (c) 2021, Linaro Limited
42828809eSJens Wiklander  */
52828809eSJens Wiklander 
6c2d44948SJens Wiklander #include <bitstring.h>
7c2d44948SJens Wiklander #include <drivers/gic.h>
8c2d44948SJens Wiklander #include <kernel/interrupt.h>
9c2d44948SJens Wiklander #include <kernel/mutex.h>
102828809eSJens Wiklander #include <kernel/notif.h>
11c2d44948SJens Wiklander #include <kernel/spinlock.h>
122828809eSJens Wiklander #include <kernel/thread.h>
132828809eSJens Wiklander #include <optee_rpc_cmd.h>
142828809eSJens Wiklander #include <types_ext.h>
152828809eSJens Wiklander 
16c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
17c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER;
18c2d44948SJens Wiklander static unsigned int notif_lock = SPINLOCK_UNLOCK;
19c2d44948SJens Wiklander 
20c2d44948SJens Wiklander SLIST_HEAD(notif_driver_head, notif_driver);
21c2d44948SJens Wiklander static struct notif_driver_head notif_driver_head =
22c2d44948SJens Wiklander 	SLIST_HEAD_INITIALIZER(&notif_driver_head);
23c2d44948SJens Wiklander 
24c2d44948SJens Wiklander static bitstr_t bit_decl(notif_values, NOTIF_ASYNC_VALUE_MAX + 1);
25c2d44948SJens Wiklander static bitstr_t bit_decl(notif_alloc_values, NOTIF_ASYNC_VALUE_MAX + 1);
26c2d44948SJens Wiklander static bool notif_started;
27c2d44948SJens Wiklander 
28c2d44948SJens Wiklander TEE_Result notif_alloc_async_value(uint32_t *val)
29c2d44948SJens Wiklander {
30c2d44948SJens Wiklander 	static bool alloc_values_inited;
31c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
32c2d44948SJens Wiklander 	int bit = 0;
33c2d44948SJens Wiklander 
34c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
35c2d44948SJens Wiklander 
36c2d44948SJens Wiklander 	if (!alloc_values_inited) {
37c2d44948SJens Wiklander 		bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF);
38c2d44948SJens Wiklander 		alloc_values_inited = true;
39c2d44948SJens Wiklander 	}
40c2d44948SJens Wiklander 
41c2d44948SJens Wiklander 	bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
42c2d44948SJens Wiklander 	if (bit >= 0) {
43c2d44948SJens Wiklander 		*val = bit;
44c2d44948SJens Wiklander 		bit_set(notif_alloc_values, bit);
45c2d44948SJens Wiklander 	}
46c2d44948SJens Wiklander 
47c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
48c2d44948SJens Wiklander 
49c2d44948SJens Wiklander 	if (bit < 0)
50c2d44948SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
51c2d44948SJens Wiklander 
52c2d44948SJens Wiklander 	return TEE_SUCCESS;
53c2d44948SJens Wiklander }
54c2d44948SJens Wiklander 
55c2d44948SJens Wiklander void notif_free_async_value(uint32_t val)
56c2d44948SJens Wiklander {
57c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
58c2d44948SJens Wiklander 
59c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
60c2d44948SJens Wiklander 
61c2d44948SJens Wiklander 	assert(val < NOTIF_ASYNC_VALUE_MAX);
62c2d44948SJens Wiklander 	assert(bit_test(notif_alloc_values, val));
63c2d44948SJens Wiklander 	bit_clear(notif_alloc_values, val);
64c2d44948SJens Wiklander 
65c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
66c2d44948SJens Wiklander }
67c2d44948SJens Wiklander 
68c2d44948SJens Wiklander uint32_t notif_get_value(bool *value_valid, bool *value_pending)
69c2d44948SJens Wiklander {
70c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
71c2d44948SJens Wiklander 	uint32_t res = 0;
72c2d44948SJens Wiklander 	int bit = 0;
73c2d44948SJens Wiklander 
74c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
75c2d44948SJens Wiklander 
76c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
77c2d44948SJens Wiklander 	*value_valid = (bit >= 0);
78c2d44948SJens Wiklander 	if (!*value_valid) {
79c2d44948SJens Wiklander 		*value_pending = false;
80c2d44948SJens Wiklander 		goto out;
81c2d44948SJens Wiklander 	}
82c2d44948SJens Wiklander 
83c2d44948SJens Wiklander 	res = bit;
84c2d44948SJens Wiklander 	bit_clear(notif_values, res);
85c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
86c2d44948SJens Wiklander 	*value_pending = (bit >= 0);
87c2d44948SJens Wiklander out:
88c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
89c2d44948SJens Wiklander 
90c2d44948SJens Wiklander 	return res;
91c2d44948SJens Wiklander }
92c2d44948SJens Wiklander 
93c2d44948SJens Wiklander void notif_send_async(uint32_t value)
94c2d44948SJens Wiklander {
95c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
96c2d44948SJens Wiklander 
97*94397285SEtienne Carriere 	static_assert(CFG_CORE_ASYNC_NOTIF_GIC_INTID >= GIC_PPI_BASE);
98c2d44948SJens Wiklander 
99c2d44948SJens Wiklander 	assert(value <= NOTIF_ASYNC_VALUE_MAX);
100c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
101c2d44948SJens Wiklander 
102c2d44948SJens Wiklander 	DMSG("0x%"PRIx32, value);
103c2d44948SJens Wiklander 	bit_set(notif_values, value);
104c2d44948SJens Wiklander 	itr_raise_pi(CFG_CORE_ASYNC_NOTIF_GIC_INTID);
105c2d44948SJens Wiklander 
106c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
107c2d44948SJens Wiklander }
108c2d44948SJens Wiklander 
109c2d44948SJens Wiklander bool notif_async_is_started(void)
110c2d44948SJens Wiklander {
111c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
112c2d44948SJens Wiklander 	bool ret = false;
113c2d44948SJens Wiklander 
114c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
115c2d44948SJens Wiklander 	ret = notif_started;
116c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
117c2d44948SJens Wiklander 
118c2d44948SJens Wiklander 	return ret;
119c2d44948SJens Wiklander }
120c2d44948SJens Wiklander 
121c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv)
122c2d44948SJens Wiklander {
123c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
124c2d44948SJens Wiklander 
125c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
126c2d44948SJens Wiklander 
127c2d44948SJens Wiklander 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
128c2d44948SJens Wiklander 
129c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
130c2d44948SJens Wiklander }
131c2d44948SJens Wiklander 
132c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv)
133c2d44948SJens Wiklander {
134c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
135c2d44948SJens Wiklander 
136c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
137c2d44948SJens Wiklander 
138c2d44948SJens Wiklander 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
139c2d44948SJens Wiklander 
140c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
141c2d44948SJens Wiklander }
142c2d44948SJens Wiklander 
143c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev)
144c2d44948SJens Wiklander {
145c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
146c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
147c2d44948SJens Wiklander 
148c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_STARTED);
149c2d44948SJens Wiklander 
150c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
151c2d44948SJens Wiklander 
152c2d44948SJens Wiklander 	if (notif_started) {
153c2d44948SJens Wiklander 		DMSG("Already started");
154c2d44948SJens Wiklander 		goto out;
155c2d44948SJens Wiklander 	}
156c2d44948SJens Wiklander 	notif_started = true;
157c2d44948SJens Wiklander 
158c2d44948SJens Wiklander 	SLIST_FOREACH(nd, &notif_driver_head, link)
159c2d44948SJens Wiklander 		if (nd->atomic_cb)
160c2d44948SJens Wiklander 			nd->atomic_cb(nd, ev);
161c2d44948SJens Wiklander 
162c2d44948SJens Wiklander out:
163c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
164c2d44948SJens Wiklander }
165c2d44948SJens Wiklander 
166c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev)
167c2d44948SJens Wiklander {
168c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
169c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
170c2d44948SJens Wiklander 	struct notif_driver *nd_tmp = NULL;
171c2d44948SJens Wiklander 
172c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED);
173c2d44948SJens Wiklander 
174c2d44948SJens Wiklander 	/* Serialize all yielding notifications */
175c2d44948SJens Wiklander 	mutex_lock(&notif_mutex);
176c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
177c2d44948SJens Wiklander 
178c2d44948SJens Wiklander 	if (!notif_started) {
179c2d44948SJens Wiklander 		DMSG("Not started ev %d", (int)ev);
180c2d44948SJens Wiklander 		goto out;
181c2d44948SJens Wiklander 	}
182c2d44948SJens Wiklander 
183c2d44948SJens Wiklander 	if (ev == NOTIF_EVENT_STOPPED)
184c2d44948SJens Wiklander 		notif_started = false;
185c2d44948SJens Wiklander 
186c2d44948SJens Wiklander 	SLIST_FOREACH_SAFE(nd, &notif_driver_head, link, nd_tmp) {
187c2d44948SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
188c2d44948SJens Wiklander 
189c2d44948SJens Wiklander 		if (nd->yielding_cb)
190c2d44948SJens Wiklander 			nd->yielding_cb(nd, ev);
191c2d44948SJens Wiklander 
192c2d44948SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
193c2d44948SJens Wiklander 
194c2d44948SJens Wiklander 		if (ev == NOTIF_EVENT_STOPPED && notif_started) {
195c2d44948SJens Wiklander 			DMSG("Started again while stopping");
196c2d44948SJens Wiklander 			goto out;
197c2d44948SJens Wiklander 		}
198c2d44948SJens Wiklander 	}
199c2d44948SJens Wiklander 
200c2d44948SJens Wiklander out:
201c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
202c2d44948SJens Wiklander 	mutex_unlock(&notif_mutex);
203c2d44948SJens Wiklander }
204c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/
205c2d44948SJens Wiklander 
2062828809eSJens Wiklander static TEE_Result notif_rpc(uint32_t func, uint32_t value)
2072828809eSJens Wiklander {
2082828809eSJens Wiklander 	struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0);
2092828809eSJens Wiklander 
2102828809eSJens Wiklander 	return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, &params);
2112828809eSJens Wiklander }
2122828809eSJens Wiklander 
2132828809eSJens Wiklander TEE_Result notif_wait(uint32_t value)
2142828809eSJens Wiklander {
2152828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value);
2162828809eSJens Wiklander }
2172828809eSJens Wiklander 
2182828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value)
2192828809eSJens Wiklander {
2202828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value);
2212828809eSJens Wiklander }
222