Re: [PATCH 2/5] MIPS: Add defs & probing of 64-bit CP0_EBase

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 29, 2016 at 02:46:00PM +0100, James Hogan wrote:
> MIPS64r2 and later cores may optionally have a 64-bit CP0_EBase
> register, with a write gate (WG) bit to allow the upper half to be
> written. The presence of this feature will need to be known about for VZ
> support in order to correctly save and restore the guest CP0_EBase
> register, so add CPU feature definitions and probing for this
> capability.

Okay, so it turns out EBase.WG can be present on MIPS32 too, to allow
writing of bits 31:30 (thanks Matt!), so this needs a little more
thought.

Cheers
James

> 
> Probing the WG bit is a bit fiddly, since 64-bit COP0 register access
> instructions were UNDEFINED for 32-bit registers prior to MIPS r6, and
> it'd be nice to be able to probe without clobbering the existing state,
> so there are 3 potential paths:
> 
> - If we do a 32-bit read of CP0_EBase and the WG bit is already set, the
>   register must be 64-bit.
> 
> - On MIPS r6 we can do a 64-bit read-modify-write to set CP0_EBase.WG,
>   since the upper bits will read 0 and be ignored on write if the
>   register is 32-bit.
> 
> - On pre-r6 cores, we do a 32-bit read-modify-write of CP0_EBase. This
>   avoids the potentially UNDEFINED behaviour, but will clobber the upper
>   32-bits of CP0_EBase if it isn't a simple sign extension (which also
>   requires us to ensure BEV=1 or modifying the exception base would be
>   UNDEFINED too). It is hopefully unlikely a bootloader would set up
>   CP0_EBase to a 64-bit segment and leave WG=0.
> 
> Signed-off-by: James Hogan <james.hogan@xxxxxxxxxx>
> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
> Cc: linux-mips@xxxxxxxxxxxxxx
> ---
>  arch/mips/include/asm/cpu-features.h |  4 ++++
>  arch/mips/include/asm/cpu.h          |  1 +
>  arch/mips/include/asm/mipsregs.h     |  3 +++
>  arch/mips/kernel/cpu-probe.c         | 35 +++++++++++++++++++++++++++++++++++
>  4 files changed, 43 insertions(+)
> 
> diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
> index da92d513a395..a3d3de8ab145 100644
> --- a/arch/mips/include/asm/cpu-features.h
> +++ b/arch/mips/include/asm/cpu-features.h
> @@ -432,4 +432,8 @@
>  #define cpu_has_nan_2008	(cpu_data[0].options & MIPS_CPU_NAN_2008)
>  #endif
>  
> +#ifndef cpu_has_ebase64
> +# define cpu_has_ebase64	(cpu_data[0].options & MIPS_CPU_EBASE64)
> +#endif
> +
>  #endif /* __ASM_CPU_FEATURES_H */
> diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
> index 79ce9ae0a3c7..11a7f78bb1f7 100644
> --- a/arch/mips/include/asm/cpu.h
> +++ b/arch/mips/include/asm/cpu.h
> @@ -403,6 +403,7 @@ enum cpu_type_enum {
>  #define MIPS_CPU_NAN_2008	MBIT_ULL(39)	/* 2008 NaN implemented */
>  #define MIPS_CPU_VP		MBIT_ULL(40)	/* MIPSr6 Virtual Processors (multi-threading) */
>  #define MIPS_CPU_LDPTE		MBIT_ULL(41)	 /* CPU has ldpte/lddir instructions */
> +#define MIPS_CPU_EBASE64	MBIT_ULL(42)	/* CPU has 64-bit EBase */
>  
>  /*
>   * CPU ASE encodings
> diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
> index 24904f1f6fe1..cc17f4886f00 100644
> --- a/arch/mips/include/asm/mipsregs.h
> +++ b/arch/mips/include/asm/mipsregs.h
> @@ -1456,6 +1456,9 @@ do {									\
>  #define read_c0_ebase()		__read_32bit_c0_register($15, 1)
>  #define write_c0_ebase(val)	__write_32bit_c0_register($15, 1, val)
>  
> +#define read_c0_ebase_64()	__read_64bit_c0_register($15, 1)
> +#define write_c0_ebase_64(val)	__write_64bit_c0_register($15, 1, val)
> +
>  #define read_c0_cdmmbase()	__read_ulong_c0_register($15, 2)
>  #define write_c0_cdmmbase(val)	__write_ulong_c0_register($15, 2, val)
>  
> diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
> index b766952afc5c..eb62c730b97f 100644
> --- a/arch/mips/kernel/cpu-probe.c
> +++ b/arch/mips/kernel/cpu-probe.c
> @@ -845,6 +845,41 @@ static void decode_configs(struct cpuinfo_mips *c)
>  	if (ok)
>  		ok = decode_config5(c);
>  
> +	/* Probe the size of the EBase register */
> +	if (config_enabled(CONFIG_64BIT) && cpu_has_mips_r2_r6) {
> +		unsigned long ebase;
> +		unsigned int status;
> +
> +		/* {read,write}_c0_ebase_64() may be UNDEFINED prior to r6 */
> +		ebase = cpu_has_mips64r6 ? read_c0_ebase_64()
> +					 : (s32)read_c0_ebase();
> +		if (ebase & MIPS_EBASE_WG) {
> +			/* WG bit already set, we can avoid the clumsy probe */
> +			c->options |= MIPS_CPU_EBASE64;
> +		} else {
> +			/* Its UNDEFINED to change EBase while BEV=0 */
> +			status = read_c0_status();
> +			write_c0_status(status | ST0_BEV);
> +			irq_enable_hazard();
> +			/*
> +			 * On pre-r6 cores, this may well clobber the upper bits
> +			 * of EBase. This is hard to avoid without potentially
> +			 * hitting UNDEFINED dm*c0 behaviour if EBase is 32-bit.
> +			 */
> +			if (cpu_has_mips64r6)
> +				write_c0_ebase_64(ebase | MIPS_EBASE_WG);
> +			else
> +				write_c0_ebase(ebase | MIPS_EBASE_WG);
> +			back_to_back_c0_hazard();
> +			/* Restore BEV */
> +			write_c0_status(status);
> +			if (read_c0_ebase() & MIPS_EBASE_WG) {
> +				c->options |= MIPS_CPU_EBASE64;
> +				write_c0_ebase(ebase);
> +			}
> +		}
> +	}
> +
>  	mips_probe_watch_registers(c);
>  
>  #ifndef CONFIG_MIPS_CPS
> -- 
> 2.4.10
> 

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux