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