irq: formalize external zephyr interrupt API

The app-facing interface for configuring interrupts was never
formally defined, instead it was defined separately for each arch
in their respective arch-specific header files. Occasionally these
would go out of sync.

Now there is a single irq.h header which defines this interface.
To avoid runtime overhead, these map to _arch_* implementations of
each that must be defined in headers pulled in by arch/cpu.h.

Change-Id: I69afbeff31fd07f981b5b291f3c427296b00a4ef
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2016-02-25 13:21:02 -08:00 committed by Gerrit Code Review
commit e444825ee3
9 changed files with 166 additions and 32 deletions

View file

@ -36,7 +36,7 @@
#include <toolchain.h> #include <toolchain.h>
#include <sections.h> #include <sections.h>
#include <sw_isr_table.h> #include <sw_isr_table.h>
#include <irq.h>
/* /*
* @brief Enable an interrupt line * @brief Enable an interrupt line
@ -48,7 +48,7 @@
* @return N/A * @return N/A
*/ */
void irq_enable(unsigned int irq) void _arch_irq_enable(unsigned int irq)
{ {
int key = irq_lock(); int key = irq_lock();
@ -65,7 +65,7 @@ void irq_enable(unsigned int irq)
* @return N/A * @return N/A
*/ */
void irq_disable(unsigned int irq) void _arch_irq_disable(unsigned int irq)
{ {
int key = irq_lock(); int key = irq_lock();
@ -158,7 +158,7 @@ void _irq_handler_set(
* @return the interrupt line number * @return the interrupt line number
*/ */
int irq_connect_dynamic( int _arch_irq_connect_dynamic(
unsigned int irq, unsigned int irq,
unsigned int prio, unsigned int prio,
void (*isr)(void *arg), void (*isr)(void *arg),

View file

@ -30,6 +30,7 @@
#include <toolchain.h> #include <toolchain.h>
#include <sections.h> #include <sections.h>
#include <sw_isr_table.h> #include <sw_isr_table.h>
#include <irq.h>
extern void __reserved(void); extern void __reserved(void);
@ -44,7 +45,7 @@ extern void __reserved(void);
* *
* @return N/A * @return N/A
*/ */
void irq_enable(unsigned int irq) void _arch_irq_enable(unsigned int irq)
{ {
/* before enabling interrupts, ensure that interrupt is cleared */ /* before enabling interrupts, ensure that interrupt is cleared */
_NvicIrqUnpend(irq); _NvicIrqUnpend(irq);
@ -60,7 +61,7 @@ void irq_enable(unsigned int irq)
* *
* @return N/A * @return N/A
*/ */
void irq_disable(unsigned int irq) void _arch_irq_disable(unsigned int irq)
{ {
_NvicIrqDisable(irq); _NvicIrqDisable(irq);
} }
@ -160,7 +161,7 @@ void _irq_handler_set(unsigned int irq,
* *
* @return the interrupt line number * @return the interrupt line number
*/ */
int irq_connect_dynamic(unsigned int irq, int _arch_irq_connect_dynamic(unsigned int irq,
unsigned int prio, unsigned int prio,
void (*isr)(void *arg), void (*isr)(void *arg),
void *arg, void *arg,

View file

@ -41,6 +41,7 @@
#include <misc/__assert.h> #include <misc/__assert.h>
#include <idtEnt.h> #include <idtEnt.h>
#include <misc/printk.h> #include <misc/printk.h>
#include <irq.h>
extern void _SpuriousIntHandler(void *); extern void _SpuriousIntHandler(void *);
extern void _SpuriousIntNoErrCodeHandler(void *); extern void _SpuriousIntNoErrCodeHandler(void *);
@ -262,7 +263,7 @@ extern void *_DynIntStubsBegin;
* vectors remaining in the specified <priority> level. * vectors remaining in the specified <priority> level.
*/ */
int irq_connect_dynamic(unsigned int irq, unsigned int priority, int _arch_irq_connect_dynamic(unsigned int irq, unsigned int priority,
void (*routine)(void *parameter), void *parameter, void (*routine)(void *parameter), void *parameter,
uint32_t flags) uint32_t flags)
{ {

View file

@ -55,6 +55,7 @@ extern "C" {
#endif #endif
#ifndef _ASMLANGUAGE #ifndef _ASMLANGUAGE
#include <irq.h>
/* internal routine documented in C file, needed by IRQ_CONNECT() macro */ /* internal routine documented in C file, needed by IRQ_CONNECT() macro */
extern void _irq_priority_set(unsigned int irq, unsigned int prio); extern void _irq_priority_set(unsigned int irq, unsigned int prio);
@ -88,7 +89,7 @@ extern void _irq_priority_set(unsigned int irq, unsigned int prio);
* *
* @return The vector assigned to this interrupt * @return The vector assigned to this interrupt
*/ */
#define IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ #define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
({ \ ({ \
enum { IRQ = irq_p }; \ enum { IRQ = irq_p }; \
static struct _IsrTableEntry _CONCAT(_isr_irq, irq_p) \ static struct _IsrTableEntry _CONCAT(_isr_irq, irq_p) \

View file

@ -26,6 +26,7 @@
#include <arch/arc/v2/aux_regs.h> #include <arch/arc/v2/aux_regs.h>
#include <toolchain/common.h> #include <toolchain/common.h>
#include <irq.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -33,18 +34,18 @@ extern "C" {
#ifdef _ASMLANGUAGE #ifdef _ASMLANGUAGE
GTEXT(_irq_exit); GTEXT(_irq_exit);
GTEXT(irq_connect) GTEXT(_arch_irq_connect)
GTEXT(irq_enable) GTEXT(_arch_irq_enable)
GTEXT(irq_disable) GTEXT(_arch_irq_disable)
#else #else
extern int irq_connect_dynamic(unsigned int irq, extern int _arch_irq_connect_dynamic(unsigned int irq,
unsigned int prio, unsigned int prio,
void (*isr)(void *arg), void (*isr)(void *arg),
void *arg, void *arg,
uint32_t flags); uint32_t flags);
extern void irq_enable(unsigned int irq); extern void _arch_irq_enable(unsigned int irq);
extern void irq_disable(unsigned int irq); extern void _arch_irq_disable(unsigned int irq);
extern void _irq_exit(void); extern void _irq_exit(void);
@ -80,7 +81,7 @@ extern void _irq_exit(void);
* "interrupt disable state" prior to the call. * "interrupt disable state" prior to the call.
*/ */
static ALWAYS_INLINE unsigned int irq_lock(void) static ALWAYS_INLINE unsigned int _arch_irq_lock(void)
{ {
unsigned int key; unsigned int key;
@ -101,7 +102,7 @@ static ALWAYS_INLINE unsigned int irq_lock(void)
* @return N/A * @return N/A
*/ */
static ALWAYS_INLINE void irq_unlock(unsigned int key) static ALWAYS_INLINE void _arch_irq_unlock(unsigned int key)
{ {
__asm__ volatile("seti %0" : : "ir"(key)); __asm__ volatile("seti %0" : : "ir"(key));
} }

View file

@ -41,6 +41,7 @@ extern "C" {
#else /* !_ASMLANGUAGE */ #else /* !_ASMLANGUAGE */
#include <stdint.h> #include <stdint.h>
#include <arch/arm/cortex_m/nvic.h> #include <arch/arm/cortex_m/nvic.h>
#include <irq.h>
/** /**
* *
@ -136,7 +137,7 @@ static ALWAYS_INLINE unsigned int find_lsb_set(uint32_t op)
* the two highest priorities from interrupting the CPU. * the two highest priorities from interrupting the CPU.
*/ */
static ALWAYS_INLINE unsigned int irq_lock(void) static ALWAYS_INLINE unsigned int _arch_irq_lock(void)
{ {
unsigned int key; unsigned int key;
@ -167,7 +168,7 @@ static ALWAYS_INLINE unsigned int irq_lock(void)
* @return N/A * @return N/A
*/ */
static ALWAYS_INLINE void irq_unlock(unsigned int key) static ALWAYS_INLINE void _arch_irq_unlock(unsigned int key)
{ {
__asm__ volatile("msr BASEPRI, %0;\n\t" : : "r"(key)); __asm__ volatile("msr BASEPRI, %0;\n\t" : : "r"(key));
} }

View file

@ -24,6 +24,7 @@
#ifndef _ARCH_ARM_CORTEXM_IRQ_H_ #ifndef _ARCH_ARM_CORTEXM_IRQ_H_
#define _ARCH_ARM_CORTEXM_IRQ_H_ #define _ARCH_ARM_CORTEXM_IRQ_H_
#include <irq.h>
#include <arch/arm/cortex_m/nvic.h> #include <arch/arm/cortex_m/nvic.h>
#include <sw_isr_table.h> #include <sw_isr_table.h>
@ -33,18 +34,18 @@ extern "C" {
#ifdef _ASMLANGUAGE #ifdef _ASMLANGUAGE
GTEXT(_IntExit); GTEXT(_IntExit);
GTEXT(irq_connect_dynamic) GTEXT(_arch_irq_connect_dynamic)
GTEXT(irq_enable) GTEXT(_arch_irq_enable)
GTEXT(irq_disable) GTEXT(_arch_irq_disable)
#else #else
extern int irq_connect_dynamic(unsigned int irq, extern int _arch_irq_connect_dynamic(unsigned int irq,
unsigned int prio, unsigned int prio,
void (*isr)(void *arg), void (*isr)(void *arg),
void *arg, void *arg,
uint32_t flags); uint32_t flags);
extern void irq_enable(unsigned int irq); extern void _arch_irq_enable(unsigned int irq);
extern void irq_disable(unsigned int irq); extern void _arch_irq_disable(unsigned int irq);
extern void _IntExit(void); extern void _IntExit(void);
@ -101,7 +102,7 @@ extern void _irq_priority_set(unsigned int irq, unsigned int prio,
* *
* @return The vector assigned to this interrupt * @return The vector assigned to this interrupt
*/ */
#define IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ #define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
({ \ ({ \
enum { IRQ = irq_p }; \ enum { IRQ = irq_p }; \
static struct _IsrTableEntry _CONCAT(_isr_irq, irq_p) \ static struct _IsrTableEntry _CONCAT(_isr_irq, irq_p) \

View file

@ -24,6 +24,8 @@
#ifndef _ARCH_IFACE_H #ifndef _ARCH_IFACE_H
#define _ARCH_IFACE_H #define _ARCH_IFACE_H
#include <irq.h>
#ifndef _ASMLANGUAGE #ifndef _ASMLANGUAGE
#include <arch/x86/asm_inline.h> #include <arch/x86/asm_inline.h>
#include <arch/x86/addr_types.h> #include <arch/x86/addr_types.h>
@ -250,7 +252,7 @@ typedef struct s_isrList {
* *
* @return The vector assigned to this interrupt * @return The vector assigned to this interrupt
*/ */
#define IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ #define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
({ \ ({ \
__asm__ __volatile__( \ __asm__ __volatile__( \
"jmp 2f\n\t" \ "jmp 2f\n\t" \
@ -404,7 +406,7 @@ void _int_latency_stop(void);
* *
*/ */
static inline __attribute__((always_inline)) unsigned int irq_lock(void) static inline __attribute__((always_inline)) unsigned int _arch_irq_lock(void)
{ {
unsigned int key = _do_irq_lock(); unsigned int key = _do_irq_lock();
@ -428,7 +430,7 @@ static inline __attribute__((always_inline)) unsigned int irq_lock(void)
* *
*/ */
static inline __attribute__((always_inline)) void irq_unlock(unsigned int key) static inline __attribute__((always_inline)) void _arch_irq_unlock(unsigned int key)
{ {
if (!(key & 0x200)) { if (!(key & 0x200)) {
return; return;
@ -460,7 +462,7 @@ typedef void (*NANO_EOI_GET_FUNC) (void *);
#endif /* CONFIG_SSE */ #endif /* CONFIG_SSE */
#endif /* CONFIG_FP_SHARING */ #endif /* CONFIG_FP_SHARING */
extern int irq_connect_dynamic(unsigned int irq, extern int _arch_irq_connect_dynamic(unsigned int irq,
unsigned int priority, unsigned int priority,
void (*routine)(void *parameter), void (*routine)(void *parameter),
void *parameter, void *parameter,
@ -470,12 +472,12 @@ extern int irq_connect_dynamic(unsigned int irq,
* @brief Enable a specific IRQ * @brief Enable a specific IRQ
* @param irq IRQ * @param irq IRQ
*/ */
extern void irq_enable(unsigned int irq); extern void _arch_irq_enable(unsigned int irq);
/** /**
* @brief Disable a specific IRQ * @brief Disable a specific IRQ
* @param irq IRQ * @param irq IRQ
*/ */
extern void irq_disable(unsigned int irq); extern void _arch_irq_disable(unsigned int irq);
#ifdef CONFIG_FP_SHARING #ifdef CONFIG_FP_SHARING
/** /**

126
include/irq.h Normal file
View file

@ -0,0 +1,126 @@
/*
* 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
* @brief Public interface for configuring interrupts
*/
#ifndef _IRQ_H_
#define _IRQ_H_
/* Pull in the arch-specific implementations */
#include <arch/cpu.h>
/**
* 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.
*
* @param irq_p IRQ line number
* @param priority_p Interrupt priority
* @param isr_p Interrupt service routine
* @param isr_param_p ISR parameter
* @param flags_p Arch-specific IRQ configuration flags
*
* @return The vector assigned to this interrupt
*/
#define IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
_ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p)
/**
* Configure a dynamic interrupt.
*
* @param irq_p IRQ line number
* @param priority_p Interrupt priority
* @param isr_p Interrupt service routine
* @param isr_param_p ISR parameter
* @param flags_p Arch-specific IRQ configuration flags
*
* @return The vector assigned to this interrupt
*/
#define irq_connect_dynamic(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
_arch_irq_connect_dynamic(irq_p, priority_p, isr_p, isr_param_p, \
flags_p)
/**
* @brief Disable all interrupts on the CPU (inline)
*
* This routine disables interrupts. It can be called from either interrupt,
* task or fiber level. This routine returns an architecture-dependent
* lock-out key representing the "interrupt disable state" prior to the call;
* this key can be passed to irq_unlock() to re-enable interrupts.
*
* The lock-out key should only be used as the argument to the irq_unlock()
* API. It should never be used to manually re-enable interrupts or to inspect
* or manipulate the contents of the source register.
*
* This function can be called recursively: it will return a key to return the
* state of interrupt locking to the previous level.
*
* WARNINGS
* Invoking a kernel routine with interrupts locked may result in
* interrupts being re-enabled for an unspecified period of time. If the
* called routine blocks, interrupts will be re-enabled while another
* thread executes, or while the system is idle.
*
* The "interrupt disable state" is an attribute of a thread. Thus, if a
* fiber or task disables interrupts and subsequently invokes a kernel
* routine that causes the calling thread to block, the interrupt
* disable state will be restored when the thread is later rescheduled
* for execution.
*
* @return An architecture-dependent unsigned int lock-out key representing the
* "interrupt disable state" prior to the call.
*
*/
#define irq_lock() _arch_irq_lock()
/**
*
* @brief Enable all interrupts on the CPU (inline)
*
* This routine re-enables interrupts on the CPU. The @a key parameter
* is an architecture-dependent lock-out key that is returned by a previous
* invocation of irq_lock().
*
* This routine can be called from either interrupt, task or fiber level
*
* @param key architecture-dependent lock-out key
*
* @return N/A
*/
#define irq_unlock(key) _arch_irq_unlock(key)
/**
* @brief Enable a specific IRQ
*
* @param irq IRQ line
* @return N/A
*/
#define irq_enable(irq) _arch_irq_enable(irq)
/**
* @brief Disable a specific IRQ
*
* @param irq IRQ line
* @return N/A
*/
#define irq_disable(irq) _arch_irq_disable(irq)
#endif /* _IRQ_H_ */