diff options
Diffstat (limited to 'arch/alpha/kernel/irq_alpha.c')
-rw-r--r-- | arch/alpha/kernel/irq_alpha.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c new file mode 100644 index 000000000000..e6ded33c6e22 --- /dev/null +++ b/arch/alpha/kernel/irq_alpha.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * Alpha specific irq code. | ||
3 | */ | ||
4 | |||
5 | #include <linux/config.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/sched.h> | ||
8 | #include <linux/irq.h> | ||
9 | #include <linux/kernel_stat.h> | ||
10 | |||
11 | #include <asm/machvec.h> | ||
12 | #include <asm/dma.h> | ||
13 | |||
14 | #include "proto.h" | ||
15 | #include "irq_impl.h" | ||
16 | |||
17 | /* Hack minimum IPL during interrupt processing for broken hardware. */ | ||
18 | #ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK | ||
19 | int __min_ipl; | ||
20 | #endif | ||
21 | |||
22 | /* | ||
23 | * Performance counter hook. A module can override this to | ||
24 | * do something useful. | ||
25 | */ | ||
26 | static void | ||
27 | dummy_perf(unsigned long vector, struct pt_regs *regs) | ||
28 | { | ||
29 | irq_err_count++; | ||
30 | printk(KERN_CRIT "Performance counter interrupt!\n"); | ||
31 | } | ||
32 | |||
33 | void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf; | ||
34 | |||
35 | /* | ||
36 | * The main interrupt entry point. | ||
37 | */ | ||
38 | |||
39 | asmlinkage void | ||
40 | do_entInt(unsigned long type, unsigned long vector, | ||
41 | unsigned long la_ptr, struct pt_regs *regs) | ||
42 | { | ||
43 | switch (type) { | ||
44 | case 0: | ||
45 | #ifdef CONFIG_SMP | ||
46 | handle_ipi(regs); | ||
47 | return; | ||
48 | #else | ||
49 | irq_err_count++; | ||
50 | printk(KERN_CRIT "Interprocessor interrupt? " | ||
51 | "You must be kidding!\n"); | ||
52 | #endif | ||
53 | break; | ||
54 | case 1: | ||
55 | #ifdef CONFIG_SMP | ||
56 | { | ||
57 | long cpu; | ||
58 | smp_percpu_timer_interrupt(regs); | ||
59 | cpu = smp_processor_id(); | ||
60 | if (cpu != boot_cpuid) { | ||
61 | kstat_cpu(cpu).irqs[RTC_IRQ]++; | ||
62 | } else { | ||
63 | handle_irq(RTC_IRQ, regs); | ||
64 | } | ||
65 | } | ||
66 | #else | ||
67 | handle_irq(RTC_IRQ, regs); | ||
68 | #endif | ||
69 | return; | ||
70 | case 2: | ||
71 | alpha_mv.machine_check(vector, la_ptr, regs); | ||
72 | return; | ||
73 | case 3: | ||
74 | alpha_mv.device_interrupt(vector, regs); | ||
75 | return; | ||
76 | case 4: | ||
77 | perf_irq(la_ptr, regs); | ||
78 | return; | ||
79 | default: | ||
80 | printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n", | ||
81 | type, vector); | ||
82 | } | ||
83 | printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps); | ||
84 | } | ||
85 | |||
86 | void __init | ||
87 | common_init_isa_dma(void) | ||
88 | { | ||
89 | outb(0, DMA1_RESET_REG); | ||
90 | outb(0, DMA2_RESET_REG); | ||
91 | outb(0, DMA1_CLR_MASK_REG); | ||
92 | outb(0, DMA2_CLR_MASK_REG); | ||
93 | } | ||
94 | |||
95 | void __init | ||
96 | init_IRQ(void) | ||
97 | { | ||
98 | /* Just in case the platform init_irq() causes interrupts/mchecks | ||
99 | (as is the case with RAWHIDE, at least). */ | ||
100 | wrent(entInt, 0); | ||
101 | |||
102 | alpha_mv.init_irq(); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * machine error checks | ||
107 | */ | ||
108 | #define MCHK_K_TPERR 0x0080 | ||
109 | #define MCHK_K_TCPERR 0x0082 | ||
110 | #define MCHK_K_HERR 0x0084 | ||
111 | #define MCHK_K_ECC_C 0x0086 | ||
112 | #define MCHK_K_ECC_NC 0x0088 | ||
113 | #define MCHK_K_OS_BUGCHECK 0x008A | ||
114 | #define MCHK_K_PAL_BUGCHECK 0x0090 | ||
115 | |||
116 | #ifndef CONFIG_SMP | ||
117 | struct mcheck_info __mcheck_info; | ||
118 | #endif | ||
119 | |||
120 | void | ||
121 | process_mcheck_info(unsigned long vector, unsigned long la_ptr, | ||
122 | struct pt_regs *regs, const char *machine, | ||
123 | int expected) | ||
124 | { | ||
125 | struct el_common *mchk_header; | ||
126 | const char *reason; | ||
127 | |||
128 | /* | ||
129 | * See if the machine check is due to a badaddr() and if so, | ||
130 | * ignore it. | ||
131 | */ | ||
132 | |||
133 | #ifdef CONFIG_VERBOSE_MCHECK | ||
134 | if (alpha_verbose_mcheck > 1) { | ||
135 | printk(KERN_CRIT "%s machine check %s\n", machine, | ||
136 | expected ? "expected." : "NOT expected!!!"); | ||
137 | } | ||
138 | #endif | ||
139 | |||
140 | if (expected) { | ||
141 | int cpu = smp_processor_id(); | ||
142 | mcheck_expected(cpu) = 0; | ||
143 | mcheck_taken(cpu) = 1; | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | mchk_header = (struct el_common *)la_ptr; | ||
148 | |||
149 | printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n", | ||
150 | machine, vector, regs->pc, mchk_header->code); | ||
151 | |||
152 | switch (mchk_header->code) { | ||
153 | /* Machine check reasons. Defined according to PALcode sources. */ | ||
154 | case 0x80: reason = "tag parity error"; break; | ||
155 | case 0x82: reason = "tag control parity error"; break; | ||
156 | case 0x84: reason = "generic hard error"; break; | ||
157 | case 0x86: reason = "correctable ECC error"; break; | ||
158 | case 0x88: reason = "uncorrectable ECC error"; break; | ||
159 | case 0x8A: reason = "OS-specific PAL bugcheck"; break; | ||
160 | case 0x90: reason = "callsys in kernel mode"; break; | ||
161 | case 0x96: reason = "i-cache read retryable error"; break; | ||
162 | case 0x98: reason = "processor detected hard error"; break; | ||
163 | |||
164 | /* System specific (these are for Alcor, at least): */ | ||
165 | case 0x202: reason = "system detected hard error"; break; | ||
166 | case 0x203: reason = "system detected uncorrectable ECC error"; break; | ||
167 | case 0x204: reason = "SIO SERR occurred on PCI bus"; break; | ||
168 | case 0x205: reason = "parity error detected by core logic"; break; | ||
169 | case 0x206: reason = "SIO IOCHK occurred on ISA bus"; break; | ||
170 | case 0x207: reason = "non-existent memory error"; break; | ||
171 | case 0x208: reason = "MCHK_K_DCSR"; break; | ||
172 | case 0x209: reason = "PCI SERR detected"; break; | ||
173 | case 0x20b: reason = "PCI data parity error detected"; break; | ||
174 | case 0x20d: reason = "PCI address parity error detected"; break; | ||
175 | case 0x20f: reason = "PCI master abort error"; break; | ||
176 | case 0x211: reason = "PCI target abort error"; break; | ||
177 | case 0x213: reason = "scatter/gather PTE invalid error"; break; | ||
178 | case 0x215: reason = "flash ROM write error"; break; | ||
179 | case 0x217: reason = "IOA timeout detected"; break; | ||
180 | case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; | ||
181 | case 0x21b: reason = "EISA fail-safe timer timeout"; break; | ||
182 | case 0x21d: reason = "EISA bus time-out"; break; | ||
183 | case 0x21f: reason = "EISA software generated NMI"; break; | ||
184 | case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; | ||
185 | default: reason = "unknown"; break; | ||
186 | } | ||
187 | |||
188 | printk(KERN_CRIT "machine check type: %s%s\n", | ||
189 | reason, mchk_header->retry ? " (retryable)" : ""); | ||
190 | |||
191 | dik_show_regs(regs, NULL); | ||
192 | |||
193 | #ifdef CONFIG_VERBOSE_MCHECK | ||
194 | if (alpha_verbose_mcheck > 1) { | ||
195 | /* Dump the logout area to give all info. */ | ||
196 | unsigned long *ptr = (unsigned long *)la_ptr; | ||
197 | long i; | ||
198 | for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { | ||
199 | printk(KERN_CRIT " +%8lx %016lx %016lx\n", | ||
200 | i*sizeof(long), ptr[i], ptr[i+1]); | ||
201 | } | ||
202 | } | ||
203 | #endif /* CONFIG_VERBOSE_MCHECK */ | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * The special RTC interrupt type. The interrupt itself was | ||
208 | * processed by PALcode, and comes in via entInt vector 1. | ||
209 | */ | ||
210 | |||
211 | static void rtc_enable_disable(unsigned int irq) { } | ||
212 | static unsigned int rtc_startup(unsigned int irq) { return 0; } | ||
213 | |||
214 | struct irqaction timer_irqaction = { | ||
215 | .handler = timer_interrupt, | ||
216 | .flags = SA_INTERRUPT, | ||
217 | .name = "timer", | ||
218 | }; | ||
219 | |||
220 | static struct hw_interrupt_type rtc_irq_type = { | ||
221 | .typename = "RTC", | ||
222 | .startup = rtc_startup, | ||
223 | .shutdown = rtc_enable_disable, | ||
224 | .enable = rtc_enable_disable, | ||
225 | .disable = rtc_enable_disable, | ||
226 | .ack = rtc_enable_disable, | ||
227 | .end = rtc_enable_disable, | ||
228 | }; | ||
229 | |||
230 | void __init | ||
231 | init_rtc_irq(void) | ||
232 | { | ||
233 | irq_desc[RTC_IRQ].status = IRQ_DISABLED; | ||
234 | irq_desc[RTC_IRQ].handler = &rtc_irq_type; | ||
235 | setup_irq(RTC_IRQ, &timer_irqaction); | ||
236 | } | ||
237 | |||
238 | /* Dummy irqactions. */ | ||
239 | struct irqaction isa_cascade_irqaction = { | ||
240 | .handler = no_action, | ||
241 | .name = "isa-cascade" | ||
242 | }; | ||
243 | |||
244 | struct irqaction timer_cascade_irqaction = { | ||
245 | .handler = no_action, | ||
246 | .name = "timer-cascade" | ||
247 | }; | ||
248 | |||
249 | struct irqaction halt_switch_irqaction = { | ||
250 | .handler = no_action, | ||
251 | .name = "halt-switch" | ||
252 | }; | ||