xref: /optee_os/core/kernel/notif.c (revision fc59f3d86e9f22a3c1295714a86b9f2b571c8bb6)
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(&notif_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(&notif_lock);
30c2d44948SJens Wiklander 	ret = notif_started;
31c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_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(&notif_lock);
43c2d44948SJens Wiklander 
44c2d44948SJens Wiklander 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
45c2d44948SJens Wiklander 
46c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_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(&notif_lock);
54c2d44948SJens Wiklander 
55c2d44948SJens Wiklander 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
56c2d44948SJens Wiklander 
57c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_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(&notif_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, &notif_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(&notif_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(&notif_mutex);
93c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_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, &notif_driver_head, link, nd_tmp) {
104c2d44948SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_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(&notif_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(&notif_lock, old_itr_status);
119c2d44948SJens Wiklander 	mutex_unlock(&notif_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, &params);
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