blob: abf52654a8bc72e8cc2ac83960e1199c8d4ebe24 [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 */
oftedalea160582011-06-01 11:04:20 +0000106 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000107 unsigned int idx, mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000109 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000116 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
117 mask &= (0xf << sbil);
118
119 /* Loop for each pending SBI slot */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000120 slot = (1 << sbil);
oftedalea160582011-06-01 11:04:20 +0000121 for (idx = 0; mask != 0; idx++, slot <<= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000122 unsigned int pil;
123 struct irq_bucket *p;
124
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000125 if (!(mask & slot))
126 continue;
127
128 mask &= ~slot;
oftedalea160582011-06-01 11:04:20 +0000129 pil = sun4d_encode_irq(sbino, sbusl, idx);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000130
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;
138 }
139 release_sbi(SBI2DEVID(sbino), slot);
140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Sam Ravnborge54f8542011-01-28 22:08:21 +0000144void sun4d_handler_irq(int pil, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
Al Viro0d844382006-10-08 14:30:44 +0100146 struct pt_regs *old_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 /* SBUS IRQ level (1 - 7) */
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000148 int sbusl = pil_to_sbus[pil];
Sam Ravnborge54f8542011-01-28 22:08:21 +0000149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 /* FIXME: Is this necessary?? */
151 cc_get_ipen();
Sam Ravnborge54f8542011-01-28 22:08:21 +0000152
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000153 cc_set_iclr(1 << pil);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000154
Daniel Hellstrom55dd23e2011-05-02 00:08:54 +0000155#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
Al Viro0d844382006-10-08 14:30:44 +0100164 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 irq_enter();
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000166 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 } else {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000179 /* SBUS interrupt */
180 sun4d_sbus_handler_irq(sbusl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
182 irq_exit();
Al Viro0d844382006-10-08 14:30:44 +0100183 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184}
185
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000186
187static void sun4d_mask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000189 struct sun4d_handler_data *handler_data = data->handler_data;
190 unsigned int real_irq;
191#ifdef CONFIG_SMP
192 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000194#endif
195 real_irq = handler_data->real_irq;
196#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 spin_lock_irqsave(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000198 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000200#else
201 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
202#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000205static void sun4d_unmask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000207 struct sun4d_handler_data *handler_data = data->handler_data;
208 unsigned int real_irq;
209#ifdef CONFIG_SMP
210 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000212#endif
213 real_irq = handler_data->real_irq;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000214
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000215#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 spin_lock_irqsave(&sun4d_imsk_lock, flags);
oftedalea160582011-06-01 11:04:20 +0000217 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000219#else
oftedalea160582011-06-01 11:04:20 +0000220 cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000221#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000224static unsigned int sun4d_startup_irq(struct irq_data *data)
225{
226 irq_link(data->irq);
227 sun4d_unmask_irq(data);
228 return 0;
229}
230
231static void sun4d_shutdown_irq(struct irq_data *data)
232{
233 sun4d_mask_irq(data);
234 irq_unlink(data->irq);
235}
236
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245#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{
David S. Miller71d37212008-08-27 02:50:57 -0700262 struct device_node *dp;
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 int cpuid = cpu_logical_map(1);
265
266 if (cpuid == -1)
267 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700268 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);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000271 board_to_cpu[board] = cpuid;
David S. Miller71d37212008-08-27 02:50:57 -0700272 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000274 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275}
276#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static void sun4d_clear_clock_irq(void)
279{
David S. Millerf5f10852008-09-13 22:04:55 -0700280 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281}
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283static void sun4d_load_profile_irq(int cpu, unsigned int limit)
284{
Tkhai Kirill62f08282012-04-04 21:49:26 +0200285 unsigned int value = limit ? timer_value(limit) : 0;
286 bw_set_prof_limit(cpu, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287}
288
David S. Millerf5f10852008-09-13 22:04:55 -0700289static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
David S. Millerf5f10852008-09-13 22:04:55 -0700291 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
294 sun4d_load_profile_irq(mid >> 3, 0);
295 cpu++;
296 }
David S. Millerf5f10852008-09-13 22:04:55 -0700297}
298
oftedal5fba1702011-06-01 10:43:50 +0000299unsigned 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
Sam Ravnborg1d059952011-02-25 23:01:19 -0800334unsigned int sun4d_build_device_irq(struct platform_device *op,
335 unsigned int real_irq)
336{
Sam Ravnborg1d059952011-02-25 23:01:19 -0800337 struct device_node *dp = op->dev.of_node;
oftedal9eeb0892011-06-01 11:11:41 +0000338 struct device_node *board_parent, *bus = dp->parent;
339 char *bus_connection;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800340 const struct linux_prom_registers *regs;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000341 unsigned int pil;
342 unsigned int irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800343 int board, slot;
344 int sbusl;
345
oftedal5fba1702011-06-01 10:43:50 +0000346 irq = real_irq;
oftedal9eeb0892011-06-01 11:11:41 +0000347 while (bus) {
348 if (!strcmp(bus->name, "sbi")) {
349 bus_connection = "io-unit";
Sam Ravnborg1d059952011-02-25 23:01:19 -0800350 break;
oftedal9eeb0892011-06-01 11:11:41 +0000351 }
Sam Ravnborg1d059952011-02-25 23:01:19 -0800352
oftedal9eeb0892011-06-01 11:11:41 +0000353 if (!strcmp(bus->name, "bootbus")) {
354 bus_connection = "cpu-unit";
355 break;
356 }
357
358 bus = bus->parent;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800359 }
oftedal9eeb0892011-06-01 11:11:41 +0000360 if (!bus)
Sam Ravnborg1d059952011-02-25 23:01:19 -0800361 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 /*
oftedal9eeb0892011-06-01 11:11:41 +0000370 * 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.
Sam Ravnborg1d059952011-02-25 23:01:19 -0800372 */
oftedal9eeb0892011-06-01 11:11:41 +0000373 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);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800376 goto err_out;
377 }
oftedal9eeb0892011-06-01 11:11:41 +0000378 board_parent = bus->parent;
379 board = of_getintprop_default(board_parent, "board#", -1);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800380 if (board == -1) {
oftedal9eeb0892011-06-01 11:11:41 +0000381 printk(KERN_ERR "%s: Error, lacks board# property.\n",
382 board_parent->full_name);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800383 goto err_out;
384 }
385
386 sbusl = pil_to_sbus[real_irq];
387 if (sbusl)
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000388 pil = sun4d_encode_irq(board, sbusl, slot);
389 else
390 pil = real_irq;
391
oftedal5fba1702011-06-01 10:43:50 +0000392 irq = _sun4d_build_device_irq(real_irq, pil, board);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800393err_out:
oftedal5fba1702011-06-01 10:43:50 +0000394 return irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800395}
396
oftedal5fba1702011-06-01 10:43:50 +0000397unsigned 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
David S. Millerf5f10852008-09-13 22:04:55 -0700403static void __init sun4d_fixup_trap_table(void)
404{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700406 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700407 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
David S. Millerf5f10852008-09-13 22:04:55 -0700409 /* Adjust so that we jump directly to smp4d_ticker */
410 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
David S. Millerf5f10852008-09-13 22:04:55 -0700412 /* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424#endif
425}
426
Tkhai Kirill62f08282012-04-04 21:49:26 +0200427static void __init sun4d_init_timers(void)
David S. Millerf5f10852008-09-13 22:04:55 -0700428{
429 struct device_node *dp;
430 struct resource res;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000431 unsigned int irq;
David S. Millerf5f10852008-09-13 22:04:55 -0700432 const u32 *reg;
433 int err;
oftedal5fba1702011-06-01 10:43:50 +0000434 int board;
David S. Millerf5f10852008-09-13 22:04:55 -0700435
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
oftedal5fba1702011-06-01 10:43:50 +0000452 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
David S. Millerf5f10852008-09-13 22:04:55 -0700460 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
Tkhai Kirill62f08282012-04-04 21:49:26 +0200470#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);
David S. Millerf5f10852008-09-13 22:04:55 -0700479
480 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700481
oftedal5fba1702011-06-01 10:43:50 +0000482 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
Tkhai Kirill62f08282012-04-04 21:49:26 +0200483 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
David S. Millerf5f10852008-09-13 22:04:55 -0700484 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000485 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
486 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700487 prom_halt();
488 }
489 sun4d_load_profile_irqs();
490 sun4d_fixup_trap_table();
491}
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493void __init sun4d_init_sbi_irq(void)
494{
David S. Miller71d37212008-08-27 02:50:57 -0700495 struct device_node *dp;
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +0000496 int target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700497
David S. Millerf8376e92008-09-13 22:05:25 -0700498 target_cpu = boot_cpu_id;
David S. Miller71d37212008-08-27 02:50:57 -0700499 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
David S. Millerf8376e92008-09-13 22:05:25 -0700504 set_sbi_tid(devid, target_cpu << 3);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000505 board_to_cpu[board] = target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700508 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000510 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
511 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700512 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 }
514 }
515}
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517void __init sun4d_init_IRQ(void)
518{
519 local_irq_disable();
520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800523
Sam Ravnborg472bc4f2012-04-04 13:21:13 +0200524 sparc_config.init_timers = sun4d_init_timers;
525 sparc_config.build_device_irq = sun4d_build_device_irq;
Tkhai Kirill62f08282012-04-04 21:49:26 +0200526 sparc_config.clock_rate = SBUS_CLOCK_RATE;
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528#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}