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