blob: a1bb2675b2801ac44891f3acf50320613e35a025 [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>
David Howells0d01ff22013-04-11 23:51:01 +01009#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/seq_file.h>
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/traps.h>
14#include <asm/irq.h>
15#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <asm/sbi.h>
17#include <asm/cacheflush.h>
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +000018#include <asm/setup.h>
David S. Miller5d83d662012-05-13 20:49:31 -070019#include <asm/oplib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Sam Ravnborg81265fd2008-12-08 01:08:24 -080021#include "kernel.h"
Al Viro32231a62007-07-21 19:18:57 -070022#include "irq.h"
23
Sam Ravnborge54f8542011-01-28 22:08:21 +000024/* Sun4d interrupts fall roughly into two categories. SBUS and
25 * cpu local. CPU local interrupts cover the timer interrupts
26 * and whatnot, and we encode those as normal PILs between
27 * 0 and 15.
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000028 * SBUS interrupts are encodes as a combination of board, level and slot.
Sam Ravnborge54f8542011-01-28 22:08:21 +000029 */
30
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000031struct sun4d_handler_data {
32 unsigned int cpuid; /* target cpu */
33 unsigned int real_irq; /* interrupt level */
34};
35
36
37static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
38{
39 return (board + 1) << 5 | (lvl << 2) | slot;
40}
41
David S. Millerf5f10852008-09-13 22:04:55 -070042struct sun4d_timer_regs {
43 u32 l10_timer_limit;
44 u32 l10_cur_countx;
45 u32 l10_limit_noclear;
46 u32 ctrl;
47 u32 l10_cur_count;
48};
49
50static struct sun4d_timer_regs __iomem *sun4d_timers;
51
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000052#define SUN4D_TIMER_IRQ 10
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +000053
54/* Specify which cpu handle interrupts from which board.
55 * Index is board - value is cpu.
56 */
57static unsigned char board_to_cpu[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static int pil_to_sbus[] = {
Sam Ravnborge54f8542011-01-28 22:08:21 +000060 0,
61 0,
62 1,
63 2,
64 0,
65 3,
66 0,
67 4,
68 0,
69 5,
70 0,
71 6,
72 0,
73 7,
74 0,
75 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -070076};
77
David S. Millerf8376e92008-09-13 22:05:25 -070078/* Exported for sun4d_smp.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -070079DEFINE_SPINLOCK(sun4d_imsk_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000081/* SBUS interrupts are encoded integers including the board number
82 * (plus one), the SBUS level, and the SBUS slot number. Sun4D
83 * IRQ dispatch is done by:
84 *
85 * 1) Reading the BW local interrupt table in order to get the bus
86 * interrupt mask.
87 *
88 * This table is indexed by SBUS interrupt level which can be
89 * derived from the PIL we got interrupted on.
90 *
91 * 2) For each bus showing interrupt pending from #1, read the
92 * SBI interrupt state register. This will indicate which slots
93 * have interrupts pending for that SBUS interrupt level.
94 *
95 * 3) Call the genreric IRQ support.
96 */
97static void sun4d_sbus_handler_irq(int sbusl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +000099 unsigned int bus_mask;
100 unsigned int sbino, slot;
101 unsigned int sbil;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000103 bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
104 bw_clear_intr_mask(sbusl, bus_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000106 sbil = (sbusl << 2);
107 /* Loop for each pending SBI */
oftedalea160582011-06-01 11:04:20 +0000108 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000109 unsigned int idx, mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000111 if (!(bus_mask & 1))
112 continue;
113 /* XXX This seems to ACK the irq twice. acquire_sbi()
114 * XXX uses swap, therefore this writes 0xf << sbil,
115 * XXX then later release_sbi() will write the individual
116 * XXX bits which were set again.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000118 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
119 mask &= (0xf << sbil);
120
121 /* Loop for each pending SBI slot */
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000122 slot = (1 << sbil);
oftedalea160582011-06-01 11:04:20 +0000123 for (idx = 0; mask != 0; idx++, slot <<= 1) {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000124 unsigned int pil;
125 struct irq_bucket *p;
126
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000127 if (!(mask & slot))
128 continue;
129
130 mask &= ~slot;
oftedalea160582011-06-01 11:04:20 +0000131 pil = sun4d_encode_irq(sbino, sbusl, idx);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000132
133 p = irq_map[pil];
134 while (p) {
135 struct irq_bucket *next;
136
137 next = p->next;
138 generic_handle_irq(p->irq);
139 p = next;
140 }
141 release_sbi(SBI2DEVID(sbino), slot);
142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
Sam Ravnborg5ac75682014-04-21 21:39:23 +0200146void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Al Viro0d844382006-10-08 14:30:44 +0100148 struct pt_regs *old_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 /* SBUS IRQ level (1 - 7) */
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000150 int sbusl = pil_to_sbus[pil];
Sam Ravnborge54f8542011-01-28 22:08:21 +0000151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 /* FIXME: Is this necessary?? */
153 cc_get_ipen();
Sam Ravnborge54f8542011-01-28 22:08:21 +0000154
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000155 cc_set_iclr(1 << pil);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000156
Daniel Hellstrom55dd23e2011-05-02 00:08:54 +0000157#ifdef CONFIG_SMP
158 /*
159 * Check IPI data structures after IRQ has been cleared. Hard and Soft
160 * IRQ can happen at the same time, so both cases are always handled.
161 */
162 if (pil == SUN4D_IPI_IRQ)
163 sun4d_ipi_interrupt();
164#endif
165
Al Viro0d844382006-10-08 14:30:44 +0100166 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 irq_enter();
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000168 if (sbusl == 0) {
169 /* cpu interrupt */
170 struct irq_bucket *p;
171
172 p = irq_map[pil];
173 while (p) {
174 struct irq_bucket *next;
175
176 next = p->next;
177 generic_handle_irq(p->irq);
178 p = next;
179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 } else {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000181 /* SBUS interrupt */
182 sun4d_sbus_handler_irq(sbusl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184 irq_exit();
Al Viro0d844382006-10-08 14:30:44 +0100185 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000188
189static void sun4d_mask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000191 struct sun4d_handler_data *handler_data = data->handler_data;
192 unsigned int real_irq;
193#ifdef CONFIG_SMP
194 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000196#endif
197 real_irq = handler_data->real_irq;
198#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 spin_lock_irqsave(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000200 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000202#else
203 cc_set_imsk(cc_get_imsk() | (1 << real_irq));
204#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000207static void sun4d_unmask_irq(struct irq_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000209 struct sun4d_handler_data *handler_data = data->handler_data;
210 unsigned int real_irq;
211#ifdef CONFIG_SMP
212 int cpuid = handler_data->cpuid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 unsigned long flags;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000214#endif
215 real_irq = handler_data->real_irq;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000216
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000217#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 spin_lock_irqsave(&sun4d_imsk_lock, flags);
oftedalea160582011-06-01 11:04:20 +0000219 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000221#else
oftedalea160582011-06-01 11:04:20 +0000222 cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000223#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000226static unsigned int sun4d_startup_irq(struct irq_data *data)
227{
228 irq_link(data->irq);
229 sun4d_unmask_irq(data);
230 return 0;
231}
232
233static void sun4d_shutdown_irq(struct irq_data *data)
234{
235 sun4d_mask_irq(data);
236 irq_unlink(data->irq);
237}
238
Sam Ravnborg5ac75682014-04-21 21:39:23 +0200239static struct irq_chip sun4d_irq = {
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000240 .name = "sun4d",
241 .irq_startup = sun4d_startup_irq,
242 .irq_shutdown = sun4d_shutdown_irq,
243 .irq_unmask = sun4d_unmask_irq,
244 .irq_mask = sun4d_mask_irq,
245};
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248/* Setup IRQ distribution scheme. */
249void __init sun4d_distribute_irqs(void)
250{
David S. Miller71d37212008-08-27 02:50:57 -0700251 struct device_node *dp;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 int cpuid = cpu_logical_map(1);
254
255 if (cpuid == -1)
256 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700257 for_each_node_by_name(dp, "sbi") {
258 int devid = of_getintprop_default(dp, "device-id", 0);
259 int board = of_getintprop_default(dp, "board#", 0);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000260 board_to_cpu[board] = cpuid;
David S. Miller71d37212008-08-27 02:50:57 -0700261 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000263 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static void sun4d_clear_clock_irq(void)
268{
David S. Millerf5f10852008-09-13 22:04:55 -0700269 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272static void sun4d_load_profile_irq(int cpu, unsigned int limit)
273{
Tkhai Kirill62f08282012-04-04 21:49:26 +0200274 unsigned int value = limit ? timer_value(limit) : 0;
275 bw_set_prof_limit(cpu, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
David S. Millerf5f10852008-09-13 22:04:55 -0700278static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
David S. Millerf5f10852008-09-13 22:04:55 -0700280 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
283 sun4d_load_profile_irq(mid >> 3, 0);
284 cpu++;
285 }
David S. Millerf5f10852008-09-13 22:04:55 -0700286}
287
Sam Ravnborg5ac75682014-04-21 21:39:23 +0200288static unsigned int _sun4d_build_device_irq(unsigned int real_irq,
289 unsigned int pil,
290 unsigned int board)
oftedal5fba1702011-06-01 10:43:50 +0000291{
292 struct sun4d_handler_data *handler_data;
293 unsigned int irq;
294
295 irq = irq_alloc(real_irq, pil);
296 if (irq == 0) {
297 prom_printf("IRQ: allocate for %d %d %d failed\n",
298 real_irq, pil, board);
299 goto err_out;
300 }
301
302 handler_data = irq_get_handler_data(irq);
303 if (unlikely(handler_data))
304 goto err_out;
305
306 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
307 if (unlikely(!handler_data)) {
308 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
309 prom_halt();
310 }
311 handler_data->cpuid = board_to_cpu[board];
312 handler_data->real_irq = real_irq;
313 irq_set_chip_and_handler_name(irq, &sun4d_irq,
314 handle_level_irq, "level");
315 irq_set_handler_data(irq, handler_data);
316
317err_out:
318 return irq;
319}
320
321
322
Sam Ravnborg5ac75682014-04-21 21:39:23 +0200323static unsigned int sun4d_build_device_irq(struct platform_device *op,
324 unsigned int real_irq)
Sam Ravnborg1d059952011-02-25 23:01:19 -0800325{
Sam Ravnborg1d059952011-02-25 23:01:19 -0800326 struct device_node *dp = op->dev.of_node;
oftedal9eeb0892011-06-01 11:11:41 +0000327 struct device_node *board_parent, *bus = dp->parent;
328 char *bus_connection;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800329 const struct linux_prom_registers *regs;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000330 unsigned int pil;
331 unsigned int irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800332 int board, slot;
333 int sbusl;
334
oftedal5fba1702011-06-01 10:43:50 +0000335 irq = real_irq;
oftedal9eeb0892011-06-01 11:11:41 +0000336 while (bus) {
337 if (!strcmp(bus->name, "sbi")) {
338 bus_connection = "io-unit";
Sam Ravnborg1d059952011-02-25 23:01:19 -0800339 break;
oftedal9eeb0892011-06-01 11:11:41 +0000340 }
Sam Ravnborg1d059952011-02-25 23:01:19 -0800341
oftedal9eeb0892011-06-01 11:11:41 +0000342 if (!strcmp(bus->name, "bootbus")) {
343 bus_connection = "cpu-unit";
344 break;
345 }
346
347 bus = bus->parent;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800348 }
oftedal9eeb0892011-06-01 11:11:41 +0000349 if (!bus)
Sam Ravnborg1d059952011-02-25 23:01:19 -0800350 goto err_out;
351
352 regs = of_get_property(dp, "reg", NULL);
353 if (!regs)
354 goto err_out;
355
356 slot = regs->which_io;
357
358 /*
oftedal9eeb0892011-06-01 11:11:41 +0000359 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
360 * lacks a "board#" property, something is very wrong.
Sam Ravnborg1d059952011-02-25 23:01:19 -0800361 */
oftedal9eeb0892011-06-01 11:11:41 +0000362 if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
363 printk(KERN_ERR "%s: Error, parent is not %s.\n",
364 bus->full_name, bus_connection);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800365 goto err_out;
366 }
oftedal9eeb0892011-06-01 11:11:41 +0000367 board_parent = bus->parent;
368 board = of_getintprop_default(board_parent, "board#", -1);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800369 if (board == -1) {
oftedal9eeb0892011-06-01 11:11:41 +0000370 printk(KERN_ERR "%s: Error, lacks board# property.\n",
371 board_parent->full_name);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800372 goto err_out;
373 }
374
375 sbusl = pil_to_sbus[real_irq];
376 if (sbusl)
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000377 pil = sun4d_encode_irq(board, sbusl, slot);
378 else
379 pil = real_irq;
380
oftedal5fba1702011-06-01 10:43:50 +0000381 irq = _sun4d_build_device_irq(real_irq, pil, board);
Sam Ravnborg1d059952011-02-25 23:01:19 -0800382err_out:
oftedal5fba1702011-06-01 10:43:50 +0000383 return irq;
Sam Ravnborg1d059952011-02-25 23:01:19 -0800384}
385
Sam Ravnborg5ac75682014-04-21 21:39:23 +0200386static unsigned int sun4d_build_timer_irq(unsigned int board,
387 unsigned int real_irq)
oftedal5fba1702011-06-01 10:43:50 +0000388{
389 return _sun4d_build_device_irq(real_irq, real_irq, board);
390}
391
392
David S. Millerf5f10852008-09-13 22:04:55 -0700393static void __init sun4d_fixup_trap_table(void)
394{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700396 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700397 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
David S. Millerf5f10852008-09-13 22:04:55 -0700399 /* Adjust so that we jump directly to smp4d_ticker */
400 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
David S. Millerf5f10852008-09-13 22:04:55 -0700402 /* For SMP we use the level 14 ticker, however the bootup code
403 * has copied the firmware's level 14 vector into the boot cpu's
404 * trap table, we must fix this now or we get squashed.
405 */
406 local_irq_save(flags);
407 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
408 trap_table->inst_one = lvl14_save[0];
409 trap_table->inst_two = lvl14_save[1];
410 trap_table->inst_three = lvl14_save[2];
411 trap_table->inst_four = lvl14_save[3];
David S. Miller5d83d662012-05-13 20:49:31 -0700412 local_ops->cache_all();
David S. Millerf5f10852008-09-13 22:04:55 -0700413 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414#endif
415}
416
Tkhai Kirill62f08282012-04-04 21:49:26 +0200417static void __init sun4d_init_timers(void)
David S. Millerf5f10852008-09-13 22:04:55 -0700418{
419 struct device_node *dp;
420 struct resource res;
Sam Ravnborg6baa9b22011-04-18 11:25:44 +0000421 unsigned int irq;
David S. Millerf5f10852008-09-13 22:04:55 -0700422 const u32 *reg;
423 int err;
oftedal5fba1702011-06-01 10:43:50 +0000424 int board;
David S. Millerf5f10852008-09-13 22:04:55 -0700425
426 dp = of_find_node_by_name(NULL, "cpu-unit");
427 if (!dp) {
428 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
429 prom_halt();
430 }
431
432 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
433 * registers via any cpu's mapping. The first 'reg' property is the
434 * bootbus.
435 */
436 reg = of_get_property(dp, "reg", NULL);
437 if (!reg) {
438 prom_printf("sun4d_init_timers: No reg property\n");
439 prom_halt();
440 }
441
oftedal5fba1702011-06-01 10:43:50 +0000442 board = of_getintprop_default(dp, "board#", -1);
443 if (board == -1) {
444 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
445 prom_halt();
446 }
447
448 of_node_put(dp);
449
David S. Millerf5f10852008-09-13 22:04:55 -0700450 res.start = reg[1];
451 res.end = reg[2] - 1;
452 res.flags = reg[0] & 0xff;
453 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
454 sizeof(struct sun4d_timer_regs), "user timer");
455 if (!sun4d_timers) {
456 prom_printf("sun4d_init_timers: Can't map timer regs\n");
457 prom_halt();
458 }
459
Tkhai Kirill62f08282012-04-04 21:49:26 +0200460#ifdef CONFIG_SMP
461 sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */
462#else
463 sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */
464 sparc_config.features |= FEAT_L10_CLOCKEVENT;
465#endif
466 sparc_config.features |= FEAT_L10_CLOCKSOURCE;
467 sbus_writel(timer_value(sparc_config.cs_period),
468 &sun4d_timers->l10_timer_limit);
David S. Millerf5f10852008-09-13 22:04:55 -0700469
470 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700471
oftedal5fba1702011-06-01 10:43:50 +0000472 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
Tkhai Kirill62f08282012-04-04 21:49:26 +0200473 err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
David S. Millerf5f10852008-09-13 22:04:55 -0700474 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000475 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
476 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700477 prom_halt();
478 }
479 sun4d_load_profile_irqs();
480 sun4d_fixup_trap_table();
481}
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483void __init sun4d_init_sbi_irq(void)
484{
David S. Miller71d37212008-08-27 02:50:57 -0700485 struct device_node *dp;
Daniel Hellstrom5fcafb72011-04-21 04:20:23 +0000486 int target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700487
David S. Millerf8376e92008-09-13 22:05:25 -0700488 target_cpu = boot_cpu_id;
David S. Miller71d37212008-08-27 02:50:57 -0700489 for_each_node_by_name(dp, "sbi") {
490 int devid = of_getintprop_default(dp, "device-id", 0);
491 int board = of_getintprop_default(dp, "board#", 0);
492 unsigned int mask;
493
David S. Millerf8376e92008-09-13 22:05:25 -0700494 set_sbi_tid(devid, target_cpu << 3);
Sam Ravnborgdb1cdd12011-04-18 11:25:42 +0000495 board_to_cpu[board] = target_cpu;
David S. Millerf8376e92008-09-13 22:05:25 -0700496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700498 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000500 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
501 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700502 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 }
504 }
505}
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507void __init sun4d_init_IRQ(void)
508{
509 local_irq_disable();
510
Sam Ravnborg472bc4f2012-04-04 13:21:13 +0200511 sparc_config.init_timers = sun4d_init_timers;
512 sparc_config.build_device_irq = sun4d_build_device_irq;
Tkhai Kirill62f08282012-04-04 21:49:26 +0200513 sparc_config.clock_rate = SBUS_CLOCK_RATE;
Sam Ravnborg08c93882012-05-14 17:30:35 +0200514 sparc_config.clear_clock_irq = sun4d_clear_clock_irq;
515 sparc_config.load_profile_irq = sun4d_load_profile_irq;
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 /* Cannot enable interrupts until OBP ticker is disabled. */
518}