blob: fc1c22f121fda584a207447254e3c461658a105f [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)) {
Sam Ravnborg70044df2011-01-28 22:08:23 +0000310 for (tmp = action; tmp->next; tmp = tmp->next)
311 /* find last entry - tmp used below */;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 } else {
313 ret = -EBUSY;
314 goto out_unlock;
315 }
Thomas Gleixner67413202006-07-01 19:29:26 -0700316 if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000317 printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n",
318 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 ret = -EBUSY;
320 goto out_unlock;
321 }
322 action = NULL; /* Or else! */
323 }
324
325 /* If this is flagged as statically allocated then we use our
326 * private struct which is never freed.
327 */
328 if (irqflags & SA_STATIC_ALLOC) {
329 if (static_irq_count < MAX_STATIC_ALLOC)
330 action = &static_irqaction[static_irq_count++];
331 else
Sam Ravnborge54f8542011-01-28 22:08:21 +0000332 printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
333 irq, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 if (action == NULL)
Sam Ravnborge54f8542011-01-28 22:08:21 +0000337 action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
338
339 if (!action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 ret = -ENOMEM;
341 goto out_unlock;
342 }
343
344 action->handler = handler;
345 action->flags = irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 action->name = devname;
347 action->next = NULL;
348 action->dev_id = dev_id;
349
350 if (tmp)
351 tmp->next = action;
352 else
353 *actionp = action;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000354
Al Viro0f516812007-07-21 19:19:38 -0700355 __enable_irq(irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 ret = 0;
358out_unlock:
359 spin_unlock_irqrestore(&irq_action_lock, flags);
360out:
361 return ret;
362}
363
364static void sun4d_disable_irq(unsigned int irq)
365{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 int tid = sbus_tid[(irq >> 5) - 1];
367 unsigned long flags;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000368
David S. Millerf8376e92008-09-13 22:05:25 -0700369 if (irq < NR_IRQS)
370 return;
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 spin_lock_irqsave(&sun4d_imsk_lock, flags);
373 cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
374 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
377static void sun4d_enable_irq(unsigned int irq)
378{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 int tid = sbus_tid[(irq >> 5) - 1];
380 unsigned long flags;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000381
David S. Millerf8376e92008-09-13 22:05:25 -0700382 if (irq < NR_IRQS)
383 return;
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 spin_lock_irqsave(&sun4d_imsk_lock, flags);
386 cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
387 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
390#ifdef CONFIG_SMP
391static void sun4d_set_cpu_int(int cpu, int level)
392{
393 sun4d_send_ipi(cpu, level);
394}
395
396static void sun4d_clear_ipi(int cpu, int level)
397{
398}
399
400static void sun4d_set_udt(int cpu)
401{
402}
403
404/* Setup IRQ distribution scheme. */
405void __init sun4d_distribute_irqs(void)
406{
David S. Miller71d37212008-08-27 02:50:57 -0700407 struct device_node *dp;
408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 int cpuid = cpu_logical_map(1);
410
411 if (cpuid == -1)
412 cpuid = cpu_logical_map(0);
David S. Miller71d37212008-08-27 02:50:57 -0700413 for_each_node_by_name(dp, "sbi") {
414 int devid = of_getintprop_default(dp, "device-id", 0);
415 int board = of_getintprop_default(dp, "board#", 0);
416 sbus_tid[board] = cpuid;
417 set_sbi_tid(devid, cpuid << 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
Sam Ravnborge54f8542011-01-28 22:08:21 +0000419 printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
421#endif
Sam Ravnborge54f8542011-01-28 22:08:21 +0000422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423static void sun4d_clear_clock_irq(void)
424{
David S. Millerf5f10852008-09-13 22:04:55 -0700425 sbus_readl(&sun4d_timers->l10_timer_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428static void sun4d_load_profile_irq(int cpu, unsigned int limit)
429{
430 bw_set_prof_limit(cpu, limit);
431}
432
David S. Millerf5f10852008-09-13 22:04:55 -0700433static void __init sun4d_load_profile_irqs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
David S. Millerf5f10852008-09-13 22:04:55 -0700435 int cpu = 0, mid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
438 sun4d_load_profile_irq(mid >> 3, 0);
439 cpu++;
440 }
David S. Millerf5f10852008-09-13 22:04:55 -0700441}
442
443static void __init sun4d_fixup_trap_table(void)
444{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445#ifdef CONFIG_SMP
David S. Millerf5f10852008-09-13 22:04:55 -0700446 unsigned long flags;
David S. Millerf5f10852008-09-13 22:04:55 -0700447 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
David S. Millerf5f10852008-09-13 22:04:55 -0700449 /* Adjust so that we jump directly to smp4d_ticker */
450 lvl14_save[2] += smp4d_ticker - real_irq_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
David S. Millerf5f10852008-09-13 22:04:55 -0700452 /* For SMP we use the level 14 ticker, however the bootup code
453 * has copied the firmware's level 14 vector into the boot cpu's
454 * trap table, we must fix this now or we get squashed.
455 */
456 local_irq_save(flags);
457 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
458 trap_table->inst_one = lvl14_save[0];
459 trap_table->inst_two = lvl14_save[1];
460 trap_table->inst_three = lvl14_save[2];
461 trap_table->inst_four = lvl14_save[3];
462 local_flush_cache_all();
463 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464#endif
465}
466
David S. Millerf5f10852008-09-13 22:04:55 -0700467static void __init sun4d_init_timers(irq_handler_t counter_fn)
468{
469 struct device_node *dp;
470 struct resource res;
471 const u32 *reg;
472 int err;
473
474 dp = of_find_node_by_name(NULL, "cpu-unit");
475 if (!dp) {
476 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
477 prom_halt();
478 }
479
480 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
481 * registers via any cpu's mapping. The first 'reg' property is the
482 * bootbus.
483 */
484 reg = of_get_property(dp, "reg", NULL);
Nicolas Palixc2e27c32008-12-03 21:10:57 -0800485 of_node_put(dp);
David S. Millerf5f10852008-09-13 22:04:55 -0700486 if (!reg) {
487 prom_printf("sun4d_init_timers: No reg property\n");
488 prom_halt();
489 }
490
491 res.start = reg[1];
492 res.end = reg[2] - 1;
493 res.flags = reg[0] & 0xff;
494 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
495 sizeof(struct sun4d_timer_regs), "user timer");
496 if (!sun4d_timers) {
497 prom_printf("sun4d_init_timers: Can't map timer regs\n");
498 prom_halt();
499 }
500
501 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
502
503 master_l10_counter = &sun4d_timers->l10_cur_count;
David S. Millerf5f10852008-09-13 22:04:55 -0700504
505 err = request_irq(TIMER_IRQ, counter_fn,
506 (IRQF_DISABLED | SA_STATIC_ALLOC),
507 "timer", NULL);
508 if (err) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000509 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
510 err);
David S. Millerf5f10852008-09-13 22:04:55 -0700511 prom_halt();
512 }
513 sun4d_load_profile_irqs();
514 sun4d_fixup_trap_table();
515}
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517void __init sun4d_init_sbi_irq(void)
518{
David S. Miller71d37212008-08-27 02:50:57 -0700519 struct device_node *dp;
David S. Millerf8376e92008-09-13 22:05:25 -0700520 int target_cpu = 0;
521
522#ifdef CONFIG_SMP
523 target_cpu = boot_cpu_id;
524#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 nsbi = 0;
David S. Miller71d37212008-08-27 02:50:57 -0700527 for_each_node_by_name(dp, "sbi")
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 nsbi++;
Sam Ravnborge54f8542011-01-28 22:08:21 +0000529 sbus_actions = kzalloc(nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
David S. Millerd4accd62006-11-30 17:11:26 -0800530 if (!sbus_actions) {
531 prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
532 prom_halt();
533 }
David S. Miller71d37212008-08-27 02:50:57 -0700534 for_each_node_by_name(dp, "sbi") {
535 int devid = of_getintprop_default(dp, "device-id", 0);
536 int board = of_getintprop_default(dp, "board#", 0);
537 unsigned int mask;
538
David S. Millerf8376e92008-09-13 22:05:25 -0700539 set_sbi_tid(devid, target_cpu << 3);
540 sbus_tid[board] = target_cpu;
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 /* Get rid of pending irqs from PROM */
David S. Miller71d37212008-08-27 02:50:57 -0700543 mask = acquire_sbi(devid, 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (mask) {
Sam Ravnborge54f8542011-01-28 22:08:21 +0000545 printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
546 mask, board);
David S. Miller71d37212008-08-27 02:50:57 -0700547 release_sbi(devid, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
549 }
550}
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552void __init sun4d_init_IRQ(void)
553{
554 local_irq_disable();
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
557 BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
558 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
Sam Ravnborgbbdc2662011-02-25 23:00:19 -0800560
561 sparc_irq_config.init_timers = sun4d_init_timers;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563#ifdef CONFIG_SMP
564 BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
565 BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
566 BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
567#endif
568 /* Cannot enable interrupts until OBP ticker is disabled. */
569}