11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 27315b7b4SJens Wiklander /* 3e9f46c74SJens Wiklander * Copyright (c) 2016-2019, Linaro Limited 47315b7b4SJens Wiklander */ 57315b7b4SJens Wiklander 667729d8dSLudovic Barre #include <kernel/dt.h> 77315b7b4SJens Wiklander #include <kernel/interrupt.h> 8e9f46c74SJens Wiklander #include <kernel/panic.h> 967729d8dSLudovic Barre #include <libfdt.h> 10acc5dd21SLudovic Barre #include <stdlib.h> 117315b7b4SJens Wiklander #include <trace.h> 121c832d7cSdavidwang #include <assert.h> 137315b7b4SJens Wiklander 147315b7b4SJens Wiklander /* 157315b7b4SJens Wiklander * NOTE! 167315b7b4SJens Wiklander * 177315b7b4SJens Wiklander * We're assuming that there's no concurrent use of this interface, except 187315b7b4SJens Wiklander * delivery of interrupts in parallel. Synchronization will be needed when 197315b7b4SJens Wiklander * we begin to modify settings after boot initialization. 207315b7b4SJens Wiklander */ 217315b7b4SJens Wiklander 220c1be93bSVolodymyr Babchuk static struct itr_chip *itr_chip __nex_bss; 230c1be93bSVolodymyr Babchuk static SLIST_HEAD(, itr_handler) handlers __nex_data = 240c1be93bSVolodymyr Babchuk SLIST_HEAD_INITIALIZER(handlers); 257315b7b4SJens Wiklander 2601980f3fSEtienne Carriere void interrupt_main_init(struct itr_chip *chip) 277315b7b4SJens Wiklander { 287315b7b4SJens Wiklander itr_chip = chip; 297315b7b4SJens Wiklander } 307315b7b4SJens Wiklander 31*e050e0a7SEtienne Carriere struct itr_chip *interrupt_get_main_chip(void) 32*e050e0a7SEtienne Carriere { 33*e050e0a7SEtienne Carriere assert(itr_chip); 34*e050e0a7SEtienne Carriere return itr_chip; 35*e050e0a7SEtienne Carriere } 36*e050e0a7SEtienne Carriere 3767729d8dSLudovic Barre #ifdef CFG_DT 38702fe5a7SClément Léger int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type, 39702fe5a7SClément Léger uint32_t *prio) 4067729d8dSLudovic Barre { 4167729d8dSLudovic Barre const uint32_t *prop = NULL; 42888bb63dSClément Léger int count = 0; 4367729d8dSLudovic Barre int it_num = DT_INFO_INVALID_INTERRUPT; 4467729d8dSLudovic Barre 4567729d8dSLudovic Barre if (!itr_chip || !itr_chip->dt_get_irq) 4667729d8dSLudovic Barre return it_num; 4767729d8dSLudovic Barre 48888bb63dSClément Léger prop = fdt_getprop(fdt, node, "interrupts", &count); 4967729d8dSLudovic Barre if (!prop) 5067729d8dSLudovic Barre return it_num; 5167729d8dSLudovic Barre 52702fe5a7SClément Léger return itr_chip->dt_get_irq(prop, count, type, prio); 5367729d8dSLudovic Barre } 5467729d8dSLudovic Barre #endif 5567729d8dSLudovic Barre 567315b7b4SJens Wiklander void itr_handle(size_t it) 577315b7b4SJens Wiklander { 581c832d7cSdavidwang struct itr_handler *h = NULL; 591c832d7cSdavidwang bool was_handled = false; 607315b7b4SJens Wiklander 611c832d7cSdavidwang SLIST_FOREACH(h, &handlers, link) { 621c832d7cSdavidwang if (h->it == it) { 631c832d7cSdavidwang if (h->handler(h) == ITRR_HANDLED) 641c832d7cSdavidwang was_handled = true; 651c832d7cSdavidwang else if (!(h->flags & ITRF_SHARED)) 661c832d7cSdavidwang break; 671c832d7cSdavidwang } 687315b7b4SJens Wiklander } 697315b7b4SJens Wiklander 701c832d7cSdavidwang if (!was_handled) { 711c832d7cSdavidwang EMSG("Disabling unhandled interrupt %zu", it); 727315b7b4SJens Wiklander itr_chip->ops->disable(itr_chip, it); 737315b7b4SJens Wiklander } 747315b7b4SJens Wiklander } 757315b7b4SJens Wiklander 76702fe5a7SClément Léger struct itr_handler *itr_alloc_add_type_prio(size_t it, itr_handler_t handler, 77702fe5a7SClément Léger uint32_t flags, void *data, 78702fe5a7SClément Léger uint32_t type, uint32_t prio) 79acc5dd21SLudovic Barre { 80acc5dd21SLudovic Barre struct itr_handler *hdl = calloc(1, sizeof(*hdl)); 81acc5dd21SLudovic Barre 82acc5dd21SLudovic Barre if (hdl) { 83acc5dd21SLudovic Barre hdl->it = it; 84acc5dd21SLudovic Barre hdl->handler = handler; 85acc5dd21SLudovic Barre hdl->flags = flags; 86acc5dd21SLudovic Barre hdl->data = data; 87702fe5a7SClément Léger itr_add_type_prio(hdl, type, prio); 88acc5dd21SLudovic Barre } 89acc5dd21SLudovic Barre 90acc5dd21SLudovic Barre return hdl; 91acc5dd21SLudovic Barre } 92acc5dd21SLudovic Barre 93acc5dd21SLudovic Barre void itr_free(struct itr_handler *hdl) 94acc5dd21SLudovic Barre { 95acc5dd21SLudovic Barre if (!hdl) 96acc5dd21SLudovic Barre return; 97acc5dd21SLudovic Barre 98acc5dd21SLudovic Barre itr_chip->ops->disable(itr_chip, hdl->it); 99acc5dd21SLudovic Barre 100acc5dd21SLudovic Barre SLIST_REMOVE(&handlers, hdl, itr_handler, link); 101acc5dd21SLudovic Barre free(hdl); 102acc5dd21SLudovic Barre } 103acc5dd21SLudovic Barre 104702fe5a7SClément Léger void itr_add_type_prio(struct itr_handler *h, uint32_t type, uint32_t prio) 1057315b7b4SJens Wiklander { 1061c832d7cSdavidwang struct itr_handler __maybe_unused *hdl = NULL; 1071c832d7cSdavidwang 1081c832d7cSdavidwang SLIST_FOREACH(hdl, &handlers, link) 1091c832d7cSdavidwang if (hdl->it == h->it) 1101c832d7cSdavidwang assert((hdl->flags & ITRF_SHARED) && 1111c832d7cSdavidwang (h->flags & ITRF_SHARED)); 1121c832d7cSdavidwang 113702fe5a7SClément Léger itr_chip->ops->add(itr_chip, h->it, type, prio); 1147315b7b4SJens Wiklander SLIST_INSERT_HEAD(&handlers, h, link); 1157315b7b4SJens Wiklander } 1167315b7b4SJens Wiklander 11726ed70ecSGuanchao Liang void itr_enable(size_t it) 1187315b7b4SJens Wiklander { 11926ed70ecSGuanchao Liang itr_chip->ops->enable(itr_chip, it); 1207315b7b4SJens Wiklander } 1217315b7b4SJens Wiklander 12226ed70ecSGuanchao Liang void itr_disable(size_t it) 1237315b7b4SJens Wiklander { 12426ed70ecSGuanchao Liang itr_chip->ops->disable(itr_chip, it); 12526ed70ecSGuanchao Liang } 12626ed70ecSGuanchao Liang 12726ed70ecSGuanchao Liang void itr_raise_pi(size_t it) 12826ed70ecSGuanchao Liang { 12926ed70ecSGuanchao Liang itr_chip->ops->raise_pi(itr_chip, it); 13026ed70ecSGuanchao Liang } 13126ed70ecSGuanchao Liang 13226ed70ecSGuanchao Liang void itr_raise_sgi(size_t it, uint8_t cpu_mask) 13326ed70ecSGuanchao Liang { 13426ed70ecSGuanchao Liang itr_chip->ops->raise_sgi(itr_chip, it, cpu_mask); 13526ed70ecSGuanchao Liang } 13626ed70ecSGuanchao Liang 13726ed70ecSGuanchao Liang void itr_set_affinity(size_t it, uint8_t cpu_mask) 13826ed70ecSGuanchao Liang { 13926ed70ecSGuanchao Liang itr_chip->ops->set_affinity(itr_chip, it, cpu_mask); 1407315b7b4SJens Wiklander } 141e9f46c74SJens Wiklander 142e9f46c74SJens Wiklander /* This function is supposed to be overridden in platform specific code */ 143358bf47cSEtienne Carriere void __weak __noreturn interrupt_main_handler(void) 144e9f46c74SJens Wiklander { 145e9f46c74SJens Wiklander panic("Secure interrupt handler not defined"); 146e9f46c74SJens Wiklander } 147