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#undef DEBUG
32
33#include <linux/export.h>
34#include <linux/threads.h>
35#include <linux/kernel_stat.h>
36#include <linux/signal.h>
37#include <linux/sched.h>
38#include <linux/ptrace.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
41#include <linux/timex.h>
42#include <linux/init.h>
43#include <linux/slab.h>
44#include <linux/delay.h>
45#include <linux/irq.h>
46#include <linux/seq_file.h>
47#include <linux/cpumask.h>
48#include <linux/profile.h>
49#include <linux/bitops.h>
50#include <linux/list.h>
51#include <linux/radix-tree.h>
52#include <linux/mutex.h>
53#include <linux/pci.h>
54#include <linux/debugfs.h>
55#include <linux/of.h>
56#include <linux/of_irq.h>
57
58#include <asm/uaccess.h>
59#include <asm/io.h>
60#include <asm/pgtable.h>
61#include <asm/irq.h>
62#include <asm/cache.h>
63#include <asm/prom.h>
64#include <asm/ptrace.h>
65#include <asm/machdep.h>
66#include <asm/udbg.h>
67#include <asm/smp.h>
68#include <asm/debug.h>
69
70#ifdef CONFIG_PPC64
71#include <asm/paca.h>
72#include <asm/firmware.h>
73#include <asm/lv1call.h>
74#endif
75#define CREATE_TRACE_POINTS
76#include <asm/trace.h>
77
78DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
79EXPORT_PER_CPU_SYMBOL(irq_stat);
80
81int __irq_offset_value;
82
83#ifdef CONFIG_PPC32
84EXPORT_SYMBOL(__irq_offset_value);
85atomic_t ppc_n_lost_interrupts;
86
87#ifdef CONFIG_TAU_INT
88extern int tau_initialized;
89extern int tau_interrupts(int);
90#endif
91#endif
92
93#ifdef CONFIG_PPC64
94
95int distribute_irqs = 1;
96
97static inline notrace unsigned long get_irq_happened(void)
98{
99 unsigned long happened;
100
101 __asm__ __volatile__("lbz %0,%1(13)"
102 : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened)));
103
104 return happened;
105}
106
107static inline notrace void set_soft_enabled(unsigned long enable)
108{
109 __asm__ __volatile__("stb %0,%1(13)"
110 : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
111}
112
113static inline notrace int decrementer_check_overflow(void)
114{
115 u64 now = get_tb_or_rtc();
116 u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
117
118 return now >= *next_tb;
119}
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135notrace unsigned int __check_irq_replay(void)
136{
137
138
139
140
141
142 unsigned char happened = local_paca->irq_happened;
143
144
145 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
146
147
148
149
150
151 if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
152 u64 tmp, tmp2;
153 lv1_get_version_info(&tmp, &tmp2);
154 }
155
156
157
158
159
160
161 local_paca->irq_happened &= ~PACA_IRQ_DEC;
162 if ((happened & PACA_IRQ_DEC) || decrementer_check_overflow())
163 return 0x900;
164
165
166 local_paca->irq_happened &= ~PACA_IRQ_EE;
167 if (happened & PACA_IRQ_EE)
168 return 0x500;
169
170#ifdef CONFIG_PPC_BOOK3E
171
172
173
174
175 local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
176 if (happened & PACA_IRQ_EE_EDGE)
177 return 0x500;
178
179 local_paca->irq_happened &= ~PACA_IRQ_DBELL;
180 if (happened & PACA_IRQ_DBELL)
181 return 0x280;
182#else
183 local_paca->irq_happened &= ~PACA_IRQ_DBELL;
184 if (happened & PACA_IRQ_DBELL) {
185 if (cpu_has_feature(CPU_FTR_HVMODE))
186 return 0xe80;
187 return 0xa00;
188 }
189#endif
190
191
192 local_paca->irq_happened &= ~PACA_IRQ_HMI;
193 if (happened & PACA_IRQ_HMI)
194 return 0xe60;
195
196
197 BUG_ON(local_paca->irq_happened != 0);
198
199 return 0;
200}
201
202notrace void arch_local_irq_restore(unsigned long en)
203{
204 unsigned char irq_happened;
205 unsigned int replay;
206
207
208 set_soft_enabled(en);
209 if (!en)
210 return;
211
212
213
214
215
216
217
218
219
220
221
222
223
224 irq_happened = get_irq_happened();
225 if (!irq_happened)
226 return;
227
228
229
230
231
232
233
234
235
236
237
238
239 if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
240 __hard_irq_disable();
241#ifdef CONFIG_TRACE_IRQFLAGS
242 else {
243
244
245
246
247
248
249 if (WARN_ON(mfmsr() & MSR_EE))
250 __hard_irq_disable();
251 }
252#endif
253
254 set_soft_enabled(0);
255
256
257
258
259
260
261 replay = __check_irq_replay();
262
263
264 set_soft_enabled(1);
265
266
267
268
269
270 if (replay) {
271 __replay_interrupt(replay);
272 return;
273 }
274
275
276 __hard_irq_enable();
277}
278EXPORT_SYMBOL(arch_local_irq_restore);
279
280
281
282
283
284
285
286
287
288
289void notrace restore_interrupts(void)
290{
291 if (irqs_disabled()) {
292 local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
293 local_irq_enable();
294 } else
295 __hard_irq_enable();
296}
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313bool prep_irq_for_idle(void)
314{
315
316
317
318
319 hard_irq_disable();
320
321
322
323
324
325 if (lazy_irq_pending())
326 return false;
327
328
329 trace_hardirqs_on();
330
331
332
333
334
335
336
337 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
338 local_paca->soft_enabled = 1;
339
340
341 return true;
342}
343
344#endif
345
346int arch_show_interrupts(struct seq_file *p, int prec)
347{
348 int j;
349
350#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
351 if (tau_initialized) {
352 seq_printf(p, "%*s: ", prec, "TAU");
353 for_each_online_cpu(j)
354 seq_printf(p, "%10u ", tau_interrupts(j));
355 seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n");
356 }
357#endif
358
359 seq_printf(p, "%*s: ", prec, "LOC");
360 for_each_online_cpu(j)
361 seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_event);
362 seq_printf(p, " Local timer interrupts for timer event device\n");
363
364 seq_printf(p, "%*s: ", prec, "LOC");
365 for_each_online_cpu(j)
366 seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_others);
367 seq_printf(p, " Local timer interrupts for others\n");
368
369 seq_printf(p, "%*s: ", prec, "SPU");
370 for_each_online_cpu(j)
371 seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
372 seq_printf(p, " Spurious interrupts\n");
373
374 seq_printf(p, "%*s: ", prec, "PMI");
375 for_each_online_cpu(j)
376 seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
377 seq_printf(p, " Performance monitoring interrupts\n");
378
379 seq_printf(p, "%*s: ", prec, "MCE");
380 for_each_online_cpu(j)
381 seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions);
382 seq_printf(p, " Machine check exceptions\n");
383
384 if (cpu_has_feature(CPU_FTR_HVMODE)) {
385 seq_printf(p, "%*s: ", prec, "HMI");
386 for_each_online_cpu(j)
387 seq_printf(p, "%10u ",
388 per_cpu(irq_stat, j).hmi_exceptions);
389 seq_printf(p, " Hypervisor Maintenance Interrupts\n");
390 }
391
392#ifdef CONFIG_PPC_DOORBELL
393 if (cpu_has_feature(CPU_FTR_DBELL)) {
394 seq_printf(p, "%*s: ", prec, "DBL");
395 for_each_online_cpu(j)
396 seq_printf(p, "%10u ", per_cpu(irq_stat, j).doorbell_irqs);
397 seq_printf(p, " Doorbell interrupts\n");
398 }
399#endif
400
401 return 0;
402}
403
404
405
406
407u64 arch_irq_stat_cpu(unsigned int cpu)
408{
409 u64 sum = per_cpu(irq_stat, cpu).timer_irqs_event;
410
411 sum += per_cpu(irq_stat, cpu).pmu_irqs;
412 sum += per_cpu(irq_stat, cpu).mce_exceptions;
413 sum += per_cpu(irq_stat, cpu).spurious_irqs;
414 sum += per_cpu(irq_stat, cpu).timer_irqs_others;
415 sum += per_cpu(irq_stat, cpu).hmi_exceptions;
416#ifdef CONFIG_PPC_DOORBELL
417 sum += per_cpu(irq_stat, cpu).doorbell_irqs;
418#endif
419
420 return sum;
421}
422
423#ifdef CONFIG_HOTPLUG_CPU
424void migrate_irqs(void)
425{
426 struct irq_desc *desc;
427 unsigned int irq;
428 static int warned;
429 cpumask_var_t mask;
430 const struct cpumask *map = cpu_online_mask;
431
432 alloc_cpumask_var(&mask, GFP_KERNEL);
433
434 for_each_irq_desc(irq, desc) {
435 struct irq_data *data;
436 struct irq_chip *chip;
437
438 data = irq_desc_get_irq_data(desc);
439 if (irqd_is_per_cpu(data))
440 continue;
441
442 chip = irq_data_get_irq_chip(data);
443
444 cpumask_and(mask, irq_data_get_affinity_mask(data), map);
445 if (cpumask_any(mask) >= nr_cpu_ids) {
446 pr_warn("Breaking affinity for irq %i\n", irq);
447 cpumask_copy(mask, map);
448 }
449 if (chip->irq_set_affinity)
450 chip->irq_set_affinity(data, mask, true);
451 else if (desc->action && !(warned++))
452 pr_err("Cannot set affinity for irq %i\n", irq);
453 }
454
455 free_cpumask_var(mask);
456
457 local_irq_enable();
458 mdelay(1);
459 local_irq_disable();
460}
461#endif
462
463static inline void check_stack_overflow(void)
464{
465#ifdef CONFIG_DEBUG_STACKOVERFLOW
466 long sp;
467
468 sp = current_stack_pointer() & (THREAD_SIZE-1);
469
470
471 if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
472 pr_err("do_IRQ: stack overflow: %ld\n",
473 sp - sizeof(struct thread_info));
474 dump_stack();
475 }
476#endif
477}
478
479void __do_irq(struct pt_regs *regs)
480{
481 unsigned int irq;
482
483 irq_enter();
484
485 trace_irq_entry(regs);
486
487 check_stack_overflow();
488
489
490
491
492
493
494 irq = ppc_md.get_irq();
495
496
497 may_hard_irq_enable();
498
499
500 if (unlikely(irq == NO_IRQ))
501 __this_cpu_inc(irq_stat.spurious_irqs);
502 else
503 generic_handle_irq(irq);
504
505 trace_irq_exit(regs);
506
507 irq_exit();
508}
509
510void do_IRQ(struct pt_regs *regs)
511{
512 struct pt_regs *old_regs = set_irq_regs(regs);
513 struct thread_info *curtp, *irqtp, *sirqtp;
514
515
516 curtp = current_thread_info();
517 irqtp = hardirq_ctx[raw_smp_processor_id()];
518 sirqtp = softirq_ctx[raw_smp_processor_id()];
519
520
521 if (unlikely(curtp == irqtp || curtp == sirqtp)) {
522 __do_irq(regs);
523 set_irq_regs(old_regs);
524 return;
525 }
526
527
528 irqtp->task = curtp->task;
529 irqtp->flags = 0;
530
531
532 irqtp->preempt_count = curtp->preempt_count;
533
534
535 call_do_irq(regs, irqtp);
536
537
538 irqtp->task = NULL;
539
540
541 if (irqtp->flags)
542 set_bits(irqtp->flags, &curtp->flags);
543
544 set_irq_regs(old_regs);
545}
546
547void __init init_IRQ(void)
548{
549 if (ppc_md.init_IRQ)
550 ppc_md.init_IRQ();
551
552 exc_lvl_ctx_init();
553
554 irq_ctx_init();
555}
556
557#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
558struct thread_info *critirq_ctx[NR_CPUS] __read_mostly;
559struct thread_info *dbgirq_ctx[NR_CPUS] __read_mostly;
560struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly;
561
562void exc_lvl_ctx_init(void)
563{
564 struct thread_info *tp;
565 int i, cpu_nr;
566
567 for_each_possible_cpu(i) {
568#ifdef CONFIG_PPC64
569 cpu_nr = i;
570#else
571#ifdef CONFIG_SMP
572 cpu_nr = get_hard_smp_processor_id(i);
573#else
574 cpu_nr = 0;
575#endif
576#endif
577
578 memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
579 tp = critirq_ctx[cpu_nr];
580 tp->cpu = cpu_nr;
581 tp->preempt_count = 0;
582
583#ifdef CONFIG_BOOKE
584 memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE);
585 tp = dbgirq_ctx[cpu_nr];
586 tp->cpu = cpu_nr;
587 tp->preempt_count = 0;
588
589 memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE);
590 tp = mcheckirq_ctx[cpu_nr];
591 tp->cpu = cpu_nr;
592 tp->preempt_count = HARDIRQ_OFFSET;
593#endif
594 }
595}
596#endif
597
598struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
599struct thread_info *hardirq_ctx[NR_CPUS] __read_mostly;
600
601void irq_ctx_init(void)
602{
603 struct thread_info *tp;
604 int i;
605
606 for_each_possible_cpu(i) {
607 memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
608 tp = softirq_ctx[i];
609 tp->cpu = i;
610
611 memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
612 tp = hardirq_ctx[i];
613 tp->cpu = i;
614 }
615}
616
617void do_softirq_own_stack(void)
618{
619 struct thread_info *curtp, *irqtp;
620
621 curtp = current_thread_info();
622 irqtp = softirq_ctx[smp_processor_id()];
623 irqtp->task = curtp->task;
624 irqtp->flags = 0;
625 call_do_softirq(irqtp);
626 irqtp->task = NULL;
627
628
629
630
631 if (irqtp->flags)
632 set_bits(irqtp->flags, &curtp->flags);
633}
634
635irq_hw_number_t virq_to_hw(unsigned int virq)
636{
637 struct irq_data *irq_data = irq_get_irq_data(virq);
638 return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
639}
640EXPORT_SYMBOL_GPL(virq_to_hw);
641
642#ifdef CONFIG_SMP
643int irq_choose_cpu(const struct cpumask *mask)
644{
645 int cpuid;
646
647 if (cpumask_equal(mask, cpu_online_mask)) {
648 static int irq_rover;
649 static DEFINE_RAW_SPINLOCK(irq_rover_lock);
650 unsigned long flags;
651
652
653do_round_robin:
654 raw_spin_lock_irqsave(&irq_rover_lock, flags);
655
656 irq_rover = cpumask_next(irq_rover, cpu_online_mask);
657 if (irq_rover >= nr_cpu_ids)
658 irq_rover = cpumask_first(cpu_online_mask);
659
660 cpuid = irq_rover;
661
662 raw_spin_unlock_irqrestore(&irq_rover_lock, flags);
663 } else {
664 cpuid = cpumask_first_and(mask, cpu_online_mask);
665 if (cpuid >= nr_cpu_ids)
666 goto do_round_robin;
667 }
668
669 return get_hard_smp_processor_id(cpuid);
670}
671#else
672int irq_choose_cpu(const struct cpumask *mask)
673{
674 return hard_smp_processor_id();
675}
676#endif
677
678int arch_early_irq_init(void)
679{
680 return 0;
681}
682
683#ifdef CONFIG_PPC64
684static int __init setup_noirqdistrib(char *str)
685{
686 distribute_irqs = 0;
687 return 1;
688}
689
690__setup("noirqdistrib", setup_noirqdistrib);
691#endif
692