From: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com
[ Upstream commit 5aedb8d8336b0a0421b58ca27d1b572aa6695b5b ]
The existing code enables the Cadence IP interrupts after the bus reset sequence. The problem with this sequence is that it might be pre-empted, giving SoundWire devices time to sync and report as ATTACHED before the interrupts are enabled. In that case, the Cadence IP will not detect a state change and will not throw an interrupt to proceed with the enumeration of a Device0.
In our overnight stress tests, we observed that a slight sub-millisecond delay in enabling interrupts after the reset was correlated with detection failures. This problem is more prevalent on the LunarLake silicon, likely due to SOC integration changes, but it was observed on earlier generations as well.
This patch reverts the sequence, with the interrupts enabled before performing the bus reset. This removes the race condition and makes sure the Cadence IP is able to detect the presence of a Device0 in all cases.
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Bard Liao yung-chuan.liao@linux.intel.com Link: https://lore.kernel.org/r/20240805115003.88035-1-yung-chuan.liao@linux.intel... Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/soundwire/intel_bus_common.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c index e5ac3cc7cb79b..179aa0d85951b 100644 --- a/drivers/soundwire/intel_bus_common.c +++ b/drivers/soundwire/intel_bus_common.c @@ -45,15 +45,15 @@ int intel_start_bus(struct sdw_intel *sdw) return ret; }
- ret = sdw_cdns_exit_reset(cdns); + ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { - dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); + dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); return ret; }
- ret = sdw_cdns_enable_interrupt(cdns, true); + ret = sdw_cdns_exit_reset(cdns); if (ret < 0) { - dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); + dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); return ret; }
@@ -136,15 +136,15 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw) return ret; }
- ret = sdw_cdns_exit_reset(cdns); + ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); + dev_err(dev, "cannot enable interrupts during resume\n"); return ret; }
- ret = sdw_cdns_enable_interrupt(cdns, true); + ret = sdw_cdns_exit_reset(cdns); if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); + dev_err(dev, "unable to exit bus reset sequence during resume\n"); return ret; }