Linux Sound subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mohammad Rafi Shaik" <mohammad.rafi.shaik@oss.qualcomm.com>
Cc: linux-sound@vger.kernel.org
Subject: Re: [PATCH v2 v2 2/2] soundwire: qcom: Add set_channel_map support to SWR master DAI
Date: Thu, 05 Nov 2026 11:29:30 +0000	[thread overview]
Message-ID: <sashiko-outbox-198950@kernel.org> (raw)
In-Reply-To: <20261105-soundwire_channel_map-v2-2-5efe2021552a@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] soundwire: qcom: lock ordering inversion in qcom_swrm_port_enable()
- [High] soundwire: qcom: zero slot masks in qcom_swrm_set_channel_map() clobber ports
- [High] soundwire: qcom: single-direction qcom_swrm_set_channel_map() clobbers other direction
--

commit c509f8b3c2506c16cc2d00c47ddc8257189902cf
Author: Mohammad Rafi Shaik <mohammad.rafi.shaik@oss.qualcomm.com>

soundwire: qcom: Add set_channel_map support to SWR master DAI

This commit adds .set_channel_map support to the Qualcomm SoundWire master
DAI so the ASoC layer can configure per-port TX and RX channel masks used by
qcom_swrm_port_enable().

> diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
> index 147e55b7a600b..c411c3628dee4 100644
> --- a/drivers/soundwire/qcom.c
> +++ b/drivers/soundwire/qcom.c

[ ... ]

> @@ -1188,12 +1192,28 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus,
>  {
>  	u32 reg;
>  	struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
> +	struct qcom_swrm_port_config *pcfg;
>  	u32 val;
>  	u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
>  
>  	reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank);
>  
>  	ctrl->reg_read(ctrl, reg, &val);
> +	pcfg = &ctrl->pconfig[enable_ch->port_num];
> +
> +	mutex_lock(&ctrl->port_lock);

[Severity: High]
Does acquiring ctrl->port_lock inside qcom_swrm_port_enable() cause a lock
ordering inversion with ctrl->bus.bus_lock?

During hw_params, qcom_swrm_hw_params() -> qcom_swrm_stream_alloc_ports()
acquires ctrl->port_lock and then calls sdw_stream_add_master(), which locks
bus->bus_lock:

drivers/soundwire/qcom.c:qcom_swrm_stream_alloc_ports() {
	guard(mutex)(&ctrl->port_lock);
	...
	sdw_stream_add_master(&ctrl->bus, &sconfig, pconfig,
			      nports, stream);
}

During stream enable and disable, sdw_enable_stream() and sdw_disable_stream()
acquire bus->bus_lock via sdw_acquire_bus_lock() before calling into
bus->port_ops->dpn_port_enable_ch(), which invokes qcom_swrm_port_enable() and
acquires ctrl->port_lock in the reverse order (bus->bus_lock ->
ctrl->port_lock).

> +	if (enable_ch->port_num <= ctrl->num_dout_ports) {
> +		if (pcfg->rx_ch_map_valid)
> +			enable_ch->ch_mask = pcfg->rx_ch_mask;
> +		else if (pcfg->tx_ch_map_valid)
> +			enable_ch->ch_mask = pcfg->tx_ch_mask;
> +	} else {
> +		if (pcfg->tx_ch_map_valid)
> +			enable_ch->ch_mask = pcfg->tx_ch_mask;
> +		else if (pcfg->rx_ch_map_valid)
> +			enable_ch->ch_mask = pcfg->rx_ch_mask;
> +	}
> +	mutex_unlock(&ctrl->port_lock);
>  
>  	if (enable_ch->enable)
>  		val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
> @@ -1413,6 +1433,39 @@ static void *qcom_swrm_get_sdw_stream(struct snd_soc_dai *dai, int direction)
>  	return ctrl->sruntime[dai->id];
>  }
>  
> +static int qcom_swrm_set_channel_map(struct snd_soc_dai *dai,
> +				     unsigned int tx_num, const unsigned int *tx_slot,
> +				     unsigned int rx_num, const unsigned int *rx_slot)
> +{
> +	struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
> +	unsigned int max_ports = ctrl->nports;
> +	unsigned int i;
> +
> +	if ((tx_num && !tx_slot) || (rx_num && !rx_slot))
> +		return -EINVAL;
> +
> +	mutex_lock(&ctrl->port_lock);
> +	for (i = 1; i <= max_ports; i++) {
> +		ctrl->pconfig[i].tx_ch_map_valid = false;
> +		ctrl->pconfig[i].rx_ch_map_valid = false;

[Severity: High]
As reported by Sashiko on v1 [1], when qcom_swrm_set_channel_map() is called
for a single stream direction, does unconditionally resetting both
tx_ch_map_valid and rx_ch_map_valid to false clobber the opposite direction's
channel map?

In qcom_snd_sdw_startup(), playback calls snd_soc_dai_set_channel_map() with
tx_num = 0 and rx_num = SDW_MAX_PORTS, whereas capture calls it with
tx_num = SDW_MAX_PORTS and rx_num = 0. Because all DAIs on the controller
share ctrl->pconfig[], starting a playback stream clears tx_ch_map_valid across
all ports and sets rx_ch_map_valid = true, while starting a capture stream
clears rx_ch_map_valid and sets tx_ch_map_valid = true.

In addition, because qcom_swrm_port_enable() falls back to the opposite
direction's mask when a port's own direction flag is false:

	if (enable_ch->port_num <= ctrl->num_dout_ports) {
		if (pcfg->rx_ch_map_valid)
			enable_ch->ch_mask = pcfg->rx_ch_mask;
		else if (pcfg->tx_ch_map_valid)
			enable_ch->ch_mask = pcfg->tx_ch_mask;
	} else {
		if (pcfg->tx_ch_map_valid)
			enable_ch->ch_mask = pcfg->tx_ch_mask;
		else if (pcfg->rx_ch_map_valid)
			enable_ch->ch_mask = pcfg->rx_ch_mask;
	}

won't DIN (TX) ports end up using pcfg->rx_ch_mask after a playback
set_channel_map() call, and DOUT (RX) ports end up using pcfg->tx_ch_mask
after a capture set_channel_map() call?

> +
> +		/* TX setup */
> +		if (tx_slot && i < tx_num) {
> +			ctrl->pconfig[i].tx_ch_mask = tx_slot[i];
> +			ctrl->pconfig[i].tx_ch_map_valid = true;
> +		}
> +
> +		/* RX setup */
> +		if (rx_slot && i < rx_num) {
> +			ctrl->pconfig[i].rx_ch_mask = rx_slot[i];
> +			ctrl->pconfig[i].rx_ch_map_valid = true;
> +		}

[Severity: High]
As reported by Sashiko on v1 [2], if tx_slot[i] or rx_slot[i] is 0 for an
unused or unmapped port in the sparse channel map array, will marking
tx_ch_map_valid or rx_ch_map_valid as true cause qcom_swrm_port_enable() to
override enable_ch->ch_mask with 0?

Codec callbacks such as wcd937x_get_channel_map() and pm4125_get_channel_map()
populate a 15-element (SDW_MAX_PORTS) sparse array where unmapped or inactive
master ports have slot[i] == 0:

sound/soc/codecs/wcd937x.c:wcd937x_get_channel_map() {
	for (i = 0; i < SDW_MAX_PORTS; i++)
		rx_slot[i] = wcd->master_channel_map[i];

	*rx_num = i;
}

Since max_ports <= 14 < SDW_MAX_PORTS, i < tx_num or i < rx_num is true for
every port 1..max_ports. Any port whose slot entry is 0 gets tx_ch_mask = 0 or
rx_ch_mask = 0 with the valid flag set to true, so qcom_swrm_port_enable() will
overwrite the stream-provided enable_ch->ch_mask with 0 instead of falling
back to the stream's channel mask.

[1] https://lore.kernel.org/r/20260629141633.86657-3-mohammad.rafi.shaik@oss.qualcomm.com
[2] https://lore.kernel.org/r/20260629141633.86657-3-mohammad.rafi.shaik@oss.qualcomm.com

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105-soundwire_channel_map-v2-0-5efe2021552a@oss.qualcomm.com?part=2

      reply	other threads:[~2026-11-05 11:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 11:10 [PATCH v2 0/2] soundwire: qcom: Restore and fix set_channel_map support for SWR master Mohammad Rafi Shaik
2026-11-05 11:10 ` [PATCH v2 v2 1/2] ASoC: qcom: sdm845: apply the SLIMbus channel map to wcd934x only Mohammad Rafi Shaik
2026-11-05 11:10 ` [PATCH v2 v2 2/2] soundwire: qcom: Add set_channel_map support to SWR master DAI Mohammad Rafi Shaik
2026-11-05 11:29   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-198950@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=mohammad.rafi.shaik@oss.qualcomm.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox