xref: /openbmc/linux/arch/mips/kernel/irq.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds  * for more details.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Code to handle x86 style IRQs plus some generic interrupt stuff.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright (C) 1992 Linus Torvalds
91da177e4SLinus Torvalds  * Copyright (C) 1994 - 2000 Ralf Baechle
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/delay.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/interrupt.h>
151da177e4SLinus Torvalds #include <linux/kernel_stat.h>
161da177e4SLinus Torvalds #include <linux/proc_fs.h>
171da177e4SLinus Torvalds #include <linux/mm.h>
181da177e4SLinus Torvalds #include <linux/random.h>
191da177e4SLinus Torvalds #include <linux/sched.h>
201da177e4SLinus Torvalds #include <linux/seq_file.h>
211da177e4SLinus Torvalds #include <linux/kallsyms.h>
2288547001SJason Wessel #include <linux/kgdb.h>
238f99a162SWu Zhangjin #include <linux/ftrace.h>
241fee9db9SMarc Zyngier #include <linux/irqdomain.h>
251da177e4SLinus Torvalds 
2660063497SArun Sharma #include <linux/atomic.h>
277c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
281da177e4SLinus Torvalds 
29fe8bd18fSMatt Redfearn void *irq_stack[NR_CPUS];
30fe8bd18fSMatt Redfearn 
311da177e4SLinus Torvalds /*
321da177e4SLinus Torvalds  * 'what should we do if we get a hw irq event on an illegal vector'.
331da177e4SLinus Torvalds  * each architecture has to answer this themselves.
341da177e4SLinus Torvalds  */
ack_bad_irq(unsigned int irq)351da177e4SLinus Torvalds void ack_bad_irq(unsigned int irq)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	printk("unexpected IRQ # %d\n", irq);
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds atomic_t irq_err_count;
411da177e4SLinus Torvalds 
arch_show_interrupts(struct seq_file * p,int prec)42f8396c17SThomas Gleixner int arch_show_interrupts(struct seq_file *p, int prec)
431da177e4SLinus Torvalds {
44f8396c17SThomas Gleixner 	seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
451da177e4SLinus Torvalds 	return 0;
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
spurious_interrupt(void)48937a8015SRalf Baechle asmlinkage void spurious_interrupt(void)
4993373ed4SRalf Baechle {
5093373ed4SRalf Baechle 	atomic_inc(&irq_err_count);
5193373ed4SRalf Baechle }
5293373ed4SRalf Baechle 
init_IRQ(void)531da177e4SLinus Torvalds void __init init_IRQ(void)
541da177e4SLinus Torvalds {
5524649c00SRalf Baechle 	int i;
5672faa7a7SLiu Xiang 	unsigned int order = get_order(IRQ_STACK_SIZE);
5724649c00SRalf Baechle 
5824649c00SRalf Baechle 	for (i = 0; i < NR_IRQS; i++)
59e4ec7989SThomas Gleixner 		irq_set_noprobe(i);
6024649c00SRalf Baechle 
61640356a4SPaul Burton 	if (cpu_has_veic)
62640356a4SPaul Burton 		clear_c0_status(ST0_IM);
63640356a4SPaul Burton 
641da177e4SLinus Torvalds 	arch_init_irq();
65fe8bd18fSMatt Redfearn 
66fe8bd18fSMatt Redfearn 	for_each_possible_cpu(i) {
6772faa7a7SLiu Xiang 		void *s = (void *)__get_free_pages(GFP_KERNEL, order);
68fe8bd18fSMatt Redfearn 
69fe8bd18fSMatt Redfearn 		irq_stack[i] = s;
70fe8bd18fSMatt Redfearn 		pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
71fe8bd18fSMatt Redfearn 			irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
72fe8bd18fSMatt Redfearn 	}
731da177e4SLinus Torvalds }
748f99a162SWu Zhangjin 
755f35b9cdSJames Hogan #ifdef CONFIG_DEBUG_STACKOVERFLOW
check_stack_overflow(void)76334c86c4SFrom: jiang.adam@gmail.com static inline void check_stack_overflow(void)
77334c86c4SFrom: jiang.adam@gmail.com {
78334c86c4SFrom: jiang.adam@gmail.com 	unsigned long sp;
79334c86c4SFrom: jiang.adam@gmail.com 
80334c86c4SFrom: jiang.adam@gmail.com 	__asm__ __volatile__("move %0, $sp" : "=r" (sp));
81334c86c4SFrom: jiang.adam@gmail.com 	sp &= THREAD_MASK;
82334c86c4SFrom: jiang.adam@gmail.com 
83334c86c4SFrom: jiang.adam@gmail.com 	/*
84334c86c4SFrom: jiang.adam@gmail.com 	 * Check for stack overflow: is there less than STACK_WARN free?
85334c86c4SFrom: jiang.adam@gmail.com 	 * STACK_WARN is defined as 1/8 of THREAD_SIZE by default.
86334c86c4SFrom: jiang.adam@gmail.com 	 */
87334c86c4SFrom: jiang.adam@gmail.com 	if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
88334c86c4SFrom: jiang.adam@gmail.com 		printk("do_IRQ: stack overflow: %ld\n",
89334c86c4SFrom: jiang.adam@gmail.com 		       sp - sizeof(struct thread_info));
90334c86c4SFrom: jiang.adam@gmail.com 		dump_stack();
91334c86c4SFrom: jiang.adam@gmail.com 	}
92334c86c4SFrom: jiang.adam@gmail.com }
93334c86c4SFrom: jiang.adam@gmail.com #else
check_stack_overflow(void)94334c86c4SFrom: jiang.adam@gmail.com static inline void check_stack_overflow(void) {}
95334c86c4SFrom: jiang.adam@gmail.com #endif
96334c86c4SFrom: jiang.adam@gmail.com 
97334c86c4SFrom: jiang.adam@gmail.com 
988f99a162SWu Zhangjin /*
998f99a162SWu Zhangjin  * do_IRQ handles all normal device IRQ's (the special
1008f99a162SWu Zhangjin  * SMP cross-CPU interrupts have their own specific
1018f99a162SWu Zhangjin  * handlers).
1028f99a162SWu Zhangjin  */
do_IRQ(unsigned int irq)1038f99a162SWu Zhangjin void __irq_entry do_IRQ(unsigned int irq)
1048f99a162SWu Zhangjin {
1058f99a162SWu Zhangjin 	irq_enter();
106334c86c4SFrom: jiang.adam@gmail.com 	check_stack_overflow();
1078f99a162SWu Zhangjin 	generic_handle_irq(irq);
1088f99a162SWu Zhangjin 	irq_exit();
1098f99a162SWu Zhangjin }
1108f99a162SWu Zhangjin 
1111fee9db9SMarc Zyngier #ifdef CONFIG_IRQ_DOMAIN
do_domain_IRQ(struct irq_domain * domain,unsigned int hwirq)1121fee9db9SMarc Zyngier void __irq_entry do_domain_IRQ(struct irq_domain *domain, unsigned int hwirq)
1131fee9db9SMarc Zyngier {
1141fee9db9SMarc Zyngier 	irq_enter();
1151fee9db9SMarc Zyngier 	check_stack_overflow();
116*4cb6f4dfSMark Rutland 	generic_handle_domain_irq(domain, hwirq);
1171fee9db9SMarc Zyngier 	irq_exit();
1181fee9db9SMarc Zyngier }
1191fee9db9SMarc Zyngier #endif
120