xref: /optee_os/core/kernel/notif.c (revision 79f8990d9d28539864d8f97f9f1cb32e289e595f)
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(&notif_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(&notif_lock);
29 	ret = notif_started;
30 	cpu_spin_unlock_xrestore(&notif_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(&notif_lock);
40 
41 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
42 
43 	cpu_spin_unlock_xrestore(&notif_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(&notif_lock);
51 
52 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
53 
54 	cpu_spin_unlock_xrestore(&notif_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(&notif_lock);
65 
66 	if (notif_started) {
67 		DMSG("Already started");
68 		goto out;
69 	}
70 	notif_started = true;
71 
72 	SLIST_FOREACH(nd, &notif_driver_head, link)
73 		if (nd->atomic_cb)
74 			nd->atomic_cb(nd, ev);
75 
76 out:
77 	cpu_spin_unlock_xrestore(&notif_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(&notif_mutex);
90 	old_itr_status = cpu_spin_lock_xsave(&notif_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, &notif_driver_head, link, nd_tmp) {
101 		cpu_spin_unlock_xrestore(&notif_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(&notif_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(&notif_lock, old_itr_status);
116 	mutex_unlock(&notif_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, &params);
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