diff options
author | Boris Gjenero <boris.gjenero@gmail.com> | 2012-10-27 12:24:14 -0400 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2013-01-24 11:26:23 +0100 |
commit | 0fec8414a35d980665e5bc47183f9f888158e087 (patch) | |
tree | 8484dd2be3f824f924537c6896a66463103a09ac /firmware/target/arm/pp | |
parent | 1789b717bab157a03ed5fcf448df035c59729cf7 (diff) |
Fix FS#12391 : Memory corruption on PP502x after commit_discard_idcache()
In commit_discard_idcache(), cache lines were marked as invalid. When
some cache lines are marked as invalid, memory corruption can occur.
This caused instability when using PP502x ATA DMA because of the many
more calls to that function. Here, commit_discard_idcache() is changed
to avoid the problem. Also, the cache is filled after being enabled to
to ensure there are never any cache lines that aren't marked as valid.
Change-Id: Ia26300acef6b0573c1f40299c496ee5cbda3dac8
Reviewed-on: http://gerrit.rockbox.org/339
Reviewed-by: Szymon Dziok <b0hoon@o2.pl>
Tested-by: Szymon Dziok <b0hoon@o2.pl>
Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
Diffstat (limited to 'firmware/target/arm/pp')
-rw-r--r-- | firmware/target/arm/pp/system-pp502x.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/firmware/target/arm/pp/system-pp502x.c b/firmware/target/arm/pp/system-pp502x.c index bb083a5d16..d3331bf9f4 100644 --- a/firmware/target/arm/pp/system-pp502x.c +++ b/firmware/target/arm/pp/system-pp502x.c @@ -219,9 +219,26 @@ void ICODE_ATTR commit_discard_idcache(void) { if (CACHE_CTL & CACHE_CTL_ENABLE) { - CACHE_OPERATION |= CACHE_OP_FLUSH | CACHE_OP_INVALIDATE; - while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); - nop; nop; nop; nop; + register int istat = disable_interrupt_save(IRQ_FIQ_STATUS); + + commit_dcache(); + + /* Cache lines which are not marked as valid can cause memory + * corruption when there are many writes to and code fetches from + * cached memory. This workaround points all cache status words past + * end of RAM and marks them as valid, but not dirty. Since that area + * is never accessed, the cache lines don't affect anything, and + * they're effectively discarded. Interrupts must be disabled here + * because any change they make to cached memory could be discarded. + */ + + register volatile unsigned long *p; + for (p = &CACHE_STATUS_BASE; + p < (&CACHE_STATUS_BASE) + 512*16/sizeof(*p); + p += 16/sizeof(*p)) + *p = ((MEMORYSIZE*0x100000) >> 11) | 0x800000; + + restore_interrupt(istat); } } @@ -253,6 +270,13 @@ static void init_cache(void) /* enable cache */ CACHE_CTL |= CACHE_CTL_INIT | CACHE_CTL_ENABLE | CACHE_CTL_RUN; nop; nop; nop; nop; + + /* Ensure all cache lines are valid for the next flush. Since this + * can run from cached RAM, rewriting of cache status words may not + * be safe and the cache is filled instead by reading. */ + register volatile char *p; + for (p = (volatile char *)0; p < (volatile char *)0x2000; p += 0x10) + (void)*p; } #endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ |