11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 27315b7b4SJens Wiklander /* 3e9f46c74SJens Wiklander * Copyright (c) 2016-2019, Linaro Limited 47315b7b4SJens Wiklander */ 57315b7b4SJens Wiklander 6*67729d8dSLudovic Barre #include <kernel/dt.h> 77315b7b4SJens Wiklander #include <kernel/interrupt.h> 8e9f46c74SJens Wiklander #include <kernel/panic.h> 9*67729d8dSLudovic Barre #include <libfdt.h> 107315b7b4SJens Wiklander #include <trace.h> 111c832d7cSdavidwang #include <assert.h> 127315b7b4SJens Wiklander 137315b7b4SJens Wiklander /* 147315b7b4SJens Wiklander * NOTE! 157315b7b4SJens Wiklander * 167315b7b4SJens Wiklander * We're assuming that there's no concurrent use of this interface, except 177315b7b4SJens Wiklander * delivery of interrupts in parallel. Synchronization will be needed when 187315b7b4SJens Wiklander * we begin to modify settings after boot initialization. 197315b7b4SJens Wiklander */ 207315b7b4SJens Wiklander 210c1be93bSVolodymyr Babchuk static struct itr_chip *itr_chip __nex_bss; 220c1be93bSVolodymyr Babchuk static SLIST_HEAD(, itr_handler) handlers __nex_data = 230c1be93bSVolodymyr Babchuk SLIST_HEAD_INITIALIZER(handlers); 247315b7b4SJens Wiklander 257315b7b4SJens Wiklander void itr_init(struct itr_chip *chip) 267315b7b4SJens Wiklander { 277315b7b4SJens Wiklander itr_chip = chip; 287315b7b4SJens Wiklander } 297315b7b4SJens Wiklander 30*67729d8dSLudovic Barre #ifdef CFG_DT 31*67729d8dSLudovic Barre int dt_get_irq(const void *fdt, int node) 32*67729d8dSLudovic Barre { 33*67729d8dSLudovic Barre const uint32_t *prop = NULL; 34*67729d8dSLudovic Barre int len = 0; 35*67729d8dSLudovic Barre int it_num = DT_INFO_INVALID_INTERRUPT; 36*67729d8dSLudovic Barre 37*67729d8dSLudovic Barre if (!itr_chip || !itr_chip->dt_get_irq) 38*67729d8dSLudovic Barre return it_num; 39*67729d8dSLudovic Barre 40*67729d8dSLudovic Barre prop = fdt_getprop(fdt, node, "interrupts", &len); 41*67729d8dSLudovic Barre if (!prop) 42*67729d8dSLudovic Barre return it_num; 43*67729d8dSLudovic Barre 44*67729d8dSLudovic Barre return itr_chip->dt_get_irq(prop, len); 45*67729d8dSLudovic Barre } 46*67729d8dSLudovic Barre #endif 47*67729d8dSLudovic Barre 487315b7b4SJens Wiklander void itr_handle(size_t it) 497315b7b4SJens Wiklander { 501c832d7cSdavidwang struct itr_handler *h = NULL; 511c832d7cSdavidwang bool was_handled = false; 527315b7b4SJens Wiklander 531c832d7cSdavidwang SLIST_FOREACH(h, &handlers, link) { 541c832d7cSdavidwang if (h->it == it) { 551c832d7cSdavidwang if (h->handler(h) == ITRR_HANDLED) 561c832d7cSdavidwang was_handled = true; 571c832d7cSdavidwang else if (!(h->flags & ITRF_SHARED)) 581c832d7cSdavidwang break; 591c832d7cSdavidwang } 607315b7b4SJens Wiklander } 617315b7b4SJens Wiklander 621c832d7cSdavidwang if (!was_handled) { 631c832d7cSdavidwang EMSG("Disabling unhandled interrupt %zu", it); 647315b7b4SJens Wiklander itr_chip->ops->disable(itr_chip, it); 657315b7b4SJens Wiklander } 667315b7b4SJens Wiklander } 677315b7b4SJens Wiklander 687315b7b4SJens Wiklander void itr_add(struct itr_handler *h) 697315b7b4SJens Wiklander { 701c832d7cSdavidwang struct itr_handler __maybe_unused *hdl = NULL; 711c832d7cSdavidwang 721c832d7cSdavidwang SLIST_FOREACH(hdl, &handlers, link) 731c832d7cSdavidwang if (hdl->it == h->it) 741c832d7cSdavidwang assert((hdl->flags & ITRF_SHARED) && 751c832d7cSdavidwang (h->flags & ITRF_SHARED)); 761c832d7cSdavidwang 777315b7b4SJens Wiklander itr_chip->ops->add(itr_chip, h->it, h->flags); 787315b7b4SJens Wiklander SLIST_INSERT_HEAD(&handlers, h, link); 797315b7b4SJens Wiklander } 807315b7b4SJens Wiklander 8126ed70ecSGuanchao Liang void itr_enable(size_t it) 827315b7b4SJens Wiklander { 8326ed70ecSGuanchao Liang itr_chip->ops->enable(itr_chip, it); 847315b7b4SJens Wiklander } 857315b7b4SJens Wiklander 8626ed70ecSGuanchao Liang void itr_disable(size_t it) 877315b7b4SJens Wiklander { 8826ed70ecSGuanchao Liang itr_chip->ops->disable(itr_chip, it); 8926ed70ecSGuanchao Liang } 9026ed70ecSGuanchao Liang 9126ed70ecSGuanchao Liang void itr_raise_pi(size_t it) 9226ed70ecSGuanchao Liang { 9326ed70ecSGuanchao Liang itr_chip->ops->raise_pi(itr_chip, it); 9426ed70ecSGuanchao Liang } 9526ed70ecSGuanchao Liang 9626ed70ecSGuanchao Liang void itr_raise_sgi(size_t it, uint8_t cpu_mask) 9726ed70ecSGuanchao Liang { 9826ed70ecSGuanchao Liang itr_chip->ops->raise_sgi(itr_chip, it, cpu_mask); 9926ed70ecSGuanchao Liang } 10026ed70ecSGuanchao Liang 10126ed70ecSGuanchao Liang void itr_set_affinity(size_t it, uint8_t cpu_mask) 10226ed70ecSGuanchao Liang { 10326ed70ecSGuanchao Liang itr_chip->ops->set_affinity(itr_chip, it, cpu_mask); 1047315b7b4SJens Wiklander } 105e9f46c74SJens Wiklander 106e9f46c74SJens Wiklander /* This function is supposed to be overridden in platform specific code */ 107e9f46c74SJens Wiklander void __weak __noreturn itr_core_handler(void) 108e9f46c74SJens Wiklander { 109e9f46c74SJens Wiklander panic("Secure interrupt handler not defined"); 110e9f46c74SJens Wiklander } 111