1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021-2023, Linaro Limited 4 */ 5 6 #include <kernel/mutex.h> 7 #include <kernel/notif.h> 8 #include <kernel/spinlock.h> 9 #include <kernel/thread.h> 10 #include <optee_rpc_cmd.h> 11 #include <types_ext.h> 12 13 #if defined(CFG_CORE_ASYNC_NOTIF) 14 static struct mutex notif_mutex = MUTEX_INITIALIZER; 15 static unsigned int notif_lock = SPINLOCK_UNLOCK; 16 static bool notif_started; 17 18 SLIST_HEAD(notif_driver_head, notif_driver); 19 static struct notif_driver_head notif_driver_head = 20 SLIST_HEAD_INITIALIZER(¬if_driver_head); 21 22 23 bool notif_async_is_started(void) 24 { 25 uint32_t old_itr_status = 0; 26 bool ret = false; 27 28 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 29 ret = notif_started; 30 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 31 32 return ret; 33 } 34 35 void notif_register_driver(struct notif_driver *ndrv) 36 { 37 uint32_t old_itr_status = 0; 38 39 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 40 41 SLIST_INSERT_HEAD(¬if_driver_head, ndrv, link); 42 43 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 44 } 45 46 void notif_unregister_driver(struct notif_driver *ndrv) 47 { 48 uint32_t old_itr_status = 0; 49 50 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 51 52 SLIST_REMOVE(¬if_driver_head, ndrv, notif_driver, link); 53 54 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 55 } 56 57 void notif_deliver_atomic_event(enum notif_event ev) 58 { 59 uint32_t old_itr_status = 0; 60 struct notif_driver *nd = NULL; 61 62 assert(ev == NOTIF_EVENT_STARTED); 63 64 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 65 66 if (notif_started) { 67 DMSG("Already started"); 68 goto out; 69 } 70 notif_started = true; 71 72 SLIST_FOREACH(nd, ¬if_driver_head, link) 73 if (nd->atomic_cb) 74 nd->atomic_cb(nd, ev); 75 76 out: 77 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 78 } 79 80 void notif_deliver_event(enum notif_event ev) 81 { 82 uint32_t old_itr_status = 0; 83 struct notif_driver *nd = NULL; 84 struct notif_driver *nd_tmp = NULL; 85 86 assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED); 87 88 /* Serialize all yielding notifications */ 89 mutex_lock(¬if_mutex); 90 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 91 92 if (!notif_started) { 93 DMSG("Not started ev %d", (int)ev); 94 goto out; 95 } 96 97 if (ev == NOTIF_EVENT_STOPPED) 98 notif_started = false; 99 100 SLIST_FOREACH_SAFE(nd, ¬if_driver_head, link, nd_tmp) { 101 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 102 103 if (nd->yielding_cb) 104 nd->yielding_cb(nd, ev); 105 106 old_itr_status = cpu_spin_lock_xsave(¬if_lock); 107 108 if (ev == NOTIF_EVENT_STOPPED && notif_started) { 109 DMSG("Started again while stopping"); 110 goto out; 111 } 112 } 113 114 out: 115 cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 116 mutex_unlock(¬if_mutex); 117 } 118 #endif /*CFG_CORE_ASYNC_NOTIF*/ 119 120 static TEE_Result notif_rpc(uint32_t func, uint32_t value) 121 { 122 struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0); 123 124 return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, ¶ms); 125 } 126 127 TEE_Result notif_wait(uint32_t value) 128 { 129 return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value); 130 } 131 132 TEE_Result notif_send_sync(uint32_t value) 133 { 134 return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value); 135 } 136