aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/sun4m_irq.c
diff options
context:
space:
mode:
authorRobert Reif <reif@earthlink.net>2008-10-07 18:24:02 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-07 18:24:02 -0400
commit6cf4a9243a7fea75e7fd6f2e1ba6fb01c805e056 (patch)
tree027e8c3244e78581d0c76376cc44d8ad28086180 /arch/sparc/kernel/sun4m_irq.c
parent5ec877083c2c4f9e2f710dc6480dc76c27cb6f55 (diff)
sparc32: sun4m interrupt mask cleanup
Here is an updated version of a patch I wrote 6 years ago http://marc.info/?l=linux-sparc&m=103939103607617&w=2 that simplifies interrupt mask lookup. It's main purpose is to add VME bus support but it's really a cleanup of the mask code. Signed-off-by: Robert Reif <reif@earthlink.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/sun4m_irq.c')
-rw-r--r--arch/sparc/kernel/sun4m_irq.c145
1 files changed, 91 insertions, 54 deletions
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index ec66d4aab098..f10317179ee6 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -71,8 +71,9 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
71 71
72#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 72#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
73#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 73#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
74#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ 74#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
75#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 */
76#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 77#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
77#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 78#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
78#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 79#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
@@ -83,10 +84,22 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
83#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 84#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
84#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 85#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
85#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)
86 93
87#define SUN4M_INT_SBUS(x) (1 << (x+7)) 94#define SUN4M_INT_SBUS(x) (1 << (x+7))
88#define SUN4M_INT_VME(x) (1 << (x)) 95#define SUN4M_INT_VME(x) (1 << (x))
89 96
97/* Interrupt levels used by OBP */
98#define OBP_INT_LEVEL_SOFT 0x10
99#define OBP_INT_LEVEL_ONBOARD 0x20
100#define OBP_INT_LEVEL_SBUS 0x30
101#define OBP_INT_LEVEL_VME 0x40
102
90/* Interrupt level assignment on sun4m: 103/* Interrupt level assignment on sun4m:
91 * 104 *
92 * level source 105 * level source
@@ -140,59 +153,57 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
140 * power: 0x22 onboard power device (XXX unknown mask bit XXX) 153 * power: 0x22 onboard power device (XXX unknown mask bit XXX)
141 */ 154 */
142 155
143/* These tables only apply for interrupts greater than 15.. 156static unsigned long irq_mask[0x50] = {
144 * 157 /* SMP */
145 * any intr value below 0x10 is considered to be a soft-int 158 0, SUN4M_SOFT_INT(1),
146 * this may be useful or it may not.. but that's how I've done it. 159 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
147 * and it won't clash with what OBP is telling us about devices. 160 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
148 * 161 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
149 * take an encoded intr value and lookup if it's valid 162 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
150 * then get the mask bits that match from irq_mask 163 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
151 * 164 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
152 * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 165 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
153 */ 166 /* soft */
154static unsigned char irq_xlate[32] = { 167 0, SUN4M_SOFT_INT(1),
155 /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 168 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
156 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 169 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
157 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 170 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
158}; 171 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
159 172 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
160static unsigned long irq_mask[] = { 173 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
161 0, /* illegal index */ 174 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
162 SUN4M_INT_SCSI, /* 1 irq 4 */ 175 /* onboard */
163 SUN4M_INT_ETHERNET, /* 2 irq 6 */ 176 0, 0, 0, 0,
164 SUN4M_INT_VIDEO, /* 3 irq 8 */ 177 SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
165 SUN4M_INT_REALTIME, /* 4 irq 10 */ 178 SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
166 SUN4M_INT_FLOPPY, /* 5 irq 11 */ 179 SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
167 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 180 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
168 SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 181 SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
169 SUN4M_INT_SBUS(0), /* 8 irq 2 */ 182 /* sbus */
170 SUN4M_INT_SBUS(1), /* 9 irq 3 */ 183 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
171 SUN4M_INT_SBUS(2), /* 10 irq 5 */ 184 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
172 SUN4M_INT_SBUS(3), /* 11 irq 7 */ 185 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
173 SUN4M_INT_SBUS(4), /* 12 irq 9 */ 186 0, SUN4M_INT_SBUS(6), 0, 0,
174 SUN4M_INT_SBUS(5), /* 13 irq 11 */ 187 /* vme */
175 SUN4M_INT_SBUS(6) /* 14 irq 13 */ 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
176}; 192};
177 193
178static unsigned long sun4m_get_irqmask(unsigned int irq) 194static unsigned long sun4m_get_irqmask(unsigned int irq)
179{ 195{
180 unsigned long mask; 196 unsigned long mask;
181 197
182 if (irq > 0x20) { 198 if (irq < 0x50)
183 /* OBIO/SBUS interrupts */ 199 mask = irq_mask[irq];
184 irq &= 0x1f; 200 else
185 mask = irq_mask[irq_xlate[irq]]; 201 mask = 0;
186 if (!mask) 202
187 printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 203 if (!mask)
188 } else { 204 printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
189 /* Soft Interrupts will come here. 205 irq);
190 * Currently there is no way to trigger them but I'm sure 206
191 * something could be cooked up.
192 */
193 irq &= 0xf;
194 mask = SUN4M_SOFT_INT(irq);
195 }
196 return mask; 207 return mask;
197} 208}
198 209
@@ -247,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
247/*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,
248/*10*/ SUN4M_INT_REALTIME, 259/*10*/ SUN4M_INT_REALTIME,
249/*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,
250/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 261/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
251/*13*/ SUN4M_INT_AUDIO, 262/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
252/*14*/ SUN4M_INT_E14, 263/*14*/ SUN4M_INT_E14,
253/*15*/ 0x00000000 264/*15*/ SUN4M_INT_ERROR
254}; 265};
255 266
256/* 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,
@@ -304,8 +315,7 @@ struct sun4m_timer_global {
304 315
305static struct sun4m_timer_global __iomem *timers_global; 316static struct sun4m_timer_global __iomem *timers_global;
306 317
307#define OBIO_INTR 0x20 318#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
308#define TIMER_IRQ (OBIO_INTR | 10)
309 319
310unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 320unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
311 321
@@ -314,6 +324,33 @@ static void sun4m_clear_clock_irq(void)
314 sbus_readl(&timers_global->l10_limit); 324 sbus_readl(&timers_global->l10_limit);
315} 325}
316 326
327void sun4m_nmi(struct pt_regs *regs)
328{
329 unsigned long afsr, afar, si;
330
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
317/* Exported for sun4m_smp.c */ 354/* Exported for sun4m_smp.c */
318void sun4m_clear_profile_irq(int cpu) 355void sun4m_clear_profile_irq(int cpu)
319{ 356{