diff options
author | Robert Reif <reif@earthlink.net> | 2008-10-07 18:24:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-07 18:24:02 -0400 |
commit | 6cf4a9243a7fea75e7fd6f2e1ba6fb01c805e056 (patch) | |
tree | 027e8c3244e78581d0c76376cc44d8ad28086180 /arch/sparc | |
parent | 5ec877083c2c4f9e2f710dc6480dc76c27cb6f55 (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')
-rw-r--r-- | arch/sparc/kernel/sun4m_irq.c | 145 | ||||
-rw-r--r-- | arch/sparc/kernel/traps.c | 17 |
2 files changed, 91 insertions, 71 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.. | 156 | static 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 */ |
154 | static 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), | |
160 | static 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 | ||
178 | static unsigned long sun4m_get_irqmask(unsigned int irq) | 194 | static 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 | ||
305 | static struct sun4m_timer_global __iomem *timers_global; | 316 | static 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 | ||
310 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); | 320 | unsigned 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 | ||
327 | void 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 */ |
318 | void sun4m_clear_profile_irq(int cpu) | 355 | void sun4m_clear_profile_irq(int cpu) |
319 | { | 356 | { |
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 5d45d5fd8c99..2b7d50659036 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c | |||
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs) | |||
43 | { | 43 | { |
44 | } | 44 | } |
45 | 45 | ||
46 | void sun4m_nmi(struct pt_regs *regs) | ||
47 | { | ||
48 | unsigned long afsr, afar; | ||
49 | |||
50 | printk("Aieee: sun4m NMI received!\n"); | ||
51 | /* XXX HyperSparc hack XXX */ | ||
52 | __asm__ __volatile__("mov 0x500, %%g1\n\t" | ||
53 | "lda [%%g1] 0x4, %0\n\t" | ||
54 | "mov 0x600, %%g1\n\t" | ||
55 | "lda [%%g1] 0x4, %1\n\t" : | ||
56 | "=r" (afsr), "=r" (afar)); | ||
57 | printk("afsr=%08lx afar=%08lx\n", afsr, afar); | ||
58 | printk("you lose buddy boy...\n"); | ||
59 | show_regs(regs); | ||
60 | prom_halt(); | ||
61 | } | ||
62 | |||
63 | void sun4d_nmi(struct pt_regs *regs) | 46 | void sun4d_nmi(struct pt_regs *regs) |
64 | { | 47 | { |
65 | printk("Aieee: sun4d NMI received!\n"); | 48 | printk("Aieee: sun4d NMI received!\n"); |