MIPS: bugfix: missed cache flush of TLB refill handler
[cascardo/linux.git] / arch / mips / loongson / loongson-3 / irq.c
1 #include <loongson.h>
2 #include <irq.h>
3 #include <linux/interrupt.h>
4 #include <linux/module.h>
5
6 #include <asm/irq_cpu.h>
7 #include <asm/i8259.h>
8 #include <asm/mipsregs.h>
9
10 unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
11
12 static void ht_irqdispatch(void)
13 {
14         unsigned int i, irq;
15
16         irq = LOONGSON_HT1_INT_VECTOR(0);
17         LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
18
19         for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
20                 if (irq & (0x1 << ht_irq[i]))
21                         do_IRQ(ht_irq[i]);
22         }
23 }
24
25 void mach_irq_dispatch(unsigned int pending)
26 {
27         if (pending & CAUSEF_IP7)
28                 do_IRQ(LOONGSON_TIMER_IRQ);
29 #if defined(CONFIG_SMP)
30         else if (pending & CAUSEF_IP6)
31                 loongson3_ipi_interrupt(NULL);
32 #endif
33         else if (pending & CAUSEF_IP3)
34                 ht_irqdispatch();
35         else if (pending & CAUSEF_IP2)
36                 do_IRQ(LOONGSON_UART_IRQ);
37         else {
38                 pr_err("%s : spurious interrupt\n", __func__);
39                 spurious_interrupt();
40         }
41 }
42
43 static struct irqaction cascade_irqaction = {
44         .handler = no_action,
45         .name = "cascade",
46 };
47
48 static inline void mask_loongson_irq(struct irq_data *d)
49 {
50         clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
51         irq_disable_hazard();
52
53         /* Workaround: UART IRQ may deliver to any core */
54         if (d->irq == LOONGSON_UART_IRQ) {
55                 int cpu = smp_processor_id();
56
57                 LOONGSON_INT_ROUTER_INTENCLR = 1 << 10;
58                 LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
59         }
60 }
61
62 static inline void unmask_loongson_irq(struct irq_data *d)
63 {
64         /* Workaround: UART IRQ may deliver to any core */
65         if (d->irq == LOONGSON_UART_IRQ) {
66                 int cpu = smp_processor_id();
67
68                 LOONGSON_INT_ROUTER_INTENSET = 1 << 10;
69                 LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
70         }
71
72         set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
73         irq_enable_hazard();
74 }
75
76  /* For MIPS IRQs which shared by all cores */
77 static struct irq_chip loongson_irq_chip = {
78         .name           = "Loongson",
79         .irq_ack        = mask_loongson_irq,
80         .irq_mask       = mask_loongson_irq,
81         .irq_mask_ack   = mask_loongson_irq,
82         .irq_unmask     = unmask_loongson_irq,
83         .irq_eoi        = unmask_loongson_irq,
84 };
85
86 void irq_router_init(void)
87 {
88         int i;
89
90         /* route LPC int to cpu core0 int 0 */
91         LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0;
92         /* route HT1 int0 ~ int7 to cpu core0 INT1*/
93         for (i = 0; i < 8; i++)
94                 LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1;
95         /* enable HT1 interrupt */
96         LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
97         /* enable router interrupt intenset */
98         LOONGSON_INT_ROUTER_INTENSET =
99                 LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
100 }
101
102 void __init mach_init_irq(void)
103 {
104         clear_c0_status(ST0_IM | ST0_BEV);
105
106         irq_router_init();
107         mips_cpu_irq_init();
108         init_i8259_irqs();
109         irq_set_chip_and_handler(LOONGSON_UART_IRQ,
110                         &loongson_irq_chip, handle_level_irq);
111
112         /* setup HT1 irq */
113         setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
114
115         set_c0_status(STATUSF_IP2 | STATUSF_IP6);
116 }
117
118 #ifdef CONFIG_HOTPLUG_CPU
119
120 void fixup_irqs(void)
121 {
122         irq_cpu_offline();
123         clear_c0_status(ST0_IM);
124 }
125
126 #endif