sparc32: generic clockevent support
[deliverable/linux.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 */
ea160584 106 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
6baa9b20
SR
107 unsigned int idx, mask;
108
6baa9b20
SR
109 if (!(bus_mask & 1))
110 continue;
111 /* XXX This seems to ACK the irq twice. acquire_sbi()
112 * XXX uses swap, therefore this writes 0xf << sbil,
113 * XXX then later release_sbi() will write the individual
114 * XXX bits which were set again.
115 */
116 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
117 mask &= (0xf << sbil);
118
119 /* Loop for each pending SBI slot */
6baa9b20 120 slot = (1 << sbil);
ea160584 121 for (idx = 0; mask != 0; idx++, slot <<= 1) {
6baa9b20
SR
122 unsigned int pil;
123 struct irq_bucket *p;
124
6baa9b20
SR
125 if (!(mask & slot))
126 continue;
127
128 mask &= ~slot;
ea160584 129 pil = sun4d_encode_irq(sbino, sbusl, idx);
6baa9b20
SR
130
131 p = irq_map[pil];
132 while (p) {
133 struct irq_bucket *next;
134
135 next = p->next;
136 generic_handle_irq(p->irq);
137 p = next;
1da177e4 138 }
6baa9b20 139 release_sbi(SBI2DEVID(sbino), slot);
1da177e4 140 }
1da177e4 141 }
1da177e4
LT
142}
143
e54f8548 144void sun4d_handler_irq(int pil, struct pt_regs *regs)
1da177e4 145{
0d84438d 146 struct pt_regs *old_regs;
1da177e4 147 /* SBUS IRQ level (1 - 7) */
d4d1ec48 148 int sbusl = pil_to_sbus[pil];
e54f8548 149
1da177e4
LT
150 /* FIXME: Is this necessary?? */
151 cc_get_ipen();
e54f8548 152
d4d1ec48 153 cc_set_iclr(1 << pil);
e54f8548 154
55dd23ec
DH
155#ifdef CONFIG_SMP
156 /*
157 * Check IPI data structures after IRQ has been cleared. Hard and Soft
158 * IRQ can happen at the same time, so both cases are always handled.
159 */
160 if (pil == SUN4D_IPI_IRQ)
161 sun4d_ipi_interrupt();
162#endif
163
0d84438d 164 old_regs = set_irq_regs(regs);
1da177e4 165 irq_enter();
6baa9b20
SR
166 if (sbusl == 0) {
167 /* cpu interrupt */
168 struct irq_bucket *p;
169
170 p = irq_map[pil];
171 while (p) {
172 struct irq_bucket *next;
173
174 next = p->next;
175 generic_handle_irq(p->irq);
176 p = next;
177 }
1da177e4 178 } else {
6baa9b20
SR
179 /* SBUS interrupt */
180 sun4d_sbus_handler_irq(sbusl);
1da177e4
LT
181 }
182 irq_exit();
0d84438d 183 set_irq_regs(old_regs);
1da177e4
LT
184}
185
6baa9b20
SR
186
187static void sun4d_mask_irq(struct irq_data *data)
1da177e4 188{
6baa9b20
SR
189 struct sun4d_handler_data *handler_data = data->handler_data;
190 unsigned int real_irq;
191#ifdef CONFIG_SMP
192 int cpuid = handler_data->cpuid;
1da177e4 193 unsigned long flags;
6baa9b20
SR
194#endif
195 real_irq = handler_data->real_irq;
196#ifdef CONFIG_SMP
197 spin_lock_irqsave(&sun4d_imsk_lock, flags);
198 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
199 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
200#else
201 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
202#endif
1da177e4
LT
203}
204
6baa9b20 205static void sun4d_unmask_irq(struct irq_data *data)
1da177e4 206{
6baa9b20
SR
207 struct sun4d_handler_data *handler_data = data->handler_data;
208 unsigned int real_irq;
209#ifdef CONFIG_SMP
210 int cpuid = handler_data->cpuid;
1da177e4 211 unsigned long flags;
6baa9b20
SR
212#endif
213 real_irq = handler_data->real_irq;
e54f8548 214
6baa9b20 215#ifdef CONFIG_SMP
1da177e4 216 spin_lock_irqsave(&sun4d_imsk_lock, flags);
ea160584 217 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
1da177e4 218 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
6baa9b20 219#else
ea160584 220 cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
6baa9b20 221#endif
1da177e4
LT
222}
223
6baa9b20 224static unsigned int sun4d_startup_irq(struct irq_data *data)
1da177e4 225{
6baa9b20
SR
226 irq_link(data->irq);
227 sun4d_unmask_irq(data);
228 return 0;
229}
f8376e93 230
6baa9b20
SR
231static void sun4d_shutdown_irq(struct irq_data *data)
232{
233 sun4d_mask_irq(data);
234 irq_unlink(data->irq);
1da177e4
LT
235}
236
6baa9b20
SR
237struct irq_chip sun4d_irq = {
238 .name = "sun4d",
239 .irq_startup = sun4d_startup_irq,
240 .irq_shutdown = sun4d_shutdown_irq,
241 .irq_unmask = sun4d_unmask_irq,
242 .irq_mask = sun4d_mask_irq,
243};
244
1da177e4
LT
245#ifdef CONFIG_SMP
246static void sun4d_set_cpu_int(int cpu, int level)
247{
248 sun4d_send_ipi(cpu, level);
249}
250
251static void sun4d_clear_ipi(int cpu, int level)
252{
253}
254
255static void sun4d_set_udt(int cpu)
256{
257}
258
259/* Setup IRQ distribution scheme. */
260void __init sun4d_distribute_irqs(void)
261{
71d37211
DM
262 struct device_node *dp;
263
1da177e4
LT
264 int cpuid = cpu_logical_map(1);
265
266 if (cpuid == -1)
267 cpuid = cpu_logical_map(0);
71d37211
DM
268 for_each_node_by_name(dp, "sbi") {
269 int devid = of_getintprop_default(dp, "device-id", 0);
270 int board = of_getintprop_default(dp, "board#", 0);
db1cdd14 271 board_to_cpu[board] = cpuid;
71d37211 272 set_sbi_tid(devid, cpuid << 3);
1da177e4 273 }
e54f8548 274 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
1da177e4
LT
275}
276#endif
e54f8548 277
1da177e4
LT
278static void sun4d_clear_clock_irq(void)
279{
f5f10857 280 sbus_readl(&sun4d_timers->l10_timer_limit);
1da177e4
LT
281}
282
1da177e4
LT
283static void sun4d_load_profile_irq(int cpu, unsigned int limit)
284{
62f08283
TK
285 unsigned int value = limit ? timer_value(limit) : 0;
286 bw_set_prof_limit(cpu, value);
1da177e4
LT
287}
288
f5f10857 289static void __init sun4d_load_profile_irqs(void)
1da177e4 290{
f5f10857 291 int cpu = 0, mid;
1da177e4 292
f5f10857
DM
293 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
294 sun4d_load_profile_irq(mid >> 3, 0);
295 cpu++;
296 }
297}
298
5fba1708 299unsigned int _sun4d_build_device_irq(unsigned int real_irq,
300 unsigned int pil,
301 unsigned int board)
302{
303 struct sun4d_handler_data *handler_data;
304 unsigned int irq;
305
306 irq = irq_alloc(real_irq, pil);
307 if (irq == 0) {
308 prom_printf("IRQ: allocate for %d %d %d failed\n",
309 real_irq, pil, board);
310 goto err_out;
311 }
312
313 handler_data = irq_get_handler_data(irq);
314 if (unlikely(handler_data))
315 goto err_out;
316
317 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
318 if (unlikely(!handler_data)) {
319 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
320 prom_halt();
321 }
322 handler_data->cpuid = board_to_cpu[board];
323 handler_data->real_irq = real_irq;
324 irq_set_chip_and_handler_name(irq, &sun4d_irq,
325 handle_level_irq, "level");
326 irq_set_handler_data(irq, handler_data);
327
328err_out:
329 return irq;
330}
331
332
333
1d05995b
SR
334unsigned int sun4d_build_device_irq(struct platform_device *op,
335 unsigned int real_irq)
336{
1d05995b 337 struct device_node *dp = op->dev.of_node;
9eeb0898 338 struct device_node *board_parent, *bus = dp->parent;
339 char *bus_connection;
1d05995b 340 const struct linux_prom_registers *regs;
6baa9b20
SR
341 unsigned int pil;
342 unsigned int irq;
1d05995b
SR
343 int board, slot;
344 int sbusl;
345
5fba1708 346 irq = real_irq;
9eeb0898 347 while (bus) {
348 if (!strcmp(bus->name, "sbi")) {
349 bus_connection = "io-unit";
1d05995b 350 break;
9eeb0898 351 }
352
353 if (!strcmp(bus->name, "bootbus")) {
354 bus_connection = "cpu-unit";
355 break;
356 }
1d05995b 357
9eeb0898 358 bus = bus->parent;
1d05995b 359 }
9eeb0898 360 if (!bus)
1d05995b
SR
361 goto err_out;
362
363 regs = of_get_property(dp, "reg", NULL);
364 if (!regs)
365 goto err_out;
366
367 slot = regs->which_io;
368
369 /*
9eeb0898 370 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
371 * lacks a "board#" property, something is very wrong.
1d05995b 372 */
9eeb0898 373 if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
374 printk(KERN_ERR "%s: Error, parent is not %s.\n",
375 bus->full_name, bus_connection);
1d05995b
SR
376 goto err_out;
377 }
9eeb0898 378 board_parent = bus->parent;
379 board = of_getintprop_default(board_parent, "board#", -1);
1d05995b 380 if (board == -1) {
9eeb0898 381 printk(KERN_ERR "%s: Error, lacks board# property.\n",
382 board_parent->full_name);
1d05995b
SR
383 goto err_out;
384 }
385
386 sbusl = pil_to_sbus[real_irq];
387 if (sbusl)
6baa9b20
SR
388 pil = sun4d_encode_irq(board, sbusl, slot);
389 else
390 pil = real_irq;
391
5fba1708 392 irq = _sun4d_build_device_irq(real_irq, pil, board);
1d05995b 393err_out:
5fba1708 394 return irq;
1d05995b
SR
395}
396
5fba1708 397unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
398{
399 return _sun4d_build_device_irq(real_irq, real_irq, board);
400}
401
402
f5f10857
DM
403static void __init sun4d_fixup_trap_table(void)
404{
1da177e4 405#ifdef CONFIG_SMP
f5f10857 406 unsigned long flags;
f5f10857 407 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
f5f10857
DM
408
409 /* Adjust so that we jump directly to smp4d_ticker */
410 lvl14_save[2] += smp4d_ticker - real_irq_entry;
411
412 /* For SMP we use the level 14 ticker, however the bootup code
413 * has copied the firmware's level 14 vector into the boot cpu's
414 * trap table, we must fix this now or we get squashed.
415 */
416 local_irq_save(flags);
417 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
418 trap_table->inst_one = lvl14_save[0];
419 trap_table->inst_two = lvl14_save[1];
420 trap_table->inst_three = lvl14_save[2];
421 trap_table->inst_four = lvl14_save[3];
422 local_flush_cache_all();
423 local_irq_restore(flags);
1da177e4 424#endif
f5f10857
DM
425}
426
62f08283 427static void __init sun4d_init_timers(void)
f5f10857
DM
428{
429 struct device_node *dp;
430 struct resource res;
6baa9b20 431 unsigned int irq;
f5f10857
DM
432 const u32 *reg;
433 int err;
5fba1708 434 int board;
f5f10857
DM
435
436 dp = of_find_node_by_name(NULL, "cpu-unit");
437 if (!dp) {
438 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
439 prom_halt();
440 }
441
442 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
443 * registers via any cpu's mapping. The first 'reg' property is the
444 * bootbus.
445 */
446 reg = of_get_property(dp, "reg", NULL);
447 if (!reg) {
448 prom_printf("sun4d_init_timers: No reg property\n");
449 prom_halt();
450 }
451
5fba1708 452 board = of_getintprop_default(dp, "board#", -1);
453 if (board == -1) {
454 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
455 prom_halt();
456 }
457
458 of_node_put(dp);
459
f5f10857
DM
460 res.start = reg[1];
461 res.end = reg[2] - 1;
462 res.flags = reg[0] & 0xff;
463 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
464 sizeof(struct sun4d_timer_regs), "user timer");
465 if (!sun4d_timers) {
466 prom_printf("sun4d_init_timers: Can't map timer regs\n");
467 prom_halt();
468 }
469
62f08283
TK
470#ifdef CONFIG_SMP
471 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
472#else
473 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
474 sparc_config.features |= FEAT_L10_CLOCKEVENT;
475#endif
476 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
477 sbus_writel(timer_value(sparc_config.cs_period),
478 &sun4d_timers->l10_timer_limit);
1da177e4 479
1da177e4 480 master_l10_counter = &sun4d_timers->l10_cur_count;
1da177e4 481
5fba1708 482 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
62f08283 483 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
f5f10857 484 if (err) {
e54f8548
SR
485 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
486 err);
1da177e4
LT
487 prom_halt();
488 }
f5f10857
DM
489 sun4d_load_profile_irqs();
490 sun4d_fixup_trap_table();
1da177e4
LT
491}
492
493void __init sun4d_init_sbi_irq(void)
494{
71d37211 495 struct device_node *dp;
5fcafb7a 496 int target_cpu;
f8376e93 497
f8376e93 498 target_cpu = boot_cpu_id;
71d37211
DM
499 for_each_node_by_name(dp, "sbi") {
500 int devid = of_getintprop_default(dp, "device-id", 0);
501 int board = of_getintprop_default(dp, "board#", 0);
502 unsigned int mask;
503
f8376e93 504 set_sbi_tid(devid, target_cpu << 3);
db1cdd14 505 board_to_cpu[board] = target_cpu;
f8376e93 506
1da177e4 507 /* Get rid of pending irqs from PROM */
71d37211 508 mask = acquire_sbi(devid, 0xffffffff);
1da177e4 509 if (mask) {
e54f8548
SR
510 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
511 mask, board);
71d37211 512 release_sbi(devid, mask);
1da177e4
LT
513 }
514 }
515}
516
1da177e4
LT
517void __init sun4d_init_IRQ(void)
518{
519 local_irq_disable();
520
1da177e4 521 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
1da177e4 522 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
bbdc2661 523
472bc4f2
SR
524 sparc_config.init_timers = sun4d_init_timers;
525 sparc_config.build_device_irq = sun4d_build_device_irq;
62f08283 526 sparc_config.clock_rate = SBUS_CLOCK_RATE;
bbdc2661 527
1da177e4
LT
528#ifdef CONFIG_SMP
529 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
530 BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
531 BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
532#endif
533 /* Cannot enable interrupts until OBP ticker is disabled. */
534}
This page took 0.549368 seconds and 5 git commands to generate.