1
2
3
4
5
6
7
8
9
10
11
12#include <linux/errno.h>
13#include <linux/linkage.h>
14#include <linux/kernel_stat.h>
15#include <linux/signal.h>
16#include <linux/sched.h>
17#include <linux/ptrace.h>
18#include <linux/smp.h>
19#include <linux/interrupt.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24
25#include <asm/ptrace.h>
26#include <asm/processor.h>
27#include <asm/system.h>
28#include <asm/psr.h>
29#include <asm/vaddrs.h>
30#include <asm/timer.h>
31#include <asm/openprom.h>
32#include <asm/oplib.h>
33#include <asm/traps.h>
34#include <asm/pgalloc.h>
35#include <asm/pgtable.h>
36#include <asm/smp.h>
37#include <asm/irq.h>
38#include <asm/io.h>
39#include <asm/cacheflush.h>
40
41#include "irq.h"
42
43struct sun4m_irq_percpu {
44 u32 pending;
45 u32 clear;
46 u32 set;
47};
48
49struct sun4m_irq_global {
50 u32 pending;
51 u32 mask;
52 u32 mask_clear;
53 u32 mask_set;
54 u32 interrupt_target;
55};
56
57
58struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
59struct sun4m_irq_global __iomem *sun4m_irq_global;
60
61
62
63
64#define SUN4M_INT_ENABLE 0x80000000
65#define SUN4M_INT_E14 0x00000080
66#define SUN4M_INT_E10 0x00080000
67
68#define SUN4M_HARD_INT(x) (0x000000001 << (x))
69#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
70
71#define SUN4M_INT_MASKALL 0x80000000
72#define SUN4M_INT_MODULE_ERR 0x40000000
73#define SUN4M_INT_M2S_WRITE_ERR 0x20000000
74#define SUN4M_INT_ECC_ERR 0x10000000
75#define SUN4M_INT_VME_ERR 0x08000000
76#define SUN4M_INT_FLOPPY 0x00400000
77#define SUN4M_INT_MODULE 0x00200000
78#define SUN4M_INT_VIDEO 0x00100000
79#define SUN4M_INT_REALTIME 0x00080000
80#define SUN4M_INT_SCSI 0x00040000
81#define SUN4M_INT_AUDIO 0x00020000
82#define SUN4M_INT_ETHERNET 0x00010000
83#define SUN4M_INT_SERIAL 0x00008000
84#define SUN4M_INT_KBDMS 0x00004000
85#define SUN4M_INT_SBUSBITS 0x00003F80
86#define SUN4M_INT_VMEBITS 0x0000007F
87
88#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
89 SUN4M_INT_M2S_WRITE_ERR | \
90 SUN4M_INT_ECC_ERR | \
91 SUN4M_INT_VME_ERR)
92
93#define SUN4M_INT_SBUS(x) (1 << (x+7))
94#define SUN4M_INT_VME(x) (1 << (x))
95
96
97#define OBP_INT_LEVEL_SOFT 0x10
98#define OBP_INT_LEVEL_ONBOARD 0x20
99#define OBP_INT_LEVEL_SBUS 0x30
100#define OBP_INT_LEVEL_VME 0x40
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155static unsigned long irq_mask[0x50] = {
156
157 0, SUN4M_SOFT_INT(1),
158 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
159 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
160 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
161 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
162 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
163 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
164 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
165
166 0, SUN4M_SOFT_INT(1),
167 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
168 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
169 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
170 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
171 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
172 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
173 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
174
175 0, 0, 0, 0,
176 SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
177 SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
178 SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
179 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
180 SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
181
182 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
183 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
184 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
185 0, SUN4M_INT_SBUS(6), 0, 0,
186
187 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
188 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
189 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
190 0, SUN4M_INT_VME(6), 0, 0
191};
192
193static unsigned long sun4m_get_irqmask(unsigned int irq)
194{
195 unsigned long mask;
196
197 if (irq < 0x50)
198 mask = irq_mask[irq];
199 else
200 mask = 0;
201
202 if (!mask)
203 printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
204 irq);
205
206 return mask;
207}
208
209static void sun4m_disable_irq(unsigned int irq_nr)
210{
211 unsigned long mask, flags;
212 int cpu = smp_processor_id();
213
214 mask = sun4m_get_irqmask(irq_nr);
215 local_irq_save(flags);
216 if (irq_nr > 15)
217 sbus_writel(mask, &sun4m_irq_global->mask_set);
218 else
219 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
220 local_irq_restore(flags);
221}
222
223static void sun4m_enable_irq(unsigned int irq_nr)
224{
225 unsigned long mask, flags;
226 int cpu = smp_processor_id();
227
228
229
230
231
232 if (irq_nr != 0x0b) {
233 mask = sun4m_get_irqmask(irq_nr);
234 local_irq_save(flags);
235 if (irq_nr > 15)
236 sbus_writel(mask, &sun4m_irq_global->mask_clear);
237 else
238 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
239 local_irq_restore(flags);
240 } else {
241 local_irq_save(flags);
242 sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
243 local_irq_restore(flags);
244 }
245}
246
247static unsigned long cpu_pil_to_imask[16] = {
248 0x00000000,
249 0x00000000,
250 SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0),
251 SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1),
252 SUN4M_INT_SCSI,
253 SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2),
254 SUN4M_INT_ETHERNET,
255 SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3),
256 SUN4M_INT_VIDEO,
257 SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
258 SUN4M_INT_REALTIME,
259 SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
260 SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
261 SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
262 SUN4M_INT_E14,
263 SUN4M_INT_ERROR
264};
265
266
267
268
269static void sun4m_disable_pil_irq(unsigned int pil)
270{
271 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
272}
273
274static void sun4m_enable_pil_irq(unsigned int pil)
275{
276 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
277}
278
279#ifdef CONFIG_SMP
280static void sun4m_send_ipi(int cpu, int level)
281{
282 unsigned long mask = sun4m_get_irqmask(level);
283 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
284}
285
286static void sun4m_clear_ipi(int cpu, int level)
287{
288 unsigned long mask = sun4m_get_irqmask(level);
289 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
290}
291
292static void sun4m_set_udt(int cpu)
293{
294 sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
295}
296#endif
297
298struct sun4m_timer_percpu {
299 u32 l14_limit;
300 u32 l14_count;
301 u32 l14_limit_noclear;
302 u32 user_timer_start_stop;
303};
304
305static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
306
307struct sun4m_timer_global {
308 u32 l10_limit;
309 u32 l10_count;
310 u32 l10_limit_noclear;
311 u32 reserved;
312 u32 timer_config;
313};
314
315static struct sun4m_timer_global __iomem *timers_global;
316
317#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
318
319unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
320
321static void sun4m_clear_clock_irq(void)
322{
323 sbus_readl(&timers_global->l10_limit);
324}
325
326void sun4m_nmi(struct pt_regs *regs)
327{
328 unsigned long afsr, afar, si;
329
330 printk(KERN_ERR "Aieee: sun4m NMI received!\n");
331
332 __asm__ __volatile__("mov 0x500, %%g1\n\t"
333 "lda [%%g1] 0x4, %0\n\t"
334 "mov 0x600, %%g1\n\t"
335 "lda [%%g1] 0x4, %1\n\t" :
336 "=r" (afsr), "=r" (afar));
337 printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
338 si = sbus_readl(&sun4m_irq_global->pending);
339 printk(KERN_ERR "si=%08lx\n", si);
340 if (si & SUN4M_INT_MODULE_ERR)
341 printk(KERN_ERR "Module async error\n");
342 if (si & SUN4M_INT_M2S_WRITE_ERR)
343 printk(KERN_ERR "MBus/SBus async error\n");
344 if (si & SUN4M_INT_ECC_ERR)
345 printk(KERN_ERR "ECC memory error\n");
346 if (si & SUN4M_INT_VME_ERR)
347 printk(KERN_ERR "VME async error\n");
348 printk(KERN_ERR "you lose buddy boy...\n");
349 show_regs(regs);
350 prom_halt();
351}
352
353
354void sun4m_clear_profile_irq(int cpu)
355{
356 sbus_readl(&timers_percpu[cpu]->l14_limit);
357}
358
359static void sun4m_load_profile_irq(int cpu, unsigned int limit)
360{
361 sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
362}
363
364static void __init sun4m_init_timers(irq_handler_t counter_fn)
365{
366 struct device_node *dp = of_find_node_by_name(NULL, "counter");
367 int i, err, len, num_cpu_timers;
368 const u32 *addr;
369
370 if (!dp) {
371 printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
372 return;
373 }
374
375 addr = of_get_property(dp, "address", &len);
376 of_node_put(dp);
377 if (!addr) {
378 printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
379 return;
380 }
381
382 num_cpu_timers = (len / sizeof(u32)) - 1;
383 for (i = 0; i < num_cpu_timers; i++) {
384 timers_percpu[i] = (void __iomem *)
385 (unsigned long) addr[i];
386 }
387 timers_global = (void __iomem *)
388 (unsigned long) addr[num_cpu_timers];
389
390 sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
391
392 master_l10_counter = &timers_global->l10_count;
393
394 err = request_irq(TIMER_IRQ, counter_fn,
395 (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
396 if (err) {
397 printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
398 err);
399 return;
400 }
401
402 for (i = 0; i < num_cpu_timers; i++)
403 sbus_writel(0, &timers_percpu[i]->l14_limit);
404 if (num_cpu_timers == 4)
405 sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
406
407#ifdef CONFIG_SMP
408 {
409 unsigned long flags;
410 extern unsigned long lvl14_save[4];
411 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
412
413
414
415
416
417 local_irq_save(flags);
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);
424 }
425#endif
426}
427
428void __init sun4m_init_IRQ(void)
429{
430 struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
431 int len, i, mid, num_cpu_iregs;
432 const u32 *addr;
433
434 if (!dp) {
435 printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
436 return;
437 }
438
439 addr = of_get_property(dp, "address", &len);
440 of_node_put(dp);
441 if (!addr) {
442 printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
443 return;
444 }
445
446 num_cpu_iregs = (len / sizeof(u32)) - 1;
447 for (i = 0; i < num_cpu_iregs; i++) {
448 sun4m_irq_percpu[i] = (void __iomem *)
449 (unsigned long) addr[i];
450 }
451 sun4m_irq_global = (void __iomem *)
452 (unsigned long) addr[num_cpu_iregs];
453
454 local_irq_disable();
455
456 sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
457 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
458 sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
459
460 if (num_cpu_iregs == 4)
461 sbus_writel(0, &sun4m_irq_global->interrupt_target);
462
463 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
464 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
465 BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
466 BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
467 BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
468 BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
469 sparc_init_timers = sun4m_init_timers;
470#ifdef CONFIG_SMP
471 BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
472 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
473 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
474#endif
475
476
477}
478