11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file contains the lowest level x86-specific interrupt
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entry, irq-stacks and irq statistics code. All the remaining
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * irq logic is done by the generic kernel/irq/ code and
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the x86-specific irq controller code. (e.g. i8259.c and
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * io_apic.c.)
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel_stat.h>
15f370513640492641b4046bfd9a6e4714f6ae530dZwane Mwaikambo#include <linux/notifier.h>
16f370513640492641b4046bfd9a6e4714f6ae530dZwane Mwaikambo#include <linux/cpu.h>
17f370513640492641b4046bfd9a6e4714f6ae530dZwane Mwaikambo#include <linux/delay.h>
1872ade5f9ca7b384a180ae6b42987f627acd9fe95Jaswinder Singh Rajput#include <linux/uaccess.h>
1942f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshan#include <linux/percpu.h>
205c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet#include <linux/mm.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22e05d723f98595b2f4d368f63636a997d98703304Thomas Gleixner#include <asm/apic.h>
23e05d723f98595b2f4d368f63636a997d98703304Thomas Gleixner
24f34e3b61f2be9628bd41244f3ecc42009c5eced5Fenghua YuDEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_PER_CPU_SYMBOL(irq_stat);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
277c3576d261ce046789a7db14f43303f8120910c7Jeremy FitzhardingeDEFINE_PER_CPU(struct pt_regs *, irq_regs);
287c3576d261ce046789a7db14f43303f8120910c7Jeremy FitzhardingeEXPORT_PER_CPU_SYMBOL(irq_regs);
297c3576d261ce046789a7db14f43303f8120910c7Jeremy Fitzhardinge
30de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner#ifdef CONFIG_DEBUG_STACKOVERFLOW
3153b5650273fea486ac8ac6c1d1e9a6cd17aa31caIngo Molnar
3253b5650273fea486ac8ac6c1d1e9a6cd17aa31caIngo Molnarint sysctl_panic_on_stackoverflow __read_mostly;
3353b5650273fea486ac8ac6c1d1e9a6cd17aa31caIngo Molnar
34de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner/* Debugging check for stack overflow: is there less than 1KB free? */
35de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerstatic int check_stack_overflow(void)
36de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner{
37de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	long sp;
38de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
39de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	__asm__ __volatile__("andl %%esp,%0" :
40de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner			     "=r" (sp) : "0" (THREAD_SIZE - 1));
41de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
42de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	return sp < (sizeof(struct thread_info) + STACK_WARN);
43de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner}
44de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
45de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerstatic void print_stack_overflow(void)
46de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner{
47de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	printk(KERN_WARNING "low stack detected by irq handler\n");
48de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	dump_stack();
4955af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka	if (sysctl_panic_on_stackoverflow)
5055af77969fbd7a841838220ea2287432e0da8ae5Mitsuo Hayasaka		panic("low stack detected by irq handler - check messages\n");
51de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner}
52de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
53de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner#else
54de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerstatic inline int check_stack_overflow(void) { return 0; }
55de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerstatic inline void print_stack_overflow(void) { }
56de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner#endif
57de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * per-CPU IRQ handling contexts (thread information and stack)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunion irq_ctx {
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct thread_info      tinfo;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32                     stack[THREAD_SIZE/sizeof(u32)];
6425897374297906eeebef8864299406bdcb5859c3Christoph Hellwig} __attribute__((aligned(THREAD_SIZE)));
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6642f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshanstatic DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
6742f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshanstatic DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixnerstatic void call_on_stack(void *func, void *stack)
7004b361abfdc522239e3a071f3afdebf5787d9f03Andi Kleen{
71403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	asm volatile("xchgl	%%ebx,%%esp	\n"
72403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     "call	*%%edi		\n"
73403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     "movl	%%ebx,%%esp	\n"
74403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     : "=b" (stack)
75403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     : "0" (stack),
76403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		       "D"(func)
77403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     : "memory", "cc", "edx", "ecx", "eax");
7804b361abfdc522239e3a071f3afdebf5787d9f03Andi Kleen}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerstatic inline int
81de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixnerexecute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
82de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner{
83de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	union irq_ctx *curctx, *irqctx;
84403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	u32 *isp, arg1, arg2;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	curctx = (union irq_ctx *) current_thread_info();
870a3aee0da4402aa19b66e458038533c896fb80c6Tejun Heo	irqctx = __this_cpu_read(hardirq_ctx);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * this is where we switch to the IRQ stack. However, if we are
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * already using the IRQ stack (because we interrupted a hardirq
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * handler) we can't do that and just have to keep using the
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * current stack (which is the irq stack already after all)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
95de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	if (unlikely(curctx == irqctx))
96de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner		return 0;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	/* build the stack frame on the IRQ stack */
9972ade5f9ca7b384a180ae6b42987f627acd9fe95Jaswinder Singh Rajput	isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
100de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	irqctx->tinfo.task = curctx->tinfo.task;
101de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	irqctx->tinfo.previous_esp = current_stack_pointer;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103986cb48c5a4de0085db94d343b4e7dcf54355ec1Linus Torvalds	/* Copy the preempt_count so that the [soft]irq checks work. */
104986cb48c5a4de0085db94d343b4e7dcf54355ec1Linus Torvalds	irqctx->tinfo.preempt_count = curctx->tinfo.preempt_count;
105de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner
106de9b10af1287bf25b9c0433de53a2e95ef611aa7Thomas Gleixner	if (unlikely(overflow))
107403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		call_on_stack(print_stack_overflow, isp);
108403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner
109403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	asm volatile("xchgl	%%ebx,%%esp	\n"
110403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     "call	*%%edi		\n"
111403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     "movl	%%ebx,%%esp	\n"
112403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     : "=a" (arg1), "=d" (arg2), "=b" (isp)
113403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     :  "0" (irq),   "1" (desc),  "2" (isp),
114403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner			"D" (desc->handle_irq)
115403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		     : "memory", "cc", "ecx");
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocate per-cpu stacks for hardirq and for softirq processing
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
122403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixnervoid __cpuinit irq_ctx_init(int cpu)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union irq_ctx *irqctx;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12642f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshan	if (per_cpu(hardirq_ctx, cpu))
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1295c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet	irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
1305c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet					       THREAD_FLAGS,
1315c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet					       THREAD_ORDER));
1327b698ea377e10b074ceef0d79218e6622d618421Brian Gerst	memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
133403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	irqctx->tinfo.cpu		= cpu;
134403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	irqctx->tinfo.preempt_count	= HARDIRQ_OFFSET;
135403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	irqctx->tinfo.addr_limit	= MAKE_MM_SEG(0);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13742f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshan	per_cpu(hardirq_ctx, cpu) = irqctx;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1395c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet	irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
1405c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet					       THREAD_FLAGS,
1415c1eb08936693cd78c71164c8bea0b086ae72c67Eric Dumazet					       THREAD_ORDER));
1427b698ea377e10b074ceef0d79218e6622d618421Brian Gerst	memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
143403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	irqctx->tinfo.cpu		= cpu;
144403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	irqctx->tinfo.addr_limit	= MAKE_MM_SEG(0);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14642f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshan	per_cpu(softirq_ctx, cpu) = irqctx;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner	printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
14942f8faecf7a88371de0f30aebb052d1ae51762c0Lai Jiangshan	       cpu, per_cpu(hardirq_ctx, cpu),  per_cpu(softirq_ctx, cpu));
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void do_softirq(void)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct thread_info *curctx;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union irq_ctx *irqctx;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *isp;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_interrupt())
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (local_softirq_pending()) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		curctx = current_thread_info();
1660a3aee0da4402aa19b66e458038533c896fb80c6Tejun Heo		irqctx = __this_cpu_read(softirq_ctx);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irqctx->tinfo.task = curctx->task;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irqctx->tinfo.previous_esp = current_stack_pointer;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* build the stack frame on the softirq stack */
17172ade5f9ca7b384a180ae6b42987f627acd9fe95Jaswinder Singh Rajput		isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
173403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		call_on_stack(__do_softirq, isp);
17455f327fa9e876758491a82af7491104f1cc3fc4dIngo Molnar		/*
1750d2eb44f631d9d0a826efa3156f157477fdaecf4Lucas De Marchi		 * Shouldn't happen, we returned above if in_interrupt():
176403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner		 */
17755f327fa9e876758491a82af7491104f1cc3fc4dIngo Molnar		WARN_ON_ONCE(softirq_count());
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
182403d8efc94cd02ae36e7db13c4edf1d06d7b7facThomas Gleixner
1839b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardingebool handle_irq(unsigned irq, struct pt_regs *regs)
1849b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge{
1859b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	struct irq_desc *desc;
1869b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	int overflow;
1879b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
1889b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	overflow = check_stack_overflow();
1899b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
1909b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	desc = irq_to_desc(irq);
1919b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	if (unlikely(!desc))
1929b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge		return false;
1939b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
194986cb48c5a4de0085db94d343b4e7dcf54355ec1Linus Torvalds	if (user_mode_vm(regs) || !execute_on_irq_stack(overflow, desc, irq)) {
1959b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge		if (unlikely(overflow))
1969b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge			print_stack_overflow();
1979b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge		desc->handle_irq(irq, desc);
1989b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	}
1999b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge
2009b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge	return true;
2019b2b76a3344146c4d8d300874e73af8161204f87Jeremy Fitzhardinge}
202