diff --git a/arch/arm/core/irq_manage.c b/arch/arm/core/irq_manage.c index a4797a910d5..ea19751e744 100644 --- a/arch/arm/core/irq_manage.c +++ b/arch/arm/core/irq_manage.c @@ -70,20 +70,42 @@ void irq_disable(unsigned int irq) * * @brief Set an interrupt's priority * - * Valid values are from 1 to 255. Interrupts of priority 1 are not masked when - * interrupts are locked system-wide, so care must be taken when using them. ISR - * installed with priority 1 interrupts cannot make kernel calls. - * - * Priority 0 is reserved for kernel usage and cannot be used. - * - * The priority is verified if ASSERT_ON is enabled. + * The priority is verified if ASSERT_ON is enabled. The maximum number + * of priority levels is a little complex, as there are some hardware + * priority levels which are reserved: three for various types of exceptions, + * and possibly one additional to support zero latency interrupts. * * @return N/A */ -void _irq_priority_set(unsigned int irq, - unsigned int prio) +void _irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) { - __ASSERT(prio > 0 && prio < 256, "invalid priority!"); + /* Hardware priority levels 0 and 1 reserved for Kernel use. + * So we add 2 to the requested priority level. If we support + * ZLI, 2 is also reserved so we add 3. + */ + +#if CONFIG_ZERO_LATENCY_IRQS +#define IRQ_PRIORITY_OFFSET 3 + /* If we have zero latency interrupts, that makes priority level 2 + * a case with special semantics; it is not masked by irq_lock(). + * Our policy is to express priority levels with special properties + * via flags + */ + if (flags | IRQ_ZERO_LATENCY) { + prio = 2; + } else { + prio += IRQ_PRIORITY_OFFSET; + } +#else +#define IRQ_PRIORITY_OFFSET 2 + ARG_UNUSED(flags); + prio += IRQ_PRIORITY_OFFSET; +#endif + /* Last priority level reserved for PendSV exception */ + __ASSERT(prio < ((1 << CONFIG_NUM_IRQ_PRIO_BITS) - 1), + "invalid priority %d! values must be less than %d\n", + prio - IRQ_PRIORITY_OFFSET, + (1 << CONFIG_NUM_IRQ_PRIO_BITS) - (IRQ_PRIORITY_OFFSET + 1)); _NvicIrqPrioSet(irq, _EXC_PRIO(prio)); } @@ -146,7 +168,7 @@ int irq_connect_dynamic(unsigned int irq, { ARG_UNUSED(flags); _irq_handler_set(irq, isr, arg); - _irq_priority_set(irq, prio); + _irq_priority_set(irq, prio, flags); return irq; } diff --git a/include/arch/arm/cortex_m/irq.h b/include/arch/arm/cortex_m/irq.h index 7c0cac8a1f0..9ac9cee72ee 100644 --- a/include/arch/arm/cortex_m/irq.h +++ b/include/arch/arm/cortex_m/irq.h @@ -57,7 +57,19 @@ extern void _IntExit(void); #define CONCAT(x, y) DO_CONCAT(x, y) /* 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, + uint32_t flags); + + +/* Flags for use with IRQ_CONNECT() or irq_connect_dynamic() */ +#if CONFIG_ZERO_LATENCY_IRQS +/** + * Set this interrupt up as a zero-latency IRQ. It has a fixed hardware + * priority level (discarding what was supplied in the interrupt's priority + * argument), and will run even if irq_lock() is active. Be careful! + */ +#define IRQ_ZERO_LATENCY (1 << 0) +#endif /** @@ -85,7 +97,7 @@ extern void _irq_priority_set(unsigned int irq, unsigned int prio); * @param priority_p Interrupt priority * @param isr_p Interrupt service routine * @param isr_param_p ISR parameter - * @param flags_p IRQ triggering options (currently unused) + * @param flags_p IRQ options * * @return The vector assigned to this interrupt */ @@ -96,7 +108,7 @@ extern void _irq_priority_set(unsigned int irq, unsigned int prio); __attribute__ ((used)) \ __attribute__ ((section(STRINGIFY(_CONCAT(.gnu.linkonce.isr_irq, irq_p))))) = \ {isr_param_p, isr_p}; \ - _irq_priority_set(irq_p, priority_p); \ + _irq_priority_set(irq_p, priority_p, flags_p); \ irq_p; \ }) diff --git a/samples/nanokernel/test/test_arm_m3_irq_vector_table/src/main.c b/samples/nanokernel/test/test_arm_m3_irq_vector_table/src/main.c index 69431fa64f8..a34ee7b032b 100644 --- a/samples/nanokernel/test/test_arm_m3_irq_vector_table/src/main.c +++ b/samples/nanokernel/test/test_arm_m3_irq_vector_table/src/main.c @@ -90,7 +90,7 @@ void main(void) for (int ii = 0; ii < 3; ii++) { irq_enable(ii); - _irq_priority_set(ii, _EXC_IRQ_DEFAULT_PRIO); + _irq_priority_set(ii, 0, 0); nano_sem_init(&sem[ii]); }