diff options
-rw-r--r-- | arch/arm/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 36 |
2 files changed, 49 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 762ae536f909..0f1ad743ccdd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -924,6 +924,19 @@ config ARM_ERRATA_460075 | |||
924 | ACTLR register. Note that setting specific bits in the ACTLR register | 924 | ACTLR register. Note that setting specific bits in the ACTLR register |
925 | may not be available in non-secure mode. | 925 | may not be available in non-secure mode. |
926 | 926 | ||
927 | config PL310_ERRATA_588369 | ||
928 | bool "Clean & Invalidate maintenance operations do not invalidate clean lines" | ||
929 | depends on CACHE_L2X0 && ARCH_OMAP4 | ||
930 | help | ||
931 | The PL310 L2 cache controller implements three types of Clean & | ||
932 | Invalidate maintenance operations: by Physical Address | ||
933 | (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). | ||
934 | They are architecturally defined to behave as the execution of a | ||
935 | clean operation followed immediately by an invalidate operation, | ||
936 | both performing to the same memory location. This functionality | ||
937 | is not correctly implemented in PL310 as clean lines are not | ||
938 | invalidated as a result of these operations. Note that this errata | ||
939 | uses Texas Instrument's secure monitor api. | ||
927 | endmenu | 940 | endmenu |
928 | 941 | ||
929 | source "arch/arm/common/Kconfig" | 942 | source "arch/arm/common/Kconfig" |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 1a14d18e5713..07334632d3e2 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -56,12 +56,42 @@ static inline void l2x0_inv_line(unsigned long addr) | |||
56 | writel(addr, base + L2X0_INV_LINE_PA); | 56 | writel(addr, base + L2X0_INV_LINE_PA); |
57 | } | 57 | } |
58 | 58 | ||
59 | #ifdef CONFIG_PL310_ERRATA_588369 | ||
60 | static void debug_writel(unsigned long val) | ||
61 | { | ||
62 | extern void omap_smc1(u32 fn, u32 arg); | ||
63 | |||
64 | /* | ||
65 | * Texas Instrument secure monitor api to modify the | ||
66 | * PL310 Debug Control Register. | ||
67 | */ | ||
68 | omap_smc1(0x100, val); | ||
69 | } | ||
70 | |||
71 | static inline void l2x0_flush_line(unsigned long addr) | ||
72 | { | ||
73 | void __iomem *base = l2x0_base; | ||
74 | |||
75 | /* Clean by PA followed by Invalidate by PA */ | ||
76 | cache_wait(base + L2X0_CLEAN_LINE_PA, 1); | ||
77 | writel(addr, base + L2X0_CLEAN_LINE_PA); | ||
78 | cache_wait(base + L2X0_INV_LINE_PA, 1); | ||
79 | writel(addr, base + L2X0_INV_LINE_PA); | ||
80 | } | ||
81 | #else | ||
82 | |||
83 | /* Optimised out for non-errata case */ | ||
84 | static inline void debug_writel(unsigned long val) | ||
85 | { | ||
86 | } | ||
87 | |||
59 | static inline void l2x0_flush_line(unsigned long addr) | 88 | static inline void l2x0_flush_line(unsigned long addr) |
60 | { | 89 | { |
61 | void __iomem *base = l2x0_base; | 90 | void __iomem *base = l2x0_base; |
62 | cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); | 91 | cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); |
63 | writel(addr, base + L2X0_CLEAN_INV_LINE_PA); | 92 | writel(addr, base + L2X0_CLEAN_INV_LINE_PA); |
64 | } | 93 | } |
94 | #endif | ||
65 | 95 | ||
66 | static inline void l2x0_inv_all(void) | 96 | static inline void l2x0_inv_all(void) |
67 | { | 97 | { |
@@ -83,13 +113,17 @@ static void l2x0_inv_range(unsigned long start, unsigned long end) | |||
83 | spin_lock_irqsave(&l2x0_lock, flags); | 113 | spin_lock_irqsave(&l2x0_lock, flags); |
84 | if (start & (CACHE_LINE_SIZE - 1)) { | 114 | if (start & (CACHE_LINE_SIZE - 1)) { |
85 | start &= ~(CACHE_LINE_SIZE - 1); | 115 | start &= ~(CACHE_LINE_SIZE - 1); |
116 | debug_writel(0x03); | ||
86 | l2x0_flush_line(start); | 117 | l2x0_flush_line(start); |
118 | debug_writel(0x00); | ||
87 | start += CACHE_LINE_SIZE; | 119 | start += CACHE_LINE_SIZE; |
88 | } | 120 | } |
89 | 121 | ||
90 | if (end & (CACHE_LINE_SIZE - 1)) { | 122 | if (end & (CACHE_LINE_SIZE - 1)) { |
91 | end &= ~(CACHE_LINE_SIZE - 1); | 123 | end &= ~(CACHE_LINE_SIZE - 1); |
124 | debug_writel(0x03); | ||
92 | l2x0_flush_line(end); | 125 | l2x0_flush_line(end); |
126 | debug_writel(0x00); | ||
93 | } | 127 | } |
94 | 128 | ||
95 | while (start < end) { | 129 | while (start < end) { |
@@ -145,10 +179,12 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
145 | while (start < end) { | 179 | while (start < end) { |
146 | unsigned long blk_end = start + min(end - start, 4096UL); | 180 | unsigned long blk_end = start + min(end - start, 4096UL); |
147 | 181 | ||
182 | debug_writel(0x03); | ||
148 | while (start < blk_end) { | 183 | while (start < blk_end) { |
149 | l2x0_flush_line(start); | 184 | l2x0_flush_line(start); |
150 | start += CACHE_LINE_SIZE; | 185 | start += CACHE_LINE_SIZE; |
151 | } | 186 | } |
187 | debug_writel(0x00); | ||
152 | 188 | ||
153 | if (blk_end < end) { | 189 | if (blk_end < end) { |
154 | spin_unlock_irqrestore(&l2x0_lock, flags); | 190 | spin_unlock_irqrestore(&l2x0_lock, flags); |