diff options
author | Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> | 2024-08-05 14:49:21 +0300 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2024-08-18 09:44:24 +0300 |
commit | f8c35d61ba01afa76846905c67862cdace7f66b0 (patch) | |
tree | 5e9b99b439c5852f5a957bdddceb8b3f34756952 /drivers/soundwire/intel_bus_common.c | |
parent | 663229e24255883f010ae4d94f9f8e9c34e57d6c (diff) | |
download | linux-f8c35d61ba01afa76846905c67862cdace7f66b0.tar.xz |
soundwire: cadence: re-check Peripheral status with delayed_work
The SoundWire peripheral enumeration is entirely based on interrupts,
more specifically sticky bits tracking state changes.
This patch adds a defensive programming check on the actual status
reported in PING frames. If for some reason an interrupt was lost or
delayed, the delayed work would detect a peripheral change of status
after the bus starts.
The 100ms defined for the delay is not completely arbitrary, if a
Peripheral didn't join the bus within that delay then probably the
hardware link is broken, and conversely if the detection didn't happen
because of software issues the 100ms is still acceptable in terms of
user experience.
The overhead of the one-shot workqueue is minimal, and the mutual
exclusion ensures that the interrupt and delayed work cannot update
the status concurrently.
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
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/20240805114921.88007-1-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/soundwire/intel_bus_common.c')
-rw-r--r-- | drivers/soundwire/intel_bus_common.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c index df944e11b9ca..2bc960d05780 100644 --- a/drivers/soundwire/intel_bus_common.c +++ b/drivers/soundwire/intel_bus_common.c @@ -60,6 +60,9 @@ int intel_start_bus(struct sdw_intel *sdw) sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -151,6 +154,9 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw) } sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -184,6 +190,9 @@ int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + schedule_delayed_work(&cdns->attach_dwork, + msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS)); + return 0; } @@ -194,6 +203,8 @@ int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) bool wake_enable = false; int ret; + cancel_delayed_work_sync(&cdns->attach_dwork); + if (clock_stop) { ret = sdw_cdns_clock_stop(cdns, true); if (ret < 0) |