* FAILED: patch "[PATCH] ALSA: aoa: i2sbus: clear stale prepared state" failed to apply to 6.6-stable tree
@ 2026-05-01 10:31 gregkh
2026-05-01 15:54 ` [PATCH 6.6.y 1/2] ALSA: aoa: Use guard() for mutex locks Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: gregkh @ 2026-05-01 10:31 UTC (permalink / raw)
To: cassiogabrielcontato, lkp, tiwai; +Cc: stable
The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 5ed060d5491597490fb53ec69da3edc4b1e8c165
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026050151-retorted-alright-ba59@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 5ed060d5491597490fb53ec69da3edc4b1e8c165 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= <cassiogabrielcontato@gmail.com>
Date: Tue, 31 Mar 2026 18:14:04 -0300
Subject: [PATCH] ALSA: aoa: i2sbus: clear stale prepared state
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The i2sbus PCM code uses pi->active to constrain the sibling stream to
an already prepared duplex format and rate in i2sbus_pcm_open().
That state is set from i2sbus_pcm_prepare(), but the current code only
clears it on close. As a result, the sibling stream can inherit stale
constraints after the prepared state has been torn down.
Clear pi->active when hw_params() or hw_free() tears down the prepared
state, and set it again only after prepare succeeds.
Replace the stale FIXME in the duplex constraint comment with a description
of the current driver behavior: i2sbus still programs a single shared
transport configuration for both directions, so mixed formats are not
supported in duplex mode.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202604010125.AvkWBYKI-lkp@intel.com/
Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260331-aoa-i2sbus-clear-stale-active-v2-1-3764ae2889a1@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 97c807e67d56..63004ece94f9 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
* currently in use (if any). */
hw->rate_min = 5512;
hw->rate_max = 192000;
- /* if the other stream is active, then we can only
- * support what it is currently using.
- * FIXME: I lied. This comment is wrong. We can support
- * anything that works with the same serial format, ie.
- * when recording 24 bit sound we can well play 16 bit
- * sound at the same time iff using the same transfer mode.
+ /* If the other stream is already prepared, keep this stream
+ * on the same duplex format and rate.
+ *
+ * i2sbus_pcm_prepare() still programs one shared transport
+ * configuration for both directions, so mixed duplex formats
+ * are not supported here.
*/
if (other->active) {
- /* FIXME: is this guaranteed by the alsa api? */
hw->formats &= pcm_format_to_bits(i2sdev->format);
- /* see above, restrict rates to the one we already have */
+ /* Restrict rates to the one already in use. */
hw->rate_min = i2sdev->rate;
hw->rate_max = i2sdev->rate;
}
@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
}
#endif
+static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+
+ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ pi->active = 0;
+}
+
+static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, int in)
+{
+ i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
+ return 0;
+}
+
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
+ i2sbus_pcm_clear_active(i2sdev, in);
return 0;
}
+static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 0);
+}
+
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 0);
}
+static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 1);
+}
+
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 1);
@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return -EINVAL;
runtime = pi->substream->runtime;
- pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
|| (i2sdev->rate != runtime->rate)))
@@ -444,9 +472,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* early exit if already programmed correctly */
/* not locking these is fine since we touch them only in this function */
- if (in_le32(&i2sdev->intfregs->serial_format) == sfr
- && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+ if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
+ in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
+ pi->active = 1;
return 0;
+ }
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -484,6 +514,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+ pi->active = 1;
return 0;
}
@@ -728,6 +759,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_playback_ops = {
.open = i2sbus_playback_open,
.close = i2sbus_playback_close,
+ .hw_params = i2sbus_playback_hw_params,
.hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
@@ -796,6 +828,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_record_ops = {
.open = i2sbus_record_open,
.close = i2sbus_record_close,
+ .hw_params = i2sbus_record_hw_params,
.hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 1/2] ALSA: aoa: Use guard() for mutex locks
2026-05-01 10:31 FAILED: patch "[PATCH] ALSA: aoa: i2sbus: clear stale prepared state" failed to apply to 6.6-stable tree gregkh
@ 2026-05-01 15:54 ` Sasha Levin
2026-05-01 15:54 ` [PATCH 6.6.y 2/2] ALSA: aoa: i2sbus: clear stale prepared state Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-05-01 15:54 UTC (permalink / raw)
To: stable; +Cc: Takashi Iwai, Sasha Levin
From: Takashi Iwai <tiwai@suse.de>
[ Upstream commit 1cb6ecbb372002ef9e531c5377e5f60122411e40 ]
Replace the manual mutex lock/unlock pairs with guard() for code
simplification.
Only code refactoring, and no behavior change.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250829151335.7342-14-tiwai@suse.de
Stable-dep-of: 5ed060d54915 ("ALSA: aoa: i2sbus: clear stale prepared state")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/aoa/codecs/onyx.c | 104 +++++++++--------------------
sound/aoa/codecs/tas.c | 113 +++++++++++---------------------
sound/aoa/core/gpio-feature.c | 20 ++----
sound/aoa/core/gpio-pmf.c | 26 +++-----
sound/aoa/soundbus/i2sbus/pcm.c | 76 +++++++--------------
5 files changed, 112 insertions(+), 227 deletions(-)
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index a8a59d71dcec9..a714a3f3f6a56 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -121,10 +121,9 @@ static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 l, r;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
@@ -145,15 +144,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
- r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
- mutex_unlock(&onyx->mutex);
+ r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1])
return 0;
- }
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
ucontrol->value.integer.value[0]
@@ -161,7 +158,6 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
ucontrol->value.integer.value[1]
- VOLUME_RANGE_SHIFT);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -197,9 +193,8 @@ static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 ig;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] =
(ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
@@ -216,14 +211,13 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
n = v;
n &= ~ONYX_ADC_PGA_GAIN_MASK;
n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
& ONYX_ADC_PGA_GAIN_MASK;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
- mutex_unlock(&onyx->mutex);
return n != v;
}
@@ -251,9 +245,8 @@ static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
- mutex_unlock(&onyx->mutex);
ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
@@ -264,13 +257,12 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic)
{
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
v &= ~ONYX_ADC_INPUT_MIC;
if (mic)
v |= ONYX_ADC_INPUT_MIC;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
- mutex_unlock(&onyx->mutex);
}
static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
@@ -311,9 +303,8 @@ static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 c;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
@@ -328,9 +319,9 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
u8 v = 0, c = 0;
int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx->analog_locked)
- goto out_unlock;
+ return -EBUSY;
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
c = v;
@@ -341,9 +332,6 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
c |= ONYX_MUTE_RIGHT;
err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -372,9 +360,8 @@ static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, address, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
@@ -393,11 +380,10 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (spdiflock && onyx->spdif_locked) {
/* even if alsamixer doesn't care.. */
- err = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
onyx_read_register(onyx, address, &v);
c = v;
@@ -406,9 +392,6 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
c |= mask;
err = onyx_write_register(onyx, address, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -489,7 +472,7 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
ucontrol->value.iec958.status[0] = v & 0x3e;
@@ -501,7 +484,6 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
ucontrol->value.iec958.status[4] = v & 0x0f;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -512,7 +494,7 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
@@ -527,7 +509,6 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -672,14 +653,13 @@ static int onyx_usable(struct codec_info_item *cii,
struct onyx *onyx = cii->codec_data;
int spdif_enabled, analog_enabled;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
analog_enabled =
(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
!= (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
- mutex_unlock(&onyx->mutex);
switch (ti->tag) {
case 0: return 1;
@@ -695,9 +675,8 @@ static int onyx_prepare(struct codec_info_item *cii,
{
u8 v;
struct onyx *onyx = cii->codec_data;
- int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
@@ -706,10 +685,9 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DAC_CONTROL,
v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
- goto out_unlock;
+ return -EBUSY;
onyx->analog_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
#endif
switch (substream->runtime->rate) {
@@ -719,8 +697,7 @@ static int onyx_prepare(struct codec_info_item *cii,
/* these rates are ok for all outputs */
/* FIXME: program spdif channel control bits here so that
* userspace doesn't have to if it only plays pcm! */
- err = 0;
- goto out_unlock;
+ return 0;
default:
/* got some rate that the digital output can't do,
* so disable and lock it */
@@ -728,16 +705,12 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DIG_INFO4,
v & ~ONYX_SPDIF_ENABLE))
- goto out_unlock;
+ return -EBUSY;
onyx->spdif_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return -EBUSY;
}
static int onyx_open(struct codec_info_item *cii,
@@ -745,9 +718,8 @@ static int onyx_open(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count++;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -757,11 +729,10 @@ static int onyx_close(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count--;
if (!onyx->open_count)
onyx->spdif_locked = onyx->analog_locked = 0;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -771,7 +742,7 @@ static int onyx_switch_clock(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* this *MUST* be more elaborate later... */
switch (what) {
case CLOCK_SWITCH_PREPARE_SLAVE:
@@ -783,7 +754,6 @@ static int onyx_switch_clock(struct codec_info_item *cii,
default: /* silence warning */
break;
}
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -794,27 +764,21 @@ static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
/* Apple does a sleep here but the datasheet says to do it on resume */
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
static int onyx_resume(struct codec_info_item *cii)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* reset codec */
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
@@ -826,17 +790,13 @@ static int onyx_resume(struct codec_info_item *cii)
/* take codec out of suspend (if it still is after reset) */
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
/* FIXME: should divide by sample rate, but 8k is the lowest we go */
msleep(2205000/8000);
/* reset all values */
onyx_register_init(onyx);
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
#endif /* CONFIG_PM */
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index ab14723900615..4446307c095ca 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -235,10 +235,9 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->cached_volume_l;
ucontrol->value.integer.value[1] = tas->cached_volume_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -254,18 +253,15 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > 177)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->cached_volume_l == ucontrol->value.integer.value[0]
- && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->cached_volume_r == ucontrol->value.integer.value[1])
return 0;
- }
tas->cached_volume_l = ucontrol->value.integer.value[0];
tas->cached_volume_r = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -285,10 +281,9 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = !tas->mute_l;
ucontrol->value.integer.value[1] = !tas->mute_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -297,18 +292,15 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mute_l == !ucontrol->value.integer.value[0]
- && tas->mute_r == !ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mute_r == !ucontrol->value.integer.value[1])
return 0;
- }
tas->mute_l = !ucontrol->value.integer.value[0];
tas->mute_r = !ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -337,10 +329,9 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->mixer_l[idx];
ucontrol->value.integer.value[1] = tas->mixer_r[idx];
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -351,19 +342,16 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
- && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
return 0;
- }
tas->mixer_l[idx] = ucontrol->value.integer.value[0];
tas->mixer_r[idx] = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_mixer(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -396,9 +384,8 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_range;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -411,16 +398,13 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->drc_range == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_range == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_range = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -440,9 +424,8 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_enabled;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -451,16 +434,13 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
- if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_enabled == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_enabled = !!ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -486,9 +466,8 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -500,7 +479,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] > 1)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
oldacr = tas->acr;
/*
@@ -512,13 +491,10 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0])
tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
TAS_ACR_B_MON_SEL_RIGHT;
- if (oldacr == tas->acr) {
- mutex_unlock(&tas->mtx);
+ if (oldacr == tas->acr)
return 0;
- }
if (tas->hw_enabled)
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -557,9 +533,8 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->treble;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -571,16 +546,13 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->treble == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->treble == ucontrol->value.integer.value[0])
return 0;
- }
tas->treble = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_treble(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -608,9 +580,8 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->bass;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -622,16 +593,13 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->bass == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->bass == ucontrol->value.integer.value[0])
return 0;
- }
tas->bass = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_bass(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -722,13 +690,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
break;
case CLOCK_SWITCH_SLAVE:
/* Clocks are back, re-init the codec */
- mutex_lock(&tas->mtx);
- tas_reset_init(tas);
- tas_set_volume(tas);
- tas_set_mixer(tas);
- tas->hw_enabled = 1;
- tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
- mutex_unlock(&tas->mtx);
+ scoped_guard(mutex, &tas->mtx) {
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
+ tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+ }
break;
default:
/* doesn't happen as of now */
@@ -743,23 +711,21 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
* our i2c device is suspended, and then take note of that! */
static int tas_suspend(struct tas *tas)
{
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas->hw_enabled = 0;
tas->acr |= TAS_ACR_ANALOG_PDOWN;
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 0;
}
static int tas_resume(struct tas *tas)
{
/* reset codec */
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas_reset_init(tas);
tas_set_volume(tas);
tas_set_mixer(tas);
tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -802,14 +768,13 @@ static int tas_init_codec(struct aoa_codec *codec)
return -EINVAL;
}
- mutex_lock(&tas->mtx);
- if (tas_reset_init(tas)) {
- printk(KERN_ERR PFX "tas failed to initialise\n");
- mutex_unlock(&tas->mtx);
- return -ENXIO;
+ scoped_guard(mutex, &tas->mtx) {
+ if (tas_reset_init(tas)) {
+ printk(KERN_ERR PFX "tas failed to initialise\n");
+ return -ENXIO;
+ }
+ tas->hw_enabled = 1;
}
- tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
aoa_get_card(),
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index 39bb409b27f6d..19ed0e6907da3 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -212,10 +212,9 @@ static void ftr_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(¬if->mutex);
}
static void gpio_enable_dual_edge(int gpio)
@@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!irq)
return -ENODEV;
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify)
@@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
if (err)
- goto out_unlock;
+ return err;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(¬if->mutex);
- return err;
+ return 0;
}
static int ftr_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
index 37866039d1ead..e76bde25e41af 100644
--- a/sound/aoa/core/gpio-pmf.c
+++ b/sound/aoa/core/gpio-pmf.c
@@ -74,10 +74,9 @@ static void pmf_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(¬if->mutex);
}
static void pmf_gpio_init(struct gpio_runtime *rt)
@@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_runtime *rt,
return -EINVAL;
}
- mutex_lock(¬if->mutex);
+ guard(mutex)(¬if->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify) {
@@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
irq_client = kzalloc(sizeof(struct pmf_irq_client),
GFP_KERNEL);
- if (!irq_client) {
- err = -ENOMEM;
- goto out_unlock;
- }
+ if (!irq_client)
+ return -ENOMEM;
irq_client->data = notif;
irq_client->handler = pmf_handle_notify_irq;
irq_client->owner = THIS_MODULE;
@@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_runtime *rt,
printk(KERN_ERR "snd-aoa: gpio layer failed to"
" register %s irq (%d)\n", name, err);
kfree(irq_client);
- goto out_unlock;
+ return err;
}
notif->gpio_private = irq_client;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(¬if->mutex);
- return err;
+ return 0;
}
static int pmf_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 07df5cc0f2d7c..dab5d92c87696 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
u64 formats = 0;
unsigned int rates = 0;
struct transfer_info v;
- int result = 0;
int bus_factor = 0, sysclock_factor = 0;
int found_this;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
@@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (pi->active) {
/* alsa messed up */
- result = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
/* we now need to assign the hw */
@@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
ti++;
}
}
- if (!masks_inited || !bus_factor || !sysclock_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ if (!masks_inited || !bus_factor || !sysclock_factor)
+ return -ENODEV;
/* bus dependent stuff */
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
@@ -194,15 +190,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
hw->periods_max = MAX_DBDMA_COMMANDS;
err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- result = err;
- goto out_unlock;
- }
+ if (err < 0)
+ return err;
list_for_each_entry(cii, &sdev->codec_list, list) {
if (cii->codec->open) {
err = cii->codec->open(cii, pi->substream);
if (err) {
- result = err;
/* unwind */
found_this = 0;
list_for_each_entry_reverse(rev,
@@ -214,14 +207,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (rev == cii)
found_this = 1;
}
- goto out_unlock;
+ return err;
}
}
}
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ return 0;
}
#undef CHECK_RATE
@@ -232,7 +223,7 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
struct pcm_info *pi;
int err = 0, tmp;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, NULL);
@@ -246,7 +237,6 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
pi->substream = NULL;
pi->active = 0;
- mutex_unlock(&i2sdev->lock);
return err;
}
@@ -330,33 +320,26 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int input_16bit;
struct pcm_info *pi, *other;
int cnt;
- int result = 0;
unsigned int cmd, stopaddr;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
- if (pi->dbdma_ring.running) {
- result = -EBUSY;
- goto out_unlock;
- }
+ if (pi->dbdma_ring.running)
+ return -EBUSY;
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
- if (!pi->substream || !pi->substream->runtime) {
- result = -EINVAL;
- goto out_unlock;
- }
+ if (!pi->substream || !pi->substream->runtime)
+ return -EINVAL;
runtime = pi->substream->runtime;
pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
- || (i2sdev->rate != runtime->rate))) {
- result = -EINVAL;
- goto out_unlock;
- }
+ || (i2sdev->rate != runtime->rate)))
+ return -EINVAL;
i2sdev->format = runtime->format;
i2sdev->rate = runtime->rate;
@@ -412,10 +395,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
bi.bus_factor = cii->codec->bus_factor;
break;
}
- if (!bi.bus_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ if (!bi.bus_factor)
+ return -ENODEV;
input_16bit = 1;
break;
case SNDRV_PCM_FORMAT_S32_BE:
@@ -426,8 +407,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
input_16bit = 0;
break;
default:
- result = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
/* we assume all sysclocks are the same! */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
@@ -438,10 +418,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (clock_and_divisors(bi.sysclock_factor,
bi.bus_factor,
runtime->rate,
- &sfr) < 0) {
- result = -EINVAL;
- goto out_unlock;
- }
+ &sfr) < 0)
+ return -EINVAL;
switch (bi.bus_factor) {
case 32:
sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
@@ -457,10 +435,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int err = 0;
if (cii->codec->prepare)
err = cii->codec->prepare(cii, &bi, pi->substream);
- if (err) {
- result = err;
- goto out_unlock;
- }
+ if (err)
+ return err;
}
/* codecs are fine with it, so set our clocks */
if (input_16bit)
@@ -476,7 +452,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* not locking these is fine since we touch them only in this function */
if (in_le32(&i2sdev->intfregs->serial_format) == sfr
&& in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
- goto out_unlock;
+ return 0;
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -514,9 +490,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ return 0;
}
#ifdef CONFIG_PM
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 2/2] ALSA: aoa: i2sbus: clear stale prepared state
2026-05-01 15:54 ` [PATCH 6.6.y 1/2] ALSA: aoa: Use guard() for mutex locks Sasha Levin
@ 2026-05-01 15:54 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-05-01 15:54 UTC (permalink / raw)
To: stable; +Cc: Cássio Gabriel, kernel test robot, Takashi Iwai, Sasha Levin
From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
[ Upstream commit 5ed060d5491597490fb53ec69da3edc4b1e8c165 ]
The i2sbus PCM code uses pi->active to constrain the sibling stream to
an already prepared duplex format and rate in i2sbus_pcm_open().
That state is set from i2sbus_pcm_prepare(), but the current code only
clears it on close. As a result, the sibling stream can inherit stale
constraints after the prepared state has been torn down.
Clear pi->active when hw_params() or hw_free() tears down the prepared
state, and set it again only after prepare succeeds.
Replace the stale FIXME in the duplex constraint comment with a description
of the current driver behavior: i2sbus still programs a single shared
transport configuration for both directions, so mixed formats are not
supported in duplex mode.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202604010125.AvkWBYKI-lkp@intel.com/
Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260331-aoa-i2sbus-clear-stale-active-v2-1-3764ae2889a1@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/aoa/soundbus/i2sbus/pcm.c | 55 ++++++++++++++++++++++++++-------
1 file changed, 44 insertions(+), 11 deletions(-)
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index dab5d92c87696..7b247fdfde8d5 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
* currently in use (if any). */
hw->rate_min = 5512;
hw->rate_max = 192000;
- /* if the other stream is active, then we can only
- * support what it is currently using.
- * FIXME: I lied. This comment is wrong. We can support
- * anything that works with the same serial format, ie.
- * when recording 24 bit sound we can well play 16 bit
- * sound at the same time iff using the same transfer mode.
+ /* If the other stream is already prepared, keep this stream
+ * on the same duplex format and rate.
+ *
+ * i2sbus_pcm_prepare() still programs one shared transport
+ * configuration for both directions, so mixed duplex formats
+ * are not supported here.
*/
if (other->active) {
- /* FIXME: is this guaranteed by the alsa api? */
hw->formats &= pcm_format_to_bits(i2sdev->format);
- /* see above, restrict rates to the one we already have */
+ /* Restrict rates to the one already in use. */
hw->rate_min = i2sdev->rate;
hw->rate_max = i2sdev->rate;
}
@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
}
#endif
+static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
+{
+ struct pcm_info *pi;
+
+ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ pi->active = 0;
+}
+
+static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, int in)
+{
+ i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
+ return 0;
+}
+
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
{
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
get_pcm_info(i2sdev, in, &pi, NULL);
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
+ i2sbus_pcm_clear_active(i2sdev, in);
return 0;
}
+static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 0);
+}
+
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 0);
}
+static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return i2sbus_hw_params(substream, params, 1);
+}
+
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
{
return i2sbus_hw_free(substream, 1);
@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
return -EINVAL;
runtime = pi->substream->runtime;
- pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
|| (i2sdev->rate != runtime->rate)))
@@ -450,9 +478,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* early exit if already programmed correctly */
/* not locking these is fine since we touch them only in this function */
- if (in_le32(&i2sdev->intfregs->serial_format) == sfr
- && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+ if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
+ in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
+ pi->active = 1;
return 0;
+ }
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -490,6 +520,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+ pi->active = 1;
return 0;
}
@@ -746,6 +777,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_playback_ops = {
.open = i2sbus_playback_open,
.close = i2sbus_playback_close,
+ .hw_params = i2sbus_playback_hw_params,
.hw_free = i2sbus_playback_hw_free,
.prepare = i2sbus_playback_prepare,
.trigger = i2sbus_playback_trigger,
@@ -814,6 +846,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
static const struct snd_pcm_ops i2sbus_record_ops = {
.open = i2sbus_record_open,
.close = i2sbus_record_close,
+ .hw_params = i2sbus_record_hw_params,
.hw_free = i2sbus_record_hw_free,
.prepare = i2sbus_record_prepare,
.trigger = i2sbus_record_trigger,
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-01 15:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-01 10:31 FAILED: patch "[PATCH] ALSA: aoa: i2sbus: clear stale prepared state" failed to apply to 6.6-stable tree gregkh
2026-05-01 15:54 ` [PATCH 6.6.y 1/2] ALSA: aoa: Use guard() for mutex locks Sasha Levin
2026-05-01 15:54 ` [PATCH 6.6.y 2/2] ALSA: aoa: i2sbus: clear stale prepared state Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.