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 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 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 147 static inline void notif_register_driver(struct notif_driver *ndrv __unused) 148 { 149 } 150 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 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 172 static inline void notif_deliver_atomic_event(enum notif_event ev __unused, 173 uint16_t guest_id __unused) 174 { 175 } 176 static inline void notif_deliver_event(enum notif_event ev __unused) 177 { 178 } 179 #endif 180 181 #endif /*__KERNEL_NOTIF_H*/ 182