All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jorijn van der Graaf" <jorijnvdgraaf@catcrafts.net>
Cc: robh@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH 3/3] ASoC: codecs: wcd9378: add TX/capture codec driver
Date: Mon, 06 Jul 2026 19:38:26 +0000	[thread overview]
Message-ID: <20260706193827.D90641F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260706192229.144137-4-jorijnvdgraaf@catcrafts.net>

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] Modifying a static global array during probe prevents multiple device instances from working correctly.
- [High] `pm_runtime_enable()` is called after `component_master_add_with_match()`, causing component probe to fail synchronously.
- [High] Missing bounds check in `wcd9378_tx_mode_put()` allows out-of-bounds enum values to be written and retrieved.
- [High] Inconsistent SoundWire bus clock scaling calculation between `wcd9378_bus_config()` and `wcd9378_swr_clk_indicate()`.
- [High] Destroying `micb_lock` in the component unbind callback leads to a use-after-destroy upon component re-bind.
- [Medium] Off-by-one error when calculating the SoundWire channel count causes incorrect bandwidth allocation.
- [Medium] Missing High-Pass Filter (HPF) init pulse configuration for ADC2 when routed via SmartJACK.
- [Medium] Concurrent ALSA control puts cause read-modify-write data races on shared driver channel maps.
- [Medium] Using asynchronous `pm_runtime_put()` in `wcd9378_unbind()` causes a race condition where the TX SoundWire slave device may not be properly suspended before removal.
--

commit 336c5ad4fab99f2ac788ce17fc541b077bfc53c9
Author: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
Subject: ASoC: codecs: wcd9378: add TX/capture codec driver

This patch adds the TX/capture driver for the Qualcomm WCD9378 audio codec
over SoundWire. It introduces analog core configuration and SDCA-style 
function blocks for SmartMIC and SmartJACK sequencers.

> diff --git a/sound/soc/codecs/wcd9378-sdw.c b/sound/soc/codecs/wcd9378-sdw.c
> --- a/sound/soc/codecs/wcd9378-sdw.c
> +++ b/sound/soc/codecs/wcd9378-sdw.c
[ ... ]
> +int wcd9378_sdw_hw_params(struct wcd9378_sdw_priv *wcd,
> +			  struct snd_pcm_substream *substream,
> +			  struct snd_pcm_hw_params *params,
> +			  struct snd_soc_dai *dai)
> +{
> +	struct sdw_port_config port_config[WCD9378_MAX_SWR_PORTS];
> +	unsigned long ch_mask;
> +	int i, j;
> +
> +	wcd->sconfig.ch_count = 1;

[Severity: Medium]
Does initializing the channel count to 1 here cause an off-by-one error?
It looks like if there are two active channels, the count will become 3,
which might lead to overallocating SoundWire bus bandwidth.

[ ... ]
> +static int wcd9378_bus_config(struct sdw_slave *slave,
> +			      struct sdw_bus_params *params)
> +{
> +	u8 scale;
> +
> +	switch (params->curr_dr_freq) {
> +	case 4800000:
> +		scale = WCD9378_SWRS_CLK_SCALE_DIV4;
> +		break;
> +	case 9600000:
> +	default:
> +		scale = WCD9378_SWRS_CLK_SCALE_DIV2;
> +		break;
> +	}

[Severity: High]
Is there a calculation mismatch between wcd9378_bus_config() and 
wcd9378_swr_clk_indicate()?

Here, a 9.6MHz double-rate frequency gets WCD9378_SWRS_CLK_SCALE_DIV2.
However, in wcd9378_swr_clk_indicate() in wcd9378.c, the bus clock is 
calculated by dividing the DR frequency by 2, resulting in 4.8MHz. That 
function then evaluates 4800000 < 9600000 and assigns 
WCD9378_SWRS_CLK_SCALE_DIV4 instead. 

Could this stall the sequencer if the configurations conflict?

[ ... ]
> +static int wcd9378_sdw_probe(struct sdw_slave *pdev,
> +			     const struct sdw_device_id *id)
> +{
[ ... ]
> +	if (wcd->is_tx) {
> +		pdev->prop.source_ports = GENMASK(WCD9378_MAX_TX_SWR_PORTS, 1);
> +		pdev->prop.src_dpn_prop = wcd9378_dpn_prop;
> +		wcd->ch_info = &wcd9378_sdw_tx_ch_info[0];
> +
> +		for (i = 0; i < master_ch_mask_size; i++)
> +			wcd->ch_info[i].master_ch_mask = WCD9378_SWRM_CH_MASK(master_ch_mask[i]);

[Severity: High]
Will this loop permanently modify the global static array wcd9378_sdw_tx_ch_info?
Since the master_ch_mask is written directly to the shared array, probing a 
second instance of this codec could overwrite the configuration for all active
devices.

> diff --git a/sound/soc/codecs/wcd9378.c b/sound/soc/codecs/wcd9378.c
> --- a/sound/soc/codecs/wcd9378.c
> +++ b/sound/soc/codecs/wcd9378.c
[ ... ]
> +static const struct wcd9378_smp_fn wcd9378_smp_jack_adc2 = {
> +	.usage_reg = WCD9378_SMP_JACK_IT31_USAGE,
> +	.micb_reg = WCD9378_SMP_JACK_IT31_MICB,
> +	.req_reg = WCD9378_SMP_JACK_PDE34_REQ_PS,
> +	.act_reg = WCD9378_SMP_JACK_PDE34_ACT_PS,
> +};

[Severity: Medium]
Should this struct also include the hpf_reg and hpf_mask fields?
When ADC2 is fed from AMIC2 via SmartJACK, the missing filter configuration
means the sequencer enable path will read zeroes, skipping the
WCD9378_ANA_TX_CH2_HPF2_INIT pulse and potentially leaving a DC offset.

[ ... ]
> +static int wcd9378_connect_port(struct wcd9378_sdw_priv *wcd, u8 port_idx,
> +				u8 ch_id, bool enable)
> +{
[ ... ]
> +	if (enable) {
> +		port_config->ch_mask |= ch_mask;
> +		wcd->master_channel_map[mstr_port_num] |= mstr_ch_mask;
> +	} else {
> +		port_config->ch_mask &= ~ch_mask;
> +		wcd->master_channel_map[mstr_port_num] &= ~mstr_ch_mask;
> +	}

[Severity: Medium]
Can concurrent ALSA control operations corrupt the channel masks?
Since wcd9378_set_swr_port() is reachable via ALSA put callbacks, multiple
userspace threads toggling switches might cause a read-modify-write data
race on port_config->ch_mask and wcd->master_channel_map.

[ ... ]
> +static int wcd9378_tx_mode_put(struct snd_kcontrol *kcontrol,
> +			       struct snd_ctl_elem_value *ucontrol)
> +{
[ ... ]
> +	u32 mode_val = ucontrol->value.enumerated.item[0];
> +
> +	if (mode_val == wcd9378->tx_mode[adc])
> +		return 0;
> +
> +	wcd9378->tx_mode[adc] = mode_val;

[Severity: High]
Could this store an out-of-bounds enum value?
Without a check verifying that mode_val is less than ARRAY_SIZE(tx_mode_mux_text),
userspace can write an invalid integer here. This value is later exposed via
wcd9378_tx_mode_get(), which might crash userspace audio servers when used as
an array index.

[ ... ]
> +static int wcd9378_soc_codec_probe(struct snd_soc_component *component)
> +{
[ ... ]
> +	ret = pm_runtime_resume_and_get(dev);
> +	if (ret < 0)
> +		return ret;

[Severity: High]
Will this pm_runtime_resume_and_get() call fail with -EACCES?
It looks like component_master_add_with_match() in wcd9378_probe() triggers
the component bind synchronously if all slaves are present, which in turn
calls wcd9378_soc_codec_probe() here. Because pm_runtime_enable() hasn't
been called yet in the master probe, the disable depth is still > 0,
causing the resume to abort audio initialization.

[ ... ]
> +static void wcd9378_unbind(struct device *dev)
> +{
> +	struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev);
> +
> +	snd_soc_unregister_component(dev);
> +	pm_runtime_put(wcd9378->txdev);

[Severity: Medium]
Should this be pm_runtime_put_sync() instead?
Using the asynchronous pm_runtime_put() queues a suspend operation that might
be cancelled immediately when the driver core calls pm_runtime_disable() upon
device removal, leaving the TX SoundWire slave device powered on.

> +	device_link_remove(dev, wcd9378->txdev);
> +	device_link_remove(dev, wcd9378->rxdev);
> +	device_link_remove(wcd9378->rxdev, wcd9378->txdev);
> +	component_unbind_all(dev, wcd9378);
> +	mutex_destroy(&wcd9378->micb_lock);

[Severity: High]
Does destroying micb_lock here prevent a successful re-bind?
The component framework allows unbinding and rebinding without fully removing
the master platform device. Since mutex_init() is only called in wcd9378_probe(),
a subsequent wcd9378_bind() will leave the destroyed mutex uninitialized, leading
to undefined behavior or a crash when wcd9378_micbias_control() tries to lock it.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260706192229.144137-1-jorijnvdgraaf@catcrafts.net?part=3

  reply	other threads:[~2026-07-06 19:38 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-06 19:22 [PATCH 0/3] ASoC: codecs: add the Qualcomm WCD9378 audio codec Jorijn van der Graaf
2026-07-06 19:22 ` [PATCH 1/3] ASoC: dt-bindings: qcom,wcd93xx-common: don't require micbias4 Jorijn van der Graaf
2026-07-06 19:22 ` [PATCH 2/3] ASoC: dt-bindings: add the Qualcomm WCD9378 audio codec Jorijn van der Graaf
2026-07-06 21:17   ` Srinivas Kandagatla
2026-07-06 22:22     ` Jorijn van der Graaf
2026-07-06 19:22 ` [PATCH 3/3] ASoC: codecs: wcd9378: add TX/capture codec driver Jorijn van der Graaf
2026-07-06 19:38   ` sashiko-bot [this message]
2026-07-06 20:35     ` Jorijn van der Graaf
2026-07-06 21:41   ` Srinivas Kandagatla
2026-07-06 22:22     ` Jorijn van der Graaf
2026-07-07 11:42   ` Pierre-Louis Bossart

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=20260706193827.D90641F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jorijnvdgraaf@catcrafts.net \
    --cc=robh@kernel.org \
    --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 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.