irq.c 3.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 *	linux/arch/alpha/kernel/irq.c
 *
 *	Copyright (C) 1995 Linus Torvalds
 *
 * This file contains the code used by various IRQ handling routines:
 * asking for different IRQ's should be done through these routines
 * instead of just grabbing them. Thus setups with different IRQ numbers
 * shouldn't result in any weird surprises, and installing new handlers
 * should be easier.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/profile.h>
#include <linux/bitops.h>

#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>

volatile unsigned long irq_err_count;

36
void ack_bad_irq(unsigned int irq)
L
Linus Torvalds 已提交
37 38 39 40 41 42 43 44
{
	irq_err_count++;
	printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq);
}

#ifdef CONFIG_SMP 
static char irq_user_affinity[NR_IRQS];

45 46
int
select_smp_affinity(unsigned int irq)
L
Linus Torvalds 已提交
47 48 49 50
{
	static int last_cpu;
	int cpu = last_cpu + 1;

51
	if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq])
52
		return 1;
L
Linus Torvalds 已提交
53 54 55 56 57

	while (!cpu_possible(cpu))
		cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
	last_cpu = cpu;

58
	irq_desc[irq].affinity = cpumask_of_cpu(cpu);
59
	irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu));
60
	return 0;
L
Linus Torvalds 已提交
61 62 63 64 65 66 67 68 69
}
#endif /* CONFIG_SMP */

int
show_interrupts(struct seq_file *p, void *v)
{
#ifdef CONFIG_SMP
	int j;
#endif
70
	int irq = *(loff_t *) v;
L
Linus Torvalds 已提交
71 72 73 74
	struct irqaction * action;
	unsigned long flags;

#ifdef CONFIG_SMP
75
	if (irq == 0) {
L
Linus Torvalds 已提交
76
		seq_puts(p, "           ");
77 78
		for_each_online_cpu(j)
			seq_printf(p, "CPU%d       ", j);
L
Linus Torvalds 已提交
79 80 81 82
		seq_putc(p, '\n');
	}
#endif

83 84 85
	if (irq < ACTUAL_NR_IRQS) {
		spin_lock_irqsave(&irq_desc[irq].lock, flags);
		action = irq_desc[irq].action;
L
Linus Torvalds 已提交
86 87
		if (!action) 
			goto unlock;
88
		seq_printf(p, "%3d: ", irq);
L
Linus Torvalds 已提交
89
#ifndef CONFIG_SMP
90
		seq_printf(p, "%10u ", kstat_irqs(irq));
L
Linus Torvalds 已提交
91
#else
92 93
		for_each_online_cpu(j)
			seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]);
L
Linus Torvalds 已提交
94
#endif
95
		seq_printf(p, " %14s", irq_desc[irq].chip->typename);
L
Linus Torvalds 已提交
96
		seq_printf(p, "  %c%s",
97
			(action->flags & IRQF_DISABLED)?'+':' ',
L
Linus Torvalds 已提交
98 99 100 101
			action->name);

		for (action=action->next; action; action = action->next) {
			seq_printf(p, ", %c%s",
102
				  (action->flags & IRQF_DISABLED)?'+':' ',
L
Linus Torvalds 已提交
103 104 105 106 107
				   action->name);
		}

		seq_putc(p, '\n');
unlock:
108 109
		spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
	} else if (irq == ACTUAL_NR_IRQS) {
L
Linus Torvalds 已提交
110 111
#ifdef CONFIG_SMP
		seq_puts(p, "IPI: ");
112 113
		for_each_online_cpu(j)
			seq_printf(p, "%10lu ", cpu_data[j].ipi_count);
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
		seq_putc(p, '\n');
#endif
		seq_printf(p, "ERR: %10lu\n", irq_err_count);
	}
	return 0;
}

/*
 * handle_irq handles all normal device IRQ's (the special
 * SMP cross-CPU interrupts have their own specific
 * handlers).
 */

#define MAX_ILLEGAL_IRQS 16

void
handle_irq(int irq, struct pt_regs * regs)
{	
	/* 
	 * We ack quickly, we don't want the irq controller
	 * thinking we're snobs just because some other CPU has
	 * disabled global interrupts (we have already done the
	 * INT_ACK cycles, it's too late to try to pretend to the
	 * controller that we aren't taking the interrupt).
	 *
	 * 0 return value means that this irq is already being
	 * handled by some other CPU. (or is disabled)
	 */
	static unsigned int illegal_count=0;
	
	if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {
		irq_err_count++;
		illegal_count++;
		printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
		       irq);
		return;
	}

	irq_enter();
153 154 155 156 157 158
	/*
	 * __do_IRQ() must be called with IPL_MAX. Note that we do not
	 * explicitly enable interrupts afterwards - some MILO PALcode
	 * (namely LX164 one) seems to have severe problems with RTI
	 * at IPL 0.
	 */
159 160
	local_irq_disable();
	__do_IRQ(irq, regs);
L
Linus Torvalds 已提交
161 162
	irq_exit();
}