irq_offload: ARC implementation

Uses the "trap_s" exception to simulate entry into IRQ context;
offloaded functions run on the FIRQ stack.

Change-Id: I310ce42b45aca5dabd1d27e486645d23fa0b118f
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2015-11-17 14:08:45 -08:00 committed by Anas Nashif
commit 2ec374a8df
7 changed files with 98 additions and 2 deletions

View file

@ -142,6 +142,14 @@ config FAULT_DUMP
(short strings). (short strings).
0: Off. 0: Off.
config IRQ_OFFLOAD
bool "Enable IRQ offload"
default n
help
Enable irq_offload() API which allows functions to be synchronously
run in interrupt context. Uses one entry in the IDT. Mainly useful
for test cases.
config XIP config XIP
default n if NSIM default n if NSIM
default y default y

View file

@ -11,3 +11,5 @@ obj-y += atomic.o thread.o thread_entry_wrapper.o \
obj-y += prep_c.o \ obj-y += prep_c.o \
reset.o \ reset.o \
vector_table.o vector_table.o
obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o

View file

@ -61,7 +61,9 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_d)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_prot_v) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_prot_v)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_privilege_v) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_privilege_v)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_swi) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_swi)
#ifndef CONFIG_IRQ_OFFLOAD
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
#endif
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_extension) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_extension)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero)
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error)
@ -91,3 +93,33 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
/* now restore the stack */ /* now restore the stack */
ld sp,[saved_stack_pointer] ld sp,[saved_stack_pointer]
rtie rtie
#ifdef CONFIG_IRQ_OFFLOAD
GTEXT(_irq_do_offload);
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
/*
* Before invoking exception handler, the kernel switches to an exception
* stack, which is really the FIRQ stack, to save the faulting thread's
* registers. It can use the FIRQ stack because it knows it is unused
* since it is save to assume that if an exception has happened in FIRQ
* handler, the problem is fatal and all the kernel can do is just print
* a diagnostic message and halt.
*/
st sp, [saved_stack_pointer]
mov_s sp, _firq_stack
add sp, sp, CONFIG_FIRQ_STACK_SIZE
/* save caller saved registers */
_create_irq_stack_frame
jl _irq_do_offload
/* if _Fault returns, restore the registers */
_pop_irq_stack_frame
/* now restore the stack */
ld sp,[saved_stack_pointer]
rtie
#endif /* CONFIG_IRQ_OFFLOAD */

View file

@ -0,0 +1,45 @@
/*
* 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.
*/
/**
* @file Software interrupts utility code - ARC implementation
*/
#include <nanokernel.h>
#include <irq_offload.h>
static irq_offload_routine_t offload_routine;
static void *offload_param;
/* Called by trap_s exception handler */
void _irq_do_offload(void)
{
offload_routine(offload_param);
}
void irq_offload(irq_offload_routine_t routine, void *parameter)
{
int key;
key = irq_lock();
offload_routine = routine;
offload_param = parameter;
__asm__ volatile ("trap_s 0");
irq_unlock(key);
}

View file

@ -37,6 +37,7 @@ extern "C" {
#include <toolchain.h> #include <toolchain.h>
#include <sections.h> #include <sections.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <vector_table.h>
#ifndef _ASMLANGUAGE #ifndef _ASMLANGUAGE
#include <nanokernel.h> /* public nanokernel API */ #include <nanokernel.h> /* public nanokernel API */
@ -249,7 +250,13 @@ static ALWAYS_INLINE void fiberRtnValueSet(struct tcs *fiber, unsigned int value
static ALWAYS_INLINE int _IS_IN_ISR(void) static ALWAYS_INLINE int _IS_IN_ISR(void)
{ {
uint32_t act = _arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_ACT); uint32_t act = _arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_ACT);
#if CONFIG_IRQ_OFFLOAD
/* Check if we're in a TRAP_S exception as well */
if (_arc_v2_aux_reg_read(_ARC_V2_STATUS32) & _ARC_V2_STATUS32_AE &&
_ARC_V2_ECR_VECTOR(_arc_v2_aux_reg_read(_ARC_V2_ECR)) == EXC_EV_TRAP) {
return 1;
}
#endif
return ((act & 0xffff) != 0); return ((act & 0xffff) != 0);
} }

View file

@ -31,6 +31,8 @@
#ifndef _VECTOR_TABLE__H_ #ifndef _VECTOR_TABLE__H_
#define _VECTOR_TABLE__H_ #define _VECTOR_TABLE__H_
#define EXC_EV_TRAP 0x9
#ifdef _ASMLANGUAGE #ifdef _ASMLANGUAGE
#include <board.h> #include <board.h>

View file

@ -58,7 +58,7 @@
#define _ARC_V2_STATUS32_H (1 << 0) #define _ARC_V2_STATUS32_H (1 << 0)
#define _ARC_V2_STATUS32_E(x) ((x) << 1) #define _ARC_V2_STATUS32_E(x) ((x) << 1)
#define _ARC_V2_STATUS32_AE_BIT 5 #define _ARC_V2_STATUS32_AE_BIT 5
#define _ARC_V2_STATUS32_AE (1 << ARC_V2_STATUS32_AE_BIT) #define _ARC_V2_STATUS32_AE (1 << _ARC_V2_STATUS32_AE_BIT)
#define _ARC_V2_STATUS32_DE (1 << 6) #define _ARC_V2_STATUS32_DE (1 << 6)
#define _ARC_V2_STATUS32_U (1 << 7) #define _ARC_V2_STATUS32_U (1 << 7)
#define _ARC_V2_STATUS32_V (1 << 8) #define _ARC_V2_STATUS32_V (1 << 8)