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 };
68 
69 /*
70  * struct notif_driver - Registration of driver notification
71  * @atomic_cb:	 A callback called in an atomic context from
72  *		 notif_deliver_atomic_event(). Currently only used to
73  *		 signal @NOTIF_EVENT_STARTED.
74  * @yielding_cb: A callback called in a yielding context from
75  *		 notif_deliver_event(). Currently only used to signal
76  *		 @NOTIF_EVENT_DO_BOTTOM_HALF and @NOTIF_EVENT_STOPPED.
77  *
78  * A atomic context means that interrupts are masked and a common spinlock
79  * is held. Calls via @atomic_cb are only atomic with regards to each
80  * other, other CPUs may execute yielding calls or even receive interrupts.
81  *
82  * A yielding context means that the function is executing in a normal
83  * threaded context allowing RPC and synchronization with other thread
84  * using mutexes and condition variables.
85  */
86 struct notif_driver {
87 	void (*atomic_cb)(struct notif_driver *ndrv, enum notif_event ev);
88 	void (*yielding_cb)(struct notif_driver *ndrv, enum notif_event ev);
89 	SLIST_ENTRY(notif_driver) link;
90 };
91 
92 #if defined(CFG_CORE_ASYNC_NOTIF)
93 bool notif_async_is_started(void);
94 #else
notif_async_is_started(void)95 static inline bool notif_async_is_started(void)
96 {
97 	return false;
98 }
99 #endif
100 
101 TEE_Result notif_alloc_async_value(uint32_t *value);
102 void notif_free_async_value(uint32_t value);
103 
104 /*
105  * Wait in normal world for a value to be sent by notif_send()
106  */
107 TEE_Result notif_wait(uint32_t value);
108 
109 /*
110  * Send an asynchronous value, note that it must be <= NOTIF_ASYNC_VALUE_MAX
111  */
112 #if defined(CFG_CORE_ASYNC_NOTIF)
113 void notif_send_async(uint32_t value);
114 #else
notif_send_async(uint32_t value __unused)115 static inline void notif_send_async(uint32_t value __unused)
116 {
117 }
118 #endif
119 
120 /*
121  * Send a sychronous value, note that it must be <= NOTIF_VALUE_MAX. The
122  * notification is synchronous even if the value happens to belong in the
123  * asynchronous range.
124  */
125 TEE_Result notif_send_sync(uint32_t value);
126 
127 /*
128  * Called by device drivers.
129  */
130 #if defined(CFG_CORE_ASYNC_NOTIF)
131 void notif_register_driver(struct notif_driver *ndrv);
132 void notif_unregister_driver(struct notif_driver *ndrv);
133 #else
notif_register_driver(struct notif_driver * ndrv __unused)134 static inline void notif_register_driver(struct notif_driver *ndrv __unused)
135 {
136 }
137 
notif_unregister_driver(struct notif_driver * ndrv __unused)138 static inline void notif_unregister_driver(struct notif_driver *ndrv __unused)
139 {
140 }
141 #endif
142 
143 /* This is called from a fast call */
144 #if defined(CFG_CORE_ASYNC_NOTIF)
145 uint32_t notif_get_value(bool *value_valid, bool *value_pending);
146 #else
notif_get_value(bool * value_valid,bool * value_pending)147 static inline uint32_t notif_get_value(bool *value_valid, bool *value_pending)
148 {
149 	*value_valid = false;
150 	*value_pending = false;
151 	return UINT32_MAX;
152 }
153 #endif
154 
155 /*
156  * These are called from yielding calls
157  */
158 #if defined(CFG_CORE_ASYNC_NOTIF)
159 void notif_deliver_atomic_event(enum notif_event ev);
160 void notif_deliver_event(enum notif_event ev);
161 #else
notif_deliver_atomic_event(enum notif_event ev __unused)162 static inline void notif_deliver_atomic_event(enum notif_event ev __unused)
163 {
164 }
165 
notif_deliver_event(enum notif_event ev __unused)166 static inline void notif_deliver_event(enum notif_event ev __unused)
167 {
168 }
169 #endif
170 
171 #endif /*__KERNEL_NOTIF_H*/
172