ARM: 6795/1: l2x0: Errata fix for flush by Way operation can cause data corrupti

PL310 implements the Clean & Invalidate by Way L2 cache maintenance
operation (offset 0x7FC). This operation runs in background so that
PL310 can handle normal accesses while it is in progress. Under very
rare circumstances, due to this erratum, write data can be lost when
PL310 treats a cacheable write transaction during a Clean & Invalidate
by Way operation.

Workaround:
Disable Write-Back and Cache Linefill (Debug Control Register)
Clean & Invalidate by Way (0x7FC)
Re-enable Write-Back and Cache Linefill (Debug Control Register)

This patch also removes any OMAP dependency on PL310 Errata's

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Santosh Shilimkar 2011-03-08 06:59:54 +01:00 committed by Russell King
parent d239b1dc09
commit 2839e06c95
3 changed files with 31 additions and 17 deletions

View File

@ -1135,7 +1135,7 @@ config ARM_ERRATA_742231
config PL310_ERRATA_588369 config PL310_ERRATA_588369
bool "Clean & Invalidate maintenance operations do not invalidate clean lines" bool "Clean & Invalidate maintenance operations do not invalidate clean lines"
depends on CACHE_L2X0 && ARCH_OMAP4 depends on CACHE_L2X0
help help
The PL310 L2 cache controller implements three types of Clean & The PL310 L2 cache controller implements three types of Clean &
Invalidate maintenance operations: by Physical Address Invalidate maintenance operations: by Physical Address
@ -1144,8 +1144,7 @@ config PL310_ERRATA_588369
clean operation followed immediately by an invalidate operation, clean operation followed immediately by an invalidate operation,
both performing to the same memory location. This functionality both performing to the same memory location. This functionality
is not correctly implemented in PL310 as clean lines are not is not correctly implemented in PL310 as clean lines are not
invalidated as a result of these operations. Note that this errata invalidated as a result of these operations.
uses Texas Instrument's secure monitor api.
config ARM_ERRATA_720789 config ARM_ERRATA_720789
bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID" bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID"
@ -1172,6 +1171,16 @@ config ARM_ERRATA_743622
visible impact on the overall performance or power consumption of the visible impact on the overall performance or power consumption of the
processor. processor.
config PL310_ERRATA_727915
bool "Background Clean & Invalidate by Way operation can cause data corruption"
depends on CACHE_L2X0
help
PL310 implements the Clean & Invalidate by Way L2 cache maintenance
operation (offset 0x7FC). This operation runs in background so that
PL310 can handle normal accesses while it is in progress. Under very
rare circumstances, due to this erratum, write data can be lost when
PL310 treats a cacheable write transaction during a Clean &
Invalidate by Way operation.
endmenu endmenu
source "arch/arm/common/Kconfig" source "arch/arm/common/Kconfig"

View File

@ -31,6 +31,7 @@ struct outer_cache_fns {
#ifdef CONFIG_OUTER_CACHE_SYNC #ifdef CONFIG_OUTER_CACHE_SYNC
void (*sync)(void); void (*sync)(void);
#endif #endif
void (*set_debug)(unsigned long);
}; };
#ifdef CONFIG_OUTER_CACHE #ifdef CONFIG_OUTER_CACHE

View File

@ -67,18 +67,24 @@ static inline void l2x0_inv_line(unsigned long addr)
writel_relaxed(addr, base + L2X0_INV_LINE_PA); writel_relaxed(addr, base + L2X0_INV_LINE_PA);
} }
#ifdef CONFIG_PL310_ERRATA_588369 #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
static void debug_writel(unsigned long val)
{
extern void omap_smc1(u32 fn, u32 arg);
/* #define debug_writel(val) outer_cache.set_debug(val)
* Texas Instrument secure monitor api to modify the
* PL310 Debug Control Register. static void l2x0_set_debug(unsigned long val)
*/ {
omap_smc1(0x100, val); writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
}
#else
/* Optimised out for non-errata case */
static inline void debug_writel(unsigned long val)
{
} }
#define l2x0_set_debug NULL
#endif
#ifdef CONFIG_PL310_ERRATA_588369
static inline void l2x0_flush_line(unsigned long addr) static inline void l2x0_flush_line(unsigned long addr)
{ {
void __iomem *base = l2x0_base; void __iomem *base = l2x0_base;
@ -91,11 +97,6 @@ static inline void l2x0_flush_line(unsigned long addr)
} }
#else #else
/* Optimised out for non-errata case */
static inline void debug_writel(unsigned long val)
{
}
static inline void l2x0_flush_line(unsigned long addr) static inline void l2x0_flush_line(unsigned long addr)
{ {
void __iomem *base = l2x0_base; void __iomem *base = l2x0_base;
@ -119,9 +120,11 @@ static void l2x0_flush_all(void)
/* clean all ways */ /* clean all ways */
spin_lock_irqsave(&l2x0_lock, flags); spin_lock_irqsave(&l2x0_lock, flags);
debug_writel(0x03);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
cache_sync(); cache_sync();
debug_writel(0x00);
spin_unlock_irqrestore(&l2x0_lock, flags); spin_unlock_irqrestore(&l2x0_lock, flags);
} }
@ -329,6 +332,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
outer_cache.flush_all = l2x0_flush_all; outer_cache.flush_all = l2x0_flush_all;
outer_cache.inv_all = l2x0_inv_all; outer_cache.inv_all = l2x0_inv_all;
outer_cache.disable = l2x0_disable; outer_cache.disable = l2x0_disable;
outer_cache.set_debug = l2x0_set_debug;
printk(KERN_INFO "%s cache controller enabled\n", type); printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",