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