blob: b2fdb3d78c1946e8e1ba43a09b585d8dc3a43c40 [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>
David S. Miller5d83d662012-05-13 20:49:31 -070018#include <asm/oplib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Sam Ravnborg81265fd2008-12-08 01:08:24 -080020#include "kernel.h"
Al Viro32231a62007-07-21 19:18:57 -070021#include "irq.h"
22
Sam Ravnborge54f8542011-01-28 22:08:21 +000023/* Sun4d interrupts fall roughly into two categories. SBUS and
24 * cpu local. CPU local interrupts cover the timer interrupts
25 * and whatnot, and we encode those as normal PILs between
26 * 0 and 15.
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000027 * SBUS interrupts are encodes as a combination of board, level and slot.
Sam Ravnborge54f8542011-01-28 22:08:21 +000028 */
29
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000030struct sun4d_handler_data {
31 unsigned int cpuid; /* target cpu */
32 unsigned int real_irq; /* interrupt level */
33};
34
35
36static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
37{
38 return (board + 1) << 5 | (lvl << 2) | slot;
39}
40
David S. Millerf5f10852008-09-13 22:04:55 -070041struct sun4d_timer_regs {
42 u32 l10_timer_limit;
43 u32 l10_cur_countx;
44 u32 l10_limit_noclear;
45 u32 ctrl;
46 u32 l10_cur_count;
47};
48
49static struct sun4d_timer_regs __iomem *sun4d_timers;
50
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000051#define SUN4D_TIMER_IRQ 10
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +000052
53/* Specify which cpu handle interrupts from which board.
54 * Index is board - value is cpu.
55 */
56static unsigned char board_to_cpu[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static int pil_to_sbus[] = {
Sam Ravnborge54f8542011-01-28 22:08:21 +000059 0,
60 0,
61 1,
62 2,
63 0,
64 3,
65 0,
66 4,
67 0,
68 5,
69 0,
70 6,
71 0,
72 7,
73 0,
74 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -070075};
76
David S. Millerf8376e92008-09-13 22:05:25 -070077/* Exported for sun4d_smp.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078DEFINE_SPINLOCK(sun4d_imsk_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000080/* SBUS interrupts are encoded integers including the board number
81 * (plus one), the SBUS level, and the SBUS slot number. Sun4D
82 * IRQ dispatch is done by:
83 *
84 * 1) Reading the BW local interrupt table in order to get the bus
85 * interrupt mask.
86 *
87 * This table is indexed by SBUS interrupt level which can be
88 * derived from the PIL we got interrupted on.
89 *
90 * 2) For each bus showing interrupt pending from #1, read the
91 * SBI interrupt state register. This will indicate which slots
92 * have interrupts pending for that SBUS interrupt level.
93 *
94 * 3) Call the genreric IRQ support.
95 */
96static void sun4d_sbus_handler_irq(int sbusl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000098 unsigned int bus_mask;
99 unsigned int sbino, slot;
100 unsigned int sbil;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000102 bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
103 bw_clear_intr_mask(sbusl, bus_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000105 sbil = (sbusl << 2);
106 /* Loop for each pending SBI */
oftedalea160582011-06-01 11:04:20 +0000107 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000108 unsigned int idx, mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000110 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 */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000121 slot = (1 << sbil);
oftedalea160582011-06-01 11:04:20 +0000122 for (idx = 0; mask != 0; idx++, slot <<= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000123 unsigned int pil;
124 struct irq_bucket *p;
125
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000126 if (!(mask & slot))
127 continue;
128
129 mask &= ~slot;
oftedalea160582011-06-01 11:04:20 +0000130 pil = sun4d_encode_irq(sbino, sbusl, idx);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000131
132 p = irq_map[pil];
133 while (p) {
134 struct irq_bucket *next;
135
136 next = p->next;
137 generic_handle_irq(p->irq);
138 p = next;
139 }
140 release_sbi(SBI2DEVID(sbino), slot);
141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
Sam Ravnborge54f8542011-01-28 22:08:21 +0000145void sun4d_handler_irq(int pil, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Al Viro0d844382006-10-08 14:30:44 +0100147 struct pt_regs *old_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 /* SBUS IRQ level (1 - 7) */
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000149 int sbusl = pil_to_sbus[pil];
Sam Ravnborge54f8542011-01-28 22:08:21 +0000150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 /* FIXME: Is this necessary?? */
152 cc_get_ipen();
Sam Ravnborge54f8542011-01-28 22:08:21 +0000153
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000154 cc_set_iclr(1 << pil);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000155
Daniel Hellstrom55dd23e2011-05-02 00:08:54 +0000156#ifdef CONFIG_SMP
157 /*
158 * Check IPI data structures after IRQ has been cleared. Hard and Soft
159 * IRQ can happen at the same time, so both cases are always handled.
160 */
161 if (pil == SUN4D_IPI_IRQ)
162 sun4d_ipi_interrupt();
163#endif
164
Al Viro0d844382006-10-08 14:30:44 +0100165 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 irq_enter();
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000167 if (sbusl == 0) {
168 /* cpu interrupt */
169 struct irq_bucket *p;
170
171 p = irq_map[pil];
172 while (p) {
173 struct irq_bucket *next;
174
175 next = p->next;
176 generic_handle_irq(p->irq);
177 p = next;
178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 } else {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000180 /* SBUS interrupt */
181 sun4d_sbus_handler_irq(sbusl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 irq_exit();
Al Viro0d844382006-10-08 14:30:44 +0100184 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000187
188static void sun4d_mask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000190 struct sun4d_handler_data *handler_data = data->handler_data;
191 unsigned int real_irq;
192#ifdef CONFIG_SMP
193 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000195#endif
196 real_irq = handler_data->real_irq;
197#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 spin_lock_irqsave(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000199 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000201#else
202 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
203#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000206static void sun4d_unmask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000208 struct sun4d_handler_data *handler_data = data->handler_data;
209 unsigned int real_irq;
210#ifdef CONFIG_SMP
211 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000213#endif
214 real_irq = handler_data->real_irq;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000215
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000216#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 spin_lock_irqsave(&sun4d_imsk_lock, flags);
oftedalea160582011-06-01 11:04:20 +0000218 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000220#else
oftedalea160582011-06-01 11:04:20 +0000221 cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000222#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000225static unsigned int sun4d_startup_irq(struct irq_data *data)
226{
227 irq_link(data->irq);
228 sun4d_unmask_irq(data);
229 return 0;
230}
231
232static void sun4d_shutdown_irq(struct irq_data *data)
233{
234 sun4d_mask_irq(data);
235 irq_unlink(data->irq);
236}
237
238struct irq_chip sun4d_irq = {
239 .name = "sun4d",
240 .irq_startup = sun4d_startup_irq,
241 .irq_shutdown = sun4d_shutdown_irq,
242 .irq_unmask = sun4d_unmask_irq,
243 .irq_mask = sun4d_mask_irq,
244};
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246#ifdef CONFIG_SMP
247static void sun4d_set_cpu_int(int cpu, int level)
248{
249 sun4d_send_ipi(cpu, level);
250}
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252/* Setup IRQ distribution scheme. */
253void __init sun4d_distribute_irqs(void)
254{
David S. Miller71d37212008-08-27 02:50:57 -0700255 struct device_node *dp;
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 int cpuid = cpu_logical_map(1);
258
259 if (cpuid == -1)
260 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700261 for_each_node_by_name(dp, "sbi") {
262 int devid = of_getintprop_default(dp, "device-id", 0);
263 int board = of_getintprop_default(dp, "board#", 0);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000264 board_to_cpu[board] = cpuid;
David S. Miller71d37212008-08-27 02:50:57 -0700265 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000267 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271static void sun4d_clear_clock_irq(void)
272{
David S. Millerf5f10852008-09-13 22:04:55 -0700273 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276static void sun4d_load_profile_irq(int cpu, unsigned int limit)
277{
Tkhai Kirill62f08282012-04-04 21:49:26 +0200278 unsigned int value = limit ? timer_value(limit) : 0;
279 bw_set_prof_limit(cpu, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280}
281
David S. Millerf5f10852008-09-13 22:04:55 -0700282static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
David S. Millerf5f10852008-09-13 22:04:55 -0700284 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
287 sun4d_load_profile_irq(mid >> 3, 0);
288 cpu++;
289 }
David S. Millerf5f10852008-09-13 22:04:55 -0700290}
291
oftedal5fba1702011-06-01 10:43:50 +0000292unsigned int _sun4d_build_device_irq(unsigned int real_irq,
293 unsigned int pil,
294 unsigned int board)
295{
296 struct sun4d_handler_data *handler_data;
297 unsigned int irq;
298
299 irq = irq_alloc(real_irq, pil);
300 if (irq == 0) {
301 prom_printf("IRQ: allocate for %d %d %d failed\n",
302 real_irq, pil, board);
303 goto err_out;
304 }
305
306 handler_data = irq_get_handler_data(irq);
307 if (unlikely(handler_data))
308 goto err_out;
309
310 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
311 if (unlikely(!handler_data)) {
312 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
313 prom_halt();
314 }
315 handler_data->cpuid = board_to_cpu[board];
316 handler_data->real_irq = real_irq;
317 irq_set_chip_and_handler_name(irq, &sun4d_irq,
318 handle_level_irq, "level");
319 irq_set_handler_data(irq, handler_data);
320
321err_out:
322 return irq;
323}
324
325
326
Sam Ravnborg1d059952011-02-25 23:01:19 -0800327unsigned int sun4d_build_device_irq(struct platform_device *op,
328 unsigned int real_irq)
329{
Sam Ravnborg1d059952011-02-25 23:01:19 -0800330 struct device_node *dp = op->dev.of_node;
oftedal9eeb0892011-06-01 11:11:41 +0000331 struct device_node *board_parent, *bus = dp->parent;
332 char *bus_connection;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800333 const struct linux_prom_registers *regs;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000334 unsigned int pil;
335 unsigned int irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800336 int board, slot;
337 int sbusl;
338
oftedal5fba1702011-06-01 10:43:50 +0000339 irq = real_irq;
oftedal9eeb0892011-06-01 11:11:41 +0000340 while (bus) {
341 if (!strcmp(bus->name, "sbi")) {
342 bus_connection = "io-unit";
Sam Ravnborg1d059952011-02-25 23:01:19 -0800343 break;
oftedal9eeb0892011-06-01 11:11:41 +0000344 }
Sam Ravnborg1d059952011-02-25 23:01:19 -0800345
oftedal9eeb0892011-06-01 11:11:41 +0000346 if (!strcmp(bus->name, "bootbus")) {
347 bus_connection = "cpu-unit";
348 break;
349 }
350
351 bus = bus->parent;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800352 }
oftedal9eeb0892011-06-01 11:11:41 +0000353 if (!bus)
Sam Ravnborg1d059952011-02-25 23:01:19 -0800354 goto err_out;
355
356 regs = of_get_property(dp, "reg", NULL);
357 if (!regs)
358 goto err_out;
359
360 slot = regs->which_io;
361
362 /*
oftedal9eeb0892011-06-01 11:11:41 +0000363 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
364 * lacks a "board#" property, something is very wrong.
Sam Ravnborg1d059952011-02-25 23:01:19 -0800365 */
oftedal9eeb0892011-06-01 11:11:41 +0000366 if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
367 printk(KERN_ERR "%s: Error, parent is not %s.\n",
368 bus->full_name, bus_connection);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800369 goto err_out;
370 }
oftedal9eeb0892011-06-01 11:11:41 +0000371 board_parent = bus->parent;
372 board = of_getintprop_default(board_parent, "board#", -1);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800373 if (board == -1) {
oftedal9eeb0892011-06-01 11:11:41 +0000374 printk(KERN_ERR "%s: Error, lacks board# property.\n",
375 board_parent->full_name);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800376 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];
David S. Miller5d83d662012-05-13 20:49:31 -0700415 local_ops->cache_all();
David S. Millerf5f10852008-09-13 22:04:55 -0700416 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417#endif
418}
419
Tkhai Kirill62f08282012-04-04 21:49:26 +0200420static void __init sun4d_init_timers(void)
David S. Millerf5f10852008-09-13 22:04:55 -0700421{
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
Tkhai Kirill62f08282012-04-04 21:49:26 +0200463#ifdef CONFIG_SMP
464 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
465#else
466 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
467 sparc_config.features |= FEAT_L10_CLOCKEVENT;
468#endif
469 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
470 sbus_writel(timer_value(sparc_config.cs_period),
471 &sun4d_timers->l10_timer_limit);
David S. Millerf5f10852008-09-13 22:04:55 -0700472
473 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700474
oftedal5fba1702011-06-01 10:43:50 +0000475 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
Tkhai Kirill62f08282012-04-04 21:49:26 +0200476 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
David S. Millerf5f10852008-09-13 22:04:55 -0700477 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000478 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
479 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700480 prom_halt();
481 }
482 sun4d_load_profile_irqs();
483 sun4d_fixup_trap_table();
484}
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486void __init sun4d_init_sbi_irq(void)
487{
David S. Miller71d37212008-08-27 02:50:57 -0700488 struct device_node *dp;
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +0000489 int target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700490
David S. Millerf8376e92008-09-13 22:05:25 -0700491 target_cpu = boot_cpu_id;
David S. Miller71d37212008-08-27 02:50:57 -0700492 for_each_node_by_name(dp, "sbi") {
493 int devid = of_getintprop_default(dp, "device-id", 0);
494 int board = of_getintprop_default(dp, "board#", 0);
495 unsigned int mask;
496
David S. Millerf8376e92008-09-13 22:05:25 -0700497 set_sbi_tid(devid, target_cpu << 3);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000498 board_to_cpu[board] = target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700501 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000503 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
504 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700505 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507 }
508}
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510void __init sun4d_init_IRQ(void)
511{
512 local_irq_disable();
513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800516
Sam Ravnborg472bc4f2012-04-04 13:21:13 +0200517 sparc_config.init_timers = sun4d_init_timers;
518 sparc_config.build_device_irq = sun4d_build_device_irq;
Tkhai Kirill62f08282012-04-04 21:49:26 +0200519 sparc_config.clock_rate = SBUS_CLOCK_RATE;
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521#ifdef CONFIG_SMP
522 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523#endif
524 /* Cannot enable interrupts until OBP ticker is disabled. */
525}