diff --git a/arch/nios2/core/Makefile b/arch/nios2/core/Makefile index 5d55e05e13a..acb31b30c59 100644 --- a/arch/nios2/core/Makefile +++ b/arch/nios2/core/Makefile @@ -4,6 +4,6 @@ ccflags-y += -I$(srctree)/kernel/microkernel/include obj-y += reset.o irq_manage.o fatal.o swap.o thread.o \ cpu_idle.o irq_offload.o prep_c.o crt0.o \ - exception.o + exception.o sw_isr_table.o obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o diff --git a/arch/nios2/core/exception.S b/arch/nios2/core/exception.S index e38785076f4..7c0a931545b 100644 --- a/arch/nios2/core/exception.S +++ b/arch/nios2/core/exception.S @@ -111,12 +111,10 @@ SECTION_FUNC(exception.entry, _exception) BRANCH_LABEL(on_irq_stack) -#if 0 /* TODO enable interrupt handling code */ /* Enter C interrupt handling code. Value of ipending will be the * function parameter since we put it in r4 */ call _enter_irq -#endif /* Interrupt handler finished and the interrupt should be serviced * now, the appropriate bits in ipending should be cleared */ diff --git a/arch/nios2/core/irq_manage.c b/arch/nios2/core/irq_manage.c index e06b8def649..e9be5552426 100644 --- a/arch/nios2/core/irq_manage.c +++ b/arch/nios2/core/irq_manage.c @@ -14,9 +14,27 @@ * limitations under the License. */ +/** + * @file + * @brief Nios II C-domain interrupt management code for use with Internal + * Interrupt Controller (IIC) + */ + + #include +#include #include #include +#include +#include + +void _irq_spurious(void *unused) +{ + ARG_UNUSED(unused); + printk("Spurious interrupt detected! ipending: %x\n", + _nios2_creg_read(NIOS2_CR_IPENDING)); + _NanoFatalErrorHandler(_NANO_ERR_SPURIOUS_INT, &_default_esf); +} void _arch_irq_enable(unsigned int irq) @@ -34,6 +52,7 @@ void _arch_irq_enable(unsigned int irq) }; + void _arch_irq_disable(unsigned int irq) { uint32_t ienable; @@ -65,3 +84,25 @@ int _arch_irq_connect_dynamic(unsigned int irq, return -1; }; +/** + * @brief Interrupt demux function + * + * Given a bitfield of pending interrupts, execute the appropriate handler + * + * @param ipending Bitfield of interrupts + */ +void _enter_irq(uint32_t ipending) +{ + int index; + + while (ipending) { + _IsrTableEntry_t *ite; + + index = find_lsb_set(ipending) - 1; + ipending &= ~(1 << index); + + ite = &_sw_isr_table[index]; + ite->isr(ite->arg); + } +} + diff --git a/arch/nios2/core/sw_isr_table.S b/arch/nios2/core/sw_isr_table.S new file mode 100644 index 00000000000..a9b1a2b0266 --- /dev/null +++ b/arch/nios2/core/sw_isr_table.S @@ -0,0 +1,61 @@ +/* sw_isr_table.S - ISR table for static ISR declarations for ARC */ + +/* + * Copyright (c) 2015 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _ASMLANGUAGE + +#include +#include +#include + +/* + * enable preprocessor features, such + * as %expr - evaluate the expression and use it as a string + */ +.altmacro + +/* + * Define an ISR table entry + * Define symbol as weak and give the section .gnu.linkonce + * prefix. This allows linker overload the symbol and the + * whole section by the one defined by a device driver + */ +.macro _isr_table_entry_declare index + WDATA(_isr_irq\index) + .section .gnu.linkonce.isr_irq\index + _isr_irq\index: .word 0xABAD1DEA, _irq_spurious +.endm + +/* + * Declare the ISR table + */ +.macro _isr_table_declare from, to + counter = \from + .rept (\to - \from) + _isr_table_entry_declare %counter + counter = counter + 1 + .endr +.endm + +GTEXT(_irq_spurious) +GDATA(_sw_isr_table) + +.section .isr_irq0 +.align +_sw_isr_table: + +_isr_table_declare 0 NIOS2_NIRQ diff --git a/include/arch/nios2/arch.h b/include/arch/nios2/arch.h index 5f0021163b4..cc676e89942 100644 --- a/include/arch/nios2/arch.h +++ b/include/arch/nios2/arch.h @@ -43,9 +43,46 @@ extern "C" { #ifndef _ASMLANGUAGE #include #include +#include -/* STUB. Eventually port ARC/ARM interrupt stuff */ -#define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) +/** + * Configure a static interrupt. + * + * All arguments must be computable by the compiler at build time; if this + * can't be done use irq_connect_dynamic() instead. + * + * Internally this function does a few things: + * + * 1. The enum statement has no effect but forces the compiler to only + * accept constant values for the irq_p parameter, very important as the + * numerical IRQ line is used to create a named section. + * + * 2. An instance of _IsrTableEntry is created containing the ISR and its + * parameter. If you look at how _sw_isr_table is created, each entry in the + * array is in its own section named by the IRQ line number. What we are doing + * here is to override one of the default entries (which points to the + * spurious IRQ handler) with what was supplied here. + * + * There is no notion of priority with the Nios II internal interrupt + * controller and no flags are currently supported. + * + * @param irq_p IRQ line number + * @param priority_p Interrupt priority (ignored) + * @param isr_p Interrupt service routine + * @param isr_param_p ISR parameter + * @param flags_p IRQ triggering options (currently unused) + * + * @return The vector assigned to this interrupt + */ +#define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ +({ \ + enum { IRQ = irq_p }; \ + static struct _IsrTableEntry _CONCAT(_isr_irq, irq_p) \ + __attribute__ ((used)) \ + __attribute__ ((section(STRINGIFY(_CONCAT(.gnu.linkonce.isr_irq, irq_p))))) = \ + {isr_param_p, isr_p}; \ + irq_p; \ +}) static ALWAYS_INLINE unsigned int _arch_irq_lock(void) { diff --git a/include/arch/nios2/linker.ld b/include/arch/nios2/linker.ld index 42e43478963..f30ba3e0310 100644 --- a/include/arch/nios2/linker.ld +++ b/include/arch/nios2/linker.ld @@ -189,6 +189,18 @@ SECTIONS #endif *(.data) *(".data.*") + + KEEP(*(.isr_irq*)) + + /* sections for IRQ0-9 */ + KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9]))) + + /* sections for IRQ10-99 */ + KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9]))) + + /* sections for IRQ100-999 */ + KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9][0-9]))) + } GROUP_LINK_IN(RAMABLE_REGION) SECTION_PROLOGUE(initlevel, (OPTIONAL),) diff --git a/include/sw_isr_table.h b/include/sw_isr_table.h index 770be085b91..04274f8286d 100644 --- a/include/sw_isr_table.h +++ b/include/sw_isr_table.h @@ -24,6 +24,8 @@ #ifndef _SW_ISR_TABLE__H_ #define _SW_ISR_TABLE__H_ +#include + #ifdef __cplusplus extern "C" { #endif @@ -43,6 +45,8 @@ typedef struct _IsrTableEntry _IsrTableEntry_t; #ifdef CONFIG_ARC extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS - 16]; +#elif CONFIG_NIOS2 +extern _IsrTableEntry_t _sw_isr_table[NIOS2_NIRQ]; #else extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS]; #endif diff --git a/include/toolchain/gcc.h b/include/toolchain/gcc.h index 5728924042e..977ed41ccd8 100644 --- a/include/toolchain/gcc.h +++ b/include/toolchain/gcc.h @@ -133,7 +133,7 @@ A##a: #if defined(_ASMLANGUAGE) && !defined(_LINKER) -#ifdef CONFIG_ARM +#if defined(CONFIG_ARM) || defined(CONFIG_NIOS2) #define GTEXT(sym) .global FUNC(sym); .type FUNC(sym), %function #define GDATA(sym) .global FUNC(sym); .type FUNC(sym), %object #define WTEXT(sym) .weak FUNC(sym); .type FUNC(sym), %function