xref: /optee_os/core/kernel/interrupt.c (revision 67729d8d5aaa4023a7f43da0af8535959956ee2e)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
27315b7b4SJens Wiklander /*
3e9f46c74SJens Wiklander  * Copyright (c) 2016-2019, Linaro Limited
47315b7b4SJens Wiklander  */
57315b7b4SJens Wiklander 
6*67729d8dSLudovic Barre #include <kernel/dt.h>
77315b7b4SJens Wiklander #include <kernel/interrupt.h>
8e9f46c74SJens Wiklander #include <kernel/panic.h>
9*67729d8dSLudovic Barre #include <libfdt.h>
107315b7b4SJens Wiklander #include <trace.h>
111c832d7cSdavidwang #include <assert.h>
127315b7b4SJens Wiklander 
137315b7b4SJens Wiklander /*
147315b7b4SJens Wiklander  * NOTE!
157315b7b4SJens Wiklander  *
167315b7b4SJens Wiklander  * We're assuming that there's no concurrent use of this interface, except
177315b7b4SJens Wiklander  * delivery of interrupts in parallel. Synchronization will be needed when
187315b7b4SJens Wiklander  * we begin to modify settings after boot initialization.
197315b7b4SJens Wiklander  */
207315b7b4SJens Wiklander 
210c1be93bSVolodymyr Babchuk static struct itr_chip *itr_chip __nex_bss;
220c1be93bSVolodymyr Babchuk static SLIST_HEAD(, itr_handler) handlers __nex_data =
230c1be93bSVolodymyr Babchuk 	SLIST_HEAD_INITIALIZER(handlers);
247315b7b4SJens Wiklander 
257315b7b4SJens Wiklander void itr_init(struct itr_chip *chip)
267315b7b4SJens Wiklander {
277315b7b4SJens Wiklander 	itr_chip = chip;
287315b7b4SJens Wiklander }
297315b7b4SJens Wiklander 
30*67729d8dSLudovic Barre #ifdef CFG_DT
31*67729d8dSLudovic Barre int dt_get_irq(const void *fdt, int node)
32*67729d8dSLudovic Barre {
33*67729d8dSLudovic Barre 	const uint32_t *prop = NULL;
34*67729d8dSLudovic Barre 	int len = 0;
35*67729d8dSLudovic Barre 	int it_num = DT_INFO_INVALID_INTERRUPT;
36*67729d8dSLudovic Barre 
37*67729d8dSLudovic Barre 	if (!itr_chip || !itr_chip->dt_get_irq)
38*67729d8dSLudovic Barre 		return it_num;
39*67729d8dSLudovic Barre 
40*67729d8dSLudovic Barre 	prop = fdt_getprop(fdt, node, "interrupts", &len);
41*67729d8dSLudovic Barre 	if (!prop)
42*67729d8dSLudovic Barre 		return it_num;
43*67729d8dSLudovic Barre 
44*67729d8dSLudovic Barre 	return itr_chip->dt_get_irq(prop, len);
45*67729d8dSLudovic Barre }
46*67729d8dSLudovic Barre #endif
47*67729d8dSLudovic Barre 
487315b7b4SJens Wiklander void itr_handle(size_t it)
497315b7b4SJens Wiklander {
501c832d7cSdavidwang 	struct itr_handler *h = NULL;
511c832d7cSdavidwang 	bool was_handled = false;
527315b7b4SJens Wiklander 
531c832d7cSdavidwang 	SLIST_FOREACH(h, &handlers, link) {
541c832d7cSdavidwang 		if (h->it == it) {
551c832d7cSdavidwang 			if (h->handler(h) == ITRR_HANDLED)
561c832d7cSdavidwang 				was_handled = true;
571c832d7cSdavidwang 			else if (!(h->flags & ITRF_SHARED))
581c832d7cSdavidwang 				break;
591c832d7cSdavidwang 		}
607315b7b4SJens Wiklander 	}
617315b7b4SJens Wiklander 
621c832d7cSdavidwang 	if (!was_handled) {
631c832d7cSdavidwang 		EMSG("Disabling unhandled interrupt %zu", it);
647315b7b4SJens Wiklander 		itr_chip->ops->disable(itr_chip, it);
657315b7b4SJens Wiklander 	}
667315b7b4SJens Wiklander }
677315b7b4SJens Wiklander 
687315b7b4SJens Wiklander void itr_add(struct itr_handler *h)
697315b7b4SJens Wiklander {
701c832d7cSdavidwang 	struct itr_handler __maybe_unused *hdl = NULL;
711c832d7cSdavidwang 
721c832d7cSdavidwang 	SLIST_FOREACH(hdl, &handlers, link)
731c832d7cSdavidwang 		if (hdl->it == h->it)
741c832d7cSdavidwang 			assert((hdl->flags & ITRF_SHARED) &&
751c832d7cSdavidwang 			       (h->flags & ITRF_SHARED));
761c832d7cSdavidwang 
777315b7b4SJens Wiklander 	itr_chip->ops->add(itr_chip, h->it, h->flags);
787315b7b4SJens Wiklander 	SLIST_INSERT_HEAD(&handlers, h, link);
797315b7b4SJens Wiklander }
807315b7b4SJens Wiklander 
8126ed70ecSGuanchao Liang void itr_enable(size_t it)
827315b7b4SJens Wiklander {
8326ed70ecSGuanchao Liang 	itr_chip->ops->enable(itr_chip, it);
847315b7b4SJens Wiklander }
857315b7b4SJens Wiklander 
8626ed70ecSGuanchao Liang void itr_disable(size_t it)
877315b7b4SJens Wiklander {
8826ed70ecSGuanchao Liang 	itr_chip->ops->disable(itr_chip, it);
8926ed70ecSGuanchao Liang }
9026ed70ecSGuanchao Liang 
9126ed70ecSGuanchao Liang void itr_raise_pi(size_t it)
9226ed70ecSGuanchao Liang {
9326ed70ecSGuanchao Liang 	itr_chip->ops->raise_pi(itr_chip, it);
9426ed70ecSGuanchao Liang }
9526ed70ecSGuanchao Liang 
9626ed70ecSGuanchao Liang void itr_raise_sgi(size_t it, uint8_t cpu_mask)
9726ed70ecSGuanchao Liang {
9826ed70ecSGuanchao Liang 	itr_chip->ops->raise_sgi(itr_chip, it, cpu_mask);
9926ed70ecSGuanchao Liang }
10026ed70ecSGuanchao Liang 
10126ed70ecSGuanchao Liang void itr_set_affinity(size_t it, uint8_t cpu_mask)
10226ed70ecSGuanchao Liang {
10326ed70ecSGuanchao Liang 	itr_chip->ops->set_affinity(itr_chip, it, cpu_mask);
1047315b7b4SJens Wiklander }
105e9f46c74SJens Wiklander 
106e9f46c74SJens Wiklander /* This function is supposed to be overridden in platform specific code */
107e9f46c74SJens Wiklander void __weak __noreturn itr_core_handler(void)
108e9f46c74SJens Wiklander {
109e9f46c74SJens Wiklander 	panic("Secure interrupt handler not defined");
110e9f46c74SJens Wiklander }
111