Subject: CPU processor personality
To: None <port-mips@netbsd.org>
From: Toru Nishimura <nisimura@itc.aist-nara.ac.jp>
List: port-mips
Date: 04/01/2000 12:56:14
Hello, Folks.

We have 4/1 of year 2000 today, but this is real;

One of my outstanding change in MIPS common area is how to aborb and
reflect various implementation peculiarities differ across MIPS
processors.  As many already know, current approach of arch/mips is
confused at best (and getting uglier than used to be).  Here is my
premature code segments to ease the issue.   I designed this to aborb
all of currently supported MIPS processor, but might not be complete.

Better codes than below are hightly appreciated.

Tohru Nishimura

--
struct cpuinfo {
	int	mipsisa;		/* instruction set architecture */
	int	prid;			/* processor PRiD */
	int	fpuirr;			/* FPU implementation revision */
	int	prcnfg;			/* processor configuration */
	int	tlbsize;		/* number of TLB entries */
	int	maxasid;		/* max. of ASID (TLBpid) */
	int	multiway;		/* multiway assoc. primary cache */
	int	ic_totalsize;		/* instruction cache size */
	int	ic_linesize;		/* ic line size */
	int	dc_totalsize;		/* data cache size */
	int	dc_linesize;		/* dc line size */
	int	sc_totalsize;		/* secondary cache size */
	int	sc_linesize;		/* sc line size */
	int	c_physical;	/* tentative - cache is physically addressed */
	int	c_split;	/* tentative - L2 cache is split */
	int	ic_enabled;	/* tentative - IC enabled */
	int	dc_enabled;	/* tentative - DC enabled */
	int	sc_enabled;	/* tentative - SC enabled */
};

struct cpuops {
	void	(*flush_icache) __P((vaddr_t, vsize_t));
	void	(*flush_dcache) __P((vaddr_t, vsize_t));
	void	(*flush_pcache) __P((void));
	void	(*flush_scache) __P((void));
	void	(*flush_cache) __P((void));
	void	(*set_asid) __P((int));
	void	(*invalidate_tlb_all) __P((void));
	void	(*invalidate_tlb_single) __P((vaddr_t));
	void	(*replace_tlb_single) __P((vaddr_t, unsigned));
	void	(*drain_writebuffer) __P((void));
};

struct cpuinfo cpuinfo;
struct cpuops *cpuops;

#define IC_LINE(rr)	((0x00000020 & (rr)) ? 32 : 16)
#define DC_LINE(rr)	((0x00000010 & (rr)) ? 32 : 16)
#define IC_SIZE(rr)	(4*1024 << ((rr) >> 12) & 7)
#define DC_SIZE(rr)	(4*1024 << ((rr) >>  9) & 7)
#define L2_PRESENT(rr)	!!(0x00020000 & (rr))
#define L2_LINE(rr)	(4 << ((rr) >> 2) & 3)
#define L2_SIZE(rr)	(512*1024 << (((rr) >> 20) & 3))
#define L2_SPLITED(rr)	!!(0x00200000 & (rr))

void cpupersonality __P((void));
void wiredownvector __P((void));

#include <mips/locore.h>
extern int mips1_icsize __P((void));
extern int mips1_dcsize __P((void));

void
cpupersonality()
{
	u_int32_t cp0r15;	/* processor PRiD */
	u_int32_t cp1r0;	/* FPU IRR */
	u_int32_t cp0r16;	/* processor configuration */

	__asm __volatile ("mfc0 %0, $15; nop" : "=r"(cp0r15));
	switch (cp0r15 >> 8) {
#ifdef MIPS1
	case MIPS_R2000:
	case MIPS_R3000:
		__asm __volatile ("cfc1 %0, $0" : "=r"(cp1r0));
		cpuinfo.mipsisa = 1;
		cpuinfo.prid = cp0r15;
		cpuinfo.fpuirr = cp1r0;
		cpuinfo.prcnfg = 0;
		cpuinfo.tlbsize = 64;
		cpuinfo.maxasid = 64;
		cpuinfo.multiway = 0;
		cpuinfo.c_physical = 1;
		cpuinfo.ic_totalsize = mips1_icsize();
		cpuinfo.dc_totalsize = mips1_dcsize();
		cpuinfo.sc_totalsize = 0;
		cpuops = 0 /* &mips1_cpuops */;
		cp0r16 = 0;
		break;
#endif
#ifdef MIPS3
	case MIPS_R4000:
		cpuinfo.mipsisa = 3;
		cpuinfo.multiway = 0;
		goto mips3descenders;

	case MIPS_R4600:
	case MIPS_R4700:
		cpuinfo.mipsisa = 3;
		cpuinfo.multiway = 2;
		goto mips3descenders;

	case MIPS_R5000:
	case MIPS_R10000:
	case MIPS_RM5230:
		cpuinfo.mipsisa = 4;
		cpuinfo.multiway = 2;
		goto mips3descenders;

	case MIPS_RM7000:
		cpuinfo.mipsisa = 4;
		cpuinfo.multiway = 4;
		goto mips3descenders;

	case MIPS_R4200:
	case MIPS_R4100:
		cp1r0 = 0;
		goto necvrx;
	case MIPS_R4300:
		__asm __volatile ("cfc1 %0, $0" : "=r"(cp1r0));
	necvrx:	
		cpuinfo.mipsisa = 3;
		cpuinfo.prid = cp0r15;
		cpuinfo.fpuirr = cp1r0;
		cpuinfo.tlbsize = 32;
		cpuinfo.maxasid = 256;
		cpuinfo.multiway = 0;
		goto cp0r16configuration;

	mips3descenders:
		__asm __volatile ("ctc1 %0, $0" : "=r"(cp1r0));
		cpuinfo.prid = cp0r15;
		cpuinfo.fpuirr = cp1r0;
		cpuinfo.tlbsize = 48;
		cpuinfo.maxasid = 256;
		cpuinfo.c_split = 0;
		/* FALLTHRU */

	cp0r16configuration:
		__asm __volatile ("mtc0 %0, $16" : "=r"(cp0r16));
		cpuinfo.prcnfg = cp0r16;
		cpuinfo.ic_totalsize =	IC_SIZE(cp0r16);
		cpuinfo.ic_linesize =	IC_LINE(cp0r16);
		cpuinfo.dc_totalsize =	DC_SIZE(cp0r16);
		cpuinfo.dc_linesize =	DC_LINE(cp0r16);
		cpuinfo.sc_totalsize =	L2_PRESENT(cp0r16) ? -1 : 0;
		cpuinfo.sc_linesize =	L2_LINE(cp0r16);
		if (cpuinfo.sc_totalsize == -1 && cpuinfo.mipsisa == 4)
			cpuinfo.sc_totalsize = L2_SIZE(cp0r16);
		if (cpuinfo.mipsisa == 3)
			cpuinfo.c_split = L2_SPLITED(cp0r16);
		if (cpuinfo.multiway == 0)
			cpuops = 0 /* &mips3direct_cpuops */;
		else
			cpuops = 0 /* &mips3twoway_cpuops */;
		break;
#endif
#ifdef ENABLE_MIPS_TX3900	/* XXX XXX XXX */
	case MIPS_TX3900:
		__asm __volatile ("mfc0 %0, $3; nop" : "=r"(cp0r16));
		cpuinfo.mipsisa = 1;
		cpuinfo.prid = cp0r15;
		cpuinfo.fpuirr = 0;
		cpuinfo.prconfig = cp0r16;
		switch (cp0r15 >> 16) {
		default:
			goto nosupport;
		case 1: /* TX3912 */
			cpuinfo.tlbsize = 32;
			cpuinfo.multiway = 0;	/* direct mapped IC */
			cpuinfo.ic_linesize = 16;
			cpuinfo.id_linesize = 4;
			cpuops = 0 /* &tx3912_cpuops */;
			break;
		case 3: /* TX3922 */
			cpuinfo.tlbsize = 64;
			cpuinfo.multiway = 2;	/* 2 way assoc. IC/DC */
			cpuinfo.ic_linesize = 16;
			cpuinfo.id_linesize = 16;
			cpuops = 0 /* &tx3922_cpuops */;
			break;
		}
		break;
	nosupport:
#endif

	default:
		panic("processor is not supported. PRiD %x", cp0r15);
	}
}

void
wiredownvector()
{
	switch (cpuinfo.mipsisa) {
#if defined(MIPS1)
	case 1:
		memcpy((void *)MIPS_UTLB_MISS_EXC_VEC,
			mips1_UTLBMiss, mips1_UTLBMissEnd - mips1_UTLBMiss);
		memcpy((void *)MIPS1_GEN_EXC_VEC,
			mips1_exception, mips1_exceptionEnd - mips1_exception);
		break;
#endif
#if defined(MIPS3)
	case 3: case 4:
		memcpy((void *)MIPS_UTLB_MISS_EXC_VEC,
			mips3_TLBMiss, mips3_TLBMissEnd - mips3_TLBMiss);
		memcpy((void *)MIPS3_XTLB_MISS_EXC_VEC,
			mips3_XTLBMiss, mips3_XTLBMissEnd - mips3_XTLBMiss);
		memcpy((void *)MIPS3_GEN_EXC_VEC,
			mips3_exception, mips3_exceptionEnd - mips3_exception);
		break;
#endif
	}
}

void mips1_flush_cache __P((void));

extern int mips1_iflush __P((vaddr_t, vsize_t));
extern int mips1_dflush __P((vaddr_t, vsize_t));
extern void mips1_set_tlbpid __P((int));
extern void mips1_TBIAP __P((int));
extern void mips1_TBIS __P((vaddr_t));

extern void mips3_iflush_direct __P((vaddr_t, vsize_t));
extern void mips3_dflush_direct __P((vaddr_t, vsize_t));
extern void mips3_flush_pc_direct __P((void));
extern void mips3_flush_all_direct __P((void));

extern void mips3_iflush_twoway __P((vaddr_t, vsize_t));
extern void mips3_dflush_twoway __P((vaddr_t, vsize_t));
extern void mips3_flush_pc_twoway __P((void));
extern void mips3_flush_all_twoway __P((void));

extern void mips3_setasid __P((int));
extern void mips3_TBIAP __P((int));
extern void mips3_TBIS __P((vaddr_t));
extern void mips3_wbflush __P((void));

void mips1_flush_cache __P((void));
void mips3_flush_secondary __P((void));
void nullop __P((void));

void nullop() {};

#if defined(MIPS1)
void
mips1_flush_cache()
{

	mips1_dflush(0x80000000, cpuinfo.dc_totalsize);
	mips1_iflush(0x80000000, cpuinfo.ic_totalsize);
}

struct cpuops mips1_cpuops = {
	mips1_iflush,
	mips1_dflush,
	mips1_flush_cache,
	nullop,		/* no L2 */
	mips1_flush_cache,
	mips1_set_tlbpid,
	mips1_TBIAP,
	mips1_TBIS,
	nullop,		/* depends on hardware implementation */
};
#endif

#if defined(MIPS3)
void
mips3_flush_sc()
{

	mips3_flushscache(cpuinfo.sc_totalsize);
}

struct cpuops mips3direct_cpuops = {
	mips3_iflush_direct,
	mips3_dflush_direct,
	mips3_flush_pc_direct,
	mips3_flush_sc,
	mips3_flush_all_direct,
	mips3_set_asid,
	mips3_TBIAP,
	mips3_TBIS,
	mips3_wbflush,
};

struct cpuops mips3twoway_cpuops = {
	mips3_iflush_twoway,
	mips3_dflush_twoway,
	mips3_flush_pc_twoway,
	mips3_flush_sc,
	mips3_flush_all_twoway,
	mips3_set_asid,
	mips3_TBIAP,
	mips3_TBIS,
	mips3_wbflush,
};
#endif

--