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