12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 22828809eSJens Wiklander /* 3a2a3dfbcSJens Wiklander * Copyright (c) 2021-2023, Linaro Limited 42828809eSJens Wiklander */ 52828809eSJens Wiklander 6c2d44948SJens Wiklander #include <kernel/mutex.h> 72828809eSJens Wiklander #include <kernel/notif.h> 8c2d44948SJens Wiklander #include <kernel/spinlock.h> 92828809eSJens Wiklander #include <kernel/thread.h> 104199b52fSJens Wiklander #include <mm/core_memprot.h> 112828809eSJens Wiklander #include <optee_rpc_cmd.h> 122828809eSJens Wiklander #include <types_ext.h> 132828809eSJens Wiklander 14c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF) 15c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER; 164199b52fSJens Wiklander static unsigned int notif_lock __nex_data = SPINLOCK_UNLOCK; 17a2a3dfbcSJens Wiklander static bool notif_started; 18c2d44948SJens Wiklander 19c2d44948SJens Wiklander SLIST_HEAD(notif_driver_head, notif_driver); 204199b52fSJens Wiklander static struct notif_driver_head notif_driver_head __nex_data = 21c2d44948SJens Wiklander SLIST_HEAD_INITIALIZER(¬if_driver_head); 22c2d44948SJens Wiklander 23c2d44948SJens Wiklander 24c2d44948SJens Wiklander bool notif_async_is_started(void) 25c2d44948SJens Wiklander { 26c2d44948SJens Wiklander uint32_t old_itr_status = 0; 27c2d44948SJens Wiklander bool ret = false; 28c2d44948SJens Wiklander 29c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 30c2d44948SJens Wiklander ret = notif_started; 31c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 32c2d44948SJens Wiklander 33c2d44948SJens Wiklander return ret; 34c2d44948SJens Wiklander } 35c2d44948SJens Wiklander 36c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv) 37c2d44948SJens Wiklander { 38c2d44948SJens Wiklander uint32_t old_itr_status = 0; 39c2d44948SJens Wiklander 40*fc59f3d8SJens Wiklander assert(is_nexus(ndrv) && is_unpaged(ndrv->atomic_cb)); 414199b52fSJens Wiklander 42c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 43c2d44948SJens Wiklander 44c2d44948SJens Wiklander SLIST_INSERT_HEAD(¬if_driver_head, ndrv, link); 45c2d44948SJens Wiklander 46c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 47c2d44948SJens Wiklander } 48c2d44948SJens Wiklander 49c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv) 50c2d44948SJens Wiklander { 51c2d44948SJens Wiklander uint32_t old_itr_status = 0; 52c2d44948SJens Wiklander 53c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 54c2d44948SJens Wiklander 55c2d44948SJens Wiklander SLIST_REMOVE(¬if_driver_head, ndrv, notif_driver, link); 56c2d44948SJens Wiklander 57c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 58c2d44948SJens Wiklander } 59c2d44948SJens Wiklander 60c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev) 61c2d44948SJens Wiklander { 62c2d44948SJens Wiklander uint32_t old_itr_status = 0; 63c2d44948SJens Wiklander struct notif_driver *nd = NULL; 64c2d44948SJens Wiklander 65c2d44948SJens Wiklander assert(ev == NOTIF_EVENT_STARTED); 66c2d44948SJens Wiklander 67c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 68c2d44948SJens Wiklander 69c2d44948SJens Wiklander if (notif_started) { 70c2d44948SJens Wiklander DMSG("Already started"); 71c2d44948SJens Wiklander goto out; 72c2d44948SJens Wiklander } 73c2d44948SJens Wiklander notif_started = true; 74c2d44948SJens Wiklander 75c2d44948SJens Wiklander SLIST_FOREACH(nd, ¬if_driver_head, link) 76c2d44948SJens Wiklander if (nd->atomic_cb) 77c2d44948SJens Wiklander nd->atomic_cb(nd, ev); 78c2d44948SJens Wiklander 79c2d44948SJens Wiklander out: 80c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 81c2d44948SJens Wiklander } 82c2d44948SJens Wiklander 83c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev) 84c2d44948SJens Wiklander { 85c2d44948SJens Wiklander uint32_t old_itr_status = 0; 86c2d44948SJens Wiklander struct notif_driver *nd = NULL; 87c2d44948SJens Wiklander struct notif_driver *nd_tmp = NULL; 88c2d44948SJens Wiklander 89c2d44948SJens Wiklander assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED); 90c2d44948SJens Wiklander 91c2d44948SJens Wiklander /* Serialize all yielding notifications */ 92c2d44948SJens Wiklander mutex_lock(¬if_mutex); 93c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 94c2d44948SJens Wiklander 95c2d44948SJens Wiklander if (!notif_started) { 96c2d44948SJens Wiklander DMSG("Not started ev %d", (int)ev); 97c2d44948SJens Wiklander goto out; 98c2d44948SJens Wiklander } 99c2d44948SJens Wiklander 100c2d44948SJens Wiklander if (ev == NOTIF_EVENT_STOPPED) 101c2d44948SJens Wiklander notif_started = false; 102c2d44948SJens Wiklander 103c2d44948SJens Wiklander SLIST_FOREACH_SAFE(nd, ¬if_driver_head, link, nd_tmp) { 104c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 105c2d44948SJens Wiklander 106c2d44948SJens Wiklander if (nd->yielding_cb) 107c2d44948SJens Wiklander nd->yielding_cb(nd, ev); 108c2d44948SJens Wiklander 109c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 110c2d44948SJens Wiklander 111c2d44948SJens Wiklander if (ev == NOTIF_EVENT_STOPPED && notif_started) { 112c2d44948SJens Wiklander DMSG("Started again while stopping"); 113c2d44948SJens Wiklander goto out; 114c2d44948SJens Wiklander } 115c2d44948SJens Wiklander } 116c2d44948SJens Wiklander 117c2d44948SJens Wiklander out: 118c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 119c2d44948SJens Wiklander mutex_unlock(¬if_mutex); 120c2d44948SJens Wiklander } 121c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/ 122c2d44948SJens Wiklander 1232828809eSJens Wiklander static TEE_Result notif_rpc(uint32_t func, uint32_t value) 1242828809eSJens Wiklander { 1252828809eSJens Wiklander struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0); 1262828809eSJens Wiklander 1272828809eSJens Wiklander return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, ¶ms); 1282828809eSJens Wiklander } 1292828809eSJens Wiklander 1302828809eSJens Wiklander TEE_Result notif_wait(uint32_t value) 1312828809eSJens Wiklander { 1322828809eSJens Wiklander return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value); 1332828809eSJens Wiklander } 1342828809eSJens Wiklander 1352828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value) 1362828809eSJens Wiklander { 1372828809eSJens Wiklander return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value); 1382828809eSJens Wiklander } 139