Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Santosh Shilimkar and committed by
Russell King
2839e06c d239b1dc

+31 -17
+12 -3
arch/arm/Kconfig
··· 1135 1135 1136 1136 config PL310_ERRATA_588369 1137 1137 bool "Clean & Invalidate maintenance operations do not invalidate clean lines" 1138 - depends on CACHE_L2X0 && ARCH_OMAP4 1138 + depends on CACHE_L2X0 1139 1139 help 1140 1140 The PL310 L2 cache controller implements three types of Clean & 1141 1141 Invalidate maintenance operations: by Physical Address ··· 1144 1144 clean operation followed immediately by an invalidate operation, 1145 1145 both performing to the same memory location. This functionality 1146 1146 is not correctly implemented in PL310 as clean lines are not 1147 - invalidated as a result of these operations. Note that this errata 1148 - uses Texas Instrument's secure monitor api. 1147 + invalidated as a result of these operations. 1149 1148 1150 1149 config ARM_ERRATA_720789 1151 1150 bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID" ··· 1171 1172 visible impact on the overall performance or power consumption of the 1172 1173 processor. 1173 1174 1175 + config PL310_ERRATA_727915 1176 + bool "Background Clean & Invalidate by Way operation can cause data corruption" 1177 + depends on CACHE_L2X0 1178 + help 1179 + PL310 implements the Clean & Invalidate by Way L2 cache maintenance 1180 + operation (offset 0x7FC). This operation runs in background so that 1181 + PL310 can handle normal accesses while it is in progress. Under very 1182 + rare circumstances, due to this erratum, write data can be lost when 1183 + PL310 treats a cacheable write transaction during a Clean & 1184 + Invalidate by Way operation. 1174 1185 endmenu 1175 1186 1176 1187 source "arch/arm/common/Kconfig"
+1
arch/arm/include/asm/outercache.h
··· 31 31 #ifdef CONFIG_OUTER_CACHE_SYNC 32 32 void (*sync)(void); 33 33 #endif 34 + void (*set_debug)(unsigned long); 34 35 }; 35 36 36 37 #ifdef CONFIG_OUTER_CACHE
+18 -14
arch/arm/mm/cache-l2x0.c
··· 67 67 writel_relaxed(addr, base + L2X0_INV_LINE_PA); 68 68 } 69 69 70 - #ifdef CONFIG_PL310_ERRATA_588369 71 - static void debug_writel(unsigned long val) 72 - { 73 - extern void omap_smc1(u32 fn, u32 arg); 70 + #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) 74 71 75 - /* 76 - * Texas Instrument secure monitor api to modify the 77 - * PL310 Debug Control Register. 78 - */ 79 - omap_smc1(0x100, val); 72 + #define debug_writel(val) outer_cache.set_debug(val) 73 + 74 + static void l2x0_set_debug(unsigned long val) 75 + { 76 + writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); 77 + } 78 + #else 79 + /* Optimised out for non-errata case */ 80 + static inline void debug_writel(unsigned long val) 81 + { 80 82 } 81 83 84 + #define l2x0_set_debug NULL 85 + #endif 86 + 87 + #ifdef CONFIG_PL310_ERRATA_588369 82 88 static inline void l2x0_flush_line(unsigned long addr) 83 89 { 84 90 void __iomem *base = l2x0_base; ··· 96 90 writel_relaxed(addr, base + L2X0_INV_LINE_PA); 97 91 } 98 92 #else 99 - 100 - /* Optimised out for non-errata case */ 101 - static inline void debug_writel(unsigned long val) 102 - { 103 - } 104 93 105 94 static inline void l2x0_flush_line(unsigned long addr) 106 95 { ··· 120 119 121 120 /* clean all ways */ 122 121 spin_lock_irqsave(&l2x0_lock, flags); 122 + debug_writel(0x03); 123 123 writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); 124 124 cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); 125 125 cache_sync(); 126 + debug_writel(0x00); 126 127 spin_unlock_irqrestore(&l2x0_lock, flags); 127 128 } 128 129 ··· 332 329 outer_cache.flush_all = l2x0_flush_all; 333 330 outer_cache.inv_all = l2x0_inv_all; 334 331 outer_cache.disable = l2x0_disable; 332 + outer_cache.set_debug = l2x0_set_debug; 335 333 336 334 printk(KERN_INFO "%s cache controller enabled\n", type); 337 335 printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",