1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/interrupt.h>
5 #include <linux/init.h>
7 #include <asm/irq_cpu.h>
9 #include <asm/mipsregs.h>
13 extern void loongson3_send_irq_by_ipi(int cpu
, int irqs
);
15 unsigned int irq_cpu
[16] = {[0 ... 15] = -1};
16 unsigned int ht_irq
[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
17 unsigned int local_irq
= 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12;
19 int plat_set_irq_affinity(struct irq_data
*d
, const struct cpumask
*affinity
,
23 struct cpumask new_affinity
;
25 /* I/O devices are connected on package-0 */
26 cpumask_copy(&new_affinity
, affinity
);
27 for_each_cpu(cpu
, affinity
)
28 if (cpu_data
[cpu
].package
> 0)
29 cpumask_clear_cpu(cpu
, &new_affinity
);
31 if (cpumask_empty(&new_affinity
))
34 cpumask_copy(d
->common
->affinity
, &new_affinity
);
36 return IRQ_SET_MASK_OK_NOCOPY
;
39 static void ht_irqdispatch(void)
42 struct irq_data
*irqd
;
43 struct cpumask affinity
;
45 irq
= LOONGSON_HT1_INT_VECTOR(0);
46 LOONGSON_HT1_INT_VECTOR(0) = irq
; /* Acknowledge the IRQs */
48 for (i
= 0; i
< ARRAY_SIZE(ht_irq
); i
++) {
49 if (!(irq
& (0x1 << ht_irq
[i
])))
52 /* handled by local core */
53 if (local_irq
& (0x1 << ht_irq
[i
])) {
58 irqd
= irq_get_irq_data(ht_irq
[i
]);
59 cpumask_and(&affinity
, irqd
->common
->affinity
, cpu_active_mask
);
60 if (cpumask_empty(&affinity
)) {
65 irq_cpu
[ht_irq
[i
]] = cpumask_next(irq_cpu
[ht_irq
[i
]], &affinity
);
66 if (irq_cpu
[ht_irq
[i
]] >= nr_cpu_ids
)
67 irq_cpu
[ht_irq
[i
]] = cpumask_first(&affinity
);
69 if (irq_cpu
[ht_irq
[i
]] == 0) {
74 /* balanced by other cores */
75 loongson3_send_irq_by_ipi(irq_cpu
[ht_irq
[i
]], (0x1 << ht_irq
[i
]));
79 #define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0)
81 void mach_irq_dispatch(unsigned int pending
)
83 if (pending
& CAUSEF_IP7
)
84 do_IRQ(LOONGSON_TIMER_IRQ
);
85 #if defined(CONFIG_SMP)
86 if (pending
& CAUSEF_IP6
)
87 loongson3_ipi_interrupt(NULL
);
89 if (pending
& CAUSEF_IP3
)
91 if (pending
& CAUSEF_IP2
)
92 do_IRQ(LOONGSON_UART_IRQ
);
93 if (pending
& UNUSED_IPS
) {
94 pr_err("%s : spurious interrupt\n", __func__
);
99 static struct irqaction cascade_irqaction
= {
100 .handler
= no_action
,
101 .flags
= IRQF_NO_SUSPEND
,
105 static inline void mask_loongson_irq(struct irq_data
*d
)
107 clear_c0_status(0x100 << (d
->irq
- MIPS_CPU_IRQ_BASE
));
108 irq_disable_hazard();
110 /* Workaround: UART IRQ may deliver to any core */
111 if (d
->irq
== LOONGSON_UART_IRQ
) {
112 int cpu
= smp_processor_id();
113 int node_id
= cpu_logical_map(cpu
) / loongson_sysconf
.cores_per_node
;
114 int core_id
= cpu_logical_map(cpu
) % loongson_sysconf
.cores_per_node
;
115 u64 intenclr_addr
= smp_group
[node_id
] |
116 (u64
)(&LOONGSON_INT_ROUTER_INTENCLR
);
117 u64 introuter_lpc_addr
= smp_group
[node_id
] |
118 (u64
)(&LOONGSON_INT_ROUTER_LPC
);
120 *(volatile u32
*)intenclr_addr
= 1 << 10;
121 *(volatile u8
*)introuter_lpc_addr
= 0x10 + (1<<core_id
);
125 static inline void unmask_loongson_irq(struct irq_data
*d
)
127 /* Workaround: UART IRQ may deliver to any core */
128 if (d
->irq
== LOONGSON_UART_IRQ
) {
129 int cpu
= smp_processor_id();
130 int node_id
= cpu_logical_map(cpu
) / loongson_sysconf
.cores_per_node
;
131 int core_id
= cpu_logical_map(cpu
) % loongson_sysconf
.cores_per_node
;
132 u64 intenset_addr
= smp_group
[node_id
] |
133 (u64
)(&LOONGSON_INT_ROUTER_INTENSET
);
134 u64 introuter_lpc_addr
= smp_group
[node_id
] |
135 (u64
)(&LOONGSON_INT_ROUTER_LPC
);
137 *(volatile u32
*)intenset_addr
= 1 << 10;
138 *(volatile u8
*)introuter_lpc_addr
= 0x10 + (1<<core_id
);
141 set_c0_status(0x100 << (d
->irq
- MIPS_CPU_IRQ_BASE
));
145 /* For MIPS IRQs which shared by all cores */
146 static struct irq_chip loongson_irq_chip
= {
148 .irq_ack
= mask_loongson_irq
,
149 .irq_mask
= mask_loongson_irq
,
150 .irq_mask_ack
= mask_loongson_irq
,
151 .irq_unmask
= unmask_loongson_irq
,
152 .irq_eoi
= unmask_loongson_irq
,
155 void irq_router_init(void)
159 /* route LPC int to cpu core0 int 0 */
160 LOONGSON_INT_ROUTER_LPC
=
161 LOONGSON_INT_COREx_INTy(loongson_sysconf
.boot_cpu_id
, 0);
162 /* route HT1 int0 ~ int7 to cpu core0 INT1*/
163 for (i
= 0; i
< 8; i
++)
164 LOONGSON_INT_ROUTER_HT1(i
) =
165 LOONGSON_INT_COREx_INTy(loongson_sysconf
.boot_cpu_id
, 1);
166 /* enable HT1 interrupt */
167 LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
168 /* enable router interrupt intenset */
169 LOONGSON_INT_ROUTER_INTENSET
=
170 LOONGSON_INT_ROUTER_INTEN
| (0xffff << 16) | 0x1 << 10;
173 void __init
mach_init_irq(void)
175 struct irq_chip
*chip
;
177 clear_c0_status(ST0_IM
| ST0_BEV
);
182 chip
= irq_get_chip(I8259A_IRQ_BASE
);
183 chip
->irq_set_affinity
= plat_set_irq_affinity
;
185 irq_set_chip_and_handler(LOONGSON_UART_IRQ
,
186 &loongson_irq_chip
, handle_level_irq
);
189 setup_irq(LOONGSON_HT1_IRQ
, &cascade_irqaction
);
191 set_c0_status(STATUSF_IP2
| STATUSF_IP6
);
194 #ifdef CONFIG_HOTPLUG_CPU
196 void fixup_irqs(void)
199 clear_c0_status(ST0_IM
);