[PATCH 2/3] ARM PJ4B: Add support for errata 6124

Will Deacon will.deacon at arm.com
Wed May 29 07:16:33 EDT 2013


On Wed, May 29, 2013 at 11:16:57AM +0100, Gregory CLEMENT wrote:
> From: Lior Amsalem <alior at marvell.com>
> 
> A rare timing scenario exists where a clean operation occurs, followed
> by an additional store operation. If a matching snoop also occurs, it
> is possible for the write-back from the original clean operation and
> the intervention from the snoop to race, which could result in data
> corruption.
> Replacing all clean cache maintenance operations with Clean &
> Invalidate operation to avoid the issue

Curious: do you not have a chicken bit for this? Upgrading clean to clean &
invalidate is a pretty common thing to do and is even architected with the
virtualisation extensions.

> [gregory.clement at free-electrons.com:add errata description in changelog]
> [gregory.clement at free-electrons.com: make this errata depend on Aramda
> XP]
> Signed-off-by: Lior Amsalem <alior at marvell.com>
> Signed-off-by: Gregory CLEMENT <gregory.clement at free-electrons.com>
> ---
>  arch/arm/Kconfig                | 13 +++++++++++++
>  arch/arm/include/asm/tlbflush.h |  8 ++++++++
>  arch/arm/mm/cache-v7.S          |  8 ++++++++
>  arch/arm/mm/proc-v7-2level.S    |  4 ++++
>  arch/arm/mm/proc-v7-3level.S    |  4 ++++
>  arch/arm/mm/proc-v7.S           |  4 ++++
>  6 files changed, 41 insertions(+)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 745781f..48cdbea 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1099,6 +1099,19 @@ config PJ4B_ERRATA_4742
>  	  The software must insert either a Data Synchronization Barrier (DSB)
>  	  or Data Memory Barrier (DMB) command immediately after the WFI/WFE instruction
>  
> +config PJ4B_ERRATA_6124
> +        bool "PJ4B Errata 6124: Multiple writebacks can be issued in a rare timing scenario associated with a clean operation and an incoming snoop"
> +        depends on CPU_PJ4B && MACH_ARMADA_XP
> +        help
> +	  A rare timing scenario exists where a clean operation occurs, followed
> +	  by an additional store operation. If a matching snoop also occurs, it
> +	  is possible for the write-back from the original clean operation and
> +	  the intervention from the snoop to race, which could result in data
> +	  corruption.
> +	  Workaround:
> +	  Replacing all clean cache maintenance operations with
> +	  Clean & Invalidate operation will avoid the issue
> +
>  config ARM_ERRATA_326103
>  	bool "ARM errata: FSR write bit incorrect on a SWP to read-only memory"
>  	depends on CPU_V6
> diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
> index a3625d1..e3a8064 100644
> --- a/arch/arm/include/asm/tlbflush.h
> +++ b/arch/arm/include/asm/tlbflush.h
> @@ -475,7 +475,11 @@ static inline void flush_pmd_entry(void *pmd)
>  {
>  	const unsigned int __tlb_flag = __cpu_tlb_flags;
>  
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +	tlb_op(TLB_DCLEAN, "c7, c14, 1	@ flush_pmd", pmd);

Can you elaborate on the comment please?

> +#else
>  	tlb_op(TLB_DCLEAN, "c7, c10, 1	@ flush_pmd", pmd);
> +#endif
>  	tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);
>  
>  	if (tlb_flag(TLB_WB))
> @@ -486,7 +490,11 @@ static inline void clean_pmd_entry(void *pmd)
>  {
>  	const unsigned int __tlb_flag = __cpu_tlb_flags;
>  
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +	tlb_op(TLB_DCLEAN, "c7, c14, 1	@ flush_pmd", pmd);

and here.

> +#else
>  	tlb_op(TLB_DCLEAN, "c7, c10, 1	@ flush_pmd", pmd);
> +#endif
>  	tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);
>  }
>  
> diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
> index 15451ee..d353649 100644
> --- a/arch/arm/mm/cache-v7.S
> +++ b/arch/arm/mm/cache-v7.S
> @@ -270,7 +270,11 @@ ENTRY(v7_coherent_user_range)
>  	ALT_UP(W(nop))
>  #endif
>  1:
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> + USER(	mcr	p15, 0, r12, c7, c14, 1	)	@ clean & invalidate D line to the point of unification

This flushes to the point of coherency (there is no PoU clean & inv).

> +#else
>   USER(	mcr	p15, 0, r12, c7, c11, 1	)	@ clean D line to the point of unification
> +#endif
>  	add	r12, r12, r2
>  	cmp	r12, r1
>  	blo	1b
> @@ -378,7 +382,11 @@ v7_dma_clean_range:
>  	ALT_UP(W(nop))
>  #endif
>  1:
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D line to the point of unification

Similarly, although I don't understand why you care about the erratum for
dma_clean_range. There should be no pending stores to the buffer, otherwise
you risk corruption anyway (from the device's point of view).

> +#else
>  	mcr	p15, 0, r0, c7, c10, 1		@ clean D / U line
> +#endif
>  	add	r0, r0, r2
>  	cmp	r0, r1
>  	blo	1b
> diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
> index 9704097..0999fd3 100644
> --- a/arch/arm/mm/proc-v7-2level.S
> +++ b/arch/arm/mm/proc-v7-2level.S
> @@ -111,8 +111,12 @@ ENTRY(cpu_v7_set_pte_ext)
>   THUMB(	add	r0, r0, #2048 )
>   THUMB(	str	r3, [r0] )
>  	ALT_SMP(mov	pc,lr)
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +	ALT_UP (mcr	p15, 0, r0, c7, c14, 1)		@ flush_pte by clean & invalidate D entry

The use of `by' is a bit confusing, since you can also do maintenance by
set/way.

> +#else
>  	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
>  #endif
> +#endif
>  	mov	pc, lr
>  ENDPROC(cpu_v7_set_pte_ext)
>  
> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
> index 363027e..7a917ff 100644
> --- a/arch/arm/mm/proc-v7-3level.S
> +++ b/arch/arm/mm/proc-v7-3level.S
> @@ -74,8 +74,12 @@ ENTRY(cpu_v7_set_pte_ext)
>  	orreq	r2, #L_PTE_RDONLY
>  1:	strd	r2, r3, [r0]
>  	ALT_SMP(mov	pc, lr)
> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +	ALT_UP (mcr	p15, 0, r0, c7, c14, 1)		@ flush_pte by clean & invalidate D entry
> +#else
>  	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
>  #endif
> +#endif
>  	mov	pc, lr
>  ENDPROC(cpu_v7_set_pte_ext)
>  
> diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
> index f872432..b86d688 100644
> --- a/arch/arm/mm/proc-v7.S
> +++ b/arch/arm/mm/proc-v7.S
> @@ -81,7 +81,11 @@ ENTRY(cpu_v7_dcache_clean_area)
>  	ALT_SMP(mov	pc, lr)			@ MP extensions imply L1 PTW
>  	ALT_UP(W(nop))
>  	dcache_line_size r2, r3

You could move the 1: label here.

> +#ifdef CONFIG_PJ4B_ERRATA_6124
> +1:	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D entry
> +#else
>  1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
> +#endif

Will



More information about the linux-arm-kernel mailing list