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