mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Fix SPU livelock from atomic DMA cache line stores
Accurate SPU DMA and Accurate Cache Line Stores were both on. Together they route every 128-byte SPU DMA store through do_cell_atomic_128_store, turning bulk DMA into one atomic reservation store per cache line. Reservation contention then outruns the rate it can drain, an SPU spins in do_putllc forever, and the PPU stalls behind it on a semaphore the SPU never signals while the RSX idles. Both default off upstream. Cache Line Stores was wrong in our defaults; SPU DMA already defaulted off but was stored on, so a default change alone would not reach anyone who had already run the app, hence the migration. Seen on Minecraft, which froze loading world chunks, that being bulk SPU DMA and little else. Load dependent, so it presented as an intermittent freeze.
This commit is contained in:
@@ -61,6 +61,7 @@ object ConfigStore {
|
||||
private const val KEY_SPU_DECODER_RESTORE = "config.migrated.spuDecoderRestoreLlvm"
|
||||
private const val KEY_XFLOAT_BACK_TO_APPROX = "config.migrated.xfloatBackToApprox"
|
||||
private const val KEY_PRECISE_SPU_OFF = "config.migrated.preciseSpuVerifyOff"
|
||||
private const val KEY_ATOMIC_DMA_OFF = "config.migrated.atomicDmaStoresOff"
|
||||
private const val KEY_RELAXED_ZCULL_ON = "config.migrated.relaxedZcullOn"
|
||||
private const val KEY_RELAXED_ZCULL_OFF = "config.migrated.relaxedZcullOff"
|
||||
private const val KEY_AFFINITY_ON = "config.migrated.affinityScheduler"
|
||||
@@ -176,6 +177,27 @@ object ConfigStore {
|
||||
MainActivityRuntime.prefs.edit { putBoolean(KEY_XFLOAT_BACK_TO_APPROX, true) }
|
||||
}
|
||||
|
||||
// Return the two reservation settings to upstream's defaults, both off.
|
||||
//
|
||||
// Accurate SPU DMA + Accurate Cache Line Stores together route every 128-byte
|
||||
// SPU DMA store through do_cell_atomic_128_store, so bulk DMA turns into one
|
||||
// atomic reservation store per cache line. Contention then outruns the rate the
|
||||
// reservations can drain and an SPU spins in do_putllc indefinitely, taking the
|
||||
// PPU down with it. Minecraft froze on world chunk load, which is bulk SPU DMA
|
||||
// and nothing else. Load-dependent, hence the intermittency.
|
||||
//
|
||||
// Both are stored true on existing installs, so the default change alone would
|
||||
// not reach anyone who has already run the app.
|
||||
if (!MainActivityRuntime.prefs.getBoolean(KEY_ATOMIC_DMA_OFF, false)) {
|
||||
if (raw != null && (parsed.ps3.accurateCacheLine || parsed.ps3.accurateSpuDma)) {
|
||||
parsed = parsed.copy(
|
||||
ps3 = parsed.ps3.copy(accurateCacheLine = false, accurateSpuDma = false),
|
||||
)
|
||||
dirty = true
|
||||
}
|
||||
MainActivityRuntime.prefs.edit { putBoolean(KEY_ATOMIC_DMA_OFF, true) }
|
||||
}
|
||||
|
||||
// Move anyone still on the old Approximate xfloat default onto Accurate.
|
||||
// Approximate corrupted SPU float registers badly enough that a job
|
||||
// manager built a DMA command out of one; see Settings.spuXFloat. A
|
||||
|
||||
@@ -156,7 +156,19 @@ data class Ps3Settings(
|
||||
*/
|
||||
val spuXFloat: Int = 1,
|
||||
val accurateSpuRsv: Boolean = true,
|
||||
val accurateCacheLine: Boolean = true,
|
||||
/**
|
||||
* Off, matching upstream, which is what this always should have been.
|
||||
*
|
||||
* With this on AND Accurate SPU DMA on, every 128-byte SPU DMA store is routed through
|
||||
* do_cell_atomic_128_store, i.e. an atomic reservation store per cache line of every
|
||||
* transfer. A game doing bulk DMA then generates reservation contention faster than it
|
||||
* can drain, and an SPU sits in do_putllc retrying forever while the PPU stalls behind
|
||||
* it and the RSX spins idle. Minecraft froze loading world chunks, which is almost
|
||||
* nothing but bulk SPU DMA.
|
||||
*
|
||||
* Load-dependent, so it presented as an intermittent freeze rather than a clean failure.
|
||||
*/
|
||||
val accurateCacheLine: Boolean = false,
|
||||
val accurateRsxRsv: Boolean = false,
|
||||
val ppuRsvPriority: Boolean = false,
|
||||
val spuVerification: Boolean = true,
|
||||
|
||||
Reference in New Issue
Block a user