diff options
Diffstat (limited to 'arch/mips/kernel/cpu-probe.c')
| -rw-r--r-- | arch/mips/kernel/cpu-probe.c | 220 | 
1 files changed, 183 insertions, 37 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 5465dc183e5..d74f957c561 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -23,6 +23,8 @@  #include <asm/cpu-type.h>  #include <asm/fpu.h>  #include <asm/mipsregs.h> +#include <asm/mipsmtregs.h> +#include <asm/msa.h>  #include <asm/watch.h>  #include <asm/elf.h>  #include <asm/spram.h> @@ -60,7 +62,7 @@ static inline void check_errata(void)  	case CPU_34K:  		/*  		 * Erratum "RPS May Cause Incorrect Instruction Execution" -		 * This code only handles VPE0, any SMP/SMTC/RTOS code +		 * This code only handles VPE0, any SMP/RTOS code  		 * making use of VPE1 will be responsable for that VPE.  		 */  		if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2) @@ -112,7 +114,7 @@ static inline unsigned long cpu_get_fpu_id(void)  	unsigned long tmp, fpu_id;  	tmp = read_c0_status(); -	__enable_fpu(); +	__enable_fpu(FPU_AS_IS);  	fpu_id = read_32bit_cp1_register(CP1_REVISION);  	write_c0_status(tmp);  	return fpu_id; @@ -126,6 +128,20 @@ static inline int __cpu_has_fpu(void)  	return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE);  } +static inline unsigned long cpu_get_msa_id(void) +{ +	unsigned long status, conf5, msa_id; + +	status = read_c0_status(); +	__enable_fpu(FPU_64BIT); +	conf5 = read_c0_config5(); +	enable_msa(); +	msa_id = read_msa_ir(); +	write_c0_config5(conf5); +	write_c0_status(status); +	return msa_id; +} +  static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)  {  #ifdef __NEED_VMBITS_PROBE @@ -163,6 +179,27 @@ 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; + +	/* It's implementation dependent how the FTLB can be enabled */ +	switch (c->cputype) { +	case CPU_PROAPTIV: +	case CPU_P5600: +		/* proAptiv & related cores use Config6 to enable the FTLB */ +		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(); +		break; +	} +} +  static inline unsigned int decode_config0(struct cpuinfo_mips *c)  {  	unsigned int config0; @@ -170,8 +207,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 +268,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;  } @@ -272,6 +317,10 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)  		c->options |= MIPS_CPU_MICROMIPS;  	if (config3 & MIPS_CONF3_VZ)  		c->ases |= MIPS_ASE_VZ; +	if (config3 & MIPS_CONF3_SC) +		c->options |= MIPS_CPU_SEGMENTS; +	if (config3 & MIPS_CONF3_MSA) +		c->ases |= MIPS_ASE_MSA;  	return config3 & MIPS_CONF_M;  } @@ -279,12 +328,51 @@ 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; @@ -299,6 +387,9 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)  	config5 &= ~MIPS_CONF5_UFR;  	write_c0_config5(config5); +	if (config5 & MIPS_CONF5_EVA) +		c->options |= MIPS_CPU_EVA; +  	return config5 & MIPS_CONF_M;  } @@ -312,6 +403,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) @@ -327,8 +421,13 @@ static void decode_configs(struct cpuinfo_mips *c)  	mips_probe_watch_registers(c); -	if (cpu_has_mips_r2) -		c->core = read_c0_ebase() & 0x3ff; +#ifndef CONFIG_MIPS_CPS +	if (cpu_has_mips_r2) { +		c->core = get_ebase_cpunum(); +		if (cpu_has_mipsmt) +			c->core >>= fls(core_nvpes()) - 1; +	} +#endif  }  #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ @@ -376,13 +475,33 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)  				__cpu_name[cpu] = "R4000PC";  			}  		} else { +			int cca = read_c0_config() & CONF_CM_CMASK; +			int mc; + +			/* +			 * SC and MC versions can't be reliably told apart, +			 * but only the latter support coherent caching +			 * modes so assume the firmware has set the KSEG0 +			 * coherency attribute reasonably (if uncached, we +			 * assume SC). +			 */ +			switch (cca) { +			case CONF_CM_CACHABLE_CE: +			case CONF_CM_CACHABLE_COW: +			case CONF_CM_CACHABLE_CUW: +				mc = 1; +				break; +			default: +				mc = 0; +				break; +			}  			if ((c->processor_id & PRID_REV_MASK) >=  			    PRID_REV_R4400) { -				c->cputype = CPU_R4400SC; -				__cpu_name[cpu] = "R4400SC"; +				c->cputype = mc ? CPU_R4400MC : CPU_R4400SC; +				__cpu_name[cpu] = mc ? "R4400MC" : "R4400SC";  			} else { -				c->cputype = CPU_R4000SC; -				__cpu_name[cpu] = "R4000SC"; +				c->cputype = mc ? CPU_R4000MC : CPU_R4000SC; +				__cpu_name[cpu] = mc ? "R4000MC" : "R4000SC";  			}  		} @@ -565,21 +684,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)  		 */  		c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;  		break; -	case PRID_IMP_RM9000: -		c->cputype = CPU_RM9000; -		__cpu_name[cpu] = "RM9000"; -		set_isa(c, MIPS_CPU_ISA_IV); -		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | -			     MIPS_CPU_LLSC; -		/* -		 * Bit 29 in the info register of the RM9000 -		 * indicates if the TLB has 48 or 64 entries. -		 * -		 * 29	   1 =>	   64 entry JTLB -		 *	   0 =>	   48 entry JTLB -		 */ -		c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48; -		break;  	case PRID_IMP_R8000:  		c->cputype = CPU_R8000;  		__cpu_name[cpu] = "RM8000"; @@ -619,17 +723,23 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)  			     MIPS_CPU_LLSC;  		c->tlbsize = 64;  		break; -	case PRID_IMP_LOONGSON2: -		c->cputype = CPU_LOONGSON2; -		__cpu_name[cpu] = "ICT Loongson-2"; - +	case PRID_IMP_LOONGSON_64:  /* Loongson-2/3 */  		switch (c->processor_id & PRID_REV_MASK) {  		case PRID_REV_LOONGSON2E: +			c->cputype = CPU_LOONGSON2; +			__cpu_name[cpu] = "ICT Loongson-2";  			set_elf_platform(cpu, "loongson2e");  			break;  		case PRID_REV_LOONGSON2F: +			c->cputype = CPU_LOONGSON2; +			__cpu_name[cpu] = "ICT Loongson-2";  			set_elf_platform(cpu, "loongson2f");  			break; +		case PRID_REV_LOONGSON3A: +			c->cputype = CPU_LOONGSON3; +			__cpu_name[cpu] = "ICT Loongson-3"; +			set_elf_platform(cpu, "loongson3a"); +			break;  		}  		set_isa(c, MIPS_CPU_ISA_III); @@ -638,7 +748,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)  			     MIPS_CPU_32FPR;  		c->tlbsize = 64;  		break; -	case PRID_IMP_LOONGSON1: +	case PRID_IMP_LOONGSON_32:  /* Loongson-1 */  		decode_configs(c);  		c->cputype = CPU_LOONGSON1; @@ -655,7 +765,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; @@ -716,11 +825,37 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)  		__cpu_name[cpu] = "MIPS 1004Kc";  		break;  	case PRID_IMP_1074K: -		c->cputype = CPU_74K; +		c->cputype = CPU_1074K;  		__cpu_name[cpu] = "MIPS 1074Kc";  		break; +	case PRID_IMP_INTERAPTIV_UP: +		c->cputype = CPU_INTERAPTIV; +		__cpu_name[cpu] = "MIPS interAptiv"; +		break; +	case PRID_IMP_INTERAPTIV_MP: +		c->cputype = CPU_INTERAPTIV; +		__cpu_name[cpu] = "MIPS interAptiv (multi)"; +		break; +	case PRID_IMP_PROAPTIV_UP: +		c->cputype = CPU_PROAPTIV; +		__cpu_name[cpu] = "MIPS proAptiv"; +		break; +	case PRID_IMP_PROAPTIV_MP: +		c->cputype = CPU_PROAPTIV; +		__cpu_name[cpu] = "MIPS proAptiv (multi)"; +		break; +	case PRID_IMP_P5600: +		c->cputype = CPU_P5600; +		__cpu_name[cpu] = "MIPS P5600"; +		break; +	case PRID_IMP_M5150: +		c->cputype = CPU_M5150; +		__cpu_name[cpu] = "MIPS M5150"; +		break;  	} +	decode_configs(c); +  	spram_config();  } @@ -891,6 +1026,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)  	decode_configs(c);  	/* JZRISC does not implement the CP0 counter. */  	c->options &= ~MIPS_CPU_COUNTER; +	BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter);  	switch (c->processor_id & PRID_IMP_MASK) {  	case PRID_IMP_JZRISC:  		c->cputype = CPU_JZRISC; @@ -923,6 +1059,8 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)  	switch (c->processor_id & PRID_IMP_MASK) {  	case PRID_IMP_NETLOGIC_XLP2XX: +	case PRID_IMP_NETLOGIC_XLP9XX: +	case PRID_IMP_NETLOGIC_XLP5XX:  		c->cputype = CPU_XLP;  		__cpu_name[cpu] = "Broadcom XLPII";  		break; @@ -1067,6 +1205,12 @@ void cpu_probe(void)  	else  		c->srsets = 1; +	if (cpu_has_msa) { +		c->msa_id = cpu_get_msa_id(); +		WARN(c->msa_id & MSA_IR_WRPF, +		     "Vector register partitioning unimplemented!"); +	} +  	cpu_probe_vmbits(c);  #ifdef CONFIG_64BIT @@ -1079,8 +1223,10 @@ void cpu_report(void)  {  	struct cpuinfo_mips *c = ¤t_cpu_data; -	printk(KERN_INFO "CPU revision is: %08x (%s)\n", -	       c->processor_id, cpu_name_string()); +	pr_info("CPU%d revision is: %08x (%s)\n", +		smp_processor_id(), c->processor_id, cpu_name_string());  	if (c->options & MIPS_CPU_FPU)  		printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id); +	if (cpu_has_msa) +		pr_info("MSA revision is: %08x\n", c->msa_id);  }  | 
