From: sashiko-bot@kernel.org
To: "Shawn Guo" <shengchao.guo@oss.qualcomm.com>
Cc: linux-sound@vger.kernel.org
Subject: Re: [PATCH 1/3] ASoC: qcom: q6apm: Wait for SPF to be ready before registering
Date: Sun, 15 Nov 2026 03:42:31 +0000 [thread overview]
Message-ID: <sashiko-outbox-215205@kernel.org> (raw)
In-Reply-To: <20261115032027.414953-2-shengchao.guo@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] ASoC: qcom: q6apm: unsynchronized state polling in
q6apm_wait_spf_ready()
- [Low] ASoC: qcom: q6apm: missing Fixes trailer for apm_probe()
readiness fix
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [Critical] ASoC: qdsp6: use-after-free in apm_probe() [1]
--
commit 57c0d12f224a6a066f01b2ff52ff14b9359892f8
Author: Shawn Guo <shengchao.guo@oss.qualcomm.com>
> ASoC: qcom: q6apm: Wait for SPF to be ready before registering
>
> apm_probe() sends APM_CMD_GET_SPF_STATE once and ignores the result.
> At cold boot this is harmless: module loading and PDR lookup delay the
> probe by tens of milliseconds after the DSP is up, so SPF is listening
> by the time the command is sent.
>
> After an ADSP restart, everything is already loaded and PDR reports the
> audio PD up at once. The GPR service is added about 0.5 ms after the
> remoteproc reports the DSP up, and SPF drops a command sent that early
> without replying:
>
> remoteproc remoteproc0: remote processor adsp is now up
> qcom,apr ...: Adding APR/GPR dev: gprsvc:service:2:1
> qcom-apm gprsvc:service:2:1: CMD timeout for [1001021] opcode
>
> Once the q6apm component is registered, a sound card whose other
> components are still bound can bind right away, inside apm_probe(), and
> issue APM_CMD_SHARED_MEM_MAP_REGIONS before SPF can handle it. The map
> times out and the card fails to come up:
>
> qcom-apm gprsvc:service:2:1: CMD timeout for [100100c] opcode
>
> Poll GET_SPF_STATE before registering the component. Simply retrying
> q6apm_get_apm_state() is not enough: it goes through
> audioreach_send_cmd_sync(), whose 5 second timeout makes every dropped
> command stall the probe, and the card with it, for 5 seconds. Instead,
> send the command directly and wait only 100 ms for the reply, for up to
> 5 seconds in total, which is the worst case of the single command sent
> before. A timed out try is retried at once, while a "not ready" reply
> or a send failure backs off for 100 ms first. On Nord, SPF answers
> within 100-200 ms of the restart. If it still does not answer, warn and
> carry on as before rather than failing the probe.
>
> Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
[Severity: Low]
Should this bug fix include a Fixes: tag for the commit that added the
unchecked q6apm_get_apm_state() call in apm_probe()?
Fixes: 5477518b8a0e ("ASoC: qdsp6: audioreach: add q6apm support")
> diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
> index 4cb597d737b16..e7ba6bc931421 100644
> --- a/sound/soc/qcom/qdsp6/q6apm.c
> +++ b/sound/soc/qcom/qdsp6/q6apm.c
[ ... ]
> @@ -154,6 +156,47 @@ static int q6apm_get_apm_state(struct q6apm *apm)
> return apm->state;
> }
>
> +/*
> + * Right after the DSP boots, the SPF drops commands without replying. Poll
> + * GET_SPF_STATE with a short timeout per try instead of the 5 s one of
> + * q6apm_send_cmd_sync(), so a dropped command does not stall the probe.
> + */
> +static bool q6apm_wait_spf_ready(struct q6apm *apm)
> +{
> + unsigned long timeout = jiffies + msecs_to_jiffies(Q6APM_SPF_READY_MS);
> + gpr_device_t *gdev = apm->gdev;
> +
> + do {
> + struct gpr_pkt *pkt __free(kfree) =
> + audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0);
> + long rc;
> +
> + if (IS_ERR(pkt))
> + return false;
> +
> + pkt->hdr.dest_domain = audioreach_gpr_dest_domain(gdev);
> +
> + mutex_lock(&apm->lock);
> + apm->result.opcode = 0;
> + apm->state = 0;
> + rc = gpr_send_pkt(gdev, pkt);
> + if (rc >= 0)
> + rc = wait_event_timeout(apm->wait,
> + apm->result.opcode == APM_CMD_RSP_GET_SPF_STATE,
> + msecs_to_jiffies(Q6APM_SPF_POLL_MS));
> + mutex_unlock(&apm->lock);
> +
> + if (apm->state)
> + return true;
[Severity: Medium]
Can q6apm_wait_spf_ready() race with apm_callback() on apm->result.opcode
and apm->state?
sound/soc/qcom/qdsp6/q6apm.c:apm_callback() {
...
case APM_CMD_RSP_GET_SPF_STATE:
apm->result.opcode = hdr->opcode;
apm->result.status = 0;
/* First word of result it state */
apm->state = result->opcode;
wake_up(&apm->wait);
break;
...
}
CPU0 CPU1 (apr_rxwq)
q6apm_wait_spf_ready()
wait_event_timeout() -> 0
/* next iteration */
mutex_lock(&apm->lock)
apm->result.opcode = 0
apm_callback()
apm->result.opcode =
APM_CMD_RSP_GET_SPF_STATE
apm->state = 1
apm->state = 0 <-- clobbers state
gpr_send_pkt()
wait_event_timeout()
/* opcode already set */
if (apm->state) /* 0 */
When a poll attempt times out just as a delayed reply arrives, the next
iteration can overwrite apm->state = 1 with 0 while leaving
apm->result.opcode set, or return true on the stale reply while the newly
sent APM_CMD_GET_SPF_STATE is still in flight to overwrite apm->result
during a later command.
Also, apm_callback() writes apm->result.opcode before apm->state without
a lock or barrier, so wait_event_timeout() can observe the opcode update
before apm->state is visible. Because apm_probe() sets g_apm = apm before
calling q6apm_wait_spf_ready(), resetting apm->state = 0 and reading it
outside apm->lock also races with concurrent q6apm_is_adsp_ready() calls.
[ ... ]
> @@ -906,7 +949,12 @@ static int apm_probe(gpr_device_t *gdev)
> dev_set_drvdata(dev, apm);
> g_apm = apm;
>
> - q6apm_get_apm_state(apm);
> + /*
> + * Once the component is registered a card can bind and send commands
> + * at once, so wait for the SPF first.
> + */
> + if (!q6apm_wait_spf_ready(apm))
> + dev_warn(dev, "SPF not ready\n");
>
> ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
> if (ret < 0) {
[Severity: Critical]
This problem wasn't introduced by this patch, but can a failure in
snd_soc_register_component() or of_platform_populate() leave g_apm
pointing to freed memory [1]?
apm is allocated with devm_kzalloc_obj(), and g_apm = apm is set before
snd_soc_register_component() and of_platform_populate(). If either call
fails, devres frees apm while g_apm remains non-NULL, causing a
use-after-free when a later caller such as q6apm_is_adsp_ready()
dereferences g_apm.
[1] https://sashiko.dev/#/bug/linux-8f66e185-2dfb-43c1-bfaa-a2be8b96868d
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261115032027.414953-1-shengchao.guo@oss.qualcomm.com?part=1
next prev parent reply other threads:[~2026-11-15 3:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-15 3:20 [PATCH 0/3] ASoC: qcom: qdsp6: Fix audio after an ADSP restart Shawn Guo
2026-11-15 3:20 ` [PATCH 1/3] ASoC: qcom: q6apm: Wait for SPF to be ready before registering Shawn Guo
2026-11-15 3:42 ` sashiko-bot [this message]
2026-11-15 3:20 ` [PATCH 2/3] ASoC: qcom: q6dsp-lpass-clocks: Restore clocks after a DSP restart Shawn Guo
2026-11-15 3:20 ` [PATCH 3/3] ASoC: qcom: q6prm: Keep the clock controller across DSP restarts Shawn Guo
2026-11-15 3:35 ` sashiko-bot
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-215205@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=shengchao.guo@oss.qualcomm.com \
/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