diff mbox

ARM: cache: detect PIPT I-cache using CTR

Message ID 1311001602-22476-1-git-send-email-will.deacon@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Will Deacon July 18, 2011, 3:06 p.m. UTC
The Cache Type Register L1Ip field identifies I-caches with a PIPT
policy using the encoding 11b.

This patch extends the cache policy parsing to identify PIPT I-caches
correctly and prevent them from being treated as VIPT aliasing in cases
where they are sufficiently large.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/include/asm/cachetype.h |    5 ++++-
 arch/arm/kernel/setup.c          |   14 +++++++++++---
 2 files changed, 15 insertions(+), 4 deletions(-)

Comments

Will Deacon July 25, 2011, 9:42 p.m. UTC | #1
Quick update on this...

On Mon, Jul 18, 2011 at 04:06:42PM +0100, Will Deacon wrote:
> The Cache Type Register L1Ip field identifies I-caches with a PIPT
> policy using the encoding 11b.
> 
> This patch extends the cache policy parsing to identify PIPT I-caches
> correctly and prevent them from being treated as VIPT aliasing in cases
> where they are sufficiently large.
> 
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm/include/asm/cachetype.h |    5 ++++-
>  arch/arm/kernel/setup.c          |   14 +++++++++++---
>  2 files changed, 15 insertions(+), 4 deletions(-)

[...]

> diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h
> index c023db0..7ea7814 100644
> --- a/arch/arm/include/asm/cachetype.h
> +++ b/arch/arm/include/asm/cachetype.h
> @@ -7,6 +7,7 @@
>  #define CACHEID_VIPT			(CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
>  #define CACHEID_ASID_TAGGED		(1 << 3)
>  #define CACHEID_VIPT_I_ALIASING		(1 << 4)
> +#define CACHEID_PIPT			(1 << 5)
>  
>  extern unsigned int cacheid;
>  
> @@ -16,6 +17,7 @@ extern unsigned int cacheid;
>  #define cache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_ALIASING)
>  #define icache_is_vivt_asid_tagged()	cacheid_is(CACHEID_ASID_TAGGED)
>  #define icache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_I_ALIASING)
> +#define icache_is_pipt()		cacheid_is(CACHEID_PIPT)

Turns out that Cortex-A15 has a PIPT D-cache toom, but I can't figure out a
sane way of detecting this. Since it doesn't really matter to Linux (VIPT
non-aliasing is the same from a software point-of-view) then perhaps it's
best not to introduce another check...

>  /*
>   * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
> @@ -26,7 +28,8 @@ extern unsigned int cacheid;
>  #if __LINUX_ARM_ARCH__ >= 7
>  #define __CACHEID_ARCH_MIN	(CACHEID_VIPT_NONALIASING |\
>  				 CACHEID_ASID_TAGGED |\
> -				 CACHEID_VIPT_I_ALIASING)
> +				 CACHEID_VIPT_I_ALIASING |\
> +				 CACHEID_PIPT)
>  #elif __LINUX_ARM_ARCH__ >= 6
>  #define	__CACHEID_ARCH_MIN	(~CACHEID_VIVT)
>  #else
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index b84e830..0374bb7 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -281,10 +281,17 @@ static void __init cacheid_init(void)
>  		if ((cachetype & (7 << 29)) == 4 << 29) {
>  			/* ARMv7 register format */
>  			cacheid = CACHEID_VIPT_NONALIASING;
> -			if ((cachetype & (3 << 14)) == 1 << 14)
> +			switch (cachetype & (3 << 14)) {
> +			case (1 << 14):
>  				cacheid |= CACHEID_ASID_TAGGED;
> -			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
> -				cacheid |= CACHEID_VIPT_I_ALIASING;
> +				break;
> +			case (3 << 14):
> +				cacheid |= CACHEID_PIPT;
> +				break;
> +			default:
> +				if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
> +					cacheid |= CACHEID_VIPT_I_ALIASING;
> +			}
>  		} else if (cachetype & (1 << 23)) {
>  			cacheid = CACHEID_VIPT_ALIASING;
>  		} else {
> @@ -303,6 +310,7 @@ static void __init cacheid_init(void)
>  		cache_is_vivt() ? "VIVT" :
>  		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
>  		icache_is_vipt_aliasing() ? "VIPT aliasing" :
> +		icache_is_pipt() ? "PIPT" :
>  		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");

... and instead change the "VIPT nonaliasing" string to "PIPT / VIPT
nonaliasing" for the D-side. I'll make that change for v2 if nobody has any
further comments.

Will
diff mbox

Patch

diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h
index c023db0..7ea7814 100644
--- a/arch/arm/include/asm/cachetype.h
+++ b/arch/arm/include/asm/cachetype.h
@@ -7,6 +7,7 @@ 
 #define CACHEID_VIPT			(CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
 #define CACHEID_ASID_TAGGED		(1 << 3)
 #define CACHEID_VIPT_I_ALIASING		(1 << 4)
+#define CACHEID_PIPT			(1 << 5)
 
 extern unsigned int cacheid;
 
@@ -16,6 +17,7 @@  extern unsigned int cacheid;
 #define cache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_ALIASING)
 #define icache_is_vivt_asid_tagged()	cacheid_is(CACHEID_ASID_TAGGED)
 #define icache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_I_ALIASING)
+#define icache_is_pipt()		cacheid_is(CACHEID_PIPT)
 
 /*
  * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
@@ -26,7 +28,8 @@  extern unsigned int cacheid;
 #if __LINUX_ARM_ARCH__ >= 7
 #define __CACHEID_ARCH_MIN	(CACHEID_VIPT_NONALIASING |\
 				 CACHEID_ASID_TAGGED |\
-				 CACHEID_VIPT_I_ALIASING)
+				 CACHEID_VIPT_I_ALIASING |\
+				 CACHEID_PIPT)
 #elif __LINUX_ARM_ARCH__ >= 6
 #define	__CACHEID_ARCH_MIN	(~CACHEID_VIVT)
 #else
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b84e830..0374bb7 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -281,10 +281,17 @@  static void __init cacheid_init(void)
 		if ((cachetype & (7 << 29)) == 4 << 29) {
 			/* ARMv7 register format */
 			cacheid = CACHEID_VIPT_NONALIASING;
-			if ((cachetype & (3 << 14)) == 1 << 14)
+			switch (cachetype & (3 << 14)) {
+			case (1 << 14):
 				cacheid |= CACHEID_ASID_TAGGED;
-			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
-				cacheid |= CACHEID_VIPT_I_ALIASING;
+				break;
+			case (3 << 14):
+				cacheid |= CACHEID_PIPT;
+				break;
+			default:
+				if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
+					cacheid |= CACHEID_VIPT_I_ALIASING;
+			}
 		} else if (cachetype & (1 << 23)) {
 			cacheid = CACHEID_VIPT_ALIASING;
 		} else {
@@ -303,6 +310,7 @@  static void __init cacheid_init(void)
 		cache_is_vivt() ? "VIVT" :
 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
+		icache_is_pipt() ? "PIPT" :
 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
 }