mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-09 23:53:28 -04:00
rk27xx: no whole-cache invalidate at run time
commit_discard_idcache() invalidated both cache ways at run time, at
every codec and plugin load and every USB connect. With the cache on,
the CPU crashed in the poll loop when that loop started a cache line of
its own; with the cache off around it, since 0e1952a4d1, code fetched
again afterwards could come back wrong. On a Samsung YP-CP3 a build
with a few changes elsewhere took an undefined instruction exception
in the USB interrupt handler at every boot into USB mode, always at
the same instruction, wherever the linker put it. The same build with
only the invalidate at USB connect replaced by a nop booted and
worked.
The original firmware invalidates the ways only once, at power-on with
the cache off, as crt0.S does, and after that only single lines. None
is needed at run time: the cache is unified and write-through, so what
the CPU writes, code included, is in memory and in any cached copy, and
every DMA into memory - SD reads, USB receives, recording - discards
the lines of its own buffer first. NAND is read by the CPU. So
commit_discard_idcache(), and commit_discard_dcache() with it, now do
nothing.
Tested on a YP-CP3, with the build that crashed: it boots into USB
mode, copies files with matching checksums, plays several formats,
runs plugins (fft with playback, bubbles), and records.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I14301a0c05736e28e53a3365c838f4a4a73052b3
This commit is contained in:
parent
9d3d2c6e67
commit
9ce3fca4cb
1 changed files with 9 additions and 26 deletions
|
|
@ -184,34 +184,17 @@ void udelay(unsigned usecs)
|
|||
);
|
||||
}
|
||||
|
||||
static void cache_invalidate_way(int way)
|
||||
{
|
||||
/* Issue invalidata way command to the cache controler */
|
||||
CACHEOP = ((way<<31)|0x2);
|
||||
|
||||
/* wait for invalidate process to complete */
|
||||
while (CACHEOP & 0x03);
|
||||
}
|
||||
|
||||
/* No whole-cache invalidate at run time, as in the original firmware: it
|
||||
* invalidates the ways once, at power-on with the cache off (crt0.S), and
|
||||
* after that only single lines. Invalidating the ways while running from
|
||||
* cached SDRAM crashed depending on where code happened to lie - with the
|
||||
* cache on in the poll loop, and with it off later, as code was fetched
|
||||
* again. None is needed: the cache is unified and write-through, so what
|
||||
* the CPU writes, code included, is in memory and in any cached copy, and
|
||||
* every DMA into memory discards the lines of its own buffer first
|
||||
* (commit_discard_dcache_range()). */
|
||||
void commit_discard_idcache(void)
|
||||
{
|
||||
int old_irq = disable_irq_save();
|
||||
unsigned long devid = DEVID;
|
||||
|
||||
/* Invalidate with the cache off, as crt0 does. This code runs from
|
||||
* cached SDRAM: invalidating the ways while fetching through them fails
|
||||
* when the poll loop starts on a cache line of its own, depending on
|
||||
* where the linker happened to put it. The cache is write-through, so
|
||||
* nothing is lost by turning it off. */
|
||||
DEVID = devid & ~(1UL << 31);
|
||||
|
||||
cache_invalidate_way(0);
|
||||
|
||||
cache_invalidate_way(1);
|
||||
|
||||
DEVID = devid;
|
||||
|
||||
restore_irq(old_irq);
|
||||
}
|
||||
void commit_discard_dcache (void) __attribute__((alias("commit_discard_idcache")));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue