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