blob: 487c1bb374f5dfee47f97395b6ba6b53daf68cdd [file] [log] [blame]
Adrian Bunk88278ca2008-05-19 16:53:02 -07001/*
Sam Ravnborge54f8542011-01-28 22:08:21 +00002 * SS1000/SC2000 interrupt handling.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Heavily based on arch/sparc/kernel/irq.c.
6 */
7
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel_stat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/seq_file.h>
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <asm/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/traps.h>
13#include <asm/irq.h>
14#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <asm/sbi.h>
16#include <asm/cacheflush.h>
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +000017#include <asm/setup.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Sam Ravnborg81265fd2008-12-08 01:08:24 -080019#include "kernel.h"
Al Viro32231a62007-07-21 19:18:57 -070020#include "irq.h"
21
Sam Ravnborge54f8542011-01-28 22:08:21 +000022/* 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.
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000026 * SBUS interrupts are encodes as a combination of board, level and slot.
Sam Ravnborge54f8542011-01-28 22:08:21 +000027 */
28
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000029struct 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
David S. Millerf5f10852008-09-13 22:04:55 -070040struct 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
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000050#define SUN4D_TIMER_IRQ 10
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +000051
52/* Specify which cpu handle interrupts from which board.
53 * Index is board - value is cpu.
54 */
55static unsigned char board_to_cpu[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static int pil_to_sbus[] = {
Sam Ravnborge54f8542011-01-28 22:08:21 +000058 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070074};
75
David S. Millerf8376e92008-09-13 22:05:25 -070076/* Exported for sun4d_smp.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077DEFINE_SPINLOCK(sun4d_imsk_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000079/* 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000097 unsigned int bus_mask;
98 unsigned int sbino, slot;
99 unsigned int sbil;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000101 bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
102 bw_clear_intr_mask(sbusl, bus_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000104 sbil = (sbusl << 2);
105 /* Loop for each pending SBI */
106 for (sbino = 0; bus_mask; sbino++) {
107 unsigned int idx, mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000109 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000117 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;
142 }
143 release_sbi(SBI2DEVID(sbino), slot);
144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
Sam Ravnborge54f8542011-01-28 22:08:21 +0000148void sun4d_handler_irq(int pil, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Al Viro0d844382006-10-08 14:30:44 +0100150 struct pt_regs *old_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 /* SBUS IRQ level (1 - 7) */
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000152 int sbusl = pil_to_sbus[pil];
Sam Ravnborge54f8542011-01-28 22:08:21 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 /* FIXME: Is this necessary?? */
155 cc_get_ipen();
Sam Ravnborge54f8542011-01-28 22:08:21 +0000156
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000157 cc_set_iclr(1 << pil);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000158
Daniel Hellstrom55dd23e2011-05-02 00:08:54 +0000159#ifdef CONFIG_SMP
160 /*
161 * Check IPI data structures after IRQ has been cleared. Hard and Soft
162 * IRQ can happen at the same time, so both cases are always handled.
163 */
164 if (pil == SUN4D_IPI_IRQ)
165 sun4d_ipi_interrupt();
166#endif
167
Al Viro0d844382006-10-08 14:30:44 +0100168 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 irq_enter();
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000170 if (sbusl == 0) {
171 /* cpu interrupt */
172 struct irq_bucket *p;
173
174 p = irq_map[pil];
175 while (p) {
176 struct irq_bucket *next;
177
178 next = p->next;
179 generic_handle_irq(p->irq);
180 p = next;
181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 } else {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000183 /* SBUS interrupt */
184 sun4d_sbus_handler_irq(sbusl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
186 irq_exit();
Al Viro0d844382006-10-08 14:30:44 +0100187 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000190
191static void sun4d_mask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000193 struct sun4d_handler_data *handler_data = data->handler_data;
194 unsigned int real_irq;
195#ifdef CONFIG_SMP
196 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000198#endif
199 real_irq = handler_data->real_irq;
200#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 spin_lock_irqsave(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000202 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000204#else
205 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
206#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000209static void sun4d_unmask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000211 struct sun4d_handler_data *handler_data = data->handler_data;
212 unsigned int real_irq;
213#ifdef CONFIG_SMP
214 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000216#endif
217 real_irq = handler_data->real_irq;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000218
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000219#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 spin_lock_irqsave(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000221 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000223#else
224 cc_set_imsk(cc_get_imsk() | ~(1 << real_irq));
225#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000228static unsigned int sun4d_startup_irq(struct irq_data *data)
229{
230 irq_link(data->irq);
231 sun4d_unmask_irq(data);
232 return 0;
233}
234
235static void sun4d_shutdown_irq(struct irq_data *data)
236{
237 sun4d_mask_irq(data);
238 irq_unlink(data->irq);
239}
240
241struct irq_chip sun4d_irq = {
242 .name = "sun4d",
243 .irq_startup = sun4d_startup_irq,
244 .irq_shutdown = sun4d_shutdown_irq,
245 .irq_unmask = sun4d_unmask_irq,
246 .irq_mask = sun4d_mask_irq,
247};
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249#ifdef CONFIG_SMP
250static void sun4d_set_cpu_int(int cpu, int level)
251{
252 sun4d_send_ipi(cpu, level);
253}
254
255static void sun4d_clear_ipi(int cpu, int level)
256{
257}
258
259static void sun4d_set_udt(int cpu)
260{
261}
262
263/* Setup IRQ distribution scheme. */
264void __init sun4d_distribute_irqs(void)
265{
David S. Miller71d37212008-08-27 02:50:57 -0700266 struct device_node *dp;
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 int cpuid = cpu_logical_map(1);
269
270 if (cpuid == -1)
271 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700272 for_each_node_by_name(dp, "sbi") {
273 int devid = of_getintprop_default(dp, "device-id", 0);
274 int board = of_getintprop_default(dp, "board#", 0);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000275 board_to_cpu[board] = cpuid;
David S. Miller71d37212008-08-27 02:50:57 -0700276 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000278 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282static void sun4d_clear_clock_irq(void)
283{
David S. Millerf5f10852008-09-13 22:04:55 -0700284 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285}
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void sun4d_load_profile_irq(int cpu, unsigned int limit)
288{
289 bw_set_prof_limit(cpu, limit);
290}
291
David S. Millerf5f10852008-09-13 22:04:55 -0700292static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
David S. Millerf5f10852008-09-13 22:04:55 -0700294 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
297 sun4d_load_profile_irq(mid >> 3, 0);
298 cpu++;
299 }
David S. Millerf5f10852008-09-13 22:04:55 -0700300}
301
oftedal5fba1702011-06-01 10:43:50 +0000302unsigned int _sun4d_build_device_irq(unsigned int real_irq,
303 unsigned int pil,
304 unsigned int board)
305{
306 struct sun4d_handler_data *handler_data;
307 unsigned int irq;
308
309 irq = irq_alloc(real_irq, pil);
310 if (irq == 0) {
311 prom_printf("IRQ: allocate for %d %d %d failed\n",
312 real_irq, pil, board);
313 goto err_out;
314 }
315
316 handler_data = irq_get_handler_data(irq);
317 if (unlikely(handler_data))
318 goto err_out;
319
320 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
321 if (unlikely(!handler_data)) {
322 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
323 prom_halt();
324 }
325 handler_data->cpuid = board_to_cpu[board];
326 handler_data->real_irq = real_irq;
327 irq_set_chip_and_handler_name(irq, &sun4d_irq,
328 handle_level_irq, "level");
329 irq_set_handler_data(irq, handler_data);
330
331err_out:
332 return irq;
333}
334
335
336
Sam Ravnborg1d059952011-02-25 23:01:19 -0800337unsigned int sun4d_build_device_irq(struct platform_device *op,
338 unsigned int real_irq)
339{
Sam Ravnborg1d059952011-02-25 23:01:19 -0800340 struct device_node *dp = op->dev.of_node;
341 struct device_node *io_unit, *sbi = dp->parent;
342 const struct linux_prom_registers *regs;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000343 unsigned int pil;
344 unsigned int irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800345 int board, slot;
346 int sbusl;
347
oftedal5fba1702011-06-01 10:43:50 +0000348 irq = real_irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800349 while (sbi) {
350 if (!strcmp(sbi->name, "sbi"))
351 break;
352
353 sbi = sbi->parent;
354 }
355 if (!sbi)
356 goto err_out;
357
358 regs = of_get_property(dp, "reg", NULL);
359 if (!regs)
360 goto err_out;
361
362 slot = regs->which_io;
363
364 /*
365 * If SBI's parent is not io-unit or the io-unit lacks
366 * a "board#" property, something is very wrong.
367 */
368 if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
369 printk("%s: Error, parent is not io-unit.\n", sbi->full_name);
370 goto err_out;
371 }
372 io_unit = sbi->parent;
373 board = of_getintprop_default(io_unit, "board#", -1);
374 if (board == -1) {
375 printk("%s: Error, lacks board# property.\n", io_unit->full_name);
376 goto err_out;
377 }
378
379 sbusl = pil_to_sbus[real_irq];
380 if (sbusl)
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000381 pil = sun4d_encode_irq(board, sbusl, slot);
382 else
383 pil = real_irq;
384
oftedal5fba1702011-06-01 10:43:50 +0000385 irq = _sun4d_build_device_irq(real_irq, pil, board);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800386err_out:
oftedal5fba1702011-06-01 10:43:50 +0000387 return irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800388}
389
oftedal5fba1702011-06-01 10:43:50 +0000390unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
391{
392 return _sun4d_build_device_irq(real_irq, real_irq, board);
393}
394
395
David S. Millerf5f10852008-09-13 22:04:55 -0700396static void __init sun4d_fixup_trap_table(void)
397{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700399 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700400 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
David S. Millerf5f10852008-09-13 22:04:55 -0700402 /* Adjust so that we jump directly to smp4d_ticker */
403 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
David S. Millerf5f10852008-09-13 22:04:55 -0700405 /* For SMP we use the level 14 ticker, however the bootup code
406 * has copied the firmware's level 14 vector into the boot cpu's
407 * trap table, we must fix this now or we get squashed.
408 */
409 local_irq_save(flags);
410 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
411 trap_table->inst_one = lvl14_save[0];
412 trap_table->inst_two = lvl14_save[1];
413 trap_table->inst_three = lvl14_save[2];
414 trap_table->inst_four = lvl14_save[3];
415 local_flush_cache_all();
416 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417#endif
418}
419
David S. Millerf5f10852008-09-13 22:04:55 -0700420static void __init sun4d_init_timers(irq_handler_t counter_fn)
421{
422 struct device_node *dp;
423 struct resource res;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000424 unsigned int irq;
David S. Millerf5f10852008-09-13 22:04:55 -0700425 const u32 *reg;
426 int err;
oftedal5fba1702011-06-01 10:43:50 +0000427 int board;
David S. Millerf5f10852008-09-13 22:04:55 -0700428
429 dp = of_find_node_by_name(NULL, "cpu-unit");
430 if (!dp) {
431 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
432 prom_halt();
433 }
434
435 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
436 * registers via any cpu's mapping. The first 'reg' property is the
437 * bootbus.
438 */
439 reg = of_get_property(dp, "reg", NULL);
440 if (!reg) {
441 prom_printf("sun4d_init_timers: No reg property\n");
442 prom_halt();
443 }
444
oftedal5fba1702011-06-01 10:43:50 +0000445 board = of_getintprop_default(dp, "board#", -1);
446 if (board == -1) {
447 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
448 prom_halt();
449 }
450
451 of_node_put(dp);
452
David S. Millerf5f10852008-09-13 22:04:55 -0700453 res.start = reg[1];
454 res.end = reg[2] - 1;
455 res.flags = reg[0] & 0xff;
456 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
457 sizeof(struct sun4d_timer_regs), "user timer");
458 if (!sun4d_timers) {
459 prom_printf("sun4d_init_timers: Can't map timer regs\n");
460 prom_halt();
461 }
462
463 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
464
465 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700466
oftedal5fba1702011-06-01 10:43:50 +0000467 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000468 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
David S. Millerf5f10852008-09-13 22:04:55 -0700469 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000470 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
471 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700472 prom_halt();
473 }
474 sun4d_load_profile_irqs();
475 sun4d_fixup_trap_table();
476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478void __init sun4d_init_sbi_irq(void)
479{
David S. Miller71d37212008-08-27 02:50:57 -0700480 struct device_node *dp;
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +0000481 int target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700482
David S. Millerf8376e92008-09-13 22:05:25 -0700483 target_cpu = boot_cpu_id;
David S. Miller71d37212008-08-27 02:50:57 -0700484 for_each_node_by_name(dp, "sbi") {
485 int devid = of_getintprop_default(dp, "device-id", 0);
486 int board = of_getintprop_default(dp, "board#", 0);
487 unsigned int mask;
488
David S. Millerf8376e92008-09-13 22:05:25 -0700489 set_sbi_tid(devid, target_cpu << 3);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000490 board_to_cpu[board] = target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700493 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000495 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
496 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700497 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
499 }
500}
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502void __init sun4d_init_IRQ(void)
503{
504 local_irq_disable();
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800508
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000509 sparc_irq_config.init_timers = sun4d_init_timers;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800510 sparc_irq_config.build_device_irq = sun4d_build_device_irq;
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512#ifdef CONFIG_SMP
513 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
514 BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
515 BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
516#endif
517 /* Cannot enable interrupts until OBP ticker is disabled. */
518}