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