1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021, Linaro Limited 4 */ 5 6 #include <bitstring.h> 7 #include <drivers/gic.h> 8 #include <kernel/interrupt.h> 9 #include <kernel/mutex.h> 10 #include <kernel/notif.h> 11 #include <kernel/spinlock.h> 12 #include <kernel/thread.h> 13 #include <optee_rpc_cmd.h> 14 #include <types_ext.h> 15 16 #if defined(CFG_CORE_ASYNC_NOTIF) 17 static struct mutex notif_mutex = MUTEX_INITIALIZER; 18 static unsigned int notif_lock = SPINLOCK_UNLOCK; 19 20 SLIST_HEAD(notif_driver_head, notif_driver); 21 static struct notif_driver_head notif_driver_head = 22 SLIST_HEAD_INITIALIZER(¬if_driver_head); 23 24 static bitstr_t bit_decl(notif_values, NOTIF_ASYNC_VALUE_MAX + 1); 25 static bitstr_t bit_decl(notif_alloc_values, NOTIF_ASYNC_VALUE_MAX + 1); 26 static bool notif_started; 27 28 TEE_Result notif_alloc_async_value(uint32_t *val) 29 { 30 static bool alloc_values_inited; 31 uint32_t old_itr_status = 0; 32 int bit = 0; 33 34 assert(interrupt_can_raise_pi(interrupt_get_main_chip())); 35 36 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 37 38 if (!alloc_values_inited) { 39 bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF); 40 alloc_values_inited = true; 41 } 42 43 bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 44 if (bit >= 0) { 45 *val = bit; 46 bit_set(notif_alloc_values, bit); 47 } 48 49 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 50 51 if (bit < 0) 52 return TEE_ERROR_OUT_OF_MEMORY; 53 54 return TEE_SUCCESS; 55 } 56 57 void notif_free_async_value(uint32_t val) 58 { 59 uint32_t old_itr_status = 0; 60 61 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 62 63 assert(val < NOTIF_ASYNC_VALUE_MAX); 64 assert(bit_test(notif_alloc_values, val)); 65 bit_clear(notif_alloc_values, val); 66 67 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 68 } 69 70 uint32_t notif_get_value(bool *value_valid, bool *value_pending) 71 { 72 uint32_t old_itr_status = 0; 73 uint32_t res = 0; 74 int bit = 0; 75 76 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 77 78 bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 79 *value_valid = (bit >= 0); 80 if (!*value_valid) { 81 *value_pending = false; 82 goto out; 83 } 84 85 res = bit; 86 bit_clear(notif_values, res); 87 bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 88 *value_pending = (bit >= 0); 89 out: 90 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 91 92 return res; 93 } 94 95 void notif_send_async(uint32_t value) 96 { 97 uint32_t old_itr_status = 0; 98 struct itr_chip *itr_chip = interrupt_get_main_chip(); 99 100 static_assert(CFG_CORE_ASYNC_NOTIF_GIC_INTID >= GIC_PPI_BASE); 101 102 assert(value <= NOTIF_ASYNC_VALUE_MAX); 103 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 104 105 DMSG("0x%"PRIx32, value); 106 bit_set(notif_values, value); 107 interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID); 108 109 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 110 } 111 112 bool notif_async_is_started(void) 113 { 114 uint32_t old_itr_status = 0; 115 bool ret = false; 116 117 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 118 ret = notif_started; 119 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 120 121 return ret; 122 } 123 124 void notif_register_driver(struct notif_driver *ndrv) 125 { 126 uint32_t old_itr_status = 0; 127 128 assert(interrupt_can_raise_pi(interrupt_get_main_chip())); 129 130 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 131 132 SLIST_INSERT_HEAD(¬if_driver_head, ndrv, link); 133 134 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 135 } 136 137 void notif_unregister_driver(struct notif_driver *ndrv) 138 { 139 uint32_t old_itr_status = 0; 140 141 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 142 143 SLIST_REMOVE(¬if_driver_head, ndrv, notif_driver, link); 144 145 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 146 } 147 148 void notif_deliver_atomic_event(enum notif_event ev) 149 { 150 uint32_t old_itr_status = 0; 151 struct notif_driver *nd = NULL; 152 153 assert(ev == NOTIF_EVENT_STARTED); 154 155 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 156 157 if (notif_started) { 158 DMSG("Already started"); 159 goto out; 160 } 161 notif_started = true; 162 163 SLIST_FOREACH(nd, ¬if_driver_head, link) 164 if (nd->atomic_cb) 165 nd->atomic_cb(nd, ev); 166 167 out: 168 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 169 } 170 171 void notif_deliver_event(enum notif_event ev) 172 { 173 uint32_t old_itr_status = 0; 174 struct notif_driver *nd = NULL; 175 struct notif_driver *nd_tmp = NULL; 176 177 assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED); 178 179 /* Serialize all yielding notifications */ 180 mutex_lock(¬if_mutex); 181 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 182 183 if (!notif_started) { 184 DMSG("Not started ev %d", (int)ev); 185 goto out; 186 } 187 188 if (ev == NOTIF_EVENT_STOPPED) 189 notif_started = false; 190 191 SLIST_FOREACH_SAFE(nd, ¬if_driver_head, link, nd_tmp) { 192 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 193 194 if (nd->yielding_cb) 195 nd->yielding_cb(nd, ev); 196 197 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 198 199 if (ev == NOTIF_EVENT_STOPPED && notif_started) { 200 DMSG("Started again while stopping"); 201 goto out; 202 } 203 } 204 205 out: 206 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 207 mutex_unlock(¬if_mutex); 208 } 209 #endif /*CFG_CORE_ASYNC_NOTIF*/ 210 211 static TEE_Result notif_rpc(uint32_t func, uint32_t value) 212 { 213 struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0); 214 215 return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, ¶ms); 216 } 217 218 TEE_Result notif_wait(uint32_t value) 219 { 220 return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value); 221 } 222 223 TEE_Result notif_send_sync(uint32_t value) 224 { 225 return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value); 226 } 227