Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cf4a924 authored by Robert Reif's avatar Robert Reif Committed by David S. Miller
Browse files

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: default avatarRobert Reif <reif@earthlink.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5ec87708
Loading
Loading
Loading
Loading
+91 −54
Original line number Diff line number Diff line
@@ -71,8 +71,9 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;

#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 */
@@ -83,10 +84,22 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
#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))

/* 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
@@ -140,59 +153,57 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
 * power:	0x22	onboard power device (XXX unknown mask bit XXX)
 */

/* 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.
 *
 * take an encoded intr value and lookup if it's valid
 * then get the mask bits that match from irq_mask
 *
 * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
 */
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 (irq < 0x50)
		mask = irq_mask[irq];
	else
		mask = 0;

	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);
	}
		printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
		       irq);

	return mask;
}

@@ -248,9 +259,9 @@ static unsigned long cpu_pil_to_imask[16] = {
/*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,
/*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,
@@ -304,8 +315,7 @@ struct sun4m_timer_global {

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);

@@ -314,6 +324,33 @@ static void sun4m_clear_clock_irq(void)
	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)
{
+0 −17
Original line number Diff line number Diff line
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs)
{
}

void sun4m_nmi(struct pt_regs *regs)
{
	unsigned long afsr, afar;

	printk("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("afsr=%08lx afar=%08lx\n", afsr, afar);
	printk("you lose buddy boy...\n");
	show_regs(regs);
	prom_halt();
}

void sun4d_nmi(struct pt_regs *regs)
{
	printk("Aieee: sun4d NMI received!\n");