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