summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Ryabinin <ryabinin.a.a@gmail.com>2012-10-31 11:50:06 +0400
committerAndrew Ryabinin <ryabinin.a.a@gmail.com>2012-10-31 09:30:10 +0100
commitb19b250de70cc4ac5b4ecbeac714e7a4aaadf5fb (patch)
treef62bb573ee8a86ff9024bb387df23b711e208ca9
parent5cfcb8f48db3da2c98aa1c9d81f2db69dd253191 (diff)
downloadrockbox-b19b250de70cc4ac5b4ecbeac714e7a4aaadf5fb.tar.gz
rockbox-b19b250de70cc4ac5b4ecbeac714e7a4aaadf5fb.zip
rk27xx: Disable interrupts before invalidating cache.
If interrupts trigger during cache invalidation this could cause memory corruption. This should be right fix for commit_discard_idcache in contrast to 72ebcbf and c1ec1ec. Change-Id: I141fb585004d4a1967b0a03bc37db3964d886564 Reviewed-on: http://gerrit.rockbox.org/345 Tested-by: Andrew Ryabinin <ryabinin.a.a@gmail.com> Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
-rw-r--r--firmware/target/arm/rk27xx/system-rk27xx.c21
1 files changed, 8 insertions, 13 deletions
diff --git a/firmware/target/arm/rk27xx/system-rk27xx.c b/firmware/target/arm/rk27xx/system-rk27xx.c
index 8e6773f816..d264476328 100644
--- a/firmware/target/arm/rk27xx/system-rk27xx.c
+++ b/firmware/target/arm/rk27xx/system-rk27xx.c
@@ -97,7 +97,7 @@ void irq_handler(void)
97 "sub sp, sp, #8 \n"); /* Reserve stack */ 97 "sub sp, sp, #8 \n"); /* Reserve stack */
98 98
99 int irq_no = INTC_ISR & 0x1f; 99 int irq_no = INTC_ISR & 0x1f;
100 100
101 irqvector[irq_no](); 101 irqvector[irq_no]();
102 102
103 /* clear interrupt */ 103 /* clear interrupt */
@@ -200,14 +200,7 @@ void udelay(unsigned usecs)
200 ); 200 );
201} 201}
202 202
203/* Invalidating both cache lines from single function 203static void cache_invalidate_way(int way)
204 * gives sometimes strange data aborts.
205 * This version resembles how OF invalidates cache.
206 * noinline attribute is to guarantee that future
207 * gcc change will not decide to inline this call (although
208 * current arm-eabi version from our toolchain doesn't do that
209 */
210static void __attribute__((noinline)) cache_invalidate_way(int way)
211{ 204{
212 /* Issue invalidata way command to the cache controler */ 205 /* Issue invalidata way command to the cache controler */
213 CACHEOP = ((way<<31)|0x2); 206 CACHEOP = ((way<<31)|0x2);
@@ -218,15 +211,13 @@ static void __attribute__((noinline)) cache_invalidate_way(int way)
218 211
219void commit_discard_idcache(void) 212void commit_discard_idcache(void)
220{ 213{
221 DEVID &= ~(1<<31); /* disable cache */ 214 int old_irq = disable_irq_save();
222 215
223 /* invalidate cache way 0 */
224 cache_invalidate_way(0); 216 cache_invalidate_way(0);
225 217
226 /* invalidate cache way 1 */
227 cache_invalidate_way(1); 218 cache_invalidate_way(1);
228 219
229 DEVID |= (1<<31); /* enable cache */ 220 restore_irq(old_irq);
230} 221}
231void commit_discard_dcache (void) __attribute__((alias("commit_discard_idcache"))); 222void commit_discard_dcache (void) __attribute__((alias("commit_discard_idcache")));
232 223
@@ -235,6 +226,8 @@ void commit_discard_dcache_range (const void *base, unsigned int size)
235 int cnt = size + ((unsigned long)base & 0x1f); 226 int cnt = size + ((unsigned long)base & 0x1f);
236 unsigned long opcode = ((unsigned long)base & 0xffffffe0) | 0x01; 227 unsigned long opcode = ((unsigned long)base & 0xffffffe0) | 0x01;
237 228
229 int old_irq = disable_irq_save();
230
238 while (cnt > 0) 231 while (cnt > 0)
239 { 232 {
240 CACHEOP = opcode; 233 CACHEOP = opcode;
@@ -244,6 +237,8 @@ void commit_discard_dcache_range (const void *base, unsigned int size)
244 cnt -= 32; 237 cnt -= 32;
245 opcode += 32; 238 opcode += 32;
246 } 239 }
240
241 restore_irq(old_irq);
247} 242}
248 243
249#ifdef HAVE_ADJUSTABLE_CPU_FREQ 244#ifdef HAVE_ADJUSTABLE_CPU_FREQ