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