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 <mm/core_memprot.h> 11 #include <stdlib.h> 12 #include <trace.h> 13 #include <assert.h> 14 15 /* 16 * NOTE! 17 * 18 * We're assuming that there's no concurrent use of this interface, except 19 * delivery of interrupts in parallel. Synchronization will be needed when 20 * we begin to modify settings after boot initialization. 21 */ 22 23 static struct itr_chip *itr_main_chip __nex_bss; 24 25 TEE_Result itr_chip_init(struct itr_chip *chip) 26 { 27 if (!itr_chip_is_valid(chip)) 28 return TEE_ERROR_BAD_PARAMETERS; 29 30 SLIST_INIT(&chip->handlers); 31 32 return TEE_SUCCESS; 33 } 34 35 void interrupt_main_init(struct itr_chip *chip) 36 { 37 if (itr_chip_init(chip)) 38 panic(); 39 40 itr_main_chip = chip; 41 } 42 43 struct itr_chip *interrupt_get_main_chip(void) 44 { 45 assert(itr_main_chip); 46 return itr_main_chip; 47 } 48 49 #ifdef CFG_DT 50 int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type, 51 uint32_t *prio) 52 { 53 const uint32_t *prop = NULL; 54 int count = 0; 55 int it_num = DT_INFO_INVALID_INTERRUPT; 56 57 if (!itr_main_chip || !itr_main_chip->dt_get_irq) 58 return it_num; 59 60 prop = fdt_getprop(fdt, node, "interrupts", &count); 61 if (!prop) 62 return it_num; 63 64 return itr_main_chip->dt_get_irq(prop, count, type, prio); 65 } 66 #endif 67 68 void itr_handle(size_t it) 69 { 70 interrupt_call_handlers(itr_main_chip, it); 71 } 72 73 struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler, 74 uint32_t flags, void *data, 75 uint32_t type, uint32_t prio) 76 { 77 struct itr_handler *hdl = calloc(1, sizeof(*hdl)); 78 79 if (hdl) { 80 hdl->it = it; 81 hdl->handler = handler; 82 hdl->flags = flags; 83 hdl->data = data; 84 itr_add_type_prio(hdl, type, prio); 85 } 86 87 return hdl; 88 } 89 90 void itr_free(struct itr_handler *hdl) 91 { 92 if (!hdl) 93 return; 94 95 itr_main_chip->ops->disable(itr_main_chip, hdl->it); 96 97 SLIST_REMOVE(&itr_main_chip->handlers, hdl, itr_handler, link); 98 free(hdl); 99 } 100 101 void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio) 102 { 103 struct itr_handler __maybe_unused *hdl = NULL; 104 105 SLIST_FOREACH(hdl, &itr_main_chip->handlers, link) 106 if (hdl->it == h->it) 107 assert((hdl->flags & ITRF_SHARED) && 108 (h->flags & ITRF_SHARED)); 109 110 itr_main_chip->ops->add(itr_main_chip, h->it, type, prio); 111 SLIST_INSERT_HEAD(&itr_main_chip->handlers, h, link); 112 } 113 114 void itr_enable(size_t it) 115 { 116 itr_main_chip->ops->enable(itr_main_chip, it); 117 } 118 119 void itr_disable(size_t it) 120 { 121 itr_main_chip->ops->disable(itr_main_chip, it); 122 } 123 124 void itr_raise_pi(size_t it) 125 { 126 itr_main_chip->ops->raise_pi(itr_main_chip, it); 127 } 128 129 void itr_raise_sgi(size_t it, uint8_t cpu_mask) 130 { 131 itr_main_chip->ops->raise_sgi(itr_main_chip, it, cpu_mask); 132 } 133 134 void itr_set_affinity(size_t it, uint8_t cpu_mask) 135 { 136 itr_main_chip->ops->set_affinity(itr_main_chip, it, cpu_mask); 137 } 138 139 /* This function is supposed to be overridden in platform specific code */ 140 void __weak __noreturn interrupt_main_handler(void) 141 { 142 panic("Secure interrupt handler not defined"); 143 } 144 145 /* 146 * Interrupt controller chip support 147 */ 148 void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num) 149 { 150 struct itr_handler *h = NULL; 151 bool was_handled = false; 152 153 assert(chip); 154 155 SLIST_FOREACH(h, &chip->handlers, link) { 156 if (h->it == itr_num) { 157 if (h->handler(h) == ITRR_HANDLED) 158 was_handled = true; 159 else if (!(h->flags & ITRF_SHARED)) 160 break; 161 } 162 } 163 164 if (!was_handled) { 165 EMSG("Mask unhandled interrupt %s:%zu", chip->name, itr_num); 166 interrupt_mask(chip, itr_num); 167 } 168 } 169 170 TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num, 171 uint32_t type, uint32_t prio) 172 { 173 chip->ops->add(chip, itr_num, type, prio); 174 175 return TEE_SUCCESS; 176 } 177 178 TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, 179 uint32_t type, uint32_t prio) 180 { 181 struct itr_handler *h = NULL; 182 183 assert(hdl && hdl->chip->ops && is_unpaged(hdl) && 184 hdl->handler && is_unpaged(hdl->handler)); 185 186 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 187 if (h->it == hdl->it && 188 (!(hdl->flags & ITRF_SHARED) || 189 !(h->flags & ITRF_SHARED))) { 190 EMSG("Shared and non-shared flags on interrupt %s#%zu", 191 hdl->chip->name, hdl->it); 192 return TEE_ERROR_GENERIC; 193 } 194 } 195 196 interrupt_configure(hdl->chip, hdl->it, type, prio); 197 198 SLIST_INSERT_HEAD(&hdl->chip->handlers, hdl, link); 199 200 return TEE_SUCCESS; 201 } 202 203 void interrupt_remove_handler(struct itr_handler *hdl) 204 { 205 struct itr_handler *h = NULL; 206 bool disable_itr = true; 207 208 if (!hdl) 209 return; 210 211 SLIST_FOREACH(h, &hdl->chip->handlers, link) 212 if (h == hdl) 213 break; 214 if (!h) { 215 DMSG("Invalid %s:%zu", hdl->chip->name, hdl->it); 216 assert(false); 217 return; 218 } 219 220 if (hdl->flags & ITRF_SHARED) { 221 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 222 if (h != hdl && h->it == hdl->it) { 223 disable_itr = false; 224 break; 225 } 226 } 227 } 228 229 if (disable_itr) 230 interrupt_disable(hdl->chip, hdl->it); 231 232 SLIST_REMOVE(&hdl->chip->handlers, hdl, itr_handler, link); 233 } 234 235 TEE_Result interrupt_alloc_add_handler(struct itr_chip *chip, size_t itr_num, 236 itr_handler_t handler, uint32_t flags, 237 void *data, struct itr_handler **out_hdl) 238 { 239 TEE_Result res = TEE_ERROR_GENERIC; 240 struct itr_handler *hdl = NULL; 241 242 hdl = calloc(1, sizeof(*hdl)); 243 if (!hdl) 244 return TEE_ERROR_OUT_OF_MEMORY; 245 246 *hdl = ITR_HANDLER(chip, itr_num, flags, handler, data); 247 248 res = interrupt_add_handler(hdl); 249 if (res) { 250 free(hdl); 251 return res; 252 } 253 254 if (out_hdl) 255 *out_hdl = hdl; 256 257 return TEE_SUCCESS; 258 } 259 260 void interrupt_remove_free_handler(struct itr_handler *hdl) 261 { 262 if (hdl) { 263 interrupt_remove_handler(hdl); 264 free(hdl); 265 } 266 } 267