xref: /optee_os/core/include/kernel/notif.h (revision c2d449482de098f1c894b94f338440e5a327813d)
12828809eSJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */
22828809eSJens Wiklander /*
32828809eSJens Wiklander  * Copyright (c) 2021, Linaro Limited
42828809eSJens Wiklander  */
52828809eSJens Wiklander 
62828809eSJens Wiklander #ifndef __KERNEL_NOTIF_H
72828809eSJens Wiklander #define __KERNEL_NOTIF_H
82828809eSJens Wiklander 
92828809eSJens Wiklander #include <compiler.h>
102828809eSJens Wiklander #include <sys/queue.h>
112828809eSJens Wiklander #include <tee_api_types.h>
122828809eSJens Wiklander #include <types_ext.h>
13*c2d44948SJens Wiklander #include <config.h>
142828809eSJens Wiklander 
15*c2d44948SJens Wiklander /*
16*c2d44948SJens Wiklander  * Notification values are divided into two kinds, asynchronous and
17*c2d44948SJens Wiklander  * synchronous, where the asynchronous has the lowest values.
18*c2d44948SJens Wiklander  * They are ordered as:
19*c2d44948SJens Wiklander  * 0			    Do bottom half
20*c2d44948SJens Wiklander  * 1..NOTIF_ASYNC_MAX	    Free for signalling in PTAs and should be
21*c2d44948SJens Wiklander  *			    allocated with notif_alloc_async_value()
22*c2d44948SJens Wiklander  * NOTIF_SYNC_VALUE_BASE..  Used as NOTIF_SYNC_VALUE_BASE + thread_id
23*c2d44948SJens Wiklander  * NOTIF_VALUE_MAX	    for mutex and condvar wait/wakeup
24*c2d44948SJens Wiklander  *
25*c2d44948SJens Wiklander  * Any value can be signalled with notif_send_sync() while only the ones
26*c2d44948SJens Wiklander  * <= NOTIF_ASYNC_VALUE_MAX can be signalled with notif_send_async().
27*c2d44948SJens Wiklander  */
28*c2d44948SJens Wiklander 
29*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
30*c2d44948SJens Wiklander #define NOTIF_ASYNC_VALUE_MAX		U(63)
31*c2d44948SJens Wiklander #define NOTIF_SYNC_VALUE_BASE		(NOTIF_ASYNC_VALUE_MAX + U(1))
32*c2d44948SJens Wiklander #else
332828809eSJens Wiklander #define NOTIF_SYNC_VALUE_BASE		0
34*c2d44948SJens Wiklander #endif
352828809eSJens Wiklander 
362828809eSJens Wiklander #define NOTIF_VALUE_MAX			(NOTIF_SYNC_VALUE_BASE + \
372828809eSJens Wiklander 					 CFG_NUM_THREADS)
382828809eSJens Wiklander 
39*c2d44948SJens Wiklander #define NOTIF_VALUE_DO_BOTTOM_HALF	0
40*c2d44948SJens Wiklander 
412828809eSJens Wiklander /*
42*c2d44948SJens Wiklander  * enum notif_event - Notification of an event
43*c2d44948SJens Wiklander  * @NOTIF_EVENT_STARTED:	Delivered in an atomic context to inform
44*c2d44948SJens Wiklander  *				drivers that normal world has enabled
45*c2d44948SJens Wiklander  *				asynchronous notifications.
46*c2d44948SJens Wiklander  * @NOTIF_EVENT_DO_BOTTOM_HALF: Delivered in a yielding context to let a
47*c2d44948SJens Wiklander  *				driver do bottom half processing.
48*c2d44948SJens Wiklander  * @NOTIF_EVENT_STOPPED:	Delivered in a yielding contest to inform
49*c2d44948SJens Wiklander  *				drivers that normal world is about to disable
50*c2d44948SJens Wiklander  *				asynchronous notifications.
51*c2d44948SJens Wiklander  *
52*c2d44948SJens Wiklander  * Once a driver has received a @NOTIF_EVENT_STARTED asynchronous notifications
53*c2d44948SJens Wiklander  * driving the @NOTIF_EVENT_DO_BOTTOM_HALF deliveries is enabled.
54*c2d44948SJens Wiklander  *
55*c2d44948SJens Wiklander  * In case a @NOTIF_EVENT_STOPPED is received there will be no more
56*c2d44948SJens Wiklander  * @NOTIF_EVENT_DO_BOTTOM_HALF events delivered, until @NOTIF_EVENT_STARTED
57*c2d44948SJens Wiklander  * has been delivered again.
58*c2d44948SJens Wiklander  *
59*c2d44948SJens Wiklander  * Note that while a @NOTIF_EVENT_STOPPED is being delivered at the same
60*c2d44948SJens Wiklander  * time may a @NOTIF_EVENT_STARTED be delivered again so a driver is
61*c2d44948SJens Wiklander  * required to sychronize accesses to its internal state.
62*c2d44948SJens Wiklander  */
63*c2d44948SJens Wiklander enum notif_event {
64*c2d44948SJens Wiklander 	NOTIF_EVENT_STARTED,
65*c2d44948SJens Wiklander 	NOTIF_EVENT_DO_BOTTOM_HALF,
66*c2d44948SJens Wiklander 	NOTIF_EVENT_STOPPED,
67*c2d44948SJens Wiklander };
68*c2d44948SJens Wiklander 
69*c2d44948SJens Wiklander /*
70*c2d44948SJens Wiklander  * struct notif_driver - Registration of driver notification
71*c2d44948SJens Wiklander  * @atomic_cb:	 A callback called in an atomic context from
72*c2d44948SJens Wiklander  *		 notif_deliver_atomic_event(). Currently only used to
73*c2d44948SJens Wiklander  *		 signal @NOTIF_EVENT_STARTED.
74*c2d44948SJens Wiklander  * @yielding_cb: A callback called in a yielding context from
75*c2d44948SJens Wiklander  *		 notif_deliver_event(). Currently only used to signal
76*c2d44948SJens Wiklander  *		 @NOTIF_EVENT_DO_BOTTOM_HALF and @NOTIF_EVENT_STOPPED.
77*c2d44948SJens Wiklander  *
78*c2d44948SJens Wiklander  * A atomic context means that interrupts are masked and a common spinlock
79*c2d44948SJens Wiklander  * is held. Calls via @atomic_cb are only atomic with regards to each
80*c2d44948SJens Wiklander  * other, other CPUs may execute yielding calls or even receive interrupts.
81*c2d44948SJens Wiklander  *
82*c2d44948SJens Wiklander  * A yielding context means that the function is executing in a normal
83*c2d44948SJens Wiklander  * threaded context allowing RPC and synchronization with other thread
84*c2d44948SJens Wiklander  * using mutexes and condition variables.
85*c2d44948SJens Wiklander  */
86*c2d44948SJens Wiklander struct notif_driver {
87*c2d44948SJens Wiklander 	void (*atomic_cb)(struct notif_driver *ndrv, enum notif_event ev);
88*c2d44948SJens Wiklander 	void (*yielding_cb)(struct notif_driver *ndrv, enum notif_event ev);
89*c2d44948SJens Wiklander 	SLIST_ENTRY(notif_driver) link;
90*c2d44948SJens Wiklander };
91*c2d44948SJens Wiklander 
92*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
93*c2d44948SJens Wiklander bool notif_async_is_started(void);
94*c2d44948SJens Wiklander #else
95*c2d44948SJens Wiklander static inline bool notif_async_is_started(void)
96*c2d44948SJens Wiklander {
97*c2d44948SJens Wiklander 	return false;
98*c2d44948SJens Wiklander }
99*c2d44948SJens Wiklander #endif
100*c2d44948SJens Wiklander 
101*c2d44948SJens Wiklander TEE_Result notif_alloc_async_value(uint32_t *value);
102*c2d44948SJens Wiklander void notif_free_async_value(uint32_t value);
103*c2d44948SJens Wiklander 
104*c2d44948SJens Wiklander /*
105*c2d44948SJens Wiklander  * Wait in normal world for a value to be sent by notif_send()
1062828809eSJens Wiklander  */
1072828809eSJens Wiklander TEE_Result notif_wait(uint32_t value);
1082828809eSJens Wiklander 
1092828809eSJens Wiklander /*
110*c2d44948SJens Wiklander  * Send an asynchronous value, note that it must be <= NOTIF_ASYNC_VALUE_MAX
111*c2d44948SJens Wiklander  */
112*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
113*c2d44948SJens Wiklander void notif_send_async(uint32_t value);
114*c2d44948SJens Wiklander #else
115*c2d44948SJens Wiklander static inline void notif_send_async(uint32_t value __unused)
116*c2d44948SJens Wiklander {
117*c2d44948SJens Wiklander }
118*c2d44948SJens Wiklander #endif
119*c2d44948SJens Wiklander 
120*c2d44948SJens Wiklander /*
121*c2d44948SJens Wiklander  * Send a sychronous value, note that it must be <= NOTIF_VALUE_MAX. The
122*c2d44948SJens Wiklander  * notification is synchronous even if the value happens to belong in the
123*c2d44948SJens Wiklander  * asynchronous range.
1242828809eSJens Wiklander  */
1252828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value);
1262828809eSJens Wiklander 
127*c2d44948SJens Wiklander /*
128*c2d44948SJens Wiklander  * Called by device drivers.
129*c2d44948SJens Wiklander  */
130*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
131*c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv);
132*c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv);
133*c2d44948SJens Wiklander #else
134*c2d44948SJens Wiklander static inline void notif_register_driver(struct notif_driver *ndrv __unused)
135*c2d44948SJens Wiklander {
136*c2d44948SJens Wiklander }
137*c2d44948SJens Wiklander 
138*c2d44948SJens Wiklander static inline void notif_unregister_driver(struct notif_driver *ndrv __unused)
139*c2d44948SJens Wiklander {
140*c2d44948SJens Wiklander }
141*c2d44948SJens Wiklander #endif
142*c2d44948SJens Wiklander 
143*c2d44948SJens Wiklander /* This is called from a fast call */
144*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
145*c2d44948SJens Wiklander uint32_t notif_get_value(bool *value_valid, bool *value_pending);
146*c2d44948SJens Wiklander #else
147*c2d44948SJens Wiklander static inline uint32_t notif_get_value(bool *value_valid, bool *value_pending)
148*c2d44948SJens Wiklander {
149*c2d44948SJens Wiklander 	*value_valid = false;
150*c2d44948SJens Wiklander 	*value_pending = false;
151*c2d44948SJens Wiklander 	return UINT32_MAX;
152*c2d44948SJens Wiklander }
153*c2d44948SJens Wiklander #endif
154*c2d44948SJens Wiklander 
155*c2d44948SJens Wiklander /*
156*c2d44948SJens Wiklander  * These are called from yielding calls
157*c2d44948SJens Wiklander  */
158*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
159*c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev);
160*c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev);
161*c2d44948SJens Wiklander #else
162*c2d44948SJens Wiklander static inline void notif_deliver_atomic_event(enum notif_event ev __unused)
163*c2d44948SJens Wiklander {
164*c2d44948SJens Wiklander }
165*c2d44948SJens Wiklander 
166*c2d44948SJens Wiklander static inline void notif_deliver_event(enum notif_event ev __unused)
167*c2d44948SJens Wiklander {
168*c2d44948SJens Wiklander }
169*c2d44948SJens Wiklander #endif
170*c2d44948SJens Wiklander 
1712828809eSJens Wiklander #endif /*__KERNEL_NOTIF_H*/
172