blob: 76be5cf0de13234ea413451dfccc53c62eed3e39 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/alpha/kernel/irq.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 *
6 * This file contains the code used by various IRQ handling routines:
7 * asking for different IRQ's should be done through these routines
8 * instead of just grabbing them. Thus setups with different IRQ numbers
9 * shouldn't result in any weird surprises, and installing new handlers
10 * should be easier.
11 */
12
13#include <linux/config.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/errno.h>
17#include <linux/kernel_stat.h>
18#include <linux/signal.h>
19#include <linux/sched.h>
20#include <linux/ptrace.h>
21#include <linux/interrupt.h>
22#include <linux/slab.h>
23#include <linux/random.h>
24#include <linux/init.h>
25#include <linux/irq.h>
26#include <linux/proc_fs.h>
27#include <linux/seq_file.h>
28#include <linux/profile.h>
29#include <linux/bitops.h>
30
31#include <asm/system.h>
32#include <asm/io.h>
33#include <asm/uaccess.h>
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035volatile unsigned long irq_err_count;
36
Ivan Kokshaysky0595bf32006-01-06 00:12:22 -080037void ack_bad_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038{
39 irq_err_count++;
40 printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq);
41}
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static char irq_user_affinity[NR_IRQS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Ivan Kokshaysky0595bf32006-01-06 00:12:22 -080046int
47select_smp_affinity(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
49 static int last_cpu;
50 int cpu = last_cpu + 1;
51
Ivan Kokshaysky0595bf32006-01-06 00:12:22 -080052 if (!irq_desc[irq].handler->set_affinity || irq_user_affinity[irq])
53 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 while (!cpu_possible(cpu))
56 cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
57 last_cpu = cpu;
58
59 irq_affinity[irq] = cpumask_of_cpu(cpu);
60 irq_desc[irq].handler->set_affinity(irq, cpumask_of_cpu(cpu));
Ivan Kokshaysky0595bf32006-01-06 00:12:22 -080061 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062}
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#endif /* CONFIG_SMP */
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065int
66show_interrupts(struct seq_file *p, void *v)
67{
68#ifdef CONFIG_SMP
69 int j;
70#endif
71 int i = *(loff_t *) v;
72 struct irqaction * action;
73 unsigned long flags;
74
75#ifdef CONFIG_SMP
76 if (i == 0) {
77 seq_puts(p, " ");
78 for (i = 0; i < NR_CPUS; i++)
79 if (cpu_online(i))
80 seq_printf(p, "CPU%d ", i);
81 seq_putc(p, '\n');
82 }
83#endif
84
85 if (i < ACTUAL_NR_IRQS) {
86 spin_lock_irqsave(&irq_desc[i].lock, flags);
87 action = irq_desc[i].action;
88 if (!action)
89 goto unlock;
90 seq_printf(p, "%3d: ",i);
91#ifndef CONFIG_SMP
92 seq_printf(p, "%10u ", kstat_irqs(i));
93#else
94 for (j = 0; j < NR_CPUS; j++)
95 if (cpu_online(j))
96 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
97#endif
98 seq_printf(p, " %14s", irq_desc[i].handler->typename);
99 seq_printf(p, " %c%s",
100 (action->flags & SA_INTERRUPT)?'+':' ',
101 action->name);
102
103 for (action=action->next; action; action = action->next) {
104 seq_printf(p, ", %c%s",
105 (action->flags & SA_INTERRUPT)?'+':' ',
106 action->name);
107 }
108
109 seq_putc(p, '\n');
110unlock:
111 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
112 } else if (i == ACTUAL_NR_IRQS) {
113#ifdef CONFIG_SMP
114 seq_puts(p, "IPI: ");
115 for (i = 0; i < NR_CPUS; i++)
116 if (cpu_online(i))
117 seq_printf(p, "%10lu ", cpu_data[i].ipi_count);
118 seq_putc(p, '\n');
119#endif
120 seq_printf(p, "ERR: %10lu\n", irq_err_count);
121 }
122 return 0;
123}
124
125
126/*
127 * handle_irq handles all normal device IRQ's (the special
128 * SMP cross-CPU interrupts have their own specific
129 * handlers).
130 */
131
132#define MAX_ILLEGAL_IRQS 16
133
134void
135handle_irq(int irq, struct pt_regs * regs)
136{
137 /*
138 * We ack quickly, we don't want the irq controller
139 * thinking we're snobs just because some other CPU has
140 * disabled global interrupts (we have already done the
141 * INT_ACK cycles, it's too late to try to pretend to the
142 * controller that we aren't taking the interrupt).
143 *
144 * 0 return value means that this irq is already being
145 * handled by some other CPU. (or is disabled)
146 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 static unsigned int illegal_count=0;
148
149 if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {
150 irq_err_count++;
151 illegal_count++;
152 printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
153 irq);
154 return;
155 }
156
157 irq_enter();
Ivan Kokshaysky0595bf32006-01-06 00:12:22 -0800158 local_irq_disable();
159 __do_IRQ(irq, regs);
160 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 irq_exit();
162}