Subject: trap.c rework
To: None <port-mips@netbsd.org>
From: Toru Nishimura <nisimura@itc.aist-nara.ac.jp>
List: port-mips
Date: 03/31/2000 14:34:05
Hello, MIPS guys

I have a change proposal of MIPS common code for how interrupt service
is dispatched; to take interrupt() routine out of MIPS common trap.c.
Instead, routine provided by the target port is called straightly.
This change would eliminate complicate adjustments done in
<machine/intr.h>, and provide saner logics to use peculiar to target
hardware.

-- proposal --

Every MIPS port provides following interrupt service routine to be
called by MIPS common code.

void
cpu_intr(status, cause, pc, ipending)
        u_int32_t status;       /* STATUS */
        u_int32_t cause;        /* CAUSE */
        u_int32_t pc;           /* EPC */
        u_int32_t ipending;     /* CAUSE & STATUS */

And, <machine/intr.h> is expected to have as follows;

/*
 * software simulated interrupt
 */
extern unsigned ssir;
#define SIR_NET         0x1

#define setsoftnet()    setsoft(SIR_NET)
#define setsoft(x) \
        do { ssir |= (x); _setsoftintr(MIPS_SOFT_INT_MASK_1); } while (0)
 
#define setsoftclock()  _setsoftintr(MIPS_SOFT_INT_MASK_0) 


Here go sample code fragments to show the impact of this proposal.

void
cobalt_intr(status, cause, pc, ipending)
	u_int32_t status;
	u_int32_t cause;
	u_int32_t pc;
	u_int32_t ipending;
{
	struct clockframe cf;
	static u_int32_t cycles;
	int s;

	uvmexp.intrs++;

	/* XXX Reverse hardlock and statclock? */
#define TICK_CYCLES 1250000			/* XXX 250 MHz XXX */
	if (ipending & MIPS_INT_MASK_5) {
		cycles = mips3_cycle_count();
		mips3_write_compare(cycles + TICK_CYCLES);

		cf.pc = pc;
		cf.sr = status;

		s = splstatclock();	/* XXX redo interrupts XXX */
		statclock(&cf);
		splx(s);		/* XXX redo interrupts XXX */

		cause &= ~MIPS_INT_MASK_5;
	}
	if (ipending & MIPS_INT_MASK_4) {
		iointr(ipending, &cf);
		cause &= ~MIPS_INT_MASK_4;
	}
	if (ipending & MIPS_INT_MASK_3) {
		s = spltty();		/* XXX redo interrupts XXX */
		comintr(com0);
		splx(s);		/* XXX redo interrupts XXX */
		cause &= ~MIPS_INT_MASK_3;
	}
	if (ipending & MIPS_INT_MASK_1) {
		s = splnet();		/* XXX redo interrupts XXX */
		tlp_intr(tlp0);
		splx(s);		/* XXX redo interrupts XXX */
		cause &= ~MIPS_INT_MASK_1;
	}
	if (ipending & MIPS_INT_MASK_2) {
		s = splnet();		/* XXX redo interrupts XXX */
		tlp_intr(tlp1);
		splx(s);		/* XXX redo interrupts XXX */
		cause &= ~MIPS_INT_MASK_1;
		cause &= ~MIPS_INT_MASK_2;
	}
	if (ipending & MIPS_INT_MASK_0) {
		volatile u_int32_t *irq_src =
				(u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c18);

		if (*irq_src & 0x00000100) {
			*irq_src = 0;

			cf.pc = pc;
			cf.sr = status;

			s = splclock();	/* XXX redo interrupts XXX */
			hardclock(&cf);
			splx(s);	/* XXX redo interrupts XXX */
		}
		cause &= ~MIPS_INT_MASK_0;
	}
	_splset ((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);

	/* software simulated interrupt */
	if ((ipending & MIPS_SOFT_INT_MASK_1)
		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {

#define DO_SIR(bit, fn)						\
	do {							\
		if (n & (bit)) {				\
			uvmexp.softs++;				\
			fn;					\
		}						\
	} while (0)

		unsigned n;
		n = ssir; ssir = 0;
		_clrsoftintr(MIPS_SOFT_INT_MASK_1);

		DO_SIR(SIR_NET, netintr());
#undef DO_SIR
	}

	/* 'softclock' interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_0) {
		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
		uvmexp.softs++;
		intrcnt[SOFTCLOCK_INTR]++;
		softclock();
	}
}

void
arc_intr(status, cause, pc, ipending)
	u_int32_t status;
	u_int32_t cause;
	u_int32_t pc;
	u_int32_t ipending;
{
	struct clockframe cf;
	static u_int32_t cycles;
	int i;

	uvmexp.intrs++;

#define TICK_CYCLES 0 /* ??? */
	if (ipending & MIPS_INT_MASK_5) {
		cycles = mips3_cycle_count();
		mips3_write_compare(cycles + TICK_CYCLES);
	}
	cf.pc = pc;
	cf.sr = status;

	/*
	 *  Check off all enabled interrupts. Called interrupt routine
	 *  returns mask of interrupts to reenable.
	 */
	for (i = 0; i < MIPS_INT_LEVELS; i++) {
		if (cpu_int_tab[i].int_mask & ipending) {
			cause &= (*cpu_int_tab[i].int_hand)(ipending, &cf);
		}
	}
	_splset((status & ~cause & MIPS3_HARD_INT_MASK) | MIPS_SR_INT_IE);

	/* software simulated interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_1)
		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {

#define DO_SIR(bit, fn)						\
	do {							\
		if (n & (bit)) {				\
			uvmexp.softs++;				\
			fn;					\
		}						\
	} while (0)

		unsigned n;
		n = ssir; ssir = 0;
		_clrsoftintr(MIPS_SOFT_INT_MASK_1);

		DO_SIR(SIR_NET, netintr());
#undef DO_SIR
	}

	/* 'softclock' interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_0) {
		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
		uvmexp.softs++;
		intrcnt[SOFTCLOCK_INTR]++;
		softclock();
	}
}

void
newsmips_intr(pc, status, cause, ipending)
	u_int32_t status;
	u_int32_t cause;
	u_int32_t pc;
	u_int32_t ipending;
{
#define	INT_MASK_DEV	(MIPS_HARD_INT_MASK &~ MIPS_INT_MASK_3)
#define	INT_MASK_FPU	MIPS_INT_MASK_3

	uvmexp.intrs++;

	/* device interrupts */
	if (ipending & INT_MASK_DEV) {
		(*platform.iointr)(status, cause, pc, ipending);
	}
	/* FPU nofiticaition */
	if (ipending & INT_MASK_FPU) {
		if (!USERMODE(status))
			goto kerneltouchedFPU;
		intrcnt[FPU_INTR]++;
		/* dealfpu(status, cause, pc); */
		MachFPInterrupt(status, cause, pc, curproc->p_md.md_regs);
	}
	
	/* software simulated interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_1)
		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {

#define DO_SIR(bit, fn)						\
	do {							\
		if (n & (bit)) {				\
			uvmexp.softs++;				\
			fn;					\
		}						\
	} while (0)

		unsigned n;
		n = ssir; ssir = 0;
		_clrsoftintr(MIPS_SOFT_INT_MASK_1);

		DO_SIR(SIR_NET, netintr());
#undef DO_SIR
	}

	/* 'softclock' interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_0) {
		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
		uvmexp.softs++;
		intrcnt[SOFTCLOCK_INTR]++;
		softclock();
	}
}

void
pmax_intr(status, cause, pc, ipending)
	u_int32_t status;
	u_int32_t cause;
	u_int32_t pc;
	u_int32_t ipending;
{
#define	INT_MASK_DEV	(MIPS_HARD_INT_MASK &~ MIPS_INT_MASK_5)
#define	INT_MASK_FPU	MIPS_INT_MASK_5

	uvmexp.intrs++;

	/* device interrupts */
	if (ipending & INT_MASK_DEV) {
		(*platform.iointr)(status, cause, pc, ipending);
	}
	/* FPU nofiticaition */
	if (ipending & INT_MASK_FPU) {
		if (!USERMODE(status))
			goto kerneltouchedFPU;
		intrcnt[FPU_INTR]++;
		/* dealfpu(status, cause, pc); */
		MachFPInterrupt(status, cause, pc, curproc->p_md.md_regs);
	}

	/* software simulated interrupt */
	if ((ipending & MIPS_SOFT_INT_MASK_1)
		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {

#define DO_SIR(bit, fn)						\
	do {							\
		if (n & (bit)) {				\
			uvmexp.softs++;				\
			fn;					\
		}						\
	} while (0)

		unsigned n;
		n = ssir; ssir = 0;
		_clrsoftintr(MIPS_SOFT_INT_MASK_1);

		DO_SIR(SIR_NET, netintr());
#undef DO_SIR
	}

	/* 'softclock' interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_0) {
		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
		uvmexp.softs++;
		intrcnt[SOFTCLOCK_INTR]++;
		softclock();
	}
	return;

kerneltouchedFPU:
	panic("kernel used FPU: PC %x, CR %x, SR %x", pc, cause, status);
}

void
hpcmips_intr(status, cause, pc, ipending)
	u_int32_t status;
	u_int32_t cause;
	u_int32_t pc;
	u_int32_t ipending;
{

	uvmexp.intrs++;

	/* device interrupts */
	(*platform.iointr)(status, cause, pc, ipending);

	/* software simulated interrupt */
	if ((ipending & MIPS_SOFT_INT_MASK_1)
		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {

#define DO_SIR(bit, fn)					\
do {							\
	if (n & (bit)) {				\
		uvmexp.softs++;				\
		fn;					\
	}						\
} while (0)

		unsigned n;
		n = ssir; ssir = 0;
		_clrsoftintr(MIPS_SOFT_INT_MASK_1);

		DO_SIR(SIR_NET, netintr());
#undef DO_SIR
	}

	/* 'softclock' interrupt */
	if (ipending & MIPS_SOFT_INT_MASK_0) {
		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
		uvmexp.softs++;
		intrcnt[SOFTCLOCK_INTR]++;
		softclock();
	}
	return;
}
--