From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED50F9463 for ; Fri, 1 May 2026 17:28:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777656489; cv=none; b=k2G4NbfO48TYD3HbIiu6YvoJsAZdimHOTMT9xrIIGu7VCHX1ZdU4X2PP9cFK24h2ITrw9SGdPKfMHbvRxE+s5r0S+K46Z88ukaNhgRkAWUwak+0eLH5zXws6eBXoS7tSSvyb5pULbtlMy6OQm0Lal9ClTD7nOHMsf3yWTshjhrk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777656489; c=relaxed/simple; bh=bDkcjD0P80Z7iVHO8mCSV5oQ7rVyysuf9tPo2VbwgwI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l7VENPruyF1E1RVAbNejnmqeY2oCSsdrk+AWjYMMn6t7S3EjvaH1o/SVl92Np3mQb8MYdU4YybyHuAcrWGHeVdnxqxbNZr1E++izDlhjsyFv6c/l7aQi/dar5nj4VHe6BKXhdq3VWVnnPgAPT2lSnGSaKu/On/xi2w5ZHf70F/o= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YqsGkw/x; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YqsGkw/x" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3D44DC2BCB4; Fri, 1 May 2026 17:28:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777656488; bh=bDkcjD0P80Z7iVHO8mCSV5oQ7rVyysuf9tPo2VbwgwI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YqsGkw/xXfBJrMJxb3Mwq4iXrB9ykeu9hjJZDwLqT2fR4MzmOENA/ebk2Mha/CADz QF2fotBc2C8Tg5Cb+T8aFMylcDBDKEIOI9BPJvTKGmpLqZAvsSCVy5sf70qj5ZWvUh jn9XHVjJwkNeBSwYUv9iT3tR8+rPGBDMfHOKht5zZPHtZ+LLFo4O6JWO6jMLMiHAbd FH4508Bj+DAuTfqvrQzOn0dPcdkPRGOTHgbj5IWwF4XZxX+oRH03X3GbIej3sxAMiR pN9QdIpvhuw8DsIv3b0390EcL/+vQCqADLvmWV88OB2ZMudEWA9pBxllhGgA9HvpmP p3KtgEyQ/RU3A== From: Sasha Levin To: stable@vger.kernel.org Cc: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= , kernel test robot , Takashi Iwai , Sasha Levin Subject: [PATCH 5.10.y 2/2] ALSA: aoa: i2sbus: clear stale prepared state Date: Fri, 1 May 2026 13:28:00 -0400 Message-ID: <20260501172800.3766490-2-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260501172800.3766490-1-sashal@kernel.org> References: <2026050153-spookily-fool-bd46@gregkh> <20260501172800.3766490-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Cássio Gabriel [ 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 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 Link: https://patch.msgid.link/20260331-aoa-i2sbus-clear-stale-active-v2-1-3764ae2889a1@gmail.com Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- 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 e95103e5f2fcd..04afdaa1bc39c 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