xref: /optee_os/core/kernel/notif_default.c (revision cb03400251f98aed22a2664509e3ed9e183800b0)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021-2023, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <bitstring.h>
8 #include <kernel/interrupt.h>
9 #include <kernel/notif.h>
10 #include <kernel/spinlock.h>
11 #include <trace.h>
12 #include <types_ext.h>
13 
14 static bitstr_t bit_decl(notif_values, NOTIF_ASYNC_VALUE_MAX + 1);
15 static bitstr_t bit_decl(notif_alloc_values, NOTIF_ASYNC_VALUE_MAX + 1);
16 static unsigned int notif_default_lock = SPINLOCK_UNLOCK;
17 
18 TEE_Result notif_alloc_async_value(uint32_t *val)
19 {
20 	static bool alloc_values_inited;
21 	uint32_t old_itr_status = 0;
22 	int bit = 0;
23 
24 	assert(interrupt_can_raise_pi(interrupt_get_main_chip()));
25 
26 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
27 
28 	if (!alloc_values_inited) {
29 		bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF);
30 		alloc_values_inited = true;
31 	}
32 
33 	bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
34 	if (bit >= 0) {
35 		*val = bit;
36 		bit_set(notif_alloc_values, bit);
37 	}
38 
39 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
40 
41 	if (bit < 0)
42 		return TEE_ERROR_OUT_OF_MEMORY;
43 
44 	return TEE_SUCCESS;
45 }
46 
47 void notif_free_async_value(uint32_t val)
48 {
49 	uint32_t old_itr_status = 0;
50 
51 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
52 
53 	assert(val < NOTIF_ASYNC_VALUE_MAX);
54 	assert(bit_test(notif_alloc_values, val));
55 	bit_clear(notif_alloc_values, val);
56 
57 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
58 }
59 
60 uint32_t notif_get_value(bool *value_valid, bool *value_pending)
61 {
62 	uint32_t old_itr_status = 0;
63 	uint32_t res = 0;
64 	int bit = 0;
65 
66 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
67 
68 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
69 	*value_valid = (bit >= 0);
70 	if (!*value_valid) {
71 		*value_pending = false;
72 		goto out;
73 	}
74 
75 	res = bit;
76 	bit_clear(notif_values, res);
77 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
78 	*value_pending = (bit >= 0);
79 out:
80 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
81 
82 	return res;
83 }
84 
85 void notif_send_async(uint32_t value, uint16_t guest_id __maybe_unused)
86 {
87 	uint32_t old_itr_status = 0;
88 	struct itr_chip *itr_chip = interrupt_get_main_chip();
89 
90 	assert(value <= NOTIF_ASYNC_VALUE_MAX && !guest_id);
91 	old_itr_status = cpu_spin_lock_xsave(&notif_default_lock);
92 
93 	bit_set(notif_values, value);
94 	interrupt_raise_pi(itr_chip, CFG_CORE_ASYNC_NOTIF_GIC_INTID);
95 
96 	cpu_spin_unlock_xrestore(&notif_default_lock, old_itr_status);
97 }
98