Skip to content

xtensa: support for more than 32 interrupts #92049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion arch/xtensa/core/irq_manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,59 @@ void z_irq_spurious(const void *arg)
__asm__ volatile("rsr.intenable %0" : "=r"(ie));
LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p",
(void *)irqs, (void *)ie);

#if XCHAL_NUM_INTERRUPTS > 32
__asm__ volatile("rsr.interrupt1 %0" : "=r"(irqs));
__asm__ volatile("rsr.intenable1 %0" : "=r"(ie));
LOG_ERR(" ** Spurious INTERRUPT1(s) %p, INTENABLE1 = %p",
(void *)irqs, (void *)ie);
#endif

#if XCHAL_NUM_INTERRUPTS > 64
__asm__ volatile("rsr.interrupt2 %0" : "=r"(irqs));
__asm__ volatile("rsr.intenable2 %0" : "=r"(ie));
LOG_ERR(" ** Spurious INTERRUPT2(s) %p, INTENABLE2 = %p",
(void *)irqs, (void *)ie);
#endif

#if XCHAL_NUM_INTERRUPTS > 96
__asm__ volatile("rsr.interrupt3 %0" : "=r"(irqs));
__asm__ volatile("rsr.intenable3 %0" : "=r"(ie));
LOG_ERR(" ** Spurious INTERRUPT3(s) %p, INTENABLE3 = %p",
(void *)irqs, (void *)ie);
#endif

xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL);
}

int xtensa_irq_is_enabled(unsigned int irq)
{
uint32_t ie;

#if XCHAL_NUM_INTERRUPTS > 32
switch (irq >> 5) {
case 0:
__asm__ volatile("rsr.intenable %0" : "=r"(ie));
break;
case 1:
__asm__ volatile("rsr.intenable1 %0" : "=r"(ie));
break;
#if XCHAL_NUM_INTERRUPTS > 64
case 2:
__asm__ volatile("rsr.intenable2 %0" : "=r"(ie));
break;
#endif
#if XCHAL_NUM_INTERRUPTS > 96
case 3:
__asm__ volatile("rsr.intenable3 %0" : "=r"(ie));
break;
#endif
default:
break;
}
#else
__asm__ volatile("rsr.intenable %0" : "=r"(ie));
#endif

return (ie & (1 << irq)) != 0U;
return (ie & (1 << (irq & 31U))) != 0U;
}
61 changes: 57 additions & 4 deletions arch/xtensa/core/irq_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,63 @@ void arch_irq_offload(irq_offload_routine_t routine, const void *parameter)
offload_params[cpu_id].fn = routine;
offload_params[cpu_id].arg = parameter;

__asm__ volatile("rsr %0, INTENABLE" : "=r"(intenable));
intenable |= BIT(ZSR_IRQ_OFFLOAD_INT);
__asm__ volatile("wsr %0, INTENABLE; wsr %0, INTSET; rsync"
:: "r"(intenable), "r"(BIT(ZSR_IRQ_OFFLOAD_INT)));
#if XCHAL_NUM_INTERRUPTS > 32
switch ((ZSR_IRQ_OFFLOAD_INT) >> 5) {
case 0:
__asm__ volatile("rsr.intenable %0" : "=r"(intenable));
break;
case 1:
__asm__ volatile("rsr.intenable1 %0" : "=r"(intenable));
break;
#if XCHAL_NUM_INTERRUPTS > 64
case 2:
__asm__ volatile("rsr.intenable2 %0" : "=r"(intenable));
break;
#endif
#if XCHAL_NUM_INTERRUPTS > 96
case 3:
__asm__ volatile("rsr.intenable3 %0" : "=r"(intenable));
break;
#endif
default:
break;
}
#else
__asm__ volatile("rsr.intenable %0" : "=r"(intenable));
#endif

intenable |= BIT((ZSR_IRQ_OFFLOAD_INT & 31U));

#if XCHAL_NUM_INTERRUPTS > 32
switch ((ZSR_IRQ_OFFLOAD_INT) >> 5) {
case 0:
__asm__ volatile("wsr.intenable %0; wsr.intset %0; rsync"
:: "r"(intenable), "r"(BIT((ZSR_IRQ_OFFLOAD_INT & 31U))));
break;
case 1:
__asm__ volatile("wsr.intenable1 %0; wsr.intset1 %0; rsync"
:: "r"(intenable), "r"(BIT((ZSR_IRQ_OFFLOAD_INT & 31U))));
break;
#if XCHAL_NUM_INTERRUPTS > 64
case 2:
__asm__ volatile("wsr.intenable2 %0; wsr.intset2 %0; rsync"
:: "r"(intenable), "r"(BIT((ZSR_IRQ_OFFLOAD_INT & 31U))));
break;
#endif
#if XCHAL_NUM_INTERRUPTS > 96
case 3:
__asm__ volatile("wsr.intenable3 %0; wsr.intset3 %0; rsync"
:: "r"(intenable), "r"(BIT((ZSR_IRQ_OFFLOAD_INT & 31U))));
break;
#endif
default:
break;
}
#else
__asm__ volatile("wsr.intenable %0; wsr.intset %0; rsync"
:: "r"(intenable), "r"(BIT((ZSR_IRQ_OFFLOAD_INT & 31U))));
#endif

arch_irq_unlock(key);
}

Expand Down
11 changes: 10 additions & 1 deletion arch/xtensa/core/startup/reset_vector.S
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,16 @@ _ResetHandler:
/* make sure that interrupts are shut off (*before* we lower
* PS.INTLEVEL and PS.EXCM!)
*/
wsr a0, INTENABLE
wsr.intenable a0
#if (XCHAL_NUM_INTERRUPTS > 32)
wsr.intenable1 a0
#endif
#if (XCHAL_NUM_INTERRUPTS > 64)
wsr.intenable2 a0
#endif
#if (XCHAL_NUM_INTERRUPTS > 96)
wsr.intenable3 a0
#endif
#endif

#if !XCHAL_HAVE_FULL_RESET
Expand Down
118 changes: 107 additions & 11 deletions arch/xtensa/core/vector_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,20 +286,116 @@ static inline void *return_to(void *interrupted)
* This may be unused depending on number of interrupt levels
* supported by the SoC.
*/
#define DEF_INT_C_HANDLER(l) \
__unused void *xtensa_int##l##_c(void *interrupted_stack) \
{ \
uint32_t irqs, intenable, m; \
usage_stop(); \
__asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \

#if XCHAL_NUM_INTERRUPTS <= 32
#define DEF_INT_C_HANDLER(l) \
__unused void *xtensa_int##l##_c(void *interrupted_stack) \
{ \
uint32_t irqs, intenable, m; \
usage_stop(); \
__asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(irqs))) { \
irqs ^= m; \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(0, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear %0" : : "r"(m)); \
} \
return return_to(interrupted_stack); \
} \
return return_to(interrupted_stack); \
}
#endif /* XCHAL_NUM_INTERRUPTS <= 32 */

#if XCHAL_NUM_INTERRUPTS > 32 && XCHAL_NUM_INTERRUPTS <= 64
#define DEF_INT_C_HANDLER(l) \
__unused void *xtensa_int##l##_c(void *interrupted_stack) \
{ \
uint32_t irqs, intenable, m; \
usage_stop(); \
__asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(0, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt1 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable1 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(1, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear1 %0" : : "r"(m)); \
} \
return return_to(interrupted_stack); \
}
#endif /* XCHAL_NUM_INTERRUPTS > 32 && XCHAL_NUM_INTERRUPTS <= 64 */

#if XCHAL_NUM_INTERRUPTS > 64 && XCHAL_NUM_INTERRUPTS <= 96
#define DEF_INT_C_HANDLER(l) \
__unused void *xtensa_int##l##_c(void *interrupted_stack) \
{ \
uint32_t irqs, intenable, m; \
usage_stop(); \
__asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(0, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt1 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable1 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(1, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear1 %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt2 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable2 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(2, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear2 %0" : : "r"(m)); \
} \
return return_to(interrupted_stack); \
}
#endif /* XCHAL_NUM_INTERRUPTS > 64 && XCHAL_NUM_INTERRUPTS <= 96 */

#if XCHAL_NUM_INTERRUPTS > 96
#define DEF_INT_C_HANDLER(l) \
__unused void *xtensa_int##l##_c(void *interrupted_stack) \
{ \
uint32_t irqs, intenable, m; \
usage_stop(); \
__asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(0, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt1 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable1 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(1, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear1 %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt2 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable2 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(2, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear2 %0" : : "r"(m)); \
} \
__asm__ volatile("rsr.interrupt3 %0" : "=r"(irqs)); \
__asm__ volatile("rsr.intenable3 %0" : "=r"(intenable)); \
irqs &= intenable; \
while ((m = _xtensa_handle_one_int##l(3, irqs))) { \
irqs ^= m; \
__asm__ volatile("wsr.intclear3 %0" : : "r"(m)); \
} \
return return_to(interrupted_stack); \
}
#endif /* XCHAL_NUM_INTERRUPTS > 96 */

#if XCHAL_HAVE_NMI
#define MAX_INTR_LEVEL XCHAL_NMILEVEL
Expand Down
10 changes: 7 additions & 3 deletions arch/xtensa/core/xtensa_intgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def emit_int_handler(ints):

# Emit the handlers
for lvl in ints_by_lvl:
cprint("static inline int _xtensa_handle_one_int" + str(lvl) + "(unsigned int mask)")
cprint("static inline int _xtensa_handle_one_int" +
str(lvl) + "(unsigned int set, unsigned int mask)")
cprint("{")

if not ints_by_lvl[lvl]:
Expand All @@ -128,11 +129,14 @@ def emit_int_handler(ints):
cprint("int irq;")
print("")

emit_int_handler(sorted(ints_by_lvl[lvl]))
if int(len(ints_by_lvl[lvl])) > 32:
emit_int_handler((sorted(ints_by_lvl[lvl]))[0:31])
else:
emit_int_handler(sorted(ints_by_lvl[lvl]))

cprint("return 0;")
cprint("handle_irq:")
cprint("_sw_isr_table[irq].isr(_sw_isr_table[irq].arg);")
cprint("_sw_isr_table[set * 32 + irq].isr(_sw_isr_table[set * 32 + irq].arg);")
cprint("return mask;")
cprint("}")
cprint("")
Loading
Loading