Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
x86
kernel
irqinit.c
Go to the documentation of this file.
1
#include <linux/linkage.h>
2
#include <linux/errno.h>
3
#include <linux/signal.h>
4
#include <linux/sched.h>
5
#include <
linux/ioport.h
>
6
#include <
linux/interrupt.h
>
7
#include <linux/timex.h>
8
#include <linux/random.h>
9
#include <
linux/kprobes.h
>
10
#include <
linux/init.h
>
11
#include <
linux/kernel_stat.h
>
12
#include <linux/device.h>
13
#include <linux/bitops.h>
14
#include <
linux/acpi.h
>
15
#include <
linux/io.h
>
16
#include <
linux/delay.h
>
17
18
#include <
linux/atomic.h
>
19
#include <asm/timer.h>
20
#include <asm/hw_irq.h>
21
#include <asm/pgtable.h>
22
#include <asm/desc.h>
23
#include <asm/apic.h>
24
#include <asm/setup.h>
25
#include <asm/i8259.h>
26
#include <asm/traps.h>
27
#include <asm/prom.h>
28
29
/*
30
* ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
31
* (these are usually mapped to vectors 0x30-0x3f)
32
*/
33
34
/*
35
* The IO-APIC gives us many more interrupt sources. Most of these
36
* are unused but an SMP system is supposed to have enough memory ...
37
* sometimes (mostly wrt. hw bugs) we get corrupted vectors all
38
* across the spectrum, so we really want to be prepared to get all
39
* of these. Plus, more powerful systems might have more than 64
40
* IO-APIC registers.
41
*
42
* (these are usually mapped into the 0x30-0xff vector range)
43
*/
44
45
#ifdef CONFIG_X86_32
46
/*
47
* Note that on a 486, we don't want to do a SIGFPE on an irq13
48
* as the irq is unreliable, and exception 16 works correctly
49
* (ie as explained in the intel literature). On a 386, you
50
* can't use exception 16 due to bad IBM design, so we have to
51
* rely on the less exact irq13.
52
*
53
* Careful.. Not only is IRQ13 unreliable, but it is also
54
* leads to races. IBM designers who came up with it should
55
* be shot.
56
*/
57
58
static
irqreturn_t
math_error_irq(
int
cpl,
void
*
dev_id
)
59
{
60
outb
(0, 0xF0);
61
if
(
ignore_fpu_irq
|| !
boot_cpu_data
.hard_math)
62
return
IRQ_NONE
;
63
math_error
(
get_irq_regs
(), 0,
X86_TRAP_MF
);
64
return
IRQ_HANDLED
;
65
}
66
67
/*
68
* New motherboards sometimes make IRQ 13 be a PCI interrupt,
69
* so allow interrupt sharing.
70
*/
71
static
struct
irqaction
fpu_irq = {
72
.
handler
= math_error_irq,
73
.name =
"fpu"
,
74
.flags =
IRQF_NO_THREAD
,
75
};
76
#endif
77
78
/*
79
* IRQ2 is cascade interrupt to second interrupt controller
80
*/
81
static
struct
irqaction
irq2 = {
82
.handler =
no_action
,
83
.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
int
vector_used_by_percpu_irq
(
unsigned
int
vector
)
92
{
93
int
cpu
;
94
95
for_each_online_cpu
(cpu) {
96
if
(
per_cpu
(vector_irq, cpu)[vector] != -1)
97
return
1;
98
}
99
100
return
0;
101
}
102
103
void
__init
init_ISA_irqs
(
void
)
104
{
105
struct
irq_chip
*
chip
=
legacy_pic
->
chip
;
106
const
char
*
name
= chip->
name
;
107
int
i
;
108
109
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
110
init_bsp_APIC
();
111
#endif
112
legacy_pic
->
init
(0);
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
}
117
118
void
__init
init_IRQ
(
void
)
119
{
120
int
i
;
121
122
/*
123
* We probably need a better place for this, but it works for
124
* now ...
125
*/
126
x86_add_irq_domains
();
127
128
/*
129
* On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
130
* If these IRQ's are handled by legacy interrupt-controllers like PIC,
131
* then this configuration will likely be static after the boot. If
132
* these IRQ's are handled by more mordern controllers like IO-APIC,
133
* then this vector space can be freed and re-used dynamically as the
134
* irq's migrate etc.
135
*/
136
for
(i = 0; i <
legacy_pic
->
nr_legacy_irqs
; i++)
137
per_cpu
(vector_irq, 0)[
IRQ0_VECTOR
+
i
] =
i
;
138
139
x86_init
.irqs.intr_init();
140
}
141
142
/*
143
* Setup the vector to irq mappings.
144
*/
145
void
setup_vector_irq
(
int
cpu
)
146
{
147
#ifndef CONFIG_X86_IO_APIC
148
int
irq
;
149
150
/*
151
* On most of the platforms, legacy PIC delivers the interrupts on the
152
* boot cpu. But there are certain platforms where PIC interrupts are
153
* delivered to multiple cpu's. If the legacy IRQ is handled by the
154
* legacy PIC, for the new cpu that is coming online, setup the static
155
* legacy vector to irq mapping:
156
*/
157
for
(irq = 0; irq <
legacy_pic
->
nr_legacy_irqs
; irq++)
158
per_cpu
(vector_irq, cpu)[
IRQ0_VECTOR
+ irq] = irq;
159
#endif
160
161
__setup_vector_irq
(cpu);
162
}
163
164
static
void
__init
smp_intr_init(
void
)
165
{
166
#ifdef CONFIG_SMP
167
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
168
/*
169
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
170
* IPI, driven by wakeup.
171
*/
172
alloc_intr_gate(
RESCHEDULE_VECTOR
,
reschedule_interrupt
);
173
174
/* IPI for generic function call */
175
alloc_intr_gate(
CALL_FUNCTION_VECTOR
,
call_function_interrupt
);
176
177
/* IPI for generic single function call */
178
alloc_intr_gate(
CALL_FUNCTION_SINGLE_VECTOR
,
179
call_function_single_interrupt
);
180
181
/* Low priority IPI to cleanup after moving an irq */
182
set_intr_gate(
IRQ_MOVE_CLEANUP_VECTOR
,
irq_move_cleanup_interrupt
);
183
set_bit
(
IRQ_MOVE_CLEANUP_VECTOR
, used_vectors);
184
185
/* IPI used for rebooting/stopping */
186
alloc_intr_gate(
REBOOT_VECTOR
,
reboot_interrupt
);
187
#endif
188
#endif
/* CONFIG_SMP */
189
}
190
191
static
void
__init
apic_intr_init(
void
)
192
{
193
smp_intr_init();
194
195
#ifdef CONFIG_X86_THERMAL_VECTOR
196
alloc_intr_gate(
THERMAL_APIC_VECTOR
,
thermal_interrupt
);
197
#endif
198
#ifdef CONFIG_X86_MCE_THRESHOLD
199
alloc_intr_gate(
THRESHOLD_APIC_VECTOR
,
threshold_interrupt
);
200
#endif
201
202
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
203
/* self generated IPI for local APIC timer */
204
alloc_intr_gate(
LOCAL_TIMER_VECTOR
,
apic_timer_interrupt
);
205
206
/* IPI for X86 platform specific use */
207
alloc_intr_gate(
X86_PLATFORM_IPI_VECTOR
,
x86_platform_ipi
);
208
209
/* IPI vectors for APIC spurious and error interrupts */
210
alloc_intr_gate(
SPURIOUS_APIC_VECTOR
,
spurious_interrupt
);
211
alloc_intr_gate(
ERROR_APIC_VECTOR
,
error_interrupt
);
212
213
/* IRQ work interrupts: */
214
# ifdef CONFIG_IRQ_WORK
215
alloc_intr_gate(
IRQ_WORK_VECTOR
,
irq_work_interrupt
);
216
# endif
217
218
#endif
219
}
220
221
void
__init
native_init_IRQ
(
void
)
222
{
223
int
i
;
224
225
/* Execute any quirks before the call gates are initialised: */
226
x86_init
.irqs.pre_vector_init();
227
228
apic_intr_init();
229
230
/*
231
* Cover the whole vector space, no vector can escape
232
* us. (some of these will be overridden and become
233
* 'special' SMP interrupts)
234
*/
235
i =
FIRST_EXTERNAL_VECTOR
;
236
for_each_clear_bit_from
(i,
used_vectors
,
NR_VECTORS
) {
237
/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
238
set_intr_gate(i,
interrupt
[i -
FIRST_EXTERNAL_VECTOR
]);
239
}
240
241
if
(!
acpi_ioapic
&& !
of_ioapic
)
242
setup_irq
(2, &irq2);
243
244
#ifdef CONFIG_X86_32
245
/*
246
* External FPU? Set up irq13 if so, for
247
* original braindamaged IBM FERR coupling.
248
*/
249
if
(
boot_cpu_data
.hard_math && !
cpu_has_fpu
)
250
setup_irq
(
FPU_IRQ
, &fpu_irq);
251
252
irq_ctx_init
(
smp_processor_id
());
253
#endif
254
}
Generated on Thu Jan 10 2013 13:20:48 for Linux Kernel by
1.8.2