aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/sun4m_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/sun4m_irq.c')
-rw-r--r--arch/sparc/kernel/sun4m_irq.c495
1 files changed, 253 insertions, 242 deletions
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 94e02de960ea..f10317179ee6 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -20,6 +20,8 @@
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/ioport.h> 22#include <linux/ioport.h>
23#include <linux/of.h>
24#include <linux/of_device.h>
23 25
24#include <asm/ptrace.h> 26#include <asm/ptrace.h>
25#include <asm/processor.h> 27#include <asm/processor.h>
@@ -35,59 +37,27 @@
35#include <asm/smp.h> 37#include <asm/smp.h>
36#include <asm/irq.h> 38#include <asm/irq.h>
37#include <asm/io.h> 39#include <asm/io.h>
38#include <asm/sbus.h>
39#include <asm/cacheflush.h> 40#include <asm/cacheflush.h>
40 41
41#include "irq.h" 42#include "irq.h"
42 43
43/* On the sun4m, just like the timers, we have both per-cpu and master 44struct sun4m_irq_percpu {
44 * interrupt registers. 45 u32 pending;
45 */ 46 u32 clear;
46 47 u32 set;
47/* These registers are used for sending/receiving irqs from/to
48 * different cpu's.
49 */
50struct sun4m_intreg_percpu {
51 unsigned int tbt; /* Interrupts still pending for this cpu. */
52
53 /* These next two registers are WRITE-ONLY and are only
54 * "on bit" sensitive, "off bits" written have NO affect.
55 */
56 unsigned int clear; /* Clear this cpus irqs here. */
57 unsigned int set; /* Set this cpus irqs here. */
58 unsigned char space[PAGE_SIZE - 12];
59}; 48};
60 49
61/* 50struct sun4m_irq_global {
62 * djhr 51 u32 pending;
63 * Actually the clear and set fields in this struct are misleading.. 52 u32 mask;
64 * according to the SLAVIO manual (and the same applies for the SEC) 53 u32 mask_clear;
65 * the clear field clears bits in the mask which will ENABLE that IRQ 54 u32 mask_set;
66 * the set field sets bits in the mask to DISABLE the IRQ. 55 u32 interrupt_target;
67 *
68 * Also the undirected_xx address in the SLAVIO is defined as
69 * RESERVED and write only..
70 *
71 * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
72 * sun4m machines, for MP the layout makes more sense.
73 */
74struct sun4m_intregs {
75 struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
76 unsigned int tbt; /* IRQ's that are still pending. */
77 unsigned int irqs; /* Master IRQ bits. */
78
79 /* Again, like the above, two these registers are WRITE-ONLY. */
80 unsigned int clear; /* Clear master IRQ's by setting bits here. */
81 unsigned int set; /* Set master IRQ's by setting bits here. */
82
83 /* This register is both READ and WRITE. */
84 unsigned int undirected_target; /* Which cpu gets undirected irqs. */
85}; 56};
86 57
87static unsigned long dummy; 58/* Code in entry.S needs to get at these register mappings. */
88 59struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
89struct sun4m_intregs *sun4m_interrupts; 60struct sun4m_irq_global __iomem *sun4m_irq_global;
90unsigned long *irq_rcvreg = &dummy;
91 61
92/* Dave Redman (djhr@tadpole.co.uk) 62/* Dave Redman (djhr@tadpole.co.uk)
93 * The sun4m interrupt registers. 63 * The sun4m interrupt registers.
@@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy;
101 71
102#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 72#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
103#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 73#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
104#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ 74#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
105#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ 75#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */
76#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */
106#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 77#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
107#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 78#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
108#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 79#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
@@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy;
113#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 84#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
114#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 85#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
115#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ 86#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
87#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */
88
89#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
90 SUN4M_INT_M2S_WRITE_ERR | \
91 SUN4M_INT_ECC_ERR | \
92 SUN4M_INT_VME_ERR)
116 93
117#define SUN4M_INT_SBUS(x) (1 << (x+7)) 94#define SUN4M_INT_SBUS(x) (1 << (x+7))
118#define SUN4M_INT_VME(x) (1 << (x)) 95#define SUN4M_INT_VME(x) (1 << (x))
119 96
120/* These tables only apply for interrupts greater than 15.. 97/* Interrupt levels used by OBP */
121 * 98#define OBP_INT_LEVEL_SOFT 0x10
122 * any intr value below 0x10 is considered to be a soft-int 99#define OBP_INT_LEVEL_ONBOARD 0x20
123 * this may be useful or it may not.. but that's how I've done it. 100#define OBP_INT_LEVEL_SBUS 0x30
124 * and it won't clash with what OBP is telling us about devices. 101#define OBP_INT_LEVEL_VME 0x40
102
103/* Interrupt level assignment on sun4m:
104 *
105 * level source
106 * ------------------------------------------------------------
107 * 1 softint-1
108 * 2 softint-2, VME/SBUS level 1
109 * 3 softint-3, VME/SBUS level 2
110 * 4 softint-4, onboard SCSI
111 * 5 softint-5, VME/SBUS level 3
112 * 6 softint-6, onboard ETHERNET
113 * 7 softint-7, VME/SBUS level 4
114 * 8 softint-8, onboard VIDEO
115 * 9 softint-9, VME/SBUS level 5, Module Interrupt
116 * 10 softint-10, system counter/timer
117 * 11 softint-11, VME/SBUS level 6, Floppy
118 * 12 softint-12, Keyboard/Mouse, Serial
119 * 13 softint-13, VME/SBUS level 7, ISDN Audio
120 * 14 softint-14, per-processor counter/timer
121 * 15 softint-15, Asynchronous Errors (broadcast)
125 * 122 *
126 * take an encoded intr value and lookup if it's valid 123 * Each interrupt source is masked distinctly in the sun4m interrupt
127 * then get the mask bits that match from irq_mask 124 * registers. The PIL level alone is therefore ambiguous, since multiple
125 * interrupt sources map to a single PIL.
128 * 126 *
129 * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 127 * This ambiguity is resolved in the 'intr' property for device nodes
128 * in the OF device tree. Each 'intr' property entry is composed of
129 * two 32-bit words. The first word is the IRQ priority value, which
130 * is what we're intersted in. The second word is the IRQ vector, which
131 * is unused.
132 *
133 * The low 4 bits of the IRQ priority indicate the PIL, and the upper
134 * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20
135 * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
136 *
137 * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
138 * whereas a value of 0x33 is SBUS level 2. Here are some sample
139 * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
140 * Tadpole S3 GX systems.
141 *
142 * esp: 0x24 onboard ESP SCSI
143 * le: 0x26 onboard Lance ETHERNET
144 * p9100: 0x32 SBUS level 1 P9100 video
145 * bpp: 0x33 SBUS level 2 BPP parallel port device
146 * DBRI: 0x39 SBUS level 5 DBRI ISDN audio
147 * SUNW,leo: 0x39 SBUS level 5 LEO video
148 * pcmcia: 0x3b SBUS level 6 PCMCIA controller
149 * uctrl: 0x3b SBUS level 6 UCTRL device
150 * modem: 0x3d SBUS level 7 MODEM
151 * zs: 0x2c onboard keyboard/mouse/serial
152 * floppy: 0x2b onboard Floppy
153 * power: 0x22 onboard power device (XXX unknown mask bit XXX)
130 */ 154 */
131static unsigned char irq_xlate[32] = {
132 /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
133 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
134 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
135};
136 155
137static unsigned long irq_mask[] = { 156static unsigned long irq_mask[0x50] = {
138 0, /* illegal index */ 157 /* SMP */
139 SUN4M_INT_SCSI, /* 1 irq 4 */ 158 0, SUN4M_SOFT_INT(1),
140 SUN4M_INT_ETHERNET, /* 2 irq 6 */ 159 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
141 SUN4M_INT_VIDEO, /* 3 irq 8 */ 160 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
142 SUN4M_INT_REALTIME, /* 4 irq 10 */ 161 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
143 SUN4M_INT_FLOPPY, /* 5 irq 11 */ 162 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
144 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 163 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
145 SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 164 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
146 SUN4M_INT_SBUS(0), /* 8 irq 2 */ 165 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
147 SUN4M_INT_SBUS(1), /* 9 irq 3 */ 166 /* soft */
148 SUN4M_INT_SBUS(2), /* 10 irq 5 */ 167 0, SUN4M_SOFT_INT(1),
149 SUN4M_INT_SBUS(3), /* 11 irq 7 */ 168 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
150 SUN4M_INT_SBUS(4), /* 12 irq 9 */ 169 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
151 SUN4M_INT_SBUS(5), /* 13 irq 11 */ 170 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
152 SUN4M_INT_SBUS(6) /* 14 irq 13 */ 171 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
172 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
173 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
174 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
175 /* onboard */
176 0, 0, 0, 0,
177 SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
178 SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
179 SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
180 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
181 SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
182 /* sbus */
183 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
184 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
185 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
186 0, SUN4M_INT_SBUS(6), 0, 0,
187 /* vme */
188 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
189 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
190 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
191 0, SUN4M_INT_VME(6), 0, 0
153}; 192};
154 193
155static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
156
157static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
158 unsigned int sbint)
159{
160 if (sbint >= sizeof(sun4m_pil_map)) {
161 printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
162 BUG();
163 }
164 return sun4m_pil_map[sbint] | 0x30;
165}
166
167static unsigned long sun4m_get_irqmask(unsigned int irq) 194static unsigned long sun4m_get_irqmask(unsigned int irq)
168{ 195{
169 unsigned long mask; 196 unsigned long mask;
170 197
171 if (irq > 0x20) { 198 if (irq < 0x50)
172 /* OBIO/SBUS interrupts */ 199 mask = irq_mask[irq];
173 irq &= 0x1f; 200 else
174 mask = irq_mask[irq_xlate[irq]]; 201 mask = 0;
175 if (!mask) 202
176 printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 203 if (!mask)
177 } else { 204 printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
178 /* Soft Interrupts will come here. 205 irq);
179 * Currently there is no way to trigger them but I'm sure 206
180 * something could be cooked up.
181 */
182 irq &= 0xf;
183 mask = SUN4M_SOFT_INT(irq);
184 }
185 return mask; 207 return mask;
186} 208}
187 209
@@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
193 mask = sun4m_get_irqmask(irq_nr); 215 mask = sun4m_get_irqmask(irq_nr);
194 local_irq_save(flags); 216 local_irq_save(flags);
195 if (irq_nr > 15) 217 if (irq_nr > 15)
196 sun4m_interrupts->set = mask; 218 sbus_writel(mask, &sun4m_irq_global->mask_set);
197 else 219 else
198 sun4m_interrupts->cpu_intregs[cpu].set = mask; 220 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
199 local_irq_restore(flags); 221 local_irq_restore(flags);
200} 222}
201 223
@@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
212 mask = sun4m_get_irqmask(irq_nr); 234 mask = sun4m_get_irqmask(irq_nr);
213 local_irq_save(flags); 235 local_irq_save(flags);
214 if (irq_nr > 15) 236 if (irq_nr > 15)
215 sun4m_interrupts->clear = mask; 237 sbus_writel(mask, &sun4m_irq_global->mask_clear);
216 else 238 else
217 sun4m_interrupts->cpu_intregs[cpu].clear = mask; 239 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
218 local_irq_restore(flags); 240 local_irq_restore(flags);
219 } else { 241 } else {
220 local_irq_save(flags); 242 local_irq_save(flags);
221 sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 243 sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
222 local_irq_restore(flags); 244 local_irq_restore(flags);
223 } 245 }
224} 246}
@@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
236/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 258/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
237/*10*/ SUN4M_INT_REALTIME, 259/*10*/ SUN4M_INT_REALTIME,
238/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 260/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
239/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 261/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
240/*13*/ SUN4M_INT_AUDIO, 262/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
241/*14*/ SUN4M_INT_E14, 263/*14*/ SUN4M_INT_E14,
242/*15*/ 0x00000000 264/*15*/ SUN4M_INT_ERROR
243}; 265};
244 266
245/* We assume the caller has disabled local interrupts when these are called, 267/* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = {
247 */ 269 */
248static void sun4m_disable_pil_irq(unsigned int pil) 270static void sun4m_disable_pil_irq(unsigned int pil)
249{ 271{
250 sun4m_interrupts->set = cpu_pil_to_imask[pil]; 272 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
251} 273}
252 274
253static void sun4m_enable_pil_irq(unsigned int pil) 275static void sun4m_enable_pil_irq(unsigned int pil)
254{ 276{
255 sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 277 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
256} 278}
257 279
258#ifdef CONFIG_SMP 280#ifdef CONFIG_SMP
259static void sun4m_send_ipi(int cpu, int level) 281static void sun4m_send_ipi(int cpu, int level)
260{ 282{
261 unsigned long mask; 283 unsigned long mask = sun4m_get_irqmask(level);
262 284 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
263 mask = sun4m_get_irqmask(level);
264 sun4m_interrupts->cpu_intregs[cpu].set = mask;
265} 285}
266 286
267static void sun4m_clear_ipi(int cpu, int level) 287static void sun4m_clear_ipi(int cpu, int level)
268{ 288{
269 unsigned long mask; 289 unsigned long mask = sun4m_get_irqmask(level);
270 290 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
271 mask = sun4m_get_irqmask(level);
272 sun4m_interrupts->cpu_intregs[cpu].clear = mask;
273} 291}
274 292
275static void sun4m_set_udt(int cpu) 293static void sun4m_set_udt(int cpu)
276{ 294{
277 sun4m_interrupts->undirected_target = cpu; 295 sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
278} 296}
279#endif 297#endif
280 298
281#define OBIO_INTR 0x20 299struct sun4m_timer_percpu {
282#define TIMER_IRQ (OBIO_INTR | 10) 300 u32 l14_limit;
283#define PROFILE_IRQ (OBIO_INTR | 14) 301 u32 l14_count;
302 u32 l14_limit_noclear;
303 u32 user_timer_start_stop;
304};
305
306static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
307
308struct sun4m_timer_global {
309 u32 l10_limit;
310 u32 l10_count;
311 u32 l10_limit_noclear;
312 u32 reserved;
313 u32 timer_config;
314};
315
316static struct sun4m_timer_global __iomem *timers_global;
317
318#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
284 319
285static struct sun4m_timer_regs *sun4m_timers;
286unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 320unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
287 321
288static void sun4m_clear_clock_irq(void) 322static void sun4m_clear_clock_irq(void)
289{ 323{
290 volatile unsigned int clear_intr; 324 sbus_readl(&timers_global->l10_limit);
291 clear_intr = sun4m_timers->l10_timer_limit;
292} 325}
293 326
294static void sun4m_clear_profile_irq(int cpu) 327void sun4m_nmi(struct pt_regs *regs)
295{ 328{
296 volatile unsigned int clear; 329 unsigned long afsr, afar, si;
297 330
298 clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; 331 printk(KERN_ERR "Aieee: sun4m NMI received!\n");
332 /* XXX HyperSparc hack XXX */
333 __asm__ __volatile__("mov 0x500, %%g1\n\t"
334 "lda [%%g1] 0x4, %0\n\t"
335 "mov 0x600, %%g1\n\t"
336 "lda [%%g1] 0x4, %1\n\t" :
337 "=r" (afsr), "=r" (afar));
338 printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
339 si = sbus_readl(&sun4m_irq_global->pending);
340 printk(KERN_ERR "si=%08lx\n", si);
341 if (si & SUN4M_INT_MODULE_ERR)
342 printk(KERN_ERR "Module async error\n");
343 if (si & SUN4M_INT_M2S_WRITE_ERR)
344 printk(KERN_ERR "MBus/SBus async error\n");
345 if (si & SUN4M_INT_ECC_ERR)
346 printk(KERN_ERR "ECC memory error\n");
347 if (si & SUN4M_INT_VME_ERR)
348 printk(KERN_ERR "VME async error\n");
349 printk(KERN_ERR "you lose buddy boy...\n");
350 show_regs(regs);
351 prom_halt();
352}
353
354/* Exported for sun4m_smp.c */
355void sun4m_clear_profile_irq(int cpu)
356{
357 sbus_readl(&timers_percpu[cpu]->l14_limit);
299} 358}
300 359
301static void sun4m_load_profile_irq(int cpu, unsigned int limit) 360static void sun4m_load_profile_irq(int cpu, unsigned int limit)
302{ 361{
303 sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; 362 sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
304} 363}
305 364
306static void __init sun4m_init_timers(irq_handler_t counter_fn) 365static void __init sun4m_init_timers(irq_handler_t counter_fn)
307{ 366{
308 int reg_count, irq, cpu; 367 struct device_node *dp = of_find_node_by_name(NULL, "counter");
309 struct linux_prom_registers cnt_regs[PROMREG_MAX]; 368 int i, err, len, num_cpu_timers;
310 int obio_node, cnt_node; 369 const u32 *addr;
311 struct resource r; 370
312 371 if (!dp) {
313 cnt_node = 0; 372 printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
314 if((obio_node = 373 return;
315 prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
316 (obio_node = prom_getchild (obio_node)) == 0 ||
317 (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
318 prom_printf("Cannot find /obio/counter node\n");
319 prom_halt();
320 } 374 }
321 reg_count = prom_getproperty(cnt_node, "reg", 375
322 (void *) cnt_regs, sizeof(cnt_regs)); 376 addr = of_get_property(dp, "address", &len);
323 reg_count = (reg_count/sizeof(struct linux_prom_registers)); 377 if (!addr) {
324 378 printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
325 /* Apply the obio ranges to the timer registers. */ 379 return;
326 prom_apply_obio_ranges(cnt_regs, reg_count);
327
328 cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
329 cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
330 cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
331 for(obio_node = 1; obio_node < 4; obio_node++) {
332 cnt_regs[obio_node].phys_addr =
333 cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
334 cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
335 cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
336 } 380 }
337 381
338 memset((char*)&r, 0, sizeof(struct resource)); 382 num_cpu_timers = (len / sizeof(u32)) - 1;
339 /* Map the per-cpu Counter registers. */ 383 for (i = 0; i < num_cpu_timers; i++) {
340 r.flags = cnt_regs[0].which_io; 384 timers_percpu[i] = (void __iomem *)
341 r.start = cnt_regs[0].phys_addr; 385 (unsigned long) addr[i];
342 sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
343 PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
344 /* Map the system Counter register. */
345 /* XXX Here we expect consequent calls to yeld adjusent maps. */
346 r.flags = cnt_regs[4].which_io;
347 r.start = cnt_regs[4].phys_addr;
348 sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
349
350 sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
351 master_l10_counter = &sun4m_timers->l10_cur_count;
352 master_l10_limit = &sun4m_timers->l10_timer_limit;
353
354 irq = request_irq(TIMER_IRQ,
355 counter_fn,
356 (IRQF_DISABLED | SA_STATIC_ALLOC),
357 "timer", NULL);
358 if (irq) {
359 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
360 prom_halt();
361 } 386 }
362 387 timers_global = (void __iomem *)
363 if (!cpu_find_by_instance(1, NULL, NULL)) { 388 (unsigned long) addr[num_cpu_timers];
364 for(cpu = 0; cpu < 4; cpu++) 389
365 sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; 390 sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
366 sun4m_interrupts->set = SUN4M_INT_E14; 391
367 } else { 392 master_l10_counter = &timers_global->l10_count;
368 sun4m_timers->cpu_timers[0].l14_timer_limit = 0; 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;
369 } 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
370#ifdef CONFIG_SMP 407#ifdef CONFIG_SMP
371 { 408 {
372 unsigned long flags; 409 unsigned long flags;
@@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
390 427
391void __init sun4m_init_IRQ(void) 428void __init sun4m_init_IRQ(void)
392{ 429{
393 int ie_node,i; 430 struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
394 struct linux_prom_registers int_regs[PROMREG_MAX]; 431 int len, i, mid, num_cpu_iregs;
395 int num_regs; 432 const u32 *addr;
396 struct resource r; 433
397 int mid; 434 if (!dp) {
398 435 printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
399 local_irq_disable(); 436 return;
400 if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
401 (ie_node = prom_getchild (ie_node)) == 0 ||
402 (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
403 prom_printf("Cannot find /obio/interrupt node\n");
404 prom_halt();
405 } 437 }
406 num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 438
407 sizeof(int_regs)); 439 addr = of_get_property(dp, "address", &len);
408 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 440 if (!addr) {
409 441 printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
410 /* Apply the obio ranges to these registers. */ 442 return;
411 prom_apply_obio_ranges(int_regs, num_regs);
412
413 int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
414 int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
415 int_regs[4].which_io = int_regs[num_regs-1].which_io;
416 for(ie_node = 1; ie_node < 4; ie_node++) {
417 int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
418 int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
419 int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
420 } 443 }
421 444
422 memset((char *)&r, 0, sizeof(struct resource)); 445 num_cpu_iregs = (len / sizeof(u32)) - 1;
423 /* Map the interrupt registers for all possible cpus. */ 446 for (i = 0; i < num_cpu_iregs; i++) {
424 r.flags = int_regs[0].which_io; 447 sun4m_irq_percpu[i] = (void __iomem *)
425 r.start = int_regs[0].phys_addr; 448 (unsigned long) addr[i];
426 sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, 449 }
427 PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 450 sun4m_irq_global = (void __iomem *)
451 (unsigned long) addr[num_cpu_iregs];
428 452
429 /* Map the system interrupt control registers. */ 453 local_irq_disable();
430 r.flags = int_regs[4].which_io;
431 r.start = int_regs[4].phys_addr;
432 sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
433 454
434 sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 455 sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
435 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 456 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
436 sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 457 sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
437 458
438 if (!cpu_find_by_instance(1, NULL, NULL)) { 459 if (num_cpu_iregs == 4)
439 /* system wide interrupts go to cpu 0, this should always 460 sbus_writel(0, &sun4m_irq_global->interrupt_target);
440 * be safe because it is guaranteed to be fitted or OBP doesn't 461
441 * come up
442 *
443 * Not sure, but writing here on SLAVIO systems may puke
444 * so I don't do it unless there is more than 1 cpu.
445 */
446 irq_rcvreg = (unsigned long *)
447 &sun4m_interrupts->undirected_target;
448 sun4m_interrupts->undirected_target = 0;
449 }
450 BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
451 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 462 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
452 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 463 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
453 BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 464 BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
454 BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 465 BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
455 BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 466 BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
456 BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
457 BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 467 BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
458 sparc_init_timers = sun4m_init_timers; 468 sparc_init_timers = sun4m_init_timers;
459#ifdef CONFIG_SMP 469#ifdef CONFIG_SMP
@@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void)
461 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 471 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
462 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 472 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
463#endif 473#endif
474
464 /* Cannot enable interrupts until OBP ticker is disabled. */ 475 /* Cannot enable interrupts until OBP ticker is disabled. */
465} 476}