Patch "ASoC: cs42l42: Avoid stale SoundWire ATTACH after hard reset" has been added to the 6.5-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ASoC: cs42l42: Avoid stale SoundWire ATTACH after hard reset

to the 6.5-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     asoc-cs42l42-avoid-stale-soundwire-attach-after-hard.patch
and it can be found in the queue-6.5 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit b7ddf716f817eeb17ec23256b5c0c3c3c9168cc9
Author: Richard Fitzgerald <rf@xxxxxxxxxxxxxxxxxxxxx>
Date:   Wed Sep 13 16:00:12 2023 +0100

    ASoC: cs42l42: Avoid stale SoundWire ATTACH after hard reset
    
    [ Upstream commit 2d066c6a78654c179f95c9beda1985d4c6befa4e ]
    
    In SoundWire mode leave hard RESET asserted when exiting probe,
    and wait for an UNATTACHED notification before deasserting RESET.
    
    If the boot state of the reset GPIO was deasserted it is possible
    that the SoundWire core had already enumerated the CS42L42 before
    cs42l42_sdw_probe() is called. When cs42l42_common_probe() hard
    resets the CS42L42 it triggers a race condition:
    
    1) After cs42l42_sdw_probe() returns the thread that called it
       will call cs42l42_sdw_update_status() to report the last
       status recorded by the SoundWire core.
    
    2) The SoundWire bus master will see a PING with the CS42L42
       now reporting as unenumerated and will trigger the core
       SoundWire code to start enumerating CS42L42.
    
    These two threads are racing against each other. If (1)
    happens before (2) a stale ATTACHED notification will be
    reported to the cs42l42 driver when in fact the status of
    cs42l42 is now unattached.
    
    To avoid this race condition:
    
    - Leave RESET asserted on exit from cs42l42_sdw_probe().
      This ensures that an UNATTACHED notification must be
      sent to the cs42l42 driver. If cs42l42 was already
      enumerated it will be seen to drop off the bus, causing
      an UNATTACH notification. If it was never enumerated the
      status is already UNATTACHED and this will be reported
      by thread (1).
    
    - When the UNATTACH notification is received, release RESET.
      This will cause CS42L42 to be enumerated and eventually
      report an ATTACHED notification.
    
    - The ATTACHED notification is now valid.
    
    Signed-off-by: Richard Fitzgerald <rf@xxxxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Stefan Binding <sbinding@xxxxxxxxxxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20230913150012.604775-4-sbinding@xxxxxxxxxxxxxxxxxxxxx
    Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index eeab07c850f95..974bae4abfad1 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -344,6 +344,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
 	switch (status) {
 	case SDW_SLAVE_ATTACHED:
 		dev_dbg(cs42l42->dev, "ATTACHED\n");
+
+		/*
+		 * The SoundWire core can report stale ATTACH notifications
+		 * if we hard-reset CS42L42 in probe() but it had already been
+		 * enumerated. Reject the ATTACH if we haven't yet seen an
+		 * UNATTACH report for the device being in reset.
+		 */
+		if (cs42l42->sdw_waiting_first_unattach)
+			break;
+
 		/*
 		 * Initialise codec, this only needs to be done once.
 		 * When resuming from suspend, resume callback will handle re-init of codec,
@@ -354,6 +364,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
 		break;
 	case SDW_SLAVE_UNATTACHED:
 		dev_dbg(cs42l42->dev, "UNATTACHED\n");
+
+		if (cs42l42->sdw_waiting_first_unattach) {
+			/*
+			 * SoundWire core has seen that CS42L42 is not on
+			 * the bus so release RESET and wait for ATTACH.
+			 */
+			cs42l42->sdw_waiting_first_unattach = false;
+			gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+		}
+
 		break;
 	default:
 		break;
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index dc93861ddfb02..2961340f15e2e 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -2330,7 +2330,16 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,
 		/* Ensure minimum reset pulse width */
 		usleep_range(10, 500);
 
-		gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+		/*
+		 * On SoundWire keep the chip in reset until we get an UNATTACH
+		 * notification from the SoundWire core. This acts as a
+		 * synchronization point to reject stale ATTACH notifications
+		 * if the chip was already enumerated before we reset it.
+		 */
+		if (cs42l42->sdw_peripheral)
+			cs42l42->sdw_waiting_first_unattach = true;
+		else
+			gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
 	}
 	usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
 
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 4bd7b85a57471..7785125b73ab9 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -53,6 +53,7 @@ struct  cs42l42_private {
 	u8 stream_use;
 	bool hp_adc_up_pending;
 	bool suspended;
+	bool sdw_waiting_first_unattach;
 	bool init_done;
 };
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux