parisc NMI backtrace support
Helge Deller
maintainerRFC PATCH 1/1 parisc NMI backtrace support
On parisc we don't have a real NMI interrupt which can be triggered at any time, even when running in a loop with external interrupts disabled.
This patch works around that limitation by adding a new virtual NMI interrupt handler which works mostly like standard interrupts and which can be triggered at any time.
Up to now we used the I flag in the PSW (PSW_I) to enable or disable external interrupts completely. The arch_local_irq_disable() and arch_local_irq_enable() functions modified that bit in the processor internal PSW register.
In the new implementation we keep the external interrupts enabled the whole time and instead modify the EIEM (external interrupt enable mask) at runtime: When we want IRQs disabled, we only allow the NMI interrupt to pass, and when we enable interrupts we unmask all IRQs in the EIEM.
The patch below is still work-in-progress which contains debug printks and comments, but it seems to work (tested on qemu) and I'm looking for feedback.
The downside of this implementation is, that the arch_irq_local* functions became bigger and due to header dependencies I wasn't able to implement them inline.
The upside is, that we now can trigger NMI backtraces at any time to analyze where the kernel hangs. This can be done via sysrq on a serial console or when logged in via "echo l > /proc/sysrq_tigger".
arch/parisc/include/asm/irq.h +8 -1
@@ -22,7 +22,8 @@#endif #define TIMER_IRQ (CPU_IRQ_BASE + 0) -#define IPI_IRQ (CPU_IRQ_BASE + 1) +#define IPI_IRQ (CPU_IRQ_BASE + 1) +#define NMI_IRQ (CPU_IRQ_BASE + 2)#define CPU_IRQ_MAX (CPU_IRQ_BASE + (BITS_PER_LONG - 1))#define NR_IRQS (CPU_IRQ_MAX + 1)
@@ -50,4 +51,10 @@ extern int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest);/* soft power switch support (power.c) */ extern struct tasklet_struct power_tasklet; +#ifdef CONFIG_SMP +extern void arch_trigger_cpumask_backtrace (const cpumask_t *mask, +bool exclude_self); +#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace +#endif +#endif /* _ASM_PARISC_IRQ_H */
arch/parisc/include/asm/irqflags.h +7 -38
50 lines not on this page · raw message
arch/parisc/kernel/irq.c +105 -6
157 lines not on this page · raw message
Helge Deller
maintainer* Helge Deller <[email protected]>:
Quoted 21 lines
On parisc we don't have a real NMI interrupt which can be triggered at any time, even when running in a loop with external interrupts disabled.
This patch works around that limitation by adding a new virtual NMI interrupt handler which works mostly like standard interrupts and which can be triggered at any time.
Up to now we used the I flag in the PSW (
PSW_I) to enable or disable external interrupts completely. Thearch_local_irq_disable()andarch_local_irq_enable()functions modified that bit in the processor internal PSW register.
In the new implementation we keep the external interrupts enabled the whole time and instead modify the EIEM (external interrupt enable mask) at runtime: When we want IRQs disabled, we only allow the NMI interrupt to pass, and when we enable interrupts we unmask all IRQs in the EIEM.The patch below is still work-in-progress which contains debug printks and comments, but it seems to work (tested on qemu) and I'm looking for feedback.
Quoted 7 lines
The downside of this implementation is, that the arch_irq_local* functions became bigger and due to header dependencies I wasn't able to implement them inline.
The upside is, that we now can trigger NMI backtraces at any time to analyze where the kernel hangs. This can be done via sysrq on a serial console or when logged in via "echo l >
/proc/sysrq_tigger".
Below is an updated patch in which the local_irq* symbols were exported with EXPORT_SYMBOL() for usage in modules.
arch/parisc/include/asm/irq.h +8 -1
@@ -22,7 +22,8 @@#endif #define TIMER_IRQ (CPU_IRQ_BASE + 0) -#define IPI_IRQ (CPU_IRQ_BASE + 1) +#define IPI_IRQ (CPU_IRQ_BASE + 1) +#define NMI_IRQ (CPU_IRQ_BASE + 2)#define CPU_IRQ_MAX (CPU_IRQ_BASE + (BITS_PER_LONG - 1))#define NR_IRQS (CPU_IRQ_MAX + 1)
@@ -50,4 +51,10 @@ extern int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest);/* soft power switch support (power.c) */ extern struct tasklet_struct power_tasklet; +#ifdef CONFIG_SMP +extern void arch_trigger_cpumask_backtrace (const cpumask_t *mask, +bool exclude_self); +#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace +#endif +#endif /* _ASM_PARISC_IRQ_H */
arch/parisc/include/asm/irqflags.h +7 -38
50 lines not on this page · raw message
arch/parisc/kernel/irq.c +112 -6
164 lines not on this page · raw message