Devicetree
 help / color / mirror / Atom feed
* [PATCH v4 0/2] ASoC: codecs: nau8360: Fix DSP routing and deadlock issues
@ 2026-09-09  2:59 Neo Chang
  2026-09-09  2:59 ` [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails Neo Chang
  2026-09-09  2:59 ` [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update Neo Chang
  0 siblings, 2 replies; 5+ messages in thread
From: Neo Chang @ 2026-09-09  2:59 UTC (permalink / raw)
  To: broonie
  Cc: lgirdwood, perex, robh, krzk+dt, linux-sound, devicetree,
	alsa-devel, neo.chang70, kchsu0, sjlin0, Neo Chang

This patch series addresses two issues in the nau8360 codec driver
regarding the DAC mux control:

1. An invalid hardware routing state that occurs when the DSP firmware
   fails to load but the userspace attempts to switch to the DSP path.

2. A pre-existing AB-BA deadlock triggered during concurrent stream
   startups or ALSA mixer updates.

---
Changes in v4:
- Patch 1/2: Changed the return value to -EBUSY instead of 0 to properly
  reject the invalid request and prevent ALSA state desync.
- Patch 1/2: Used dev_warn_ratelimited() instead of dev_warn().
- Patch 2/2: Added a fix for the AB-BA deadlock in nau8360_dac_mux_put_enum().
  (Reported by Sashiko AI)

Changes in v3:
- Block the DSP path selection if the firmware fails to load to prevent
  invalid routing states.

Changes in v2:
- Use snd_soc_component_update_bits() to prevent register overwriting.
  (Reported by Sashiko AI)
- Fix missing bit shift for default PEQ band. (Reported by Sashiko AI)

Neo Chang (2):
  ASoC: codecs: nau8360: Block DSP path selection when firmware load
    fails
  ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update

 sound/soc/codecs/nau8360.c | 19 +++++++++++++------
 sound/soc/codecs/nau8360.h |  6 ++++++
 2 files changed, 19 insertions(+), 6 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails
  2026-09-09  2:59 [PATCH v4 0/2] ASoC: codecs: nau8360: Fix DSP routing and deadlock issues Neo Chang
@ 2026-09-09  2:59 ` Neo Chang
  2026-09-09  3:13   ` sashiko-bot
  2026-09-09  2:59 ` [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update Neo Chang
  1 sibling, 1 reply; 5+ messages in thread
From: Neo Chang @ 2026-09-09  2:59 UTC (permalink / raw)
  To: broonie
  Cc: lgirdwood, perex, robh, krzk+dt, linux-sound, devicetree,
	alsa-devel, neo.chang70, kchsu0, sjlin0, Neo Chang

Block the DSP path selection if the firmware fails to load to prevent
invalid routing states.

If the firmware is not ready, nau8360_dac_mux_put_enum() will print
a rate-limited warning and return -EBUSY. This rejects the invalid
userspace request and maintains the original hardware state without
causing audio wrong status.

Signed-off-by: Neo Chang <YLCHANG2@nuvoton.com>
---
 sound/soc/codecs/nau8360.c | 7 ++++++-
 sound/soc/codecs/nau8360.h | 6 ++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/nau8360.c b/sound/soc/codecs/nau8360.c
index 89b8ee80d6c8..277aa982c341 100644
--- a/sound/soc/codecs/nau8360.c
+++ b/sound/soc/codecs/nau8360.c
@@ -715,10 +715,15 @@ static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
 	int ret = 0;
 
 	if (snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY) {
-		dev_warn(nau8360->dev, "changing path is not allowed during playback");
+		dev_warn_ratelimited(nau8360->dev, "changing path is not allowed during playback");
 		return ret;
 	}
 
+	if (item[0] == NAU8360_DAC_SRC_DSP && !nau8360->load_fw_done) {
+		dev_warn_ratelimited(nau8360->dev, "Cannot enable DSP: Firmware not ready or disabled\n");
+		return -EBUSY;
+	}
+
 	mutex_lock(&nau8360->lock);
 
 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
diff --git a/sound/soc/codecs/nau8360.h b/sound/soc/codecs/nau8360.h
index cc640ba8c838..71396747c0fa 100644
--- a/sound/soc/codecs/nau8360.h
+++ b/sound/soc/codecs/nau8360.h
@@ -870,6 +870,12 @@ enum {
 	NAU8360_TDM_TXN,
 };
 
+/* DAC Source Path*/
+enum {
+	NAU8360_DAC_SRC_HW1 = 0,
+	NAU8360_DAC_SRC_DSP,
+};
+
 /* PLL Source */
 enum {
 	NAU8360_PLL_MCLK,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update
  2026-09-09  2:59 [PATCH v4 0/2] ASoC: codecs: nau8360: Fix DSP routing and deadlock issues Neo Chang
  2026-09-09  2:59 ` [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails Neo Chang
@ 2026-09-09  2:59 ` Neo Chang
  2026-09-09  3:30   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Neo Chang @ 2026-09-09  2:59 UTC (permalink / raw)
  To: broonie
  Cc: lgirdwood, perex, robh, krzk+dt, linux-sound, devicetree,
	alsa-devel, neo.chang70, kchsu0, sjlin0, Neo Chang, Sashiko AI

nau8360_dac_mux_put_enum() acquires nau8360->lock before the DAPM mutex,
causing an AB-BA lock inversion. This deadlocks with concurrent stream
startups or mixer updates, which acquire locks in the reverse order.

Fix this by replacing nau8360->lock with the DAPM mutex to protect
pre-checks, releasing it before calling snd_soc_dapm_put_enum_double().

Reported-by: Sashiko AI <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260908030342.222655-1-YLCHANG2@nuvoton.com?part=1
Signed-off-by: Neo Chang <YLCHANG2@nuvoton.com>
---
 sound/soc/codecs/nau8360.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/nau8360.c b/sound/soc/codecs/nau8360.c
index 277aa982c341..7f83c737e8af 100644
--- a/sound/soc/codecs/nau8360.c
+++ b/sound/soc/codecs/nau8360.c
@@ -689,6 +689,8 @@ static void nau8360_dsp_switch(struct snd_soc_component *component, bool enable)
 	struct regmap *regmap = nau8360->regmap;
 	int value = NAU8360_PEQ_BAND_8;
 
+	mutex_lock(&nau8360->lock);
+
 	/* If DSP is enabled, unstall HW3 engine and DSP, loading DSP firmware,
 	 * and configure PEQ after dsp reset.
 	 */
@@ -702,6 +704,7 @@ static void nau8360_dsp_switch(struct snd_soc_component *component, bool enable)
 	regmap_update_bits(regmap, NAU8360_R9D_PEQ_CTL, NAU8360_PEQ_BAND_MASK,
 		value << NAU8360_PEQ_BAND_SFT);
 
+	mutex_unlock(&nau8360->lock);
 }
 
 static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
@@ -714,27 +717,26 @@ static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
 	unsigned int *item = ucontrol->value.enumerated.item;
 	int ret = 0;
 
+	snd_soc_dapm_mutex_lock(dapm);
 	if (snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY) {
 		dev_warn_ratelimited(nau8360->dev, "changing path is not allowed during playback");
+		snd_soc_dapm_mutex_unlock(dapm);
 		return ret;
 	}
 
 	if (item[0] == NAU8360_DAC_SRC_DSP && !nau8360->load_fw_done) {
 		dev_warn_ratelimited(nau8360->dev, "Cannot enable DSP: Firmware not ready or disabled\n");
+		snd_soc_dapm_mutex_unlock(dapm);
 		return -EBUSY;
 	}
-
-	mutex_lock(&nau8360->lock);
+	snd_soc_dapm_mutex_unlock(dapm);
 
 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
 	if (ret <= 0)
-		goto unlock;
+		return ret;
 
 	nau8360_dsp_switch(component, snd_soc_enum_item_to_val(e, item[0]));
 
-unlock:
-	mutex_unlock(&nau8360->lock);
-
 	return ret;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails
  2026-09-09  2:59 ` [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails Neo Chang
@ 2026-09-09  3:13   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-09  3:13 UTC (permalink / raw)
  To: Neo Chang; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Time-of-check to time-of-use (TOCTOU) race when checking DAPM bias level, allowing path changes during active playback.
--

commit b29bd8969729968f9e98cb8e88c840d31f1aa474
Author: Neo Chang <YLCHANG2@nuvoton.com>

ASoC: codecs: nau8360: Block DSP path selection when firmware load fails
    
This commit blocks DSP path selection if the firmware fails to load,
preventing invalid routing states. It ensures invalid userspace requests
are rejected with -EBUSY to maintain the original hardware state.

> diff --git a/sound/soc/codecs/nau8360.c b/sound/soc/codecs/nau8360.c
> --- a/sound/soc/codecs/nau8360.c
> +++ b/sound/soc/codecs/nau8360.c
> @@ -715,10 +715,15 @@ static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
>  	int ret = 0;
>  
>  	if (snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY) {
> -		dev_warn(nau8360->dev, "changing path is not allowed during playback");
> +		dev_warn_ratelimited(nau8360->dev, "changing path is not allowed during playback");
>  		return ret;
>  	}
>  
> +	if (item[0] == NAU8360_DAC_SRC_DSP && !nau8360->load_fw_done) {
> +		dev_warn_ratelimited(nau8360->dev, "Cannot enable DSP: Firmware not ready or disabled\n");
> +		return -EBUSY;
> +	}
> +
>  	mutex_lock(&nau8360->lock);
>  
>  	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);

[Severity: High]
This is a pre-existing issue, but does nau8360_dac_mux_put_enum() have a
time-of-check to time-of-use (TOCTOU) race when checking the DAPM bias level?

The follow-up fix in this series ("ASoC: codecs: nau8360: Fix AB-BA deadlock
in mux update") adds dapm_mutex locking to this function but fails to resolve
the race condition.

If a concurrent userspace mixer update and a PCM stream start occur, the mixer
update thread can check that the bias level is <= SND_SOC_BIAS_STANDBY.

Once the lock is dropped (or before it is held, in the current patch state),
the PCM stream can start, acquire the dapm_mutex, transition the bias level to
SND_SOC_BIAS_ON, and release the lock.

Then, snd_soc_dapm_put_enum_double() re-acquires the lock internally and
blindly applies the path change while playback is active.

Can this sequence cause the hardware routing path to be mutated while audio
is active, potentially leading to invalid hardware routing states or audio
glitches?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260909025947.287120-1-YLCHANG2@nuvoton.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update
  2026-09-09  2:59 ` [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update Neo Chang
@ 2026-09-09  3:30   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-09  3:30 UTC (permalink / raw)
  To: Neo Chang; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Use-after-free (UAF) due to unbalanced lifecycle operations between devres component unregistration and background work cancellation.
- [High] Time-of-check to time-of-use (TOCTOU) race when verifying the DAPM bias level constraint before updating DAPM paths.
- [Medium] Returning 0 instead of an error code when rejecting a mux change during playback.
- [Medium] Bogus locking and data race when checking `load_fw_done` flag.
--

commit e1e283a6d218bffef7bd342646768fdbef3b2320
Author: Neo Chang <YLCHANG2@nuvoton.com>

ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update

This commit fixes an AB-BA lock inversion by replacing nau8360->lock with
the DAPM mutex to protect pre-checks. It drops the lock before calling
snd_soc_dapm_put_enum_double() to avoid deadlocks with concurrent stream
startups or mixer updates.

Link: https://sashiko.dev/#/patchset/20260908030342.222655-1-YLCHANG2@nuvoton.com?part=1

> diff --git a/sound/soc/codecs/nau8360.c b/sound/soc/codecs/nau8360.c
> index 277aa982c341e..7f83c737e8af8 100644
> --- a/sound/soc/codecs/nau8360.c
> +++ b/sound/soc/codecs/nau8360.c
[ ... ]
> @@ -714,27 +717,26 @@ static int nau8360_dac_mux_put_enum(struct snd_kcontrol *kcontrol,
>  	unsigned int *item = ucontrol->value.enumerated.item;
>  	int ret = 0;
>  
> +	snd_soc_dapm_mutex_lock(dapm);
>  	if (snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY) {
>  		dev_warn_ratelimited(nau8360->dev, "changing path is not allowed during playback");
> +		snd_soc_dapm_mutex_unlock(dapm);
>  		return ret;

[Severity: Medium]
This is a pre-existing issue, but does this return success to the ALSA
framework when the change was actually rejected?

Since ret is initialized to 0, userspace might incorrectly believe the request
was accepted or benignly ignored when it attempts to change the control during
playback.

>  	}
>  
>  	if (item[0] == NAU8360_DAC_SRC_DSP && !nau8360->load_fw_done) {

[Severity: Medium]
This isn't a bug introduced by this patch, but does the dapm_mutex actually
protect this load_fw_done flag?

Since nau8360_load_fw_work() asynchronously sets nau8360->load_fw_done = true
without acquiring dapm_mutex, it appears the read here remains a plain C data
race and the lock provides no actual synchronization.

>  		dev_warn_ratelimited(nau8360->dev, "Cannot enable DSP: Firmware not ready or disabled\n");
> +		snd_soc_dapm_mutex_unlock(dapm);
>  		return -EBUSY;
>  	}
> -
> -	mutex_lock(&nau8360->lock);
> +	snd_soc_dapm_mutex_unlock(dapm);
>  
>  	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);

[Severity: High]
This is a pre-existing issue, but could dropping the lock here before calling
snd_soc_dapm_put_enum_double() create a race condition?

Since snd_soc_dapm_put_enum_double() re-acquires the same dapm mutex
internally, there is a window where the lock is released. A concurrent PCM
stream startup could acquire the DAPM lock in this window, increment the bias
level, and start playback.

Once the stream starts, snd_soc_dapm_put_enum_double() acquires the lock and
blindly applies the mux routing change during active playback, circumventing
the driver's intended safety constraint checked earlier.

>  	if (ret <= 0)
> -		goto unlock;
> +		return ret;
>  
>  	nau8360_dsp_switch(component, snd_soc_enum_item_to_val(e, item[0]));
>  
> -unlock:
> -	mutex_unlock(&nau8360->lock);
> -
>  	return ret;
>  }

[Severity: Critical]
This is a pre-existing issue, but is there a use-after-free risk between
devres component unregistration and background work cancellation?

In nau8360_i2c_remove(), the background work is cancelled:

    cancel_work_sync(&nau8360->load_fw_work);

However, the ASoC component is registered using devm_snd_soc_register_component().
Due to devres cleanup ordering, the component remains registered after
nau8360_i2c_remove() finishes, until the devres release unregisters it.

During this window, an asynchronous sound card bind (e.g., from deferred probe)
could successfully acquire the module reference and call nau8360_codec_probe(),
which reschedules the work:

    schedule_work(&nau8360->load_fw_work);

The devres release would then continue, unregistering the component and freeing
the nau8360 struct without canceling the newly scheduled work.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260909025947.287120-1-YLCHANG2@nuvoton.com?part=2

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-09  3:30 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09  2:59 [PATCH v4 0/2] ASoC: codecs: nau8360: Fix DSP routing and deadlock issues Neo Chang
2026-09-09  2:59 ` [PATCH v4 1/2] ASoC: codecs: nau8360: Block DSP path selection when firmware load fails Neo Chang
2026-09-09  3:13   ` sashiko-bot
2026-09-09  2:59 ` [PATCH v4 2/2] ASoC: codecs: nau8360: Fix AB-BA deadlock in mux update Neo Chang
2026-09-09  3:30   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox