xref: /optee_os/core/kernel/interrupt.c (revision e050e0a73848fc518b555ef194ec1ddd1ab743f2)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
27315b7b4SJens Wiklander /*
3e9f46c74SJens Wiklander  * Copyright (c) 2016-2019, Linaro Limited
47315b7b4SJens Wiklander  */
57315b7b4SJens Wiklander 
667729d8dSLudovic Barre #include <kernel/dt.h>
77315b7b4SJens Wiklander #include <kernel/interrupt.h>
8e9f46c74SJens Wiklander #include <kernel/panic.h>
967729d8dSLudovic Barre #include <libfdt.h>
10acc5dd21SLudovic Barre #include <stdlib.h>
117315b7b4SJens Wiklander #include <trace.h>
121c832d7cSdavidwang #include <assert.h>
137315b7b4SJens Wiklander 
147315b7b4SJens Wiklander /*
157315b7b4SJens Wiklander  * NOTE!
167315b7b4SJens Wiklander  *
177315b7b4SJens Wiklander  * We're assuming that there's no concurrent use of this interface, except
187315b7b4SJens Wiklander  * delivery of interrupts in parallel. Synchronization will be needed when
197315b7b4SJens Wiklander  * we begin to modify settings after boot initialization.
207315b7b4SJens Wiklander  */
217315b7b4SJens Wiklander 
220c1be93bSVolodymyr Babchuk static struct itr_chip *itr_chip __nex_bss;
230c1be93bSVolodymyr Babchuk static SLIST_HEAD(, itr_handler) handlers __nex_data =
240c1be93bSVolodymyr Babchuk 	SLIST_HEAD_INITIALIZER(handlers);
257315b7b4SJens Wiklander 
2601980f3fSEtienne Carriere void interrupt_main_init(struct itr_chip *chip)
277315b7b4SJens Wiklander {
287315b7b4SJens Wiklander 	itr_chip = chip;
297315b7b4SJens Wiklander }
307315b7b4SJens Wiklander 
31*e050e0a7SEtienne Carriere struct itr_chip *interrupt_get_main_chip(void)
32*e050e0a7SEtienne Carriere {
33*e050e0a7SEtienne Carriere 	assert(itr_chip);
34*e050e0a7SEtienne Carriere 	return itr_chip;
35*e050e0a7SEtienne Carriere }
36*e050e0a7SEtienne Carriere 
3767729d8dSLudovic Barre #ifdef CFG_DT
38702fe5a7SClément Léger int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
39702fe5a7SClément Léger 			 uint32_t *prio)
4067729d8dSLudovic Barre {
4167729d8dSLudovic Barre 	const uint32_t *prop = NULL;
42888bb63dSClément Léger 	int count = 0;
4367729d8dSLudovic Barre 	int it_num = DT_INFO_INVALID_INTERRUPT;
4467729d8dSLudovic Barre 
4567729d8dSLudovic Barre 	if (!itr_chip || !itr_chip->dt_get_irq)
4667729d8dSLudovic Barre 		return it_num;
4767729d8dSLudovic Barre 
48888bb63dSClément Léger 	prop = fdt_getprop(fdt, node, "interrupts", &count);
4967729d8dSLudovic Barre 	if (!prop)
5067729d8dSLudovic Barre 		return it_num;
5167729d8dSLudovic Barre 
52702fe5a7SClément Léger 	return itr_chip->dt_get_irq(prop, count, type, prio);
5367729d8dSLudovic Barre }
5467729d8dSLudovic Barre #endif
5567729d8dSLudovic Barre 
567315b7b4SJens Wiklander void itr_handle(size_t it)
577315b7b4SJens Wiklander {
581c832d7cSdavidwang 	struct itr_handler *h = NULL;
591c832d7cSdavidwang 	bool was_handled = false;
607315b7b4SJens Wiklander 
611c832d7cSdavidwang 	SLIST_FOREACH(h, &handlers, link) {
621c832d7cSdavidwang 		if (h->it == it) {
631c832d7cSdavidwang 			if (h->handler(h) == ITRR_HANDLED)
641c832d7cSdavidwang 				was_handled = true;
651c832d7cSdavidwang 			else if (!(h->flags & ITRF_SHARED))
661c832d7cSdavidwang 				break;
671c832d7cSdavidwang 		}
687315b7b4SJens Wiklander 	}
697315b7b4SJens Wiklander 
701c832d7cSdavidwang 	if (!was_handled) {
711c832d7cSdavidwang 		EMSG("Disabling unhandled interrupt %zu", it);
727315b7b4SJens Wiklander 		itr_chip->ops->disable(itr_chip, it);
737315b7b4SJens Wiklander 	}
747315b7b4SJens Wiklander }
757315b7b4SJens Wiklander 
76702fe5a7SClément Léger struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler,
77702fe5a7SClément Léger 					    uint32_t flags, void *data,
78702fe5a7SClément Léger 					    uint32_t type, uint32_t prio)
79acc5dd21SLudovic Barre {
80acc5dd21SLudovic Barre 	struct itr_handler *hdl = calloc(1, sizeof(*hdl));
81acc5dd21SLudovic Barre 
82acc5dd21SLudovic Barre 	if (hdl) {
83acc5dd21SLudovic Barre 		hdl->it = it;
84acc5dd21SLudovic Barre 		hdl->handler = handler;
85acc5dd21SLudovic Barre 		hdl->flags = flags;
86acc5dd21SLudovic Barre 		hdl->data = data;
87702fe5a7SClément Léger 		itr_add_type_prio(hdl, type, prio);
88acc5dd21SLudovic Barre 	}
89acc5dd21SLudovic Barre 
90acc5dd21SLudovic Barre 	return hdl;
91acc5dd21SLudovic Barre }
92acc5dd21SLudovic Barre 
93acc5dd21SLudovic Barre void itr_free(struct itr_handler *hdl)
94acc5dd21SLudovic Barre {
95acc5dd21SLudovic Barre 	if (!hdl)
96acc5dd21SLudovic Barre 		return;
97acc5dd21SLudovic Barre 
98acc5dd21SLudovic Barre 	itr_chip->ops->disable(itr_chip, hdl->it);
99acc5dd21SLudovic Barre 
100acc5dd21SLudovic Barre 	SLIST_REMOVE(&handlers, hdl, itr_handler, link);
101acc5dd21SLudovic Barre 	free(hdl);
102acc5dd21SLudovic Barre }
103acc5dd21SLudovic Barre 
104702fe5a7SClément Léger void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio)
1057315b7b4SJens Wiklander {
1061c832d7cSdavidwang 	struct itr_handler __maybe_unused *hdl = NULL;
1071c832d7cSdavidwang 
1081c832d7cSdavidwang 	SLIST_FOREACH(hdl, &handlers, link)
1091c832d7cSdavidwang 		if (hdl->it == h->it)
1101c832d7cSdavidwang 			assert((hdl->flags & ITRF_SHARED) &&
1111c832d7cSdavidwang 			       (h->flags & ITRF_SHARED));
1121c832d7cSdavidwang 
113702fe5a7SClément Léger 	itr_chip->ops->add(itr_chip, h->it, type, prio);
1147315b7b4SJens Wiklander 	SLIST_INSERT_HEAD(&handlers, h, link);
1157315b7b4SJens Wiklander }
1167315b7b4SJens Wiklander 
11726ed70ecSGuanchao Liang void itr_enable(size_t it)
1187315b7b4SJens Wiklander {
11926ed70ecSGuanchao Liang 	itr_chip->ops->enable(itr_chip, it);
1207315b7b4SJens Wiklander }
1217315b7b4SJens Wiklander 
12226ed70ecSGuanchao Liang void itr_disable(size_t it)
1237315b7b4SJens Wiklander {
12426ed70ecSGuanchao Liang 	itr_chip->ops->disable(itr_chip, it);
12526ed70ecSGuanchao Liang }
12626ed70ecSGuanchao Liang 
12726ed70ecSGuanchao Liang void itr_raise_pi(size_t it)
12826ed70ecSGuanchao Liang {
12926ed70ecSGuanchao Liang 	itr_chip->ops->raise_pi(itr_chip, it);
13026ed70ecSGuanchao Liang }
13126ed70ecSGuanchao Liang 
13226ed70ecSGuanchao Liang void itr_raise_sgi(size_t it, uint8_t cpu_mask)
13326ed70ecSGuanchao Liang {
13426ed70ecSGuanchao Liang 	itr_chip->ops->raise_sgi(itr_chip, it, cpu_mask);
13526ed70ecSGuanchao Liang }
13626ed70ecSGuanchao Liang 
13726ed70ecSGuanchao Liang void itr_set_affinity(size_t it, uint8_t cpu_mask)
13826ed70ecSGuanchao Liang {
13926ed70ecSGuanchao Liang 	itr_chip->ops->set_affinity(itr_chip, it, cpu_mask);
1407315b7b4SJens Wiklander }
141e9f46c74SJens Wiklander 
142e9f46c74SJens Wiklander /* This function is supposed to be overridden in platform specific code */
143358bf47cSEtienne Carriere void __weak __noreturn interrupt_main_handler(void)
144e9f46c74SJens Wiklander {
145e9f46c74SJens Wiklander 	panic("Secure interrupt handler not defined");
146e9f46c74SJens Wiklander }
147