12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 22828809eSJens Wiklander /* 3*d237e616SJens Wiklander * Copyright (c) 2021-2024, Linaro Limited 42828809eSJens Wiklander */ 52828809eSJens Wiklander 6*d237e616SJens Wiklander #include <initcall.h> 7c2d44948SJens Wiklander #include <kernel/mutex.h> 82828809eSJens Wiklander #include <kernel/notif.h> 9*d237e616SJens Wiklander #include <kernel/panic.h> 10c2d44948SJens Wiklander #include <kernel/spinlock.h> 112828809eSJens Wiklander #include <kernel/thread.h> 12*d237e616SJens Wiklander #include <kernel/virtualization.h> 134199b52fSJens Wiklander #include <mm/core_memprot.h> 142828809eSJens Wiklander #include <optee_rpc_cmd.h> 152828809eSJens Wiklander #include <types_ext.h> 162828809eSJens Wiklander 17c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF) 18*d237e616SJens Wiklander struct notif_data { 19*d237e616SJens Wiklander bool notif_started; 20*d237e616SJens Wiklander }; 21*d237e616SJens Wiklander 22c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER; 234199b52fSJens Wiklander static unsigned int notif_lock __nex_data = SPINLOCK_UNLOCK; 24*d237e616SJens Wiklander 25*d237e616SJens Wiklander static struct notif_data default_notif_data; 26*d237e616SJens Wiklander static unsigned int notif_data_id __nex_bss; 27c2d44948SJens Wiklander 28c2d44948SJens Wiklander SLIST_HEAD(notif_driver_head, notif_driver); 294199b52fSJens Wiklander static struct notif_driver_head notif_driver_head __nex_data = 30c2d44948SJens Wiklander SLIST_HEAD_INITIALIZER(¬if_driver_head); 31c2d44948SJens Wiklander 32*d237e616SJens Wiklander static struct notif_data *get_notif_data(struct guest_partition *prtn) 33c2d44948SJens Wiklander { 34*d237e616SJens Wiklander if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) { 35*d237e616SJens Wiklander assert(prtn); 36*d237e616SJens Wiklander return virt_get_guest_spec_data(prtn, notif_data_id); 37*d237e616SJens Wiklander } 38*d237e616SJens Wiklander return &default_notif_data; 39*d237e616SJens Wiklander } 40*d237e616SJens Wiklander 41*d237e616SJens Wiklander bool notif_async_is_started(uint16_t guest_id) 42*d237e616SJens Wiklander { 43*d237e616SJens Wiklander struct guest_partition *prtn = virt_get_guest(guest_id); 44c2d44948SJens Wiklander uint32_t old_itr_status = 0; 45c2d44948SJens Wiklander bool ret = false; 46c2d44948SJens Wiklander 47*d237e616SJens Wiklander if (!IS_ENABLED(CFG_NS_VIRTUALIZATION) || prtn) { 48*d237e616SJens Wiklander struct notif_data *ndata = get_notif_data(prtn); 49c2d44948SJens Wiklander 50*d237e616SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 51*d237e616SJens Wiklander ret = ndata->notif_started; 52*d237e616SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 53*d237e616SJens Wiklander } 54*d237e616SJens Wiklander 55*d237e616SJens Wiklander virt_put_guest(prtn); 56c2d44948SJens Wiklander return ret; 57c2d44948SJens Wiklander } 58c2d44948SJens Wiklander 59c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv) 60c2d44948SJens Wiklander { 61c2d44948SJens Wiklander uint32_t old_itr_status = 0; 62c2d44948SJens Wiklander 63fc59f3d8SJens Wiklander assert(is_nexus(ndrv) && is_unpaged(ndrv->atomic_cb)); 644199b52fSJens Wiklander 65c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 66c2d44948SJens Wiklander 67c2d44948SJens Wiklander SLIST_INSERT_HEAD(¬if_driver_head, ndrv, link); 68c2d44948SJens Wiklander 69c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 70c2d44948SJens Wiklander } 71c2d44948SJens Wiklander 72c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv) 73c2d44948SJens Wiklander { 74c2d44948SJens Wiklander uint32_t old_itr_status = 0; 75c2d44948SJens Wiklander 76c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 77c2d44948SJens Wiklander 78c2d44948SJens Wiklander SLIST_REMOVE(¬if_driver_head, ndrv, notif_driver, link); 79c2d44948SJens Wiklander 80c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 81c2d44948SJens Wiklander } 82c2d44948SJens Wiklander 83*d237e616SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev, uint16_t guest_id) 84c2d44948SJens Wiklander { 85*d237e616SJens Wiklander struct guest_partition *prtn = virt_get_guest(guest_id); 86*d237e616SJens Wiklander struct notif_data *ndata = get_notif_data(prtn); 87c2d44948SJens Wiklander struct notif_driver *nd = NULL; 88*d237e616SJens Wiklander uint32_t old_itr_status = 0; 89c2d44948SJens Wiklander 90c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 91c2d44948SJens Wiklander 92*d237e616SJens Wiklander switch (ev) { 93*d237e616SJens Wiklander case NOTIF_EVENT_STARTED: 94*d237e616SJens Wiklander if (ndata->notif_started) { 95c2d44948SJens Wiklander DMSG("Already started"); 96c2d44948SJens Wiklander goto out; 97c2d44948SJens Wiklander } 98*d237e616SJens Wiklander ndata->notif_started = true; 99*d237e616SJens Wiklander break; 100*d237e616SJens Wiklander case NOTIF_EVENT_SHUTDOWN: 101*d237e616SJens Wiklander break; 102*d237e616SJens Wiklander default: 103*d237e616SJens Wiklander EMSG("Unknown event %d", (int)ev); 104*d237e616SJens Wiklander panic(); 105*d237e616SJens Wiklander } 106c2d44948SJens Wiklander 107c2d44948SJens Wiklander SLIST_FOREACH(nd, ¬if_driver_head, link) 108c2d44948SJens Wiklander if (nd->atomic_cb) 109*d237e616SJens Wiklander nd->atomic_cb(nd, ev, guest_id); 110c2d44948SJens Wiklander 111c2d44948SJens Wiklander out: 112c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 113*d237e616SJens Wiklander virt_put_guest(prtn); 114c2d44948SJens Wiklander } 115c2d44948SJens Wiklander 116c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev) 117c2d44948SJens Wiklander { 118*d237e616SJens Wiklander struct guest_partition *prtn = virt_get_current_guest(); 119*d237e616SJens Wiklander struct notif_data *ndata = get_notif_data(prtn); 120c2d44948SJens Wiklander uint32_t old_itr_status = 0; 121c2d44948SJens Wiklander struct notif_driver *nd = NULL; 122c2d44948SJens Wiklander struct notif_driver *nd_tmp = NULL; 123c2d44948SJens Wiklander 124c2d44948SJens Wiklander assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED); 125c2d44948SJens Wiklander 126c2d44948SJens Wiklander /* Serialize all yielding notifications */ 127c2d44948SJens Wiklander mutex_lock(¬if_mutex); 128c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 129c2d44948SJens Wiklander 130*d237e616SJens Wiklander if (!ndata || !ndata->notif_started) { 131c2d44948SJens Wiklander DMSG("Not started ev %d", (int)ev); 132c2d44948SJens Wiklander goto out; 133c2d44948SJens Wiklander } 134c2d44948SJens Wiklander 135c2d44948SJens Wiklander if (ev == NOTIF_EVENT_STOPPED) 136*d237e616SJens Wiklander ndata->notif_started = false; 137c2d44948SJens Wiklander 138c2d44948SJens Wiklander SLIST_FOREACH_SAFE(nd, ¬if_driver_head, link, nd_tmp) { 139c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 140c2d44948SJens Wiklander 141c2d44948SJens Wiklander if (nd->yielding_cb) 142c2d44948SJens Wiklander nd->yielding_cb(nd, ev); 143c2d44948SJens Wiklander 144c2d44948SJens Wiklander old_itr_status = cpu_spin_lock_xsave(¬if_lock); 145c2d44948SJens Wiklander 146*d237e616SJens Wiklander if (ev == NOTIF_EVENT_STOPPED && ndata->notif_started) { 147c2d44948SJens Wiklander DMSG("Started again while stopping"); 148c2d44948SJens Wiklander goto out; 149c2d44948SJens Wiklander } 150c2d44948SJens Wiklander } 151c2d44948SJens Wiklander 152c2d44948SJens Wiklander out: 153c2d44948SJens Wiklander cpu_spin_unlock_xrestore(¬if_lock, old_itr_status); 154c2d44948SJens Wiklander mutex_unlock(¬if_mutex); 155*d237e616SJens Wiklander virt_put_guest(prtn); 156c2d44948SJens Wiklander } 157c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/ 158c2d44948SJens Wiklander 159450f8adaSGavin Liu static TEE_Result notif_rpc(uint32_t func, uint32_t value1, uint32_t value2) 1602828809eSJens Wiklander { 161450f8adaSGavin Liu struct thread_param params = 162450f8adaSGavin Liu THREAD_PARAM_VALUE(IN, func, value1, value2); 1632828809eSJens Wiklander 1642828809eSJens Wiklander return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, ¶ms); 1652828809eSJens Wiklander } 1662828809eSJens Wiklander 1672828809eSJens Wiklander TEE_Result notif_wait(uint32_t value) 1682828809eSJens Wiklander { 169450f8adaSGavin Liu return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, 0); 1702828809eSJens Wiklander } 1712828809eSJens Wiklander 1722828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value) 1732828809eSJens Wiklander { 174450f8adaSGavin Liu return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value, 0); 175450f8adaSGavin Liu } 176450f8adaSGavin Liu 177450f8adaSGavin Liu TEE_Result notif_wait_timeout(uint32_t value, uint32_t timeout_ms) 178450f8adaSGavin Liu { 179450f8adaSGavin Liu return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, timeout_ms); 1802828809eSJens Wiklander } 181*d237e616SJens Wiklander 182*d237e616SJens Wiklander #ifdef CFG_NS_VIRTUALIZATION 183*d237e616SJens Wiklander static TEE_Result nex_init_notif(void) 184*d237e616SJens Wiklander { 185*d237e616SJens Wiklander return virt_add_guest_spec_data(¬if_data_id, 186*d237e616SJens Wiklander sizeof(struct notif_data), NULL); 187*d237e616SJens Wiklander } 188*d237e616SJens Wiklander nex_early_init(nex_init_notif); 189*d237e616SJens Wiklander #endif 190