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 * 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 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 134 static inline void notif_register_driver(struct notif_driver *ndrv __unused) 135 { 136 } 137 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 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 162 static inline void notif_deliver_atomic_event(enum notif_event ev __unused) 163 { 164 } 165 166 static inline void notif_deliver_event(enum notif_event ev __unused) 167 { 168 } 169 #endif 170 171 #endif /*__KERNEL_NOTIF_H*/ 172