xref: /optee_os/core/kernel/notif.c (revision da637b6b319a81e0107093153b9adb2c821088b3)
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 
34*da637b6bSEtienne Carriere 	assert(interrupt_can_raise_pi(interrupt_get_main_chip()));
35*da637b6bSEtienne Carriere 
36c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
37c2d44948SJens Wiklander 
38c2d44948SJens Wiklander 	if (!alloc_values_inited) {
39c2d44948SJens Wiklander 		bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF);
40c2d44948SJens Wiklander 		alloc_values_inited = true;
41c2d44948SJens Wiklander 	}
42c2d44948SJens Wiklander 
43c2d44948SJens Wiklander 	bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
44c2d44948SJens Wiklander 	if (bit >= 0) {
45c2d44948SJens Wiklander 		*val = bit;
46c2d44948SJens Wiklander 		bit_set(notif_alloc_values, bit);
47c2d44948SJens Wiklander 	}
48c2d44948SJens Wiklander 
49c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
50c2d44948SJens Wiklander 
51c2d44948SJens Wiklander 	if (bit < 0)
52c2d44948SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
53c2d44948SJens Wiklander 
54c2d44948SJens Wiklander 	return TEE_SUCCESS;
55c2d44948SJens Wiklander }
56c2d44948SJens Wiklander 
57c2d44948SJens Wiklander void notif_free_async_value(uint32_t val)
58c2d44948SJens Wiklander {
59c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
60c2d44948SJens Wiklander 
61c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
62c2d44948SJens Wiklander 
63c2d44948SJens Wiklander 	assert(val < NOTIF_ASYNC_VALUE_MAX);
64c2d44948SJens Wiklander 	assert(bit_test(notif_alloc_values, val));
65c2d44948SJens Wiklander 	bit_clear(notif_alloc_values, val);
66c2d44948SJens Wiklander 
67c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
68c2d44948SJens Wiklander }
69c2d44948SJens Wiklander 
70c2d44948SJens Wiklander uint32_t notif_get_value(bool *value_valid, bool *value_pending)
71c2d44948SJens Wiklander {
72c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
73c2d44948SJens Wiklander 	uint32_t res = 0;
74c2d44948SJens Wiklander 	int bit = 0;
75c2d44948SJens Wiklander 
76c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
77c2d44948SJens Wiklander 
78c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
79c2d44948SJens Wiklander 	*value_valid = (bit >= 0);
80c2d44948SJens Wiklander 	if (!*value_valid) {
81c2d44948SJens Wiklander 		*value_pending = false;
82c2d44948SJens Wiklander 		goto out;
83c2d44948SJens Wiklander 	}
84c2d44948SJens Wiklander 
85c2d44948SJens Wiklander 	res = bit;
86c2d44948SJens Wiklander 	bit_clear(notif_values, res);
87c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
88c2d44948SJens Wiklander 	*value_pending = (bit >= 0);
89c2d44948SJens Wiklander out:
90c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
91c2d44948SJens Wiklander 
92c2d44948SJens Wiklander 	return res;
93c2d44948SJens Wiklander }
94c2d44948SJens Wiklander 
95c2d44948SJens Wiklander void notif_send_async(uint32_t value)
96c2d44948SJens Wiklander {
97c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
98*da637b6bSEtienne Carriere 	struct itr_chip *itr_chip = interrupt_get_main_chip();
99c2d44948SJens Wiklander 
10094397285SEtienne Carriere 	static_assert(CFG_CORE_ASYNC_NOTIF_GIC_INTID >= GIC_PPI_BASE);
101c2d44948SJens Wiklander 
102c2d44948SJens Wiklander 	assert(value <= NOTIF_ASYNC_VALUE_MAX);
103c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
104c2d44948SJens Wiklander 
105c2d44948SJens Wiklander 	DMSG("0x%"PRIx32, value);
106c2d44948SJens Wiklander 	bit_set(notif_values, value);
107*da637b6bSEtienne Carriere 	interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID);
108c2d44948SJens Wiklander 
109c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
110c2d44948SJens Wiklander }
111c2d44948SJens Wiklander 
112c2d44948SJens Wiklander bool notif_async_is_started(void)
113c2d44948SJens Wiklander {
114c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
115c2d44948SJens Wiklander 	bool ret = false;
116c2d44948SJens Wiklander 
117c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
118c2d44948SJens Wiklander 	ret = notif_started;
119c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
120c2d44948SJens Wiklander 
121c2d44948SJens Wiklander 	return ret;
122c2d44948SJens Wiklander }
123c2d44948SJens Wiklander 
124c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv)
125c2d44948SJens Wiklander {
126c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
127c2d44948SJens Wiklander 
128*da637b6bSEtienne Carriere 	assert(interrupt_can_raise_pi(interrupt_get_main_chip()));
129*da637b6bSEtienne Carriere 
130c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
131c2d44948SJens Wiklander 
132c2d44948SJens Wiklander 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
133c2d44948SJens Wiklander 
134c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
135c2d44948SJens Wiklander }
136c2d44948SJens Wiklander 
137c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv)
138c2d44948SJens Wiklander {
139c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
140c2d44948SJens Wiklander 
141c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
142c2d44948SJens Wiklander 
143c2d44948SJens Wiklander 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
144c2d44948SJens Wiklander 
145c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
146c2d44948SJens Wiklander }
147c2d44948SJens Wiklander 
148c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev)
149c2d44948SJens Wiklander {
150c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
151c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
152c2d44948SJens Wiklander 
153c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_STARTED);
154c2d44948SJens Wiklander 
155c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
156c2d44948SJens Wiklander 
157c2d44948SJens Wiklander 	if (notif_started) {
158c2d44948SJens Wiklander 		DMSG("Already started");
159c2d44948SJens Wiklander 		goto out;
160c2d44948SJens Wiklander 	}
161c2d44948SJens Wiklander 	notif_started = true;
162c2d44948SJens Wiklander 
163c2d44948SJens Wiklander 	SLIST_FOREACH(nd, &notif_driver_head, link)
164c2d44948SJens Wiklander 		if (nd->atomic_cb)
165c2d44948SJens Wiklander 			nd->atomic_cb(nd, ev);
166c2d44948SJens Wiklander 
167c2d44948SJens Wiklander out:
168c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
169c2d44948SJens Wiklander }
170c2d44948SJens Wiklander 
171c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev)
172c2d44948SJens Wiklander {
173c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
174c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
175c2d44948SJens Wiklander 	struct notif_driver *nd_tmp = NULL;
176c2d44948SJens Wiklander 
177c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED);
178c2d44948SJens Wiklander 
179c2d44948SJens Wiklander 	/* Serialize all yielding notifications */
180c2d44948SJens Wiklander 	mutex_lock(&notif_mutex);
181c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
182c2d44948SJens Wiklander 
183c2d44948SJens Wiklander 	if (!notif_started) {
184c2d44948SJens Wiklander 		DMSG("Not started ev %d", (int)ev);
185c2d44948SJens Wiklander 		goto out;
186c2d44948SJens Wiklander 	}
187c2d44948SJens Wiklander 
188c2d44948SJens Wiklander 	if (ev == NOTIF_EVENT_STOPPED)
189c2d44948SJens Wiklander 		notif_started = false;
190c2d44948SJens Wiklander 
191c2d44948SJens Wiklander 	SLIST_FOREACH_SAFE(nd, &notif_driver_head, link, nd_tmp) {
192c2d44948SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
193c2d44948SJens Wiklander 
194c2d44948SJens Wiklander 		if (nd->yielding_cb)
195c2d44948SJens Wiklander 			nd->yielding_cb(nd, ev);
196c2d44948SJens Wiklander 
197c2d44948SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
198c2d44948SJens Wiklander 
199c2d44948SJens Wiklander 		if (ev == NOTIF_EVENT_STOPPED && notif_started) {
200c2d44948SJens Wiklander 			DMSG("Started again while stopping");
201c2d44948SJens Wiklander 			goto out;
202c2d44948SJens Wiklander 		}
203c2d44948SJens Wiklander 	}
204c2d44948SJens Wiklander 
205c2d44948SJens Wiklander out:
206c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
207c2d44948SJens Wiklander 	mutex_unlock(&notif_mutex);
208c2d44948SJens Wiklander }
209c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/
210c2d44948SJens Wiklander 
2112828809eSJens Wiklander static TEE_Result notif_rpc(uint32_t func, uint32_t value)
2122828809eSJens Wiklander {
2132828809eSJens Wiklander 	struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0);
2142828809eSJens Wiklander 
2152828809eSJens Wiklander 	return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, &params);
2162828809eSJens Wiklander }
2172828809eSJens Wiklander 
2182828809eSJens Wiklander TEE_Result notif_wait(uint32_t value)
2192828809eSJens Wiklander {
2202828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value);
2212828809eSJens Wiklander }
2222828809eSJens Wiklander 
2232828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value)
2242828809eSJens Wiklander {
2252828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value);
2262828809eSJens Wiklander }
227