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