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 34*da637b6bSEtienne Carriere assert(interrupt_can_raise_pi(interrupt_get_main_chip())); 35*da637b6bSEtienne Carriere 36c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 37c2d44948SJens Wiklander 38c2d44948SJens Wiklander if (!alloc_values_inited) { 39c2d44948SJens Wiklander bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF); 40c2d44948SJens Wiklander alloc_values_inited = true; 41c2d44948SJens Wiklander } 42c2d44948SJens Wiklander 43c2d44948SJens Wiklander bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 44c2d44948SJens Wiklander if (bit >= 0) { 45c2d44948SJens Wiklander *val = bit; 46c2d44948SJens Wiklander bit_set(notif_alloc_values, bit); 47c2d44948SJens Wiklander } 48c2d44948SJens Wiklander 49c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 50c2d44948SJens Wiklander 51c2d44948SJens Wiklander if (bit < 0) 52c2d44948SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 53c2d44948SJens Wiklander 54c2d44948SJens Wiklander return TEE_SUCCESS; 55c2d44948SJens Wiklander } 56c2d44948SJens Wiklander 57c2d44948SJens Wiklander void notif_free_async_value(uint32_t val) 58c2d44948SJens Wiklander { 59c2d44948SJens Wiklander uint32_t old_itr_status = 0; 60c2d44948SJens Wiklander 61c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 62c2d44948SJens Wiklander 63c2d44948SJens Wiklander assert(val < NOTIF_ASYNC_VALUE_MAX); 64c2d44948SJens Wiklander assert(bit_test(notif_alloc_values, val)); 65c2d44948SJens Wiklander bit_clear(notif_alloc_values, val); 66c2d44948SJens Wiklander 67c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 68c2d44948SJens Wiklander } 69c2d44948SJens Wiklander 70c2d44948SJens Wiklander uint32_t notif_get_value(bool *value_valid, bool *value_pending) 71c2d44948SJens Wiklander { 72c2d44948SJens Wiklander uint32_t old_itr_status = 0; 73c2d44948SJens Wiklander uint32_t res = 0; 74c2d44948SJens Wiklander int bit = 0; 75c2d44948SJens Wiklander 76c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 77c2d44948SJens Wiklander 78c2d44948SJens Wiklander bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 79c2d44948SJens Wiklander *value_valid = (bit >= 0); 80c2d44948SJens Wiklander if (!*value_valid) { 81c2d44948SJens Wiklander *value_pending = false; 82c2d44948SJens Wiklander goto out; 83c2d44948SJens Wiklander } 84c2d44948SJens Wiklander 85c2d44948SJens Wiklander res = bit; 86c2d44948SJens Wiklander bit_clear(notif_values, res); 87c2d44948SJens Wiklander bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit); 88c2d44948SJens Wiklander *value_pending = (bit >= 0); 89c2d44948SJens Wiklander out: 90c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 91c2d44948SJens Wiklander 92c2d44948SJens Wiklander return res; 93c2d44948SJens Wiklander } 94c2d44948SJens Wiklander 95c2d44948SJens Wiklander void notif_send_async(uint32_t value) 96c2d44948SJens Wiklander { 97c2d44948SJens Wiklander uint32_t old_itr_status = 0; 98*da637b6bSEtienne Carriere struct itr_chip *itr_chip = interrupt_get_main_chip(); 99c2d44948SJens Wiklander 10094397285SEtienne Carriere static_assert(CFG_CORE_ASYNC_NOTIF_GIC_INTID >= GIC_PPI_BASE); 101c2d44948SJens Wiklander 102c2d44948SJens Wiklander assert(value <= NOTIF_ASYNC_VALUE_MAX); 103c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 104c2d44948SJens Wiklander 105c2d44948SJens Wiklander DMSG("0x%"PRIx32, value); 106c2d44948SJens Wiklander bit_set(notif_values, value); 107*da637b6bSEtienne Carriere interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID); 108c2d44948SJens Wiklander 109c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 110c2d44948SJens Wiklander } 111c2d44948SJens Wiklander 112c2d44948SJens Wiklander bool notif_async_is_started(void) 113c2d44948SJens Wiklander { 114c2d44948SJens Wiklander uint32_t old_itr_status = 0; 115c2d44948SJens Wiklander bool ret = false; 116c2d44948SJens Wiklander 117c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 118c2d44948SJens Wiklander ret = notif_started; 119c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 120c2d44948SJens Wiklander 121c2d44948SJens Wiklander return ret; 122c2d44948SJens Wiklander } 123c2d44948SJens Wiklander 124c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv) 125c2d44948SJens Wiklander { 126c2d44948SJens Wiklander uint32_t old_itr_status = 0; 127c2d44948SJens Wiklander 128*da637b6bSEtienne Carriere assert(interrupt_can_raise_pi(interrupt_get_main_chip())); 129*da637b6bSEtienne Carriere 130c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 131c2d44948SJens Wiklander 132c2d44948SJens Wiklander SLIST_INSERT_HEAD(¬if_driver_head, ndrv, link); 133c2d44948SJens Wiklander 134c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 135c2d44948SJens Wiklander } 136c2d44948SJens Wiklander 137c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv) 138c2d44948SJens Wiklander { 139c2d44948SJens Wiklander uint32_t old_itr_status = 0; 140c2d44948SJens Wiklander 141c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 142c2d44948SJens Wiklander 143c2d44948SJens Wiklander SLIST_REMOVE(¬if_driver_head, ndrv, notif_driver, link); 144c2d44948SJens Wiklander 145c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 146c2d44948SJens Wiklander } 147c2d44948SJens Wiklander 148c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev) 149c2d44948SJens Wiklander { 150c2d44948SJens Wiklander uint32_t old_itr_status = 0; 151c2d44948SJens Wiklander struct notif_driver *nd = NULL; 152c2d44948SJens Wiklander 153c2d44948SJens Wiklander assert(ev == NOTIF_EVENT_STARTED); 154c2d44948SJens Wiklander 155c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 156c2d44948SJens Wiklander 157c2d44948SJens Wiklander if (notif_started) { 158c2d44948SJens Wiklander DMSG("Already started"); 159c2d44948SJens Wiklander goto out; 160c2d44948SJens Wiklander } 161c2d44948SJens Wiklander notif_started = true; 162c2d44948SJens Wiklander 163c2d44948SJens Wiklander SLIST_FOREACH(nd, ¬if_driver_head, link) 164c2d44948SJens Wiklander if (nd->atomic_cb) 165c2d44948SJens Wiklander nd->atomic_cb(nd, ev); 166c2d44948SJens Wiklander 167c2d44948SJens Wiklander out: 168c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 169c2d44948SJens Wiklander } 170c2d44948SJens Wiklander 171c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev) 172c2d44948SJens Wiklander { 173c2d44948SJens Wiklander uint32_t old_itr_status = 0; 174c2d44948SJens Wiklander struct notif_driver *nd = NULL; 175c2d44948SJens Wiklander struct notif_driver *nd_tmp = NULL; 176c2d44948SJens Wiklander 177c2d44948SJens Wiklander assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED); 178c2d44948SJens Wiklander 179c2d44948SJens Wiklander /* Serialize all yielding notifications */ 180c2d44948SJens Wiklander mutex_lock(¬if_mutex); 181c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 182c2d44948SJens Wiklander 183c2d44948SJens Wiklander if (!notif_started) { 184c2d44948SJens Wiklander DMSG("Not started ev %d", (int)ev); 185c2d44948SJens Wiklander goto out; 186c2d44948SJens Wiklander } 187c2d44948SJens Wiklander 188c2d44948SJens Wiklander if (ev == NOTIF_EVENT_STOPPED) 189c2d44948SJens Wiklander notif_started = false; 190c2d44948SJens Wiklander 191c2d44948SJens Wiklander SLIST_FOREACH_SAFE(nd, ¬if_driver_head, link, nd_tmp) { 192c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 193c2d44948SJens Wiklander 194c2d44948SJens Wiklander if (nd->yielding_cb) 195c2d44948SJens Wiklander nd->yielding_cb(nd, ev); 196c2d44948SJens Wiklander 197c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 198c2d44948SJens Wiklander 199c2d44948SJens Wiklander if (ev == NOTIF_EVENT_STOPPED && notif_started) { 200c2d44948SJens Wiklander DMSG("Started again while stopping"); 201c2d44948SJens Wiklander goto out; 202c2d44948SJens Wiklander } 203c2d44948SJens Wiklander } 204c2d44948SJens Wiklander 205c2d44948SJens Wiklander out: 206c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 207c2d44948SJens Wiklander mutex_unlock(¬if_mutex); 208c2d44948SJens Wiklander } 209c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/ 210c2d44948SJens Wiklander 2112828809eSJens Wiklander static TEE_Result notif_rpc(uint32_t func, uint32_t value) 2122828809eSJens Wiklander { 2132828809eSJens Wiklander struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0); 2142828809eSJens Wiklander 2152828809eSJens Wiklander return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, ¶ms); 2162828809eSJens Wiklander } 2172828809eSJens Wiklander 2182828809eSJens Wiklander TEE_Result notif_wait(uint32_t value) 2192828809eSJens Wiklander { 2202828809eSJens Wiklander return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value); 2212828809eSJens Wiklander } 2222828809eSJens Wiklander 2232828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value) 2242828809eSJens Wiklander { 2252828809eSJens Wiklander return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value); 2262828809eSJens Wiklander } 227