blob: e490ac9327c7463462e30a31bf03f65cfd3e98a0 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247/* Setup IRQ distribution scheme. */
248void __init sun4d_distribute_irqs(void)
249{
David S. Miller71d37212008-08-27 02:50:57 -0700250 struct device_node *dp;
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 int cpuid = cpu_logical_map(1);
253
254 if (cpuid == -1)
255 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700256 for_each_node_by_name(dp, "sbi") {
257 int devid = of_getintprop_default(dp, "device-id", 0);
258 int board = of_getintprop_default(dp, "board#", 0);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000259 board_to_cpu[board] = cpuid;
David S. Miller71d37212008-08-27 02:50:57 -0700260 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000262 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263}
264#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static void sun4d_clear_clock_irq(void)
267{
David S. Millerf5f10852008-09-13 22:04:55 -0700268 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269}
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271static void sun4d_load_profile_irq(int cpu, unsigned int limit)
272{
Tkhai Kirill62f08282012-04-04 21:49:26 +0200273 unsigned int value = limit ? timer_value(limit) : 0;
274 bw_set_prof_limit(cpu, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275}
276
David S. Millerf5f10852008-09-13 22:04:55 -0700277static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
David S. Millerf5f10852008-09-13 22:04:55 -0700279 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
282 sun4d_load_profile_irq(mid >> 3, 0);
283 cpu++;
284 }
David S. Millerf5f10852008-09-13 22:04:55 -0700285}
286
oftedal5fba1702011-06-01 10:43:50 +0000287unsigned int _sun4d_build_device_irq(unsigned int real_irq,
288 unsigned int pil,
289 unsigned int board)
290{
291 struct sun4d_handler_data *handler_data;
292 unsigned int irq;
293
294 irq = irq_alloc(real_irq, pil);
295 if (irq == 0) {
296 prom_printf("IRQ: allocate for %d %d %d failed\n",
297 real_irq, pil, board);
298 goto err_out;
299 }
300
301 handler_data = irq_get_handler_data(irq);
302 if (unlikely(handler_data))
303 goto err_out;
304
305 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
306 if (unlikely(!handler_data)) {
307 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
308 prom_halt();
309 }
310 handler_data->cpuid = board_to_cpu[board];
311 handler_data->real_irq = real_irq;
312 irq_set_chip_and_handler_name(irq, &sun4d_irq,
313 handle_level_irq, "level");
314 irq_set_handler_data(irq, handler_data);
315
316err_out:
317 return irq;
318}
319
320
321
Sam Ravnborg1d059952011-02-25 23:01:19 -0800322unsigned int sun4d_build_device_irq(struct platform_device *op,
323 unsigned int real_irq)
324{
Sam Ravnborg1d059952011-02-25 23:01:19 -0800325 struct device_node *dp = op->dev.of_node;
oftedal9eeb0892011-06-01 11:11:41 +0000326 struct device_node *board_parent, *bus = dp->parent;
327 char *bus_connection;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800328 const struct linux_prom_registers *regs;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000329 unsigned int pil;
330 unsigned int irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800331 int board, slot;
332 int sbusl;
333
oftedal5fba1702011-06-01 10:43:50 +0000334 irq = real_irq;
oftedal9eeb0892011-06-01 11:11:41 +0000335 while (bus) {
336 if (!strcmp(bus->name, "sbi")) {
337 bus_connection = "io-unit";
Sam Ravnborg1d059952011-02-25 23:01:19 -0800338 break;
oftedal9eeb0892011-06-01 11:11:41 +0000339 }
Sam Ravnborg1d059952011-02-25 23:01:19 -0800340
oftedal9eeb0892011-06-01 11:11:41 +0000341 if (!strcmp(bus->name, "bootbus")) {
342 bus_connection = "cpu-unit";
343 break;
344 }
345
346 bus = bus->parent;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800347 }
oftedal9eeb0892011-06-01 11:11:41 +0000348 if (!bus)
Sam Ravnborg1d059952011-02-25 23:01:19 -0800349 goto err_out;
350
351 regs = of_get_property(dp, "reg", NULL);
352 if (!regs)
353 goto err_out;
354
355 slot = regs->which_io;
356
357 /*
oftedal9eeb0892011-06-01 11:11:41 +0000358 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
359 * lacks a "board#" property, something is very wrong.
Sam Ravnborg1d059952011-02-25 23:01:19 -0800360 */
oftedal9eeb0892011-06-01 11:11:41 +0000361 if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
362 printk(KERN_ERR "%s: Error, parent is not %s.\n",
363 bus->full_name, bus_connection);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800364 goto err_out;
365 }
oftedal9eeb0892011-06-01 11:11:41 +0000366 board_parent = bus->parent;
367 board = of_getintprop_default(board_parent, "board#", -1);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800368 if (board == -1) {
oftedal9eeb0892011-06-01 11:11:41 +0000369 printk(KERN_ERR "%s: Error, lacks board# property.\n",
370 board_parent->full_name);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800371 goto err_out;
372 }
373
374 sbusl = pil_to_sbus[real_irq];
375 if (sbusl)
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000376 pil = sun4d_encode_irq(board, sbusl, slot);
377 else
378 pil = real_irq;
379
oftedal5fba1702011-06-01 10:43:50 +0000380 irq = _sun4d_build_device_irq(real_irq, pil, board);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800381err_out:
oftedal5fba1702011-06-01 10:43:50 +0000382 return irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800383}
384
oftedal5fba1702011-06-01 10:43:50 +0000385unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
386{
387 return _sun4d_build_device_irq(real_irq, real_irq, board);
388}
389
390
David S. Millerf5f10852008-09-13 22:04:55 -0700391static void __init sun4d_fixup_trap_table(void)
392{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700394 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700395 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
David S. Millerf5f10852008-09-13 22:04:55 -0700397 /* Adjust so that we jump directly to smp4d_ticker */
398 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
David S. Millerf5f10852008-09-13 22:04:55 -0700400 /* For SMP we use the level 14 ticker, however the bootup code
401 * has copied the firmware's level 14 vector into the boot cpu's
402 * trap table, we must fix this now or we get squashed.
403 */
404 local_irq_save(flags);
405 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
406 trap_table->inst_one = lvl14_save[0];
407 trap_table->inst_two = lvl14_save[1];
408 trap_table->inst_three = lvl14_save[2];
409 trap_table->inst_four = lvl14_save[3];
David S. Miller5d83d662012-05-13 20:49:31 -0700410 local_ops->cache_all();
David S. Millerf5f10852008-09-13 22:04:55 -0700411 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412#endif
413}
414
Tkhai Kirill62f08282012-04-04 21:49:26 +0200415static void __init sun4d_init_timers(void)
David S. Millerf5f10852008-09-13 22:04:55 -0700416{
417 struct device_node *dp;
418 struct resource res;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000419 unsigned int irq;
David S. Millerf5f10852008-09-13 22:04:55 -0700420 const u32 *reg;
421 int err;
oftedal5fba1702011-06-01 10:43:50 +0000422 int board;
David S. Millerf5f10852008-09-13 22:04:55 -0700423
424 dp = of_find_node_by_name(NULL, "cpu-unit");
425 if (!dp) {
426 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
427 prom_halt();
428 }
429
430 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
431 * registers via any cpu's mapping. The first 'reg' property is the
432 * bootbus.
433 */
434 reg = of_get_property(dp, "reg", NULL);
435 if (!reg) {
436 prom_printf("sun4d_init_timers: No reg property\n");
437 prom_halt();
438 }
439
oftedal5fba1702011-06-01 10:43:50 +0000440 board = of_getintprop_default(dp, "board#", -1);
441 if (board == -1) {
442 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
443 prom_halt();
444 }
445
446 of_node_put(dp);
447
David S. Millerf5f10852008-09-13 22:04:55 -0700448 res.start = reg[1];
449 res.end = reg[2] - 1;
450 res.flags = reg[0] & 0xff;
451 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
452 sizeof(struct sun4d_timer_regs), "user timer");
453 if (!sun4d_timers) {
454 prom_printf("sun4d_init_timers: Can't map timer regs\n");
455 prom_halt();
456 }
457
Tkhai Kirill62f08282012-04-04 21:49:26 +0200458#ifdef CONFIG_SMP
459 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
460#else
461 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
462 sparc_config.features |= FEAT_L10_CLOCKEVENT;
463#endif
464 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
465 sbus_writel(timer_value(sparc_config.cs_period),
466 &sun4d_timers->l10_timer_limit);
David S. Millerf5f10852008-09-13 22:04:55 -0700467
468 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700469
oftedal5fba1702011-06-01 10:43:50 +0000470 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
Tkhai Kirill62f08282012-04-04 21:49:26 +0200471 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
David S. Millerf5f10852008-09-13 22:04:55 -0700472 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000473 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
474 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700475 prom_halt();
476 }
477 sun4d_load_profile_irqs();
478 sun4d_fixup_trap_table();
479}
480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481void __init sun4d_init_sbi_irq(void)
482{
David S. Miller71d37212008-08-27 02:50:57 -0700483 struct device_node *dp;
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +0000484 int target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700485
David S. Millerf8376e92008-09-13 22:05:25 -0700486 target_cpu = boot_cpu_id;
David S. Miller71d37212008-08-27 02:50:57 -0700487 for_each_node_by_name(dp, "sbi") {
488 int devid = of_getintprop_default(dp, "device-id", 0);
489 int board = of_getintprop_default(dp, "board#", 0);
490 unsigned int mask;
491
David S. Millerf8376e92008-09-13 22:05:25 -0700492 set_sbi_tid(devid, target_cpu << 3);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000493 board_to_cpu[board] = target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700496 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000498 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
499 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700500 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 }
503}
504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505void __init sun4d_init_IRQ(void)
506{
507 local_irq_disable();
508
Sam Ravnborg472bc4f2012-04-04 13:21:13 +0200509 sparc_config.init_timers = sun4d_init_timers;
510 sparc_config.build_device_irq = sun4d_build_device_irq;
Tkhai Kirill62f08282012-04-04 21:49:26 +0200511 sparc_config.clock_rate = SBUS_CLOCK_RATE;
Sam Ravnborg08c93882012-05-14 17:30:35 +0200512 sparc_config.clear_clock_irq = sun4d_clear_clock_irq;
513 sparc_config.load_profile_irq = sun4d_load_profile_irq;
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 /* Cannot enable interrupts until OBP ticker is disabled. */
516}