diff options
Diffstat (limited to 'arch/mn10300/kernel/irq.c')
-rw-r--r-- | arch/mn10300/kernel/irq.c | 276 |
1 files changed, 246 insertions, 30 deletions
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c index e2d5ed891f37..c2e44597c22b 100644 --- a/arch/mn10300/kernel/irq.c +++ b/arch/mn10300/kernel/irq.c | |||
@@ -12,11 +12,26 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
15 | #include <linux/cpumask.h> | ||
15 | #include <asm/setup.h> | 16 | #include <asm/setup.h> |
17 | #include <asm/serial-regs.h> | ||
16 | 18 | ||
17 | unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7; | 19 | unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = { |
20 | [0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7 | ||
21 | }; | ||
18 | EXPORT_SYMBOL(__mn10300_irq_enabled_epsw); | 22 | EXPORT_SYMBOL(__mn10300_irq_enabled_epsw); |
19 | 23 | ||
24 | #ifdef CONFIG_SMP | ||
25 | static char irq_affinity_online[NR_IRQS] = { | ||
26 | [0 ... NR_IRQS - 1] = 0 | ||
27 | }; | ||
28 | |||
29 | #define NR_IRQ_WORDS ((NR_IRQS + 31) / 32) | ||
30 | static unsigned long irq_affinity_request[NR_IRQ_WORDS] = { | ||
31 | [0 ... NR_IRQ_WORDS - 1] = 0 | ||
32 | }; | ||
33 | #endif /* CONFIG_SMP */ | ||
34 | |||
20 | atomic_t irq_err_count; | 35 | atomic_t irq_err_count; |
21 | 36 | ||
22 | /* | 37 | /* |
@@ -24,30 +39,67 @@ atomic_t irq_err_count; | |||
24 | */ | 39 | */ |
25 | static void mn10300_cpupic_ack(unsigned int irq) | 40 | static void mn10300_cpupic_ack(unsigned int irq) |
26 | { | 41 | { |
42 | unsigned long flags; | ||
27 | u16 tmp; | 43 | u16 tmp; |
28 | *(volatile u8 *) &GxICR(irq) = GxICR_DETECT; | 44 | |
45 | flags = arch_local_cli_save(); | ||
46 | GxICR_u8(irq) = GxICR_DETECT; | ||
29 | tmp = GxICR(irq); | 47 | tmp = GxICR(irq); |
48 | arch_local_irq_restore(flags); | ||
30 | } | 49 | } |
31 | 50 | ||
32 | static void mn10300_cpupic_mask(unsigned int irq) | 51 | static void __mask_and_set_icr(unsigned int irq, |
52 | unsigned int mask, unsigned int set) | ||
33 | { | 53 | { |
34 | u16 tmp = GxICR(irq); | 54 | unsigned long flags; |
35 | GxICR(irq) = (tmp & GxICR_LEVEL); | 55 | u16 tmp; |
56 | |||
57 | flags = arch_local_cli_save(); | ||
58 | tmp = GxICR(irq); | ||
59 | GxICR(irq) = (tmp & mask) | set; | ||
36 | tmp = GxICR(irq); | 60 | tmp = GxICR(irq); |
61 | arch_local_irq_restore(flags); | ||
62 | } | ||
63 | |||
64 | static void mn10300_cpupic_mask(unsigned int irq) | ||
65 | { | ||
66 | __mask_and_set_icr(irq, GxICR_LEVEL, 0); | ||
37 | } | 67 | } |
38 | 68 | ||
39 | static void mn10300_cpupic_mask_ack(unsigned int irq) | 69 | static void mn10300_cpupic_mask_ack(unsigned int irq) |
40 | { | 70 | { |
41 | u16 tmp = GxICR(irq); | 71 | #ifdef CONFIG_SMP |
42 | GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; | 72 | unsigned long flags; |
43 | tmp = GxICR(irq); | 73 | u16 tmp; |
74 | |||
75 | flags = arch_local_cli_save(); | ||
76 | |||
77 | if (!test_and_clear_bit(irq, irq_affinity_request)) { | ||
78 | tmp = GxICR(irq); | ||
79 | GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; | ||
80 | tmp = GxICR(irq); | ||
81 | } else { | ||
82 | u16 tmp2; | ||
83 | tmp = GxICR(irq); | ||
84 | GxICR(irq) = (tmp & GxICR_LEVEL); | ||
85 | tmp2 = GxICR(irq); | ||
86 | |||
87 | irq_affinity_online[irq] = | ||
88 | any_online_cpu(*irq_desc[irq].affinity); | ||
89 | CROSS_GxICR(irq, irq_affinity_online[irq]) = | ||
90 | (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT; | ||
91 | tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); | ||
92 | } | ||
93 | |||
94 | arch_local_irq_restore(flags); | ||
95 | #else /* CONFIG_SMP */ | ||
96 | __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_DETECT); | ||
97 | #endif /* CONFIG_SMP */ | ||
44 | } | 98 | } |
45 | 99 | ||
46 | static void mn10300_cpupic_unmask(unsigned int irq) | 100 | static void mn10300_cpupic_unmask(unsigned int irq) |
47 | { | 101 | { |
48 | u16 tmp = GxICR(irq); | 102 | __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE); |
49 | GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE; | ||
50 | tmp = GxICR(irq); | ||
51 | } | 103 | } |
52 | 104 | ||
53 | static void mn10300_cpupic_unmask_clear(unsigned int irq) | 105 | static void mn10300_cpupic_unmask_clear(unsigned int irq) |
@@ -56,11 +108,89 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq) | |||
56 | * device has ceased to assert its interrupt line and the interrupt | 108 | * device has ceased to assert its interrupt line and the interrupt |
57 | * channel has been disabled in the PIC, so for level-triggered | 109 | * channel has been disabled in the PIC, so for level-triggered |
58 | * interrupts we need to clear the request bit when we re-enable */ | 110 | * interrupts we need to clear the request bit when we re-enable */ |
59 | u16 tmp = GxICR(irq); | 111 | #ifdef CONFIG_SMP |
60 | GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | 112 | unsigned long flags; |
61 | tmp = GxICR(irq); | 113 | u16 tmp; |
114 | |||
115 | flags = arch_local_cli_save(); | ||
116 | |||
117 | if (!test_and_clear_bit(irq, irq_affinity_request)) { | ||
118 | tmp = GxICR(irq); | ||
119 | GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | ||
120 | tmp = GxICR(irq); | ||
121 | } else { | ||
122 | tmp = GxICR(irq); | ||
123 | |||
124 | irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); | ||
125 | CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | ||
126 | tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); | ||
127 | } | ||
128 | |||
129 | arch_local_irq_restore(flags); | ||
130 | #else /* CONFIG_SMP */ | ||
131 | __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE | GxICR_DETECT); | ||
132 | #endif /* CONFIG_SMP */ | ||
62 | } | 133 | } |
63 | 134 | ||
135 | #ifdef CONFIG_SMP | ||
136 | static int | ||
137 | mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | int err; | ||
141 | |||
142 | flags = arch_local_cli_save(); | ||
143 | |||
144 | /* check irq no */ | ||
145 | switch (irq) { | ||
146 | case TMJCIRQ: | ||
147 | case RESCHEDULE_IPI: | ||
148 | case CALL_FUNC_SINGLE_IPI: | ||
149 | case LOCAL_TIMER_IPI: | ||
150 | case FLUSH_CACHE_IPI: | ||
151 | case CALL_FUNCTION_NMI_IPI: | ||
152 | case GDB_NMI_IPI: | ||
153 | #ifdef CONFIG_MN10300_TTYSM0 | ||
154 | case SC0RXIRQ: | ||
155 | case SC0TXIRQ: | ||
156 | #ifdef CONFIG_MN10300_TTYSM0_TIMER8 | ||
157 | case TM8IRQ: | ||
158 | #elif CONFIG_MN10300_TTYSM0_TIMER2 | ||
159 | case TM2IRQ: | ||
160 | #endif /* CONFIG_MN10300_TTYSM0_TIMER8 */ | ||
161 | #endif /* CONFIG_MN10300_TTYSM0 */ | ||
162 | |||
163 | #ifdef CONFIG_MN10300_TTYSM1 | ||
164 | case SC1RXIRQ: | ||
165 | case SC1TXIRQ: | ||
166 | #ifdef CONFIG_MN10300_TTYSM1_TIMER12 | ||
167 | case TM12IRQ: | ||
168 | #elif CONFIG_MN10300_TTYSM1_TIMER9 | ||
169 | case TM9IRQ: | ||
170 | #elif CONFIG_MN10300_TTYSM1_TIMER3 | ||
171 | case TM3IRQ: | ||
172 | #endif /* CONFIG_MN10300_TTYSM1_TIMER12 */ | ||
173 | #endif /* CONFIG_MN10300_TTYSM1 */ | ||
174 | |||
175 | #ifdef CONFIG_MN10300_TTYSM2 | ||
176 | case SC2RXIRQ: | ||
177 | case SC2TXIRQ: | ||
178 | case TM10IRQ: | ||
179 | #endif /* CONFIG_MN10300_TTYSM2 */ | ||
180 | err = -1; | ||
181 | break; | ||
182 | |||
183 | default: | ||
184 | set_bit(irq, irq_affinity_request); | ||
185 | err = 0; | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | arch_local_irq_restore(flags); | ||
190 | return err; | ||
191 | } | ||
192 | #endif /* CONFIG_SMP */ | ||
193 | |||
64 | /* | 194 | /* |
65 | * MN10300 PIC level-triggered IRQ handling. | 195 | * MN10300 PIC level-triggered IRQ handling. |
66 | * | 196 | * |
@@ -79,6 +209,9 @@ static struct irq_chip mn10300_cpu_pic_level = { | |||
79 | .mask = mn10300_cpupic_mask, | 209 | .mask = mn10300_cpupic_mask, |
80 | .mask_ack = mn10300_cpupic_mask, | 210 | .mask_ack = mn10300_cpupic_mask, |
81 | .unmask = mn10300_cpupic_unmask_clear, | 211 | .unmask = mn10300_cpupic_unmask_clear, |
212 | #ifdef CONFIG_SMP | ||
213 | .set_affinity = mn10300_cpupic_setaffinity, | ||
214 | #endif | ||
82 | }; | 215 | }; |
83 | 216 | ||
84 | /* | 217 | /* |
@@ -94,6 +227,9 @@ static struct irq_chip mn10300_cpu_pic_edge = { | |||
94 | .mask = mn10300_cpupic_mask, | 227 | .mask = mn10300_cpupic_mask, |
95 | .mask_ack = mn10300_cpupic_mask_ack, | 228 | .mask_ack = mn10300_cpupic_mask_ack, |
96 | .unmask = mn10300_cpupic_unmask, | 229 | .unmask = mn10300_cpupic_unmask, |
230 | #ifdef CONFIG_SMP | ||
231 | .set_affinity = mn10300_cpupic_setaffinity, | ||
232 | #endif | ||
97 | }; | 233 | }; |
98 | 234 | ||
99 | /* | 235 | /* |
@@ -111,14 +247,34 @@ void ack_bad_irq(int irq) | |||
111 | */ | 247 | */ |
112 | void set_intr_level(int irq, u16 level) | 248 | void set_intr_level(int irq, u16 level) |
113 | { | 249 | { |
114 | u16 tmp; | 250 | BUG_ON(in_interrupt()); |
115 | 251 | ||
116 | if (in_interrupt()) | 252 | __mask_and_set_icr(irq, GxICR_ENABLE, level); |
117 | BUG(); | 253 | } |
118 | 254 | ||
119 | tmp = GxICR(irq); | 255 | void mn10300_intc_set_level(unsigned int irq, unsigned int level) |
120 | GxICR(irq) = (tmp & GxICR_ENABLE) | level; | 256 | { |
121 | tmp = GxICR(irq); | 257 | set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL); |
258 | } | ||
259 | |||
260 | void mn10300_intc_clear(unsigned int irq) | ||
261 | { | ||
262 | __mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT); | ||
263 | } | ||
264 | |||
265 | void mn10300_intc_set(unsigned int irq) | ||
266 | { | ||
267 | __mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT); | ||
268 | } | ||
269 | |||
270 | void mn10300_intc_enable(unsigned int irq) | ||
271 | { | ||
272 | mn10300_cpupic_unmask(irq); | ||
273 | } | ||
274 | |||
275 | void mn10300_intc_disable(unsigned int irq) | ||
276 | { | ||
277 | mn10300_cpupic_mask(irq); | ||
122 | } | 278 | } |
123 | 279 | ||
124 | /* | 280 | /* |
@@ -126,7 +282,7 @@ void set_intr_level(int irq, u16 level) | |||
126 | * than before | 282 | * than before |
127 | * - see Documentation/mn10300/features.txt | 283 | * - see Documentation/mn10300/features.txt |
128 | */ | 284 | */ |
129 | void set_intr_postackable(int irq) | 285 | void mn10300_set_lateack_irq_type(int irq) |
130 | { | 286 | { |
131 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level, | 287 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level, |
132 | handle_level_irq); | 288 | handle_level_irq); |
@@ -147,6 +303,7 @@ void __init init_IRQ(void) | |||
147 | * interrupts */ | 303 | * interrupts */ |
148 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge, | 304 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge, |
149 | handle_level_irq); | 305 | handle_level_irq); |
306 | |||
150 | unit_init_IRQ(); | 307 | unit_init_IRQ(); |
151 | } | 308 | } |
152 | 309 | ||
@@ -156,20 +313,22 @@ void __init init_IRQ(void) | |||
156 | asmlinkage void do_IRQ(void) | 313 | asmlinkage void do_IRQ(void) |
157 | { | 314 | { |
158 | unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw; | 315 | unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw; |
316 | unsigned int cpu_id = smp_processor_id(); | ||
159 | int irq; | 317 | int irq; |
160 | 318 | ||
161 | sp = current_stack_pointer(); | 319 | sp = current_stack_pointer(); |
162 | if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN) | 320 | BUG_ON(sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN); |
163 | BUG(); | ||
164 | 321 | ||
165 | /* make sure local_irq_enable() doesn't muck up the interrupt priority | 322 | /* make sure local_irq_enable() doesn't muck up the interrupt priority |
166 | * setting in EPSW */ | 323 | * setting in EPSW */ |
167 | old_irq_enabled_epsw = __mn10300_irq_enabled_epsw; | 324 | old_irq_enabled_epsw = __mn10300_irq_enabled_epsw[cpu_id]; |
168 | local_save_flags(epsw); | 325 | local_save_flags(epsw); |
169 | __mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw); | 326 | __mn10300_irq_enabled_epsw[cpu_id] = EPSW_IE | (EPSW_IM & epsw); |
170 | irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL; | 327 | irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL; |
171 | 328 | ||
172 | __IRQ_STAT(smp_processor_id(), __irq_count)++; | 329 | #ifdef CONFIG_MN10300_WD_TIMER |
330 | __IRQ_STAT(cpu_id, __irq_count)++; | ||
331 | #endif | ||
173 | 332 | ||
174 | irq_enter(); | 333 | irq_enter(); |
175 | 334 | ||
@@ -189,7 +348,7 @@ asmlinkage void do_IRQ(void) | |||
189 | local_irq_restore(epsw); | 348 | local_irq_restore(epsw); |
190 | } | 349 | } |
191 | 350 | ||
192 | __mn10300_irq_enabled_epsw = old_irq_enabled_epsw; | 351 | __mn10300_irq_enabled_epsw[cpu_id] = old_irq_enabled_epsw; |
193 | 352 | ||
194 | irq_exit(); | 353 | irq_exit(); |
195 | } | 354 | } |
@@ -222,9 +381,16 @@ int show_interrupts(struct seq_file *p, void *v) | |||
222 | seq_printf(p, "%3d: ", i); | 381 | seq_printf(p, "%3d: ", i); |
223 | for_each_present_cpu(cpu) | 382 | for_each_present_cpu(cpu) |
224 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); | 383 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); |
225 | seq_printf(p, " %14s.%u", irq_desc[i].chip->name, | 384 | |
226 | (GxICR(i) & GxICR_LEVEL) >> | 385 | if (i < NR_CPU_IRQS) |
227 | GxICR_LEVEL_SHIFT); | 386 | seq_printf(p, " %14s.%u", |
387 | irq_desc[i].chip->name, | ||
388 | (GxICR(i) & GxICR_LEVEL) >> | ||
389 | GxICR_LEVEL_SHIFT); | ||
390 | else | ||
391 | seq_printf(p, " %14s", | ||
392 | irq_desc[i].chip->name); | ||
393 | |||
228 | seq_printf(p, " %s", action->name); | 394 | seq_printf(p, " %s", action->name); |
229 | 395 | ||
230 | for (action = action->next; | 396 | for (action = action->next; |
@@ -240,11 +406,13 @@ int show_interrupts(struct seq_file *p, void *v) | |||
240 | 406 | ||
241 | /* polish off with NMI and error counters */ | 407 | /* polish off with NMI and error counters */ |
242 | case NR_IRQS: | 408 | case NR_IRQS: |
409 | #ifdef CONFIG_MN10300_WD_TIMER | ||
243 | seq_printf(p, "NMI: "); | 410 | seq_printf(p, "NMI: "); |
244 | for (j = 0; j < NR_CPUS; j++) | 411 | for (j = 0; j < NR_CPUS; j++) |
245 | if (cpu_online(j)) | 412 | if (cpu_online(j)) |
246 | seq_printf(p, "%10u ", nmi_count(j)); | 413 | seq_printf(p, "%10u ", nmi_count(j)); |
247 | seq_putc(p, '\n'); | 414 | seq_putc(p, '\n'); |
415 | #endif | ||
248 | 416 | ||
249 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | 417 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); |
250 | break; | 418 | break; |
@@ -252,3 +420,51 @@ int show_interrupts(struct seq_file *p, void *v) | |||
252 | 420 | ||
253 | return 0; | 421 | return 0; |
254 | } | 422 | } |
423 | |||
424 | #ifdef CONFIG_HOTPLUG_CPU | ||
425 | void migrate_irqs(void) | ||
426 | { | ||
427 | irq_desc_t *desc; | ||
428 | int irq; | ||
429 | unsigned int self, new; | ||
430 | unsigned long flags; | ||
431 | |||
432 | self = smp_processor_id(); | ||
433 | for (irq = 0; irq < NR_IRQS; irq++) { | ||
434 | desc = irq_desc + irq; | ||
435 | |||
436 | if (desc->status == IRQ_PER_CPU) | ||
437 | continue; | ||
438 | |||
439 | if (cpu_isset(self, irq_desc[irq].affinity) && | ||
440 | !cpus_intersects(irq_affinity[irq], cpu_online_map)) { | ||
441 | int cpu_id; | ||
442 | cpu_id = first_cpu(cpu_online_map); | ||
443 | cpu_set(cpu_id, irq_desc[irq].affinity); | ||
444 | } | ||
445 | /* We need to operate irq_affinity_online atomically. */ | ||
446 | arch_local_cli_save(flags); | ||
447 | if (irq_affinity_online[irq] == self) { | ||
448 | u16 x, tmp; | ||
449 | |||
450 | x = GxICR(irq); | ||
451 | GxICR(irq) = x & GxICR_LEVEL; | ||
452 | tmp = GxICR(irq); | ||
453 | |||
454 | new = any_online_cpu(irq_desc[irq].affinity); | ||
455 | irq_affinity_online[irq] = new; | ||
456 | |||
457 | CROSS_GxICR(irq, new) = | ||
458 | (x & GxICR_LEVEL) | GxICR_DETECT; | ||
459 | tmp = CROSS_GxICR(irq, new); | ||
460 | |||
461 | x &= GxICR_LEVEL | GxICR_ENABLE; | ||
462 | if (GxICR(irq) & GxICR_REQUEST) { | ||
463 | x |= GxICR_REQUEST | GxICR_DETECT; | ||
464 | CROSS_GxICR(irq, new) = x; | ||
465 | tmp = CROSS_GxICR(irq, new); | ||
466 | } | ||
467 | arch_local_irq_restore(flags); | ||
468 | } | ||
469 | } | ||
470 | #endif /* CONFIG_HOTPLUG_CPU */ | ||