]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - arch/sparc/kernel/sun4d_irq.c
sparc32, sun4m: Implemented SMP IPIs support for SUN4M machines
[mirror_ubuntu-focal-kernel.git] / arch / sparc / kernel / sun4d_irq.c
CommitLineData
88278ca2 1/*
e54f8548 2 * SS1000/SC2000 interrupt handling.
1da177e4
LT
3 *
4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Heavily based on arch/sparc/kernel/irq.c.
6 */
7
1da177e4 8#include <linux/kernel_stat.h>
1da177e4 9#include <linux/seq_file.h>
e54f8548 10
1da177e4 11#include <asm/timer.h>
1da177e4
LT
12#include <asm/traps.h>
13#include <asm/irq.h>
14#include <asm/io.h>
1da177e4
LT
15#include <asm/sbi.h>
16#include <asm/cacheflush.h>
5fcafb7a 17#include <asm/setup.h>
1da177e4 18
81265fd9 19#include "kernel.h"
32231a66
AV
20#include "irq.h"
21
e54f8548
SR
22/* Sun4d interrupts fall roughly into two categories. SBUS and
23 * cpu local. CPU local interrupts cover the timer interrupts
24 * and whatnot, and we encode those as normal PILs between
25 * 0 and 15.
6baa9b20 26 * SBUS interrupts are encodes as a combination of board, level and slot.
e54f8548
SR
27 */
28
6baa9b20
SR
29struct sun4d_handler_data {
30 unsigned int cpuid; /* target cpu */
31 unsigned int real_irq; /* interrupt level */
32};
33
34
35static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
36{
37 return (board + 1) << 5 | (lvl << 2) | slot;
38}
39
f5f10857
DM
40struct sun4d_timer_regs {
41 u32 l10_timer_limit;
42 u32 l10_cur_countx;
43 u32 l10_limit_noclear;
44 u32 ctrl;
45 u32 l10_cur_count;
46};
47
48static struct sun4d_timer_regs __iomem *sun4d_timers;
49
6baa9b20 50#define SUN4D_TIMER_IRQ 10
db1cdd14
SR
51
52/* Specify which cpu handle interrupts from which board.
53 * Index is board - value is cpu.
54 */
55static unsigned char board_to_cpu[32];
1da177e4 56
1da177e4 57static int pil_to_sbus[] = {
e54f8548
SR
58 0,
59 0,
60 1,
61 2,
62 0,
63 3,
64 0,
65 4,
66 0,
67 5,
68 0,
69 6,
70 0,
71 7,
72 0,
73 0,
1da177e4
LT
74};
75
f8376e93 76/* Exported for sun4d_smp.c */
1da177e4 77DEFINE_SPINLOCK(sun4d_imsk_lock);
1da177e4 78
6baa9b20
SR
79/* SBUS interrupts are encoded integers including the board number
80 * (plus one), the SBUS level, and the SBUS slot number. Sun4D
81 * IRQ dispatch is done by:
82 *
83 * 1) Reading the BW local interrupt table in order to get the bus
84 * interrupt mask.
85 *
86 * This table is indexed by SBUS interrupt level which can be
87 * derived from the PIL we got interrupted on.
88 *
89 * 2) For each bus showing interrupt pending from #1, read the
90 * SBI interrupt state register. This will indicate which slots
91 * have interrupts pending for that SBUS interrupt level.
92 *
93 * 3) Call the genreric IRQ support.
94 */
95static void sun4d_sbus_handler_irq(int sbusl)
1da177e4 96{
6baa9b20
SR
97 unsigned int bus_mask;
98 unsigned int sbino, slot;
99 unsigned int sbil;
100
101 bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
102 bw_clear_intr_mask(sbusl, bus_mask);
103
104 sbil = (sbusl << 2);
105 /* Loop for each pending SBI */
106 for (sbino = 0; bus_mask; sbino++) {
107 unsigned int idx, mask;
108
109 bus_mask >>= 1;
110 if (!(bus_mask & 1))
111 continue;
112 /* XXX This seems to ACK the irq twice. acquire_sbi()
113 * XXX uses swap, therefore this writes 0xf << sbil,
114 * XXX then later release_sbi() will write the individual
115 * XXX bits which were set again.
116 */
117 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
118 mask &= (0xf << sbil);
119
120 /* Loop for each pending SBI slot */
121 idx = 0;
122 slot = (1 << sbil);
123 while (mask != 0) {
124 unsigned int pil;
125 struct irq_bucket *p;
126
127 idx++;
128 slot <<= 1;
129 if (!(mask & slot))
130 continue;
131
132 mask &= ~slot;
133 pil = sun4d_encode_irq(sbino, sbil, idx);
134
135 p = irq_map[pil];
136 while (p) {
137 struct irq_bucket *next;
138
139 next = p->next;
140 generic_handle_irq(p->irq);
141 p = next;
1da177e4 142 }
6baa9b20 143 release_sbi(SBI2DEVID(sbino), slot);
1da177e4 144 }
1da177e4 145 }
1da177e4
LT
146}
147
e54f8548 148void sun4d_handler_irq(int pil, struct pt_regs *regs)
1da177e4 149{
0d84438d 150 struct pt_regs *old_regs;
1da177e4 151 /* SBUS IRQ level (1 - 7) */
d4d1ec48 152 int sbusl = pil_to_sbus[pil];
e54f8548 153
1da177e4
LT
154 /* FIXME: Is this necessary?? */
155 cc_get_ipen();
e54f8548 156
d4d1ec48 157 cc_set_iclr(1 << pil);
e54f8548 158
0d84438d 159 old_regs = set_irq_regs(regs);
1da177e4 160 irq_enter();
6baa9b20
SR
161 if (sbusl == 0) {
162 /* cpu interrupt */
163 struct irq_bucket *p;
164
165 p = irq_map[pil];
166 while (p) {
167 struct irq_bucket *next;
168
169 next = p->next;
170 generic_handle_irq(p->irq);
171 p = next;
172 }
1da177e4 173 } else {
6baa9b20
SR
174 /* SBUS interrupt */
175 sun4d_sbus_handler_irq(sbusl);
1da177e4
LT
176 }
177 irq_exit();
0d84438d 178 set_irq_regs(old_regs);
1da177e4
LT
179}
180
6baa9b20
SR
181
182static void sun4d_mask_irq(struct irq_data *data)
1da177e4 183{
6baa9b20
SR
184 struct sun4d_handler_data *handler_data = data->handler_data;
185 unsigned int real_irq;
186#ifdef CONFIG_SMP
187 int cpuid = handler_data->cpuid;
1da177e4 188 unsigned long flags;
6baa9b20
SR
189#endif
190 real_irq = handler_data->real_irq;
191#ifdef CONFIG_SMP
192 spin_lock_irqsave(&sun4d_imsk_lock, flags);
193 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
194 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
195#else
196 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
197#endif
1da177e4
LT
198}
199
6baa9b20 200static void sun4d_unmask_irq(struct irq_data *data)
1da177e4 201{
6baa9b20
SR
202 struct sun4d_handler_data *handler_data = data->handler_data;
203 unsigned int real_irq;
204#ifdef CONFIG_SMP
205 int cpuid = handler_data->cpuid;
1da177e4 206 unsigned long flags;
6baa9b20
SR
207#endif
208 real_irq = handler_data->real_irq;
e54f8548 209
6baa9b20 210#ifdef CONFIG_SMP
1da177e4 211 spin_lock_irqsave(&sun4d_imsk_lock, flags);
6baa9b20 212 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq));
1da177e4 213 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
6baa9b20
SR
214#else
215 cc_set_imsk(cc_get_imsk() | ~(1 << real_irq));
216#endif
1da177e4
LT
217}
218
6baa9b20 219static unsigned int sun4d_startup_irq(struct irq_data *data)
1da177e4 220{
6baa9b20
SR
221 irq_link(data->irq);
222 sun4d_unmask_irq(data);
223 return 0;
224}
f8376e93 225
6baa9b20
SR
226static void sun4d_shutdown_irq(struct irq_data *data)
227{
228 sun4d_mask_irq(data);
229 irq_unlink(data->irq);
1da177e4
LT
230}
231
6baa9b20
SR
232struct irq_chip sun4d_irq = {
233 .name = "sun4d",
234 .irq_startup = sun4d_startup_irq,
235 .irq_shutdown = sun4d_shutdown_irq,
236 .irq_unmask = sun4d_unmask_irq,
237 .irq_mask = sun4d_mask_irq,
238};
239
1da177e4
LT
240#ifdef CONFIG_SMP
241static void sun4d_set_cpu_int(int cpu, int level)
242{
243 sun4d_send_ipi(cpu, level);
244}
245
246static void sun4d_clear_ipi(int cpu, int level)
247{
248}
249
250static void sun4d_set_udt(int cpu)
251{
252}
253
254/* Setup IRQ distribution scheme. */
255void __init sun4d_distribute_irqs(void)
256{
71d37211
DM
257 struct device_node *dp;
258
1da177e4
LT
259 int cpuid = cpu_logical_map(1);
260
261 if (cpuid == -1)
262 cpuid = cpu_logical_map(0);
71d37211
DM
263 for_each_node_by_name(dp, "sbi") {
264 int devid = of_getintprop_default(dp, "device-id", 0);
265 int board = of_getintprop_default(dp, "board#", 0);
db1cdd14 266 board_to_cpu[board] = cpuid;
71d37211 267 set_sbi_tid(devid, cpuid << 3);
1da177e4 268 }
e54f8548 269 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
1da177e4
LT
270}
271#endif
e54f8548 272
1da177e4
LT
273static void sun4d_clear_clock_irq(void)
274{
f5f10857 275 sbus_readl(&sun4d_timers->l10_timer_limit);
1da177e4
LT
276}
277
1da177e4
LT
278static void sun4d_load_profile_irq(int cpu, unsigned int limit)
279{
280 bw_set_prof_limit(cpu, limit);
281}
282
f5f10857 283static void __init sun4d_load_profile_irqs(void)
1da177e4 284{
f5f10857 285 int cpu = 0, mid;
1da177e4 286
f5f10857
DM
287 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
288 sun4d_load_profile_irq(mid >> 3, 0);
289 cpu++;
290 }
291}
292
1d05995b
SR
293unsigned int sun4d_build_device_irq(struct platform_device *op,
294 unsigned int real_irq)
295{
1d05995b
SR
296 struct device_node *dp = op->dev.of_node;
297 struct device_node *io_unit, *sbi = dp->parent;
298 const struct linux_prom_registers *regs;
6baa9b20
SR
299 struct sun4d_handler_data *handler_data;
300 unsigned int pil;
301 unsigned int irq;
1d05995b
SR
302 int board, slot;
303 int sbusl;
304
6baa9b20 305 irq = 0;
1d05995b
SR
306 while (sbi) {
307 if (!strcmp(sbi->name, "sbi"))
308 break;
309
310 sbi = sbi->parent;
311 }
312 if (!sbi)
313 goto err_out;
314
315 regs = of_get_property(dp, "reg", NULL);
316 if (!regs)
317 goto err_out;
318
319 slot = regs->which_io;
320
321 /*
322 * If SBI's parent is not io-unit or the io-unit lacks
323 * a "board#" property, something is very wrong.
324 */
325 if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
326 printk("%s: Error, parent is not io-unit.\n", sbi->full_name);
327 goto err_out;
328 }
329 io_unit = sbi->parent;
330 board = of_getintprop_default(io_unit, "board#", -1);
331 if (board == -1) {
332 printk("%s: Error, lacks board# property.\n", io_unit->full_name);
333 goto err_out;
334 }
335
336 sbusl = pil_to_sbus[real_irq];
337 if (sbusl)
6baa9b20
SR
338 pil = sun4d_encode_irq(board, sbusl, slot);
339 else
340 pil = real_irq;
341
342 irq = irq_alloc(real_irq, pil);
343 if (irq == 0)
344 goto err_out;
345
346 handler_data = irq_get_handler_data(irq);
347 if (unlikely(handler_data))
348 goto err_out;
349
350 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
351 if (unlikely(!handler_data)) {
352 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
353 prom_halt();
354 }
355 handler_data->cpuid = board_to_cpu[board];
356 handler_data->real_irq = real_irq;
357 irq_set_chip_and_handler_name(irq, &sun4d_irq,
358 handle_level_irq, "level");
359 irq_set_handler_data(irq, handler_data);
1d05995b
SR
360
361err_out:
362 return real_irq;
363}
364
f5f10857
DM
365static void __init sun4d_fixup_trap_table(void)
366{
1da177e4 367#ifdef CONFIG_SMP
f5f10857 368 unsigned long flags;
f5f10857 369 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
f5f10857
DM
370
371 /* Adjust so that we jump directly to smp4d_ticker */
372 lvl14_save[2] += smp4d_ticker - real_irq_entry;
373
374 /* For SMP we use the level 14 ticker, however the bootup code
375 * has copied the firmware's level 14 vector into the boot cpu's
376 * trap table, we must fix this now or we get squashed.
377 */
378 local_irq_save(flags);
379 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
380 trap_table->inst_one = lvl14_save[0];
381 trap_table->inst_two = lvl14_save[1];
382 trap_table->inst_three = lvl14_save[2];
383 trap_table->inst_four = lvl14_save[3];
384 local_flush_cache_all();
385 local_irq_restore(flags);
1da177e4 386#endif
f5f10857
DM
387}
388
389static void __init sun4d_init_timers(irq_handler_t counter_fn)
390{
391 struct device_node *dp;
392 struct resource res;
6baa9b20 393 unsigned int irq;
f5f10857
DM
394 const u32 *reg;
395 int err;
396
397 dp = of_find_node_by_name(NULL, "cpu-unit");
398 if (!dp) {
399 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
400 prom_halt();
401 }
402
403 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
404 * registers via any cpu's mapping. The first 'reg' property is the
405 * bootbus.
406 */
407 reg = of_get_property(dp, "reg", NULL);
c2e27c35 408 of_node_put(dp);
f5f10857
DM
409 if (!reg) {
410 prom_printf("sun4d_init_timers: No reg property\n");
411 prom_halt();
412 }
413
414 res.start = reg[1];
415 res.end = reg[2] - 1;
416 res.flags = reg[0] & 0xff;
417 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
418 sizeof(struct sun4d_timer_regs), "user timer");
419 if (!sun4d_timers) {
420 prom_printf("sun4d_init_timers: Can't map timer regs\n");
421 prom_halt();
422 }
423
424 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
1da177e4 425
1da177e4 426 master_l10_counter = &sun4d_timers->l10_cur_count;
1da177e4 427
6baa9b20
SR
428 irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ);
429 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
f5f10857 430 if (err) {
e54f8548
SR
431 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
432 err);
1da177e4
LT
433 prom_halt();
434 }
f5f10857
DM
435 sun4d_load_profile_irqs();
436 sun4d_fixup_trap_table();
1da177e4
LT
437}
438
439void __init sun4d_init_sbi_irq(void)
440{
71d37211 441 struct device_node *dp;
5fcafb7a 442 int target_cpu;
f8376e93 443
f8376e93 444 target_cpu = boot_cpu_id;
71d37211
DM
445 for_each_node_by_name(dp, "sbi") {
446 int devid = of_getintprop_default(dp, "device-id", 0);
447 int board = of_getintprop_default(dp, "board#", 0);
448 unsigned int mask;
449
f8376e93 450 set_sbi_tid(devid, target_cpu << 3);
db1cdd14 451 board_to_cpu[board] = target_cpu;
f8376e93 452
1da177e4 453 /* Get rid of pending irqs from PROM */
71d37211 454 mask = acquire_sbi(devid, 0xffffffff);
1da177e4 455 if (mask) {
e54f8548
SR
456 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
457 mask, board);
71d37211 458 release_sbi(devid, mask);
1da177e4
LT
459 }
460 }
461}
462
1da177e4
LT
463void __init sun4d_init_IRQ(void)
464{
465 local_irq_disable();
466
1da177e4 467 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
1da177e4 468 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
bbdc2661 469
6baa9b20 470 sparc_irq_config.init_timers = sun4d_init_timers;
1d05995b 471 sparc_irq_config.build_device_irq = sun4d_build_device_irq;
bbdc2661 472
1da177e4
LT
473#ifdef CONFIG_SMP
474 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
475 BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
476 BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
477#endif
478 /* Cannot enable interrupts until OBP ticker is disabled. */
479}