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 struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler, 69 uint32_t flags, void *data, 70 uint32_t type, uint32_t prio) 71 { 72 struct itr_handler *hdl = calloc(1, sizeof(*hdl)); 73 74 if (hdl) { 75 hdl->it = it; 76 hdl->handler = handler; 77 hdl->flags = flags; 78 hdl->data = data; 79 itr_add_type_prio(hdl, type, prio); 80 } 81 82 return hdl; 83 } 84 85 void itr_free(struct itr_handler *hdl) 86 { 87 if (!hdl) 88 return; 89 90 itr_main_chip->ops->disable(itr_main_chip, hdl->it); 91 92 SLIST_REMOVE(&itr_main_chip->handlers, hdl, itr_handler, link); 93 free(hdl); 94 } 95 96 void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio) 97 { 98 struct itr_handler __maybe_unused *hdl = NULL; 99 100 SLIST_FOREACH(hdl, &itr_main_chip->handlers, link) 101 if (hdl->it == h->it) 102 assert((hdl->flags & ITRF_SHARED) && 103 (h->flags & ITRF_SHARED)); 104 105 itr_main_chip->ops->add(itr_main_chip, h->it, type, prio); 106 SLIST_INSERT_HEAD(&itr_main_chip->handlers, h, link); 107 } 108 109 void itr_enable(size_t it) 110 { 111 itr_main_chip->ops->enable(itr_main_chip, it); 112 } 113 114 void itr_disable(size_t it) 115 { 116 itr_main_chip->ops->disable(itr_main_chip, it); 117 } 118 119 void itr_raise_pi(size_t it) 120 { 121 itr_main_chip->ops->raise_pi(itr_main_chip, it); 122 } 123 124 void itr_raise_sgi(size_t it, uint8_t cpu_mask) 125 { 126 itr_main_chip->ops->raise_sgi(itr_main_chip, it, cpu_mask); 127 } 128 129 void itr_set_affinity(size_t it, uint8_t cpu_mask) 130 { 131 itr_main_chip->ops->set_affinity(itr_main_chip, it, cpu_mask); 132 } 133 134 /* This function is supposed to be overridden in platform specific code */ 135 void __weak __noreturn interrupt_main_handler(void) 136 { 137 panic("Secure interrupt handler not defined"); 138 } 139 140 /* 141 * Interrupt controller chip support 142 */ 143 void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num) 144 { 145 struct itr_handler *h = NULL; 146 bool was_handled = false; 147 148 assert(chip); 149 150 SLIST_FOREACH(h, &chip->handlers, link) { 151 if (h->it == itr_num) { 152 if (h->handler(h) == ITRR_HANDLED) 153 was_handled = true; 154 else if (!(h->flags & ITRF_SHARED)) 155 break; 156 } 157 } 158 159 if (!was_handled) { 160 EMSG("Mask unhandled interrupt %s:%zu", chip->name, itr_num); 161 interrupt_mask(chip, itr_num); 162 } 163 } 164 165 TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num, 166 uint32_t type, uint32_t prio) 167 { 168 chip->ops->add(chip, itr_num, type, prio); 169 170 return TEE_SUCCESS; 171 } 172 173 TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, 174 uint32_t type, uint32_t prio) 175 { 176 struct itr_handler *h = NULL; 177 178 assert(hdl && hdl->chip->ops && is_unpaged(hdl) && 179 hdl->handler && is_unpaged(hdl->handler)); 180 181 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 182 if (h->it == hdl->it && 183 (!(hdl->flags & ITRF_SHARED) || 184 !(h->flags & ITRF_SHARED))) { 185 EMSG("Shared and non-shared flags on interrupt %s#%zu", 186 hdl->chip->name, hdl->it); 187 return TEE_ERROR_GENERIC; 188 } 189 } 190 191 interrupt_configure(hdl->chip, hdl->it, type, prio); 192 193 SLIST_INSERT_HEAD(&hdl->chip->handlers, hdl, link); 194 195 return TEE_SUCCESS; 196 } 197 198 void interrupt_remove_handler(struct itr_handler *hdl) 199 { 200 struct itr_handler *h = NULL; 201 bool disable_itr = true; 202 203 if (!hdl) 204 return; 205 206 SLIST_FOREACH(h, &hdl->chip->handlers, link) 207 if (h == hdl) 208 break; 209 if (!h) { 210 DMSG("Invalid %s:%zu", hdl->chip->name, hdl->it); 211 assert(false); 212 return; 213 } 214 215 if (hdl->flags & ITRF_SHARED) { 216 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 217 if (h != hdl && h->it == hdl->it) { 218 disable_itr = false; 219 break; 220 } 221 } 222 } 223 224 if (disable_itr) 225 interrupt_disable(hdl->chip, hdl->it); 226 227 SLIST_REMOVE(&hdl->chip->handlers, hdl, itr_handler, link); 228 } 229 230 TEE_Result interrupt_alloc_add_conf_handler(struct itr_chip *chip, 231 size_t itr_num, 232 itr_handler_t handler, 233 uint32_t flags, void *data, 234 uint32_t type, uint32_t prio, 235 struct itr_handler **out_hdl) 236 { 237 TEE_Result res = TEE_ERROR_GENERIC; 238 struct itr_handler *hdl = NULL; 239 240 hdl = calloc(1, sizeof(*hdl)); 241 if (!hdl) 242 return TEE_ERROR_OUT_OF_MEMORY; 243 244 *hdl = ITR_HANDLER(chip, itr_num, flags, handler, data); 245 246 res = interrupt_add_configure_handler(hdl, type, prio); 247 if (res) { 248 free(hdl); 249 return res; 250 } 251 252 if (out_hdl) 253 *out_hdl = hdl; 254 255 return TEE_SUCCESS; 256 } 257 258 void interrupt_remove_free_handler(struct itr_handler *hdl) 259 { 260 if (hdl) { 261 interrupt_remove_handler(hdl); 262 free(hdl); 263 } 264 } 265