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 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 * Wait timeout in normal world for a value to be sent by notif_send() 111 */ 112 TEE_Result notif_wait_timeout(uint32_t value, uint32_t timeout_ms); 113 114 /* 115 * Send an asynchronous value, note that it must be <= NOTIF_ASYNC_VALUE_MAX 116 */ 117 #if defined(CFG_CORE_ASYNC_NOTIF) 118 void notif_send_async(uint32_t value); 119 #else 120 static inline void notif_send_async(uint32_t value __unused) 121 { 122 } 123 #endif 124 125 /* 126 * Send a sychronous value, note that it must be <= NOTIF_VALUE_MAX. The 127 * notification is synchronous even if the value happens to belong in the 128 * asynchronous range. 129 */ 130 TEE_Result notif_send_sync(uint32_t value); 131 132 /* 133 * Called by device drivers. 134 */ 135 #if defined(CFG_CORE_ASYNC_NOTIF) 136 void notif_register_driver(struct notif_driver *ndrv); 137 void notif_unregister_driver(struct notif_driver *ndrv); 138 #else 139 static inline void notif_register_driver(struct notif_driver *ndrv __unused) 140 { 141 } 142 143 static inline void notif_unregister_driver(struct notif_driver *ndrv __unused) 144 { 145 } 146 #endif 147 148 /* This is called from a fast call */ 149 #if defined(CFG_CORE_ASYNC_NOTIF) 150 uint32_t notif_get_value(bool *value_valid, bool *value_pending); 151 #else 152 static inline uint32_t notif_get_value(bool *value_valid, bool *value_pending) 153 { 154 *value_valid = false; 155 *value_pending = false; 156 return UINT32_MAX; 157 } 158 #endif 159 160 /* 161 * These are called from yielding calls 162 */ 163 #if defined(CFG_CORE_ASYNC_NOTIF) 164 void notif_deliver_atomic_event(enum notif_event ev); 165 void notif_deliver_event(enum notif_event ev); 166 #else 167 static inline void notif_deliver_atomic_event(enum notif_event ev __unused) 168 { 169 } 170 171 static inline void notif_deliver_event(enum notif_event ev __unused) 172 { 173 } 174 #endif 175 176 #endif /*__KERNEL_NOTIF_H*/ 177