nios2: add static interrupt handling code

Supports Internal Interrupt Controller only for now; EIC
supoort tracked in ZEP-258.

Change-Id: I2d9c5180e61c06b377fce4bda8a59042b68d58f2
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2016-06-21 12:18:50 -07:00 committed by Inaky Perez-Gonzalez
commit 738dec483e
8 changed files with 159 additions and 6 deletions

View file

@ -4,6 +4,6 @@ ccflags-y += -I$(srctree)/kernel/microkernel/include
obj-y += reset.o irq_manage.o fatal.o swap.o thread.o \ obj-y += reset.o irq_manage.o fatal.o swap.o thread.o \
cpu_idle.o irq_offload.o prep_c.o crt0.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 obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o

View file

@ -111,12 +111,10 @@ SECTION_FUNC(exception.entry, _exception)
BRANCH_LABEL(on_irq_stack) BRANCH_LABEL(on_irq_stack)
#if 0 /* TODO enable interrupt handling code */
/* Enter C interrupt handling code. Value of ipending will be the /* Enter C interrupt handling code. Value of ipending will be the
* function parameter since we put it in r4 * function parameter since we put it in r4
*/ */
call _enter_irq call _enter_irq
#endif
/* Interrupt handler finished and the interrupt should be serviced /* Interrupt handler finished and the interrupt should be serviced
* now, the appropriate bits in ipending should be cleared */ * now, the appropriate bits in ipending should be cleared */

View file

@ -14,9 +14,27 @@
* limitations under the License. * limitations under the License.
*/ */
/**
* @file
* @brief Nios II C-domain interrupt management code for use with Internal
* Interrupt Controller (IIC)
*/
#include <nanokernel.h> #include <nanokernel.h>
#include <nano_private.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <irq.h> #include <irq.h>
#include <misc/printk.h>
#include <sw_isr_table.h>
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) 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) void _arch_irq_disable(unsigned int irq)
{ {
uint32_t ienable; uint32_t ienable;
@ -65,3 +84,25 @@ int _arch_irq_connect_dynamic(unsigned int irq,
return -1; 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);
}
}

View file

@ -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 <toolchain.h>
#include <sections.h>
#include <arch/cpu.h>
/*
* 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

View file

@ -43,9 +43,46 @@ extern "C" {
#ifndef _ASMLANGUAGE #ifndef _ASMLANGUAGE
#include <stdint.h> #include <stdint.h>
#include <irq.h> #include <irq.h>
#include <sw_isr_table.h>
/* 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) static ALWAYS_INLINE unsigned int _arch_irq_lock(void)
{ {

View file

@ -189,6 +189,18 @@ SECTIONS
#endif #endif
*(.data) *(.data)
*(".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) } GROUP_LINK_IN(RAMABLE_REGION)
SECTION_PROLOGUE(initlevel, (OPTIONAL),) SECTION_PROLOGUE(initlevel, (OPTIONAL),)

View file

@ -24,6 +24,8 @@
#ifndef _SW_ISR_TABLE__H_ #ifndef _SW_ISR_TABLE__H_
#define _SW_ISR_TABLE__H_ #define _SW_ISR_TABLE__H_
#include <arch/cpu.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -43,6 +45,8 @@ typedef struct _IsrTableEntry _IsrTableEntry_t;
#ifdef CONFIG_ARC #ifdef CONFIG_ARC
extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS - 16]; extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS - 16];
#elif CONFIG_NIOS2
extern _IsrTableEntry_t _sw_isr_table[NIOS2_NIRQ];
#else #else
extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS]; extern _IsrTableEntry_t _sw_isr_table[CONFIG_NUM_IRQS];
#endif #endif

View file

@ -133,7 +133,7 @@ A##a:
#if defined(_ASMLANGUAGE) && !defined(_LINKER) #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 GTEXT(sym) .global FUNC(sym); .type FUNC(sym), %function
#define GDATA(sym) .global FUNC(sym); .type FUNC(sym), %object #define GDATA(sym) .global FUNC(sym); .type FUNC(sym), %object
#define WTEXT(sym) .weak FUNC(sym); .type FUNC(sym), %function #define WTEXT(sym) .weak FUNC(sym); .type FUNC(sym), %function