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 B43083019DC for ; Fri, 1 May 2026 17:13:22 +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=1777655602; cv=none; b=TBwP1lsicjBWMM85DiOxLJBYhu+kW9Yo0Cp7K1WcaS7gGXvq9V75nTOTWJ/1Ky4BA0D1FWpJHAqB1SDxxi5cBleaFZHW3gVQGauVECJ4gZiHs8ZUdxrvRRerQwLDbBr4+DTQyla1HGOdGVZvdAfcPUTO3izWNQdV/l3QPbRATjw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777655602; c=relaxed/simple; bh=03eKvLKLhrDYWRPbmG2WTWedFNbaFD29J9GoMt35t5M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HbHQE35Aa4MHe71VtoTIQewbKJBnUjITADrSZeO6g9EHSAwdLxtc5qknBIh6LVmHL+YPtWZuqrq6tdGPFCs9dMcD2bbwmbeWGdPnONWMJRojAMD2kkLMX46ZNdPABE2v2pDshs7cpTqWb343biB19Bwm4VLqSlWI3JX33MTO+4U= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Id5BaLEr; 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="Id5BaLEr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E762AC2BCB9; Fri, 1 May 2026 17:13:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777655602; bh=03eKvLKLhrDYWRPbmG2WTWedFNbaFD29J9GoMt35t5M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Id5BaLErbqWe42PlO1Gz6JaqX7mHotl1jiXRAMkop9nHpflOI6ZhERa7KEFSD5v+i u1VDgn1MDPJuBy9rbpj4vwUhOnXJu6XrCWJEa3C2aGw1coA7NVXb2dU0ZWxQjOD6vi iGA7J+5RU21c7RiYs8ReazGqcv1dQRCyMjbCvV976dCoRfQPg/97pwwSlLOAF0WV59 saaVkSB/EeyWwvNEOpylRvrdbdgNSru1es/fcZvm8k+L7SOMLzI/Pbv+gsWY7ntKPG otO+gkrlmeLZcKOrZpdll+1xIANsafaFSWGjszg7vRFRoiyhhq+0TBmtbOdEgEJnBw 1P3Nw+rrwiMyA== 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.15.y 2/2] ALSA: aoa: i2sbus: clear stale prepared state Date: Fri, 1 May 2026 13:13:18 -0400 Message-ID: <20260501171318.3681281-2-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260501171318.3681281-1-sashal@kernel.org> References: <2026050152-boxcar-lair-830c@gregkh> <20260501171318.3681281-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 086c49d457c34..6190cd4c892b0 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