irqinit.c 7.6 KB
Newer Older
1
#include <linux/linkage.h>
L
Linus Torvalds 已提交
2 3 4 5 6
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
7
#include <linux/timex.h>
L
Linus Torvalds 已提交
8
#include <linux/random.h>
9
#include <linux/kprobes.h>
L
Linus Torvalds 已提交
10 11
#include <linux/init.h>
#include <linux/kernel_stat.h>
K
Kay Sievers 已提交
12
#include <linux/device.h>
L
Linus Torvalds 已提交
13
#include <linux/bitops.h>
14
#include <linux/acpi.h>
15 16
#include <linux/io.h>
#include <linux/delay.h>
L
Linus Torvalds 已提交
17

A
Arun Sharma 已提交
18
#include <linux/atomic.h>
L
Linus Torvalds 已提交
19
#include <asm/timer.h>
20
#include <asm/hw_irq.h>
L
Linus Torvalds 已提交
21 22 23
#include <asm/pgtable.h>
#include <asm/desc.h>
#include <asm/apic.h>
I
Ingo Molnar 已提交
24
#include <asm/setup.h>
L
Linus Torvalds 已提交
25
#include <asm/i8259.h>
26
#include <asm/traps.h>
27
#include <asm/prom.h>
L
Linus Torvalds 已提交
28

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*
 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
 * (these are usually mapped to vectors 0x30-0x3f)
 */

/*
 * The IO-APIC gives us many more interrupt sources. Most of these
 * are unused but an SMP system is supposed to have enough memory ...
 * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
 * across the spectrum, so we really want to be prepared to get all
 * of these. Plus, more powerful systems might have more than 64
 * IO-APIC registers.
 *
 * (these are usually mapped into the 0x30-0xff vector range)
 */
L
Linus Torvalds 已提交
44

45
#ifdef CONFIG_X86_32
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56 57
/*
 * Note that on a 486, we don't want to do a SIGFPE on an irq13
 * as the irq is unreliable, and exception 16 works correctly
 * (ie as explained in the intel literature). On a 386, you
 * can't use exception 16 due to bad IBM design, so we have to
 * rely on the less exact irq13.
 *
 * Careful.. Not only is IRQ13 unreliable, but it is also
 * leads to races. IBM designers who came up with it should
 * be shot.
 */

58
static irqreturn_t math_error_irq(int cpl, void *dev_id)
L
Linus Torvalds 已提交
59
{
60
	outb(0, 0xF0);
L
Linus Torvalds 已提交
61 62
	if (ignore_fpu_irq || !boot_cpu_data.hard_math)
		return IRQ_NONE;
63
	math_error(get_irq_regs(), 0, 16);
L
Linus Torvalds 已提交
64 65 66 67 68 69 70
	return IRQ_HANDLED;
}

/*
 * New motherboards sometimes make IRQ 13 be a PCI interrupt,
 * so allow interrupt sharing.
 */
71 72 73
static struct irqaction fpu_irq = {
	.handler = math_error_irq,
	.name = "fpu",
74
	.flags = IRQF_NO_THREAD,
75
};
L
Linus Torvalds 已提交
76 77
#endif

78 79 80 81 82 83
/*
 * IRQ2 is cascade interrupt to second interrupt controller
 */
static struct irqaction irq2 = {
	.handler = no_action,
	.name = "cascade",
84
	.flags = IRQF_NO_THREAD,
85 86
};

87
DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
88
	[0 ... NR_VECTORS - 1] = -1,
89 90
};

91 92 93 94 95 96 97 98 99 100 101 102
int vector_used_by_percpu_irq(unsigned int vector)
{
	int cpu;

	for_each_online_cpu(cpu) {
		if (per_cpu(vector_irq, cpu)[vector] != -1)
			return 1;
	}

	return 0;
}

103
void __init init_ISA_irqs(void)
L
Linus Torvalds 已提交
104
{
105 106
	struct irq_chip *chip = legacy_pic->chip;
	const char *name = chip->name;
L
Linus Torvalds 已提交
107 108
	int i;

109
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
110 111
	init_bsp_APIC();
#endif
112
	legacy_pic->init(0);
L
Linus Torvalds 已提交
113

114
	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
115
		irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);
116
}
L
Linus Torvalds 已提交
117

118
void __init init_IRQ(void)
119
{
120 121
	int i;

122 123 124 125 126 127
	/*
	 * We probably need a better place for this, but it works for
	 * now ...
	 */
	x86_add_irq_domains();

128 129 130 131 132 133 134 135
	/*
	 * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
	 * If these IRQ's are handled by legacy interrupt-controllers like PIC,
	 * then this configuration will likely be static after the boot. If
	 * these IRQ's are handled by more mordern controllers like IO-APIC,
	 * then this vector space can be freed and re-used dynamically as the
	 * irq's migrate etc.
	 */
136
	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
137 138
		per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;

139 140
	x86_init.irqs.intr_init();
}
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
/*
 * Setup the vector to irq mappings.
 */
void setup_vector_irq(int cpu)
{
#ifndef CONFIG_X86_IO_APIC
	int irq;

	/*
	 * On most of the platforms, legacy PIC delivers the interrupts on the
	 * boot cpu. But there are certain platforms where PIC interrupts are
	 * delivered to multiple cpu's. If the legacy IRQ is handled by the
	 * legacy PIC, for the new cpu that is coming online, setup the static
	 * legacy vector to irq mapping:
	 */
	for (irq = 0; irq < legacy_pic->nr_legacy_irqs; irq++)
		per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq;
#endif

	__setup_vector_irq(cpu);
}

164 165
static void __init smp_intr_init(void)
{
166 167
#ifdef CONFIG_SMP
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
168 169 170 171 172 173
	/*
	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
	 * IPI, driven by wakeup.
	 */
	alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);

T
Tejun Heo 已提交
174
	/* IPIs for invalidation */
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
#define ALLOC_INVTLB_VEC(NR) \
	alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+NR, \
		invalidate_interrupt##NR)

	switch (NUM_INVALIDATE_TLB_VECTORS) {
	default:
		ALLOC_INVTLB_VEC(31);
	case 31:
		ALLOC_INVTLB_VEC(30);
	case 30:
		ALLOC_INVTLB_VEC(29);
	case 29:
		ALLOC_INVTLB_VEC(28);
	case 28:
		ALLOC_INVTLB_VEC(27);
	case 27:
		ALLOC_INVTLB_VEC(26);
	case 26:
		ALLOC_INVTLB_VEC(25);
	case 25:
		ALLOC_INVTLB_VEC(24);
	case 24:
		ALLOC_INVTLB_VEC(23);
	case 23:
		ALLOC_INVTLB_VEC(22);
	case 22:
		ALLOC_INVTLB_VEC(21);
	case 21:
		ALLOC_INVTLB_VEC(20);
	case 20:
		ALLOC_INVTLB_VEC(19);
	case 19:
		ALLOC_INVTLB_VEC(18);
	case 18:
		ALLOC_INVTLB_VEC(17);
	case 17:
		ALLOC_INVTLB_VEC(16);
	case 16:
		ALLOC_INVTLB_VEC(15);
	case 15:
		ALLOC_INVTLB_VEC(14);
	case 14:
		ALLOC_INVTLB_VEC(13);
	case 13:
		ALLOC_INVTLB_VEC(12);
	case 12:
		ALLOC_INVTLB_VEC(11);
	case 11:
		ALLOC_INVTLB_VEC(10);
	case 10:
		ALLOC_INVTLB_VEC(9);
	case 9:
		ALLOC_INVTLB_VEC(8);
	case 8:
		ALLOC_INVTLB_VEC(7);
	case 7:
		ALLOC_INVTLB_VEC(6);
	case 6:
		ALLOC_INVTLB_VEC(5);
	case 5:
		ALLOC_INVTLB_VEC(4);
	case 4:
		ALLOC_INVTLB_VEC(3);
	case 3:
		ALLOC_INVTLB_VEC(2);
	case 2:
		ALLOC_INVTLB_VEC(1);
	case 1:
		ALLOC_INVTLB_VEC(0);
		break;
	}
246 247 248 249

	/* IPI for generic function call */
	alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);

250
	/* IPI for generic single function call */
251
	alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
252
			call_function_single_interrupt);
253 254 255

	/* Low priority IPI to cleanup after moving an irq */
	set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
256
	set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
257 258 259

	/* IPI used for rebooting/stopping */
	alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt);
260
#endif
261
#endif /* CONFIG_SMP */
262 263
}

264
static void __init apic_intr_init(void)
L
Linus Torvalds 已提交
265
{
266
	smp_intr_init();
267

268
#ifdef CONFIG_X86_THERMAL_VECTOR
269
	alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
270
#endif
271
#ifdef CONFIG_X86_MCE_THRESHOLD
272 273 274 275
	alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
#endif

#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
276 277 278
	/* self generated IPI for local APIC timer */
	alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);

279 280
	/* IPI for X86 platform specific use */
	alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi);
281

282 283 284 285
	/* IPI vectors for APIC spurious and error interrupts */
	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);

286 287 288
	/* IRQ work interrupts: */
# ifdef CONFIG_IRQ_WORK
	alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt);
289 290
# endif

291
#endif
292
}
293

294 295 296 297 298
void __init native_init_IRQ(void)
{
	int i;

	/* Execute any quirks before the call gates are initialised: */
299
	x86_init.irqs.pre_vector_init();
300

Y
Yinghai Lu 已提交
301 302
	apic_intr_init();

303 304 305 306 307
	/*
	 * Cover the whole vector space, no vector can escape
	 * us. (some of these will be overridden and become
	 * 'special' SMP interrupts)
	 */
308
	for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
Y
Yinghai Lu 已提交
309 310
		/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
		if (!test_bit(i, used_vectors))
311
			set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
312
	}
313

314
	if (!acpi_ioapic && !of_ioapic)
315 316
		setup_irq(2, &irq2);

317
#ifdef CONFIG_X86_32
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325
	/*
	 * External FPU? Set up irq13 if so, for
	 * original braindamaged IBM FERR coupling.
	 */
	if (boot_cpu_data.hard_math && !cpu_has_fpu)
		setup_irq(FPU_IRQ, &fpu_irq);

	irq_ctx_init(smp_processor_id());
326
#endif
L
Linus Torvalds 已提交
327
}