blob: b2e3fbf7c6facf0865a2fcf150f371c6fdd8546f [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>
17
Sam Ravnborg81265fd2008-12-08 01:08:24 -080018#include "kernel.h"
Al Viro32231a62007-07-21 19:18:57 -070019#include "irq.h"
20
Sam Ravnborge54f8542011-01-28 22:08:21 +000021/* Sun4d interrupts fall roughly into two categories. SBUS and
22 * cpu local. CPU local interrupts cover the timer interrupts
23 * and whatnot, and we encode those as normal PILs between
24 * 0 and 15.
25 *
26 * SBUS interrupts are encoded integers including the board number
27 * (plus one), the SBUS level, and the SBUS slot number. Sun4D
28 * IRQ dispatch is done by:
29 *
30 * 1) Reading the BW local interrupt table in order to get the bus
31 * interrupt mask.
32 *
33 * This table is indexed by SBUS interrupt level which can be
34 * derived from the PIL we got interrupted on.
35 *
36 * 2) For each bus showing interrupt pending from #1, read the
37 * SBI interrupt state register. This will indicate which slots
38 * have interrupts pending for that SBUS interrupt level.
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#define TIMER_IRQ 10
52
53#define MAX_STATIC_ALLOC 4
Adrian Bunkc61c65c2008-06-05 11:40:58 -070054static unsigned char sbus_tid[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Bob Breuera54123e2006-03-23 22:36:19 -080056static struct irqaction *irq_action[NR_IRQS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Adrian Bunkc61c65c2008-06-05 11:40:58 -070058static struct sbus_action {
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 struct irqaction *action;
60 /* For SMP this needs to be extended */
61} *sbus_actions;
62
63static int pil_to_sbus[] = {
Sam Ravnborge54f8542011-01-28 22:08:21 +000064 0,
65 0,
66 1,
67 2,
68 0,
69 3,
70 0,
71 4,
72 0,
73 5,
74 0,
75 6,
76 0,
77 7,
78 0,
79 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -070080};
81
82static int sbus_to_pil[] = {
Sam Ravnborge54f8542011-01-28 22:08:21 +000083 0,
84 2,
85 3,
86 5,
87 7,
88 9,
89 11,
90 13,
Linus Torvalds1da177e2005-04-16 15:20:36 -070091};
92
93static int nsbi;
David S. Millerf8376e92008-09-13 22:05:25 -070094
95/* Exported for sun4d_smp.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096DEFINE_SPINLOCK(sun4d_imsk_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98int show_sun4d_interrupts(struct seq_file *p, void *v)
99{
100 int i = *(loff_t *) v, j = 0, k = 0, sbusl;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000101 struct irqaction *action;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 unsigned long flags;
103#ifdef CONFIG_SMP
104 int x;
105#endif
106
107 spin_lock_irqsave(&irq_action_lock, flags);
108 if (i < NR_IRQS) {
109 sbusl = pil_to_sbus[i];
110 if (!sbusl) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000111 action = *(i + irq_action);
112 if (!action)
113 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 } else {
115 for (j = 0; j < nsbi; j++) {
116 for (k = 0; k < 4; k++)
Sam Ravnborge54f8542011-01-28 22:08:21 +0000117 action = sbus_actions[(j << 5) + (sbusl << 2) + k].action;
118 if (action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 goto found_it;
120 }
121 goto out_unlock;
122 }
123found_it: seq_printf(p, "%3d: ", i);
124#ifndef CONFIG_SMP
125 seq_printf(p, "%10u ", kstat_irqs(i));
126#else
Andrew Morton394e3902006-03-23 03:01:05 -0800127 for_each_online_cpu(x)
128 seq_printf(p, "%10u ",
129 kstat_cpu(cpu_logical_map(x)).irqs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130#endif
131 seq_printf(p, "%c %s",
Thomas Gleixner67413202006-07-01 19:29:26 -0700132 (action->flags & IRQF_DISABLED) ? '+' : ' ',
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 action->name);
134 action = action->next;
135 for (;;) {
136 for (; action; action = action->next) {
137 seq_printf(p, ",%s %s",
Thomas Gleixner67413202006-07-01 19:29:26 -0700138 (action->flags & IRQF_DISABLED) ? " +" : "",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 action->name);
140 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000141 if (!sbusl)
142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 k++;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000144 if (k < 4) {
145 action = sbus_actions[(j << 5) + (sbusl << 2) + k].action;
146 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 j++;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000148 if (j == nsbi)
149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 k = 0;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000151 action = sbus_actions[(j << 5) + (sbusl << 2)].action;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
153 }
154 seq_putc(p, '\n');
155 }
156out_unlock:
157 spin_unlock_irqrestore(&irq_action_lock, flags);
158 return 0;
159}
160
161void sun4d_free_irq(unsigned int irq, void *dev_id)
162{
163 struct irqaction *action, **actionp;
164 struct irqaction *tmp = NULL;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000165 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 spin_lock_irqsave(&irq_action_lock, flags);
168 if (irq < 15)
169 actionp = irq + irq_action;
170 else
171 actionp = &(sbus_actions[irq - (1 << 5)].action);
172 action = *actionp;
173 if (!action) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000174 printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 goto out_unlock;
176 }
177 if (dev_id) {
178 for (; action; action = action->next) {
179 if (action->dev_id == dev_id)
180 break;
181 tmp = action;
182 }
183 if (!action) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000184 printk(KERN_ERR "Trying to free free shared IRQ%d\n",
185 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 goto out_unlock;
187 }
Thomas Gleixner67413202006-07-01 19:29:26 -0700188 } else if (action->flags & IRQF_SHARED) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000189 printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n",
190 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 goto out_unlock;
192 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000193 if (action->flags & SA_STATIC_ALLOC) {
194 /*
195 * This interrupt is marked as specially allocated
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 * so it is a bad idea to free it.
197 */
Sam Ravnborge54f8542011-01-28 22:08:21 +0000198 printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 irq, action->name);
200 goto out_unlock;
201 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000202
Julia Lawall0d0659c2010-06-04 16:17:37 -0700203 if (tmp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 tmp->next = action->next;
205 else
206 *actionp = action->next;
207
208 spin_unlock_irqrestore(&irq_action_lock, flags);
209
210 synchronize_irq(irq);
211
212 spin_lock_irqsave(&irq_action_lock, flags);
213
214 kfree(action);
215
216 if (!(*actionp))
Al Viro0f516812007-07-21 19:19:38 -0700217 __disable_irq(irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219out_unlock:
220 spin_unlock_irqrestore(&irq_action_lock, flags);
221}
222
Sam Ravnborge54f8542011-01-28 22:08:21 +0000223void sun4d_handler_irq(int pil, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
Al Viro0d844382006-10-08 14:30:44 +0100225 struct pt_regs *old_regs;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000226 struct irqaction *action;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 int cpu = smp_processor_id();
228 /* SBUS IRQ level (1 - 7) */
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000229 int sbusl = pil_to_sbus[pil];
Sam Ravnborge54f8542011-01-28 22:08:21 +0000230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 /* FIXME: Is this necessary?? */
232 cc_get_ipen();
Sam Ravnborge54f8542011-01-28 22:08:21 +0000233
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000234 cc_set_iclr(1 << pil);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000235
Al Viro0d844382006-10-08 14:30:44 +0100236 old_regs = set_irq_regs(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 irq_enter();
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000238 kstat_cpu(cpu).irqs[pil]++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (!sbusl) {
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000240 action = *(pil + irq_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (!action)
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000242 unexpected_irq(pil, NULL, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 do {
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000244 action->handler(pil, action->dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 action = action->next;
246 } while (action);
247 } else {
248 int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
249 int sbino;
250 struct sbus_action *actionp;
251 unsigned mask, slot;
252 int sbil = (sbusl << 2);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 bw_clear_intr_mask(sbusl, bus_mask);
Sam Ravnborge54f8542011-01-28 22:08:21 +0000255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* Loop for each pending SBI */
257 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1)
258 if (bus_mask & 1) {
259 mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
260 mask &= (0xf << sbil);
261 actionp = sbus_actions + (sbino << 5) + (sbil);
262 /* Loop for each pending SBI slot */
263 for (slot = (1 << sbil); mask; slot <<= 1, actionp++)
264 if (mask & slot) {
265 mask &= ~slot;
266 action = actionp->action;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 if (!action)
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000269 unexpected_irq(pil, NULL, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 do {
Sam Ravnborgd4d1ec42011-01-22 11:32:15 +0000271 action->handler(pil, action->dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 action = action->next;
273 } while (action);
274 release_sbi(SBI2DEVID(sbino), slot);
275 }
276 }
277 }
278 irq_exit();
Al Viro0d844382006-10-08 14:30:44 +0100279 set_irq_regs(old_regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280}
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282int sun4d_request_irq(unsigned int irq,
David Howells40220c12006-10-09 12:19:47 +0100283 irq_handler_t handler,
Sam Ravnborge54f8542011-01-28 22:08:21 +0000284 unsigned long irqflags, const char *devname, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
286 struct irqaction *action, *tmp = NULL, **actionp;
287 unsigned long flags;
288 int ret;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000289
290 if (irq > 14 && irq < (1 << 5)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 ret = -EINVAL;
292 goto out;
293 }
294
295 if (!handler) {
296 ret = -EINVAL;
297 goto out;
298 }
299
300 spin_lock_irqsave(&irq_action_lock, flags);
301
302 if (irq >= (1 << 5))
303 actionp = &(sbus_actions[irq - (1 << 5)].action);
304 else
305 actionp = irq + irq_action;
306 action = *actionp;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (action) {
Thomas Gleixner67413202006-07-01 19:29:26 -0700309 if ((action->flags & IRQF_SHARED) && (irqflags & IRQF_SHARED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 for (tmp = action; tmp->next; tmp = tmp->next);
311 } else {
312 ret = -EBUSY;
313 goto out_unlock;
314 }
Thomas Gleixner67413202006-07-01 19:29:26 -0700315 if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000316 printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n",
317 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 ret = -EBUSY;
319 goto out_unlock;
320 }
321 action = NULL; /* Or else! */
322 }
323
324 /* If this is flagged as statically allocated then we use our
325 * private struct which is never freed.
326 */
327 if (irqflags & SA_STATIC_ALLOC) {
328 if (static_irq_count < MAX_STATIC_ALLOC)
329 action = &static_irqaction[static_irq_count++];
330 else
Sam Ravnborge54f8542011-01-28 22:08:21 +0000331 printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
332 irq, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 if (action == NULL)
Sam Ravnborge54f8542011-01-28 22:08:21 +0000336 action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
337
338 if (!action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 ret = -ENOMEM;
340 goto out_unlock;
341 }
342
343 action->handler = handler;
344 action->flags = irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 action->name = devname;
346 action->next = NULL;
347 action->dev_id = dev_id;
348
349 if (tmp)
350 tmp->next = action;
351 else
352 *actionp = action;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000353
Al Viro0f516812007-07-21 19:19:38 -0700354 __enable_irq(irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 ret = 0;
357out_unlock:
358 spin_unlock_irqrestore(&irq_action_lock, flags);
359out:
360 return ret;
361}
362
363static void sun4d_disable_irq(unsigned int irq)
364{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 int tid = sbus_tid[(irq >> 5) - 1];
366 unsigned long flags;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000367
David S. Millerf8376e92008-09-13 22:05:25 -0700368 if (irq < NR_IRQS)
369 return;
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 spin_lock_irqsave(&sun4d_imsk_lock, flags);
372 cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
373 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
376static void sun4d_enable_irq(unsigned int irq)
377{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 int tid = sbus_tid[(irq >> 5) - 1];
379 unsigned long flags;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000380
David S. Millerf8376e92008-09-13 22:05:25 -0700381 if (irq < NR_IRQS)
382 return;
383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 spin_lock_irqsave(&sun4d_imsk_lock, flags);
385 cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
386 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
389#ifdef CONFIG_SMP
390static void sun4d_set_cpu_int(int cpu, int level)
391{
392 sun4d_send_ipi(cpu, level);
393}
394
395static void sun4d_clear_ipi(int cpu, int level)
396{
397}
398
399static void sun4d_set_udt(int cpu)
400{
401}
402
403/* Setup IRQ distribution scheme. */
404void __init sun4d_distribute_irqs(void)
405{
David S. Miller71d37212008-08-27 02:50:57 -0700406 struct device_node *dp;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int cpuid = cpu_logical_map(1);
409
410 if (cpuid == -1)
411 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700412 for_each_node_by_name(dp, "sbi") {
413 int devid = of_getintprop_default(dp, "device-id", 0);
414 int board = of_getintprop_default(dp, "board#", 0);
415 sbus_tid[board] = cpuid;
416 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000418 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422static void sun4d_clear_clock_irq(void)
423{
David S. Millerf5f10852008-09-13 22:04:55 -0700424 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427static void sun4d_load_profile_irq(int cpu, unsigned int limit)
428{
429 bw_set_prof_limit(cpu, limit);
430}
431
David S. Millerf5f10852008-09-13 22:04:55 -0700432static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433{
David S. Millerf5f10852008-09-13 22:04:55 -0700434 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
437 sun4d_load_profile_irq(mid >> 3, 0);
438 cpu++;
439 }
David S. Millerf5f10852008-09-13 22:04:55 -0700440}
441
442static void __init sun4d_fixup_trap_table(void)
443{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700445 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700446 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
David S. Millerf5f10852008-09-13 22:04:55 -0700448 /* Adjust so that we jump directly to smp4d_ticker */
449 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
David S. Millerf5f10852008-09-13 22:04:55 -0700451 /* For SMP we use the level 14 ticker, however the bootup code
452 * has copied the firmware's level 14 vector into the boot cpu's
453 * trap table, we must fix this now or we get squashed.
454 */
455 local_irq_save(flags);
456 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
457 trap_table->inst_one = lvl14_save[0];
458 trap_table->inst_two = lvl14_save[1];
459 trap_table->inst_three = lvl14_save[2];
460 trap_table->inst_four = lvl14_save[3];
461 local_flush_cache_all();
462 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463#endif
464}
465
David S. Millerf5f10852008-09-13 22:04:55 -0700466static void __init sun4d_init_timers(irq_handler_t counter_fn)
467{
468 struct device_node *dp;
469 struct resource res;
470 const u32 *reg;
471 int err;
472
473 dp = of_find_node_by_name(NULL, "cpu-unit");
474 if (!dp) {
475 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
476 prom_halt();
477 }
478
479 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
480 * registers via any cpu's mapping. The first 'reg' property is the
481 * bootbus.
482 */
483 reg = of_get_property(dp, "reg", NULL);
Nicolas Palixc2e27c32008-12-03 21:10:57 -0800484 of_node_put(dp);
David S. Millerf5f10852008-09-13 22:04:55 -0700485 if (!reg) {
486 prom_printf("sun4d_init_timers: No reg property\n");
487 prom_halt();
488 }
489
490 res.start = reg[1];
491 res.end = reg[2] - 1;
492 res.flags = reg[0] & 0xff;
493 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
494 sizeof(struct sun4d_timer_regs), "user timer");
495 if (!sun4d_timers) {
496 prom_printf("sun4d_init_timers: Can't map timer regs\n");
497 prom_halt();
498 }
499
500 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
501
502 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700503
504 err = request_irq(TIMER_IRQ, counter_fn,
505 (IRQF_DISABLED | SA_STATIC_ALLOC),
506 "timer", NULL);
507 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000508 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
509 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700510 prom_halt();
511 }
512 sun4d_load_profile_irqs();
513 sun4d_fixup_trap_table();
514}
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516void __init sun4d_init_sbi_irq(void)
517{
David S. Miller71d37212008-08-27 02:50:57 -0700518 struct device_node *dp;
David S. Millerf8376e92008-09-13 22:05:25 -0700519 int target_cpu = 0;
520
521#ifdef CONFIG_SMP
522 target_cpu = boot_cpu_id;
523#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 nsbi = 0;
David S. Miller71d37212008-08-27 02:50:57 -0700526 for_each_node_by_name(dp, "sbi")
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 nsbi++;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000528 sbus_actions = kzalloc(nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
David S. Millerd4accd62006-11-30 17:11:26 -0800529 if (!sbus_actions) {
530 prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
531 prom_halt();
532 }
David S. Miller71d37212008-08-27 02:50:57 -0700533 for_each_node_by_name(dp, "sbi") {
534 int devid = of_getintprop_default(dp, "device-id", 0);
535 int board = of_getintprop_default(dp, "board#", 0);
536 unsigned int mask;
537
David S. Millerf8376e92008-09-13 22:05:25 -0700538 set_sbi_tid(devid, target_cpu << 3);
539 sbus_tid[board] = target_cpu;
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700542 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000544 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
545 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700546 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
548 }
549}
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551void __init sun4d_init_IRQ(void)
552{
553 local_irq_disable();
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
556 BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
557 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 sparc_init_timers = sun4d_init_timers;
560#ifdef CONFIG_SMP
561 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
562 BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
563 BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
564#endif
565 /* Cannot enable interrupts until OBP ticker is disabled. */
566}