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

Commit 75b5b5e0 authored by Leonid Yegoshin's avatar Leonid Yegoshin Committed by Ralf Baechle
Browse files

MIPS: Add support for FTLBs



The Fixed Page Size TLB (FTLB) is a set-associative dual entry TLB. Its
purpose is to reduce the number of TLB misses by increasing the effective
TLB size and keep the implementation complexity to minimum levels.
A supported core can have both VTLB and FTLB.

Reviewed-by: default avatarJames Hogan <james.hogan@imgtec.com>
Reviewed-by: default avatarPaul Burton <paul.burton@imgtec.com>
Signed-off-by: default avatarLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: default avatarMarkos Chandras <markos.chandras@imgtec.com>
Signed-off-by: default avatarJohn Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/6139/
parent 601cfa7b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -52,6 +52,9 @@ struct cpuinfo_mips {
	unsigned int		cputype;
	int			isa_level;
	int			tlbsize;
	int			tlbsizevtlb;
	int			tlbsizeftlbsets;
	int			tlbsizeftlbways;
	struct cache_desc	icache; /* Primary I-cache */
	struct cache_desc	dcache; /* Primary D or combined I/D cache */
	struct cache_desc	scache; /* Secondary cache */
+2 −0
Original line number Diff line number Diff line
@@ -645,6 +645,8 @@
#define MIPS_CONF5_K		(_ULCAST_(1) << 30)

#define MIPS_CONF6_SYND		(_ULCAST_(1) << 13)
/* proAptiv FTLB on/off bit */
#define MIPS_CONF6_FTLBEN	(_ULCAST_(1) << 15)

#define MIPS_CONF7_WII		(_ULCAST_(1) << 31)

+25 −0
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@

#include <spaces.h>
#include <linux/const.h>
#include <linux/kernel.h>
#include <asm/mipsregs.h>

/*
 * PAGE_SHIFT determines the page size
@@ -33,6 +35,29 @@
#define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK	(~((1 << PAGE_SHIFT) - 1))

/*
 * This is used for calculating the real page sizes
 * for FTLB or VTLB + FTLB confugrations.
 */
static inline unsigned int page_size_ftlb(unsigned int mmuextdef)
{
	switch (mmuextdef) {
	case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
		if (PAGE_SIZE == (1 << 30))
			return 5;
		if (PAGE_SIZE == (1llu << 32))
			return 6;
		if (PAGE_SIZE > (256 << 10))
			return 7; /* reserved */
			/* fall through */
	case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
		return (PAGE_SHIFT - 10) / 2;
	default:
		panic("Invalid FTLB configuration with Conf4_mmuextdef=%d value\n",
		      mmuextdef >> 14);
	}
}

#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
#define HPAGE_SHIFT	(PAGE_SHIFT + PAGE_SHIFT - 3)
#define HPAGE_SIZE	(_AC(1,UL) << HPAGE_SHIFT)
+72 −7
Original line number Diff line number Diff line
@@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
static char unknown_isa[] = KERN_ERR \
	"Unsupported ISA type, c0.config0: %d.";

static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
{
	unsigned int config6;
	/*
	 * Config6 is implementation dependent and it's currently only
	 * used by proAptiv
	 */
	if (c->cputype == CPU_PROAPTIV) {
		config6 = read_c0_config6();
		if (enable)
			/* Enable FTLB */
			write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
		else
			/* Disable FTLB */
			write_c0_config6(config6 &  ~MIPS_CONF6_FTLBEN);
		back_to_back_c0_hazard();
	}
}

static inline unsigned int decode_config0(struct cpuinfo_mips *c)
{
	unsigned int config0;
@@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)

	config0 = read_c0_config();

	if (((config0 & MIPS_CONF_MT) >> 7) == 1)
	/*
	 * Look for Standard TLB or Dual VTLB and FTLB
	 */
	if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
	    (((config0 & MIPS_CONF_MT) >> 7) == 4))
		c->options |= MIPS_CPU_TLB;

	isa = (config0 & MIPS_CONF_AT) >> 13;
	switch (isa) {
	case 0:
@@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
		c->options |= MIPS_CPU_FPU;
		c->options |= MIPS_CPU_32FPR;
	}
	if (cpu_has_tlb)
	if (cpu_has_tlb) {
		c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
		c->tlbsizevtlb = c->tlbsize;
		c->tlbsizeftlbsets = 0;
	}

	return config1 & MIPS_CONF_M;
}
@@ -281,16 +308,50 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
static inline unsigned int decode_config4(struct cpuinfo_mips *c)
{
	unsigned int config4;
	unsigned int newcf4;
	unsigned int mmuextdef;
	unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;

	config4 = read_c0_config4();

	if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
	    && cpu_has_tlb)
		c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;

	if (cpu_has_tlb) {
		if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
			c->options |= MIPS_CPU_TLBINV;
		mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
		switch (mmuextdef) {
		case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
			c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
			c->tlbsizevtlb = c->tlbsize;
			break;
		case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
			c->tlbsizevtlb +=
				((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
				  MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
			c->tlbsize = c->tlbsizevtlb;
			ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
			/* fall through */
		case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
			newcf4 = (config4 & ~ftlb_page) |
				(page_size_ftlb(mmuextdef) <<
				 MIPS_CONF4_FTLBPAGESIZE_SHIFT);
			write_c0_config4(newcf4);
			back_to_back_c0_hazard();
			config4 = read_c0_config4();
			if (config4 != newcf4) {
				pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
				       PAGE_SIZE, config4);
				/* Switch FTLB off */
				set_ftlb_enable(c, 0);
				break;
			}
			c->tlbsizeftlbsets = 1 <<
				((config4 & MIPS_CONF4_FTLBSETS) >>
				 MIPS_CONF4_FTLBSETS_SHIFT);
			c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
					      MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
			c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
			break;
		}
	}

	c->kscratch_mask = (config4 >> 16) & 0xff;
@@ -319,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c)

	c->scache.flags = MIPS_CACHE_NOT_PRESENT;

	/* Enable FTLB if present */
	set_ftlb_enable(c, 1);

	ok = decode_config0(c);			/* Read Config registers.  */
	BUG_ON(!ok);				/* Arch spec violation!	 */
	if (ok)
@@ -682,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)

static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
{
	decode_configs(c);
	switch (c->processor_id & PRID_IMP_MASK) {
	case PRID_IMP_4KC:
		c->cputype = CPU_4KC;
@@ -756,6 +819,8 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
		break;
	}

	decode_configs(c);

	spram_config();
}

+1 −0
Original line number Diff line number Diff line
@@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
	BUILD_HANDLER ov ov sti silent			/* #12 */
	BUILD_HANDLER tr tr sti silent			/* #13 */
	BUILD_HANDLER fpe fpe fpe silent		/* #15 */
	BUILD_HANDLER ftlb ftlb none silent		/* #16 */
	BUILD_HANDLER mdmx mdmx sti silent		/* #22 */
#ifdef	CONFIG_HARDWARE_WATCHPOINTS
	/*
Loading