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_chip __nex_bss;
23 static SLIST_HEAD(, itr_handler) handlers __nex_data =
24 	SLIST_HEAD_INITIALIZER(handlers);
25 
itr_init(struct itr_chip * chip)26 void itr_init(struct itr_chip *chip)
27 {
28 	itr_chip = chip;
29 }
30 
31 #ifdef CFG_DT
dt_get_irq_type_prio(const void * fdt,int node,uint32_t * type,uint32_t * prio)32 int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
33 			 uint32_t *prio)
34 {
35 	const uint32_t *prop = NULL;
36 	int count = 0;
37 	int it_num = DT_INFO_INVALID_INTERRUPT;
38 
39 	if (!itr_chip || !itr_chip->dt_get_irq)
40 		return it_num;
41 
42 	prop = fdt_getprop(fdt, node, "interrupts", &count);
43 	if (!prop)
44 		return it_num;
45 
46 	return itr_chip->dt_get_irq(prop, count, type, prio);
47 }
48 #endif
49 
itr_handle(size_t it)50 void itr_handle(size_t it)
51 {
52 	struct itr_handler *h = NULL;
53 	bool was_handled = false;
54 
55 	SLIST_FOREACH(h, &handlers, link) {
56 		if (h->it == it) {
57 			if (h->handler(h) == ITRR_HANDLED)
58 				was_handled = true;
59 			else if (!(h->flags & ITRF_SHARED))
60 				break;
61 		}
62 	}
63 
64 	if (!was_handled) {
65 		EMSG("Disabling unhandled interrupt %zu", it);
66 		itr_chip->ops->disable(itr_chip, it);
67 	}
68 }
69 
itr_alloc_add_type_prio(size_t it,itr_handler_t handler,uint32_t flags,void * data,uint32_t type,uint32_t prio)70 struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler,
71 					    uint32_t flags, void *data,
72 					    uint32_t type, uint32_t prio)
73 {
74 	struct itr_handler *hdl = calloc(1, sizeof(*hdl));
75 
76 	if (hdl) {
77 		hdl->it = it;
78 		hdl->handler = handler;
79 		hdl->flags = flags;
80 		hdl->data = data;
81 		itr_add_type_prio(hdl, type, prio);
82 	}
83 
84 	return hdl;
85 }
86 
itr_free(struct itr_handler * hdl)87 void itr_free(struct itr_handler *hdl)
88 {
89 	if (!hdl)
90 		return;
91 
92 	itr_chip->ops->disable(itr_chip, hdl->it);
93 
94 	SLIST_REMOVE(&handlers, hdl, itr_handler, link);
95 	free(hdl);
96 }
97 
itr_add_type_prio(struct itr_handler * h,uint32_t type,uint32_t prio)98 void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio)
99 {
100 	struct itr_handler __maybe_unused *hdl = NULL;
101 
102 	SLIST_FOREACH(hdl, &handlers, link)
103 		if (hdl->it == h->it)
104 			assert((hdl->flags & ITRF_SHARED) &&
105 			       (h->flags & ITRF_SHARED));
106 
107 	itr_chip->ops->add(itr_chip, h->it, type, prio);
108 	SLIST_INSERT_HEAD(&handlers, h, link);
109 }
110 
itr_enable(size_t it)111 void itr_enable(size_t it)
112 {
113 	itr_chip->ops->enable(itr_chip, it);
114 }
115 
itr_disable(size_t it)116 void itr_disable(size_t it)
117 {
118 	itr_chip->ops->disable(itr_chip, it);
119 }
120 
itr_raise_pi(size_t it)121 void itr_raise_pi(size_t it)
122 {
123 	itr_chip->ops->raise_pi(itr_chip, it);
124 }
125 
itr_raise_sgi(size_t it,uint8_t cpu_mask)126 void itr_raise_sgi(size_t it, uint8_t cpu_mask)
127 {
128 	itr_chip->ops->raise_sgi(itr_chip, it, cpu_mask);
129 }
130 
itr_set_affinity(size_t it,uint8_t cpu_mask)131 void itr_set_affinity(size_t it, uint8_t cpu_mask)
132 {
133 	itr_chip->ops->set_affinity(itr_chip, it, cpu_mask);
134 }
135 
136 /* This function is supposed to be overridden in platform specific code */
itr_core_handler(void)137 void __weak __noreturn itr_core_handler(void)
138 {
139 	panic("Secure interrupt handler not defined");
140 }
141