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 /* This function is supposed to be overridden in platform specific code */ 69 void __weak __noreturn interrupt_main_handler(void) 70 { 71 panic("Secure interrupt handler not defined"); 72 } 73 74 /* 75 * Interrupt controller chip support 76 */ 77 void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num) 78 { 79 struct itr_handler *h = NULL; 80 bool was_handled = false; 81 82 assert(chip); 83 84 SLIST_FOREACH(h, &chip->handlers, link) { 85 if (h->it == itr_num) { 86 if (h->handler(h) == ITRR_HANDLED) 87 was_handled = true; 88 else if (!(h->flags & ITRF_SHARED)) 89 break; 90 } 91 } 92 93 if (!was_handled) { 94 EMSG("Mask unhandled interrupt %s:%zu", chip->name, itr_num); 95 interrupt_mask(chip, itr_num); 96 } 97 } 98 99 TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num, 100 uint32_t type, uint32_t prio) 101 { 102 chip->ops->add(chip, itr_num, type, prio); 103 104 return TEE_SUCCESS; 105 } 106 107 TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl, 108 uint32_t type, uint32_t prio) 109 { 110 struct itr_handler *h = NULL; 111 112 assert(hdl && hdl->chip->ops && is_unpaged(hdl) && 113 hdl->handler && is_unpaged(hdl->handler)); 114 115 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 116 if (h->it == hdl->it && 117 (!(hdl->flags & ITRF_SHARED) || 118 !(h->flags & ITRF_SHARED))) { 119 EMSG("Shared and non-shared flags on interrupt %s#%zu", 120 hdl->chip->name, hdl->it); 121 return TEE_ERROR_GENERIC; 122 } 123 } 124 125 interrupt_configure(hdl->chip, hdl->it, type, prio); 126 127 SLIST_INSERT_HEAD(&hdl->chip->handlers, hdl, link); 128 129 return TEE_SUCCESS; 130 } 131 132 void interrupt_remove_handler(struct itr_handler *hdl) 133 { 134 struct itr_handler *h = NULL; 135 bool disable_itr = true; 136 137 if (!hdl) 138 return; 139 140 SLIST_FOREACH(h, &hdl->chip->handlers, link) 141 if (h == hdl) 142 break; 143 if (!h) { 144 DMSG("Invalid %s:%zu", hdl->chip->name, hdl->it); 145 assert(false); 146 return; 147 } 148 149 if (hdl->flags & ITRF_SHARED) { 150 SLIST_FOREACH(h, &hdl->chip->handlers, link) { 151 if (h != hdl && h->it == hdl->it) { 152 disable_itr = false; 153 break; 154 } 155 } 156 } 157 158 if (disable_itr) 159 interrupt_disable(hdl->chip, hdl->it); 160 161 SLIST_REMOVE(&hdl->chip->handlers, hdl, itr_handler, link); 162 } 163 164 TEE_Result interrupt_alloc_add_conf_handler(struct itr_chip *chip, 165 size_t itr_num, 166 itr_handler_t handler, 167 uint32_t flags, void *data, 168 uint32_t type, uint32_t prio, 169 struct itr_handler **out_hdl) 170 { 171 TEE_Result res = TEE_ERROR_GENERIC; 172 struct itr_handler *hdl = NULL; 173 174 hdl = calloc(1, sizeof(*hdl)); 175 if (!hdl) 176 return TEE_ERROR_OUT_OF_MEMORY; 177 178 *hdl = ITR_HANDLER(chip, itr_num, flags, handler, data); 179 180 res = interrupt_add_configure_handler(hdl, type, prio); 181 if (res) { 182 free(hdl); 183 return res; 184 } 185 186 if (out_hdl) 187 *out_hdl = hdl; 188 189 return TEE_SUCCESS; 190 } 191 192 void interrupt_remove_free_handler(struct itr_handler *hdl) 193 { 194 if (hdl) { 195 interrupt_remove_handler(hdl); 196 free(hdl); 197 } 198 } 199