struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
struct sun4m_irq_global __iomem *sun4m_irq_global;
-static unsigned long dummy;
-unsigned long *irq_rcvreg = &dummy;
-
/* Dave Redman (djhr@tadpole.co.uk)
* The sun4m interrupt registers.
*/
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
-#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
-#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
+#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
+#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */
+#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
+#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */
+
+#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
+ SUN4M_INT_M2S_WRITE_ERR | \
+ SUN4M_INT_ECC_ERR | \
+ SUN4M_INT_VME_ERR)
#define SUN4M_INT_SBUS(x) (1 << (x+7))
#define SUN4M_INT_VME(x) (1 << (x))
-/* These tables only apply for interrupts greater than 15..
- *
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define OBP_INT_LEVEL_SOFT 0x10
+#define OBP_INT_LEVEL_ONBOARD 0x20
+#define OBP_INT_LEVEL_SBUS 0x30
+#define OBP_INT_LEVEL_VME 0x40
+
+/* Interrupt level assignment on sun4m:
+ *
+ * level source
+ * ------------------------------------------------------------
+ * 1 softint-1
+ * 2 softint-2, VME/SBUS level 1
+ * 3 softint-3, VME/SBUS level 2
+ * 4 softint-4, onboard SCSI
+ * 5 softint-5, VME/SBUS level 3
+ * 6 softint-6, onboard ETHERNET
+ * 7 softint-7, VME/SBUS level 4
+ * 8 softint-8, onboard VIDEO
+ * 9 softint-9, VME/SBUS level 5, Module Interrupt
+ * 10 softint-10, system counter/timer
+ * 11 softint-11, VME/SBUS level 6, Floppy
+ * 12 softint-12, Keyboard/Mouse, Serial
+ * 13 softint-13, VME/SBUS level 7, ISDN Audio
+ * 14 softint-14, per-processor counter/timer
+ * 15 softint-15, Asynchronous Errors (broadcast)
+ *
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers. The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
*
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree. Each 'intr' property entry is composed of
+ * two 32-bit words. The first word is the IRQ priority value, which
+ * is what we're intersted in. The second word is the IRQ vector, which
+ * is unused.
*
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2. Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp: 0x24 onboard ESP SCSI
+ * le: 0x26 onboard Lance ETHERNET
+ * p9100: 0x32 SBUS level 1 P9100 video
+ * bpp: 0x33 SBUS level 2 BPP parallel port device
+ * DBRI: 0x39 SBUS level 5 DBRI ISDN audio
+ * SUNW,leo: 0x39 SBUS level 5 LEO video
+ * pcmcia: 0x3b SBUS level 6 PCMCIA controller
+ * uctrl: 0x3b SBUS level 6 UCTRL device
+ * modem: 0x3d SBUS level 7 MODEM
+ * zs: 0x2c onboard keyboard/mouse/serial
+ * floppy: 0x2b onboard Floppy
+ * power: 0x22 onboard power device (XXX unknown mask bit XXX)
*/
-static unsigned char irq_xlate[32] = {
- /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
- 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
- 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
-};
-static unsigned long irq_mask[] = {
- 0, /* illegal index */
- SUN4M_INT_SCSI, /* 1 irq 4 */
- SUN4M_INT_ETHERNET, /* 2 irq 6 */
- SUN4M_INT_VIDEO, /* 3 irq 8 */
- SUN4M_INT_REALTIME, /* 4 irq 10 */
- SUN4M_INT_FLOPPY, /* 5 irq 11 */
- (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */
- SUN4M_INT_MODULE_ERR, /* 7 irq 15 */
- SUN4M_INT_SBUS(0), /* 8 irq 2 */
- SUN4M_INT_SBUS(1), /* 9 irq 3 */
- SUN4M_INT_SBUS(2), /* 10 irq 5 */
- SUN4M_INT_SBUS(3), /* 11 irq 7 */
- SUN4M_INT_SBUS(4), /* 12 irq 9 */
- SUN4M_INT_SBUS(5), /* 13 irq 11 */
- SUN4M_INT_SBUS(6) /* 14 irq 13 */
+static unsigned long irq_mask[0x50] = {
+ /* SMP */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* soft */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* onboard */
+ 0, 0, 0, 0,
+ SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
+ SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+ SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+ (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+ SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+ /* sbus */
+ 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+ 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+ 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+ 0, SUN4M_INT_SBUS(6), 0, 0,
+ /* vme */
+ 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+ 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+ 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+ 0, SUN4M_INT_VME(6), 0, 0
};
static unsigned long sun4m_get_irqmask(unsigned int irq)
{
unsigned long mask;
- if (irq > 0x20) {
- /* OBIO/SBUS interrupts */
- irq &= 0x1f;
- mask = irq_mask[irq_xlate[irq]];
- if (!mask)
- printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
- } else {
- /* Soft Interrupts will come here.
- * Currently there is no way to trigger them but I'm sure
- * something could be cooked up.
- */
- irq &= 0xf;
- mask = SUN4M_SOFT_INT(irq);
- }
+ if (irq < 0x50)
+ mask = irq_mask[irq];
+ else
+ mask = 0;
+
+ if (!mask)
+ printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+ irq);
+
return mask;
}
/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
/*10*/ SUN4M_INT_REALTIME,
/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
/*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
};
/* We assume the caller has disabled local interrupts when these are called,
static struct sun4m_timer_global __iomem *timers_global;
-#define OBIO_INTR 0x20
-#define TIMER_IRQ (OBIO_INTR | 10)
+#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
sbus_readl(&timers_global->l10_limit);
}
+void sun4m_nmi(struct pt_regs *regs)
+{
+ unsigned long afsr, afar, si;
+
+ printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+ /* XXX HyperSparc hack XXX */
+ __asm__ __volatile__("mov 0x500, %%g1\n\t"
+ "lda [%%g1] 0x4, %0\n\t"
+ "mov 0x600, %%g1\n\t"
+ "lda [%%g1] 0x4, %1\n\t" :
+ "=r" (afsr), "=r" (afar));
+ printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+ si = sbus_readl(&sun4m_irq_global->pending);
+ printk(KERN_ERR "si=%08lx\n", si);
+ if (si & SUN4M_INT_MODULE_ERR)
+ printk(KERN_ERR "Module async error\n");
+ if (si & SUN4M_INT_M2S_WRITE_ERR)
+ printk(KERN_ERR "MBus/SBus async error\n");
+ if (si & SUN4M_INT_ECC_ERR)
+ printk(KERN_ERR "ECC memory error\n");
+ if (si & SUN4M_INT_VME_ERR)
+ printk(KERN_ERR "VME async error\n");
+ printk(KERN_ERR "you lose buddy boy...\n");
+ show_regs(regs);
+ prom_halt();
+}
+
/* Exported for sun4m_smp.c */
void sun4m_clear_profile_irq(int cpu)
{
}
addr = of_get_property(dp, "address", &len);
+ of_node_put(dp);
if (!addr) {
printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
return;
sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
master_l10_counter = &timers_global->l10_count;
- master_l10_limit = &timers_global->l10_limit;
err = request_irq(TIMER_IRQ, counter_fn,
(IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
}
addr = of_get_property(dp, "address", &len);
+ of_node_put(dp);
if (!addr) {
printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
return;
for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
- if (num_cpu_iregs == 4) {
- irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target;
+ if (num_cpu_iregs == 4)
sbus_writel(0, &sun4m_irq_global->interrupt_target);
- }
+
BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);