irq.c 3.9 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 36
/*
 *	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/config.h>
#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;

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

#ifdef CONFIG_SMP 
static char irq_user_affinity[NR_IRQS];

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

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

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

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

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

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

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

		for (action=action->next; action; action = action->next) {
			seq_printf(p, ", %c%s",
				  (action->flags & SA_INTERRUPT)?'+':' ',
				   action->name);
		}

		seq_putc(p, '\n');
unlock:
109 110
		spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
	} else if (irq == ACTUAL_NR_IRQS) {
L
Linus Torvalds 已提交
111 112
#ifdef CONFIG_SMP
		seq_puts(p, "IPI: ");
113 114
		for_each_online_cpu(j)
			seq_printf(p, "%10lu ", cpu_data[j].ipi_count);
L
Linus Torvalds 已提交
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 153
		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();
154 155 156 157 158 159
	/*
	 * __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.
	 */
160 161
	local_irq_disable();
	__do_IRQ(irq, regs);
L
Linus Torvalds 已提交
162 163
	irq_exit();
}