xref: /optee_os/core/kernel/interrupt.c (revision b357d34fe91f4e7f6e0eacea17a7fbe5f6c01e7e)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016-2019, Linaro Limited
4  */
5 
6 #include <kernel/dt.h>
7 #include <kernel/interrupt.h>
8 #include <kernel/panic.h>
9 #include <libfdt.h>
10 #include <stdlib.h>
11 #include <trace.h>
12 #include <assert.h>
13 
14 /*
15  * NOTE!
16  *
17  * We're assuming that there's no concurrent use of this interface, except
18  * delivery of interrupts in parallel. Synchronization will be needed when
19  * we begin to modify settings after boot initialization.
20  */
21 
22 static struct itr_chip *itr_main_chip __nex_bss;
23 static SLIST_HEAD(, itr_handler) handlers __nex_data =
24 	SLIST_HEAD_INITIALIZER(handlers);
25 
26 void interrupt_main_init(struct itr_chip *chip)
27 {
28 	itr_main_chip = chip;
29 }
30 
31 struct itr_chip *interrupt_get_main_chip(void)
32 {
33 	assert(itr_main_chip);
34 	return itr_main_chip;
35 }
36 
37 #ifdef CFG_DT
38 int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
39 			 uint32_t *prio)
40 {
41 	const uint32_t *prop = NULL;
42 	int count = 0;
43 	int it_num = DT_INFO_INVALID_INTERRUPT;
44 
45 	if (!itr_main_chip || !itr_main_chip->dt_get_irq)
46 		return it_num;
47 
48 	prop = fdt_getprop(fdt, node, "interrupts", &count);
49 	if (!prop)
50 		return it_num;
51 
52 	return itr_main_chip->dt_get_irq(prop, count, type, prio);
53 }
54 #endif
55 
56 void itr_handle(size_t it)
57 {
58 	struct itr_handler *h = NULL;
59 	bool was_handled = false;
60 
61 	SLIST_FOREACH(h, &handlers, link) {
62 		if (h->it == it) {
63 			if (h->handler(h) == ITRR_HANDLED)
64 				was_handled = true;
65 			else if (!(h->flags & ITRF_SHARED))
66 				break;
67 		}
68 	}
69 
70 	if (!was_handled) {
71 		EMSG("Disabling unhandled interrupt %zu", it);
72 		itr_main_chip->ops->disable(itr_main_chip, it);
73 	}
74 }
75 
76 struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler,
77 					    uint32_t flags, void *data,
78 					    uint32_t type, uint32_t prio)
79 {
80 	struct itr_handler *hdl = calloc(1, sizeof(*hdl));
81 
82 	if (hdl) {
83 		hdl->it = it;
84 		hdl->handler = handler;
85 		hdl->flags = flags;
86 		hdl->data = data;
87 		itr_add_type_prio(hdl, type, prio);
88 	}
89 
90 	return hdl;
91 }
92 
93 void itr_free(struct itr_handler *hdl)
94 {
95 	if (!hdl)
96 		return;
97 
98 	itr_main_chip->ops->disable(itr_main_chip, hdl->it);
99 
100 	SLIST_REMOVE(&handlers, hdl, itr_handler, link);
101 	free(hdl);
102 }
103 
104 void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio)
105 {
106 	struct itr_handler __maybe_unused *hdl = NULL;
107 
108 	SLIST_FOREACH(hdl, &handlers, link)
109 		if (hdl->it == h->it)
110 			assert((hdl->flags & ITRF_SHARED) &&
111 			       (h->flags & ITRF_SHARED));
112 
113 	itr_main_chip->ops->add(itr_main_chip, h->it, type, prio);
114 	SLIST_INSERT_HEAD(&handlers, h, link);
115 }
116 
117 void itr_enable(size_t it)
118 {
119 	itr_main_chip->ops->enable(itr_main_chip, it);
120 }
121 
122 void itr_disable(size_t it)
123 {
124 	itr_main_chip->ops->disable(itr_main_chip, it);
125 }
126 
127 void itr_raise_pi(size_t it)
128 {
129 	itr_main_chip->ops->raise_pi(itr_main_chip, it);
130 }
131 
132 void itr_raise_sgi(size_t it, uint8_t cpu_mask)
133 {
134 	itr_main_chip->ops->raise_sgi(itr_main_chip, it, cpu_mask);
135 }
136 
137 void itr_set_affinity(size_t it, uint8_t cpu_mask)
138 {
139 	itr_main_chip->ops->set_affinity(itr_main_chip, it, cpu_mask);
140 }
141 
142 /* This function is supposed to be overridden in platform specific code */
143 void __weak __noreturn interrupt_main_handler(void)
144 {
145 	panic("Secure interrupt handler not defined");
146 }
147