The patch below does not apply to the 5.15-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to stable@vger.kernel.org.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y git checkout FETCH_HEAD git cherry-pick -x 23261f0de09427367e99f39f588e31e2856a690e # <resolve conflicts, build, test, etc.> git commit -s git send-email --to 'stable@vger.kernel.org' --in-reply-to '2026010551-backpedal-chatroom-a9c7@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 23261f0de09427367e99f39f588e31e2856a690e Mon Sep 17 00:00:00 2001 From: Johan Hovold johan@kernel.org Date: Mon, 24 Nov 2025 11:49:07 +0100 Subject: [PATCH] ASoC: stm32: sai: fix OF node leak on probe
The reference taken to the sync provider OF node when probing the platform device is currently only dropped if the set_sync() callback fails during DAI probe.
Make sure to drop the reference on platform probe failures (e.g. probe deferral) and on driver unbind.
This also avoids a potential use-after-free in case the DAI is ever reprobed without first rebinding the platform driver.
Fixes: 5914d285f6b7 ("ASoC: stm32: sai: Add synchronization support") Fixes: d4180b4c02e7 ("ASoC: stm32: sai: fix set_sync service") Cc: Olivier Moysan olivier.moysan@st.com Cc: stable@vger.kernel.org # 4.16: d4180b4c02e7 Signed-off-by: Johan Hovold johan@kernel.org Reviewed-by: olivier moysan olivier.moysan@foss.st.com Link: https://patch.msgid.link/20251124104908.15754-4-johan@kernel.org Signed-off-by: Mark Brown broonie@kernel.org
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 7065aeb0e524..00cf24ceca2d 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -138,7 +138,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, "Device not found for node %pOFn\n", np_provider); - of_node_put(np_provider); return -ENODEV; }
@@ -147,21 +146,16 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); - ret = -EINVAL; - goto error; + return -EINVAL; }
/* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) - goto error; + return ret;
/* Configure sync provider */ - ret = stm32_sai_sync_conf_provider(sai_provider, synco); - -error: - of_node_put(np_provider); - return ret; + return stm32_sai_sync_conf_provider(sai_provider, synco); }
static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 7a005b4ad304..5ae4d2577f28 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1586,7 +1586,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, dev_err(&pdev->dev, "External synchro not supported\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } sai->sync = SAI_SYNC_EXTERNAL;
@@ -1595,7 +1596,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) { dev_err(&pdev->dev, "Wrong SAI index\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; }
if (of_property_match_string(args.np, "compatible", @@ -1609,7 +1611,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (!sai->synco) { dev_err(&pdev->dev, "Unknown SAI sub-block\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } }
@@ -1619,13 +1622,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); - if (IS_ERR(sai->sai_ck)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), - "Missing kernel clock sai_ck\n"); + if (IS_ERR(sai->sai_ck)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), + "Missing kernel clock sai_ck\n"); + goto err_put_sync_provider; + }
ret = clk_prepare(sai->pdata->pclk); if (ret < 0) - return ret; + goto err_put_sync_provider;
if (STM_SAI_IS_F4(sai->pdata)) return 0; @@ -1647,6 +1652,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); +err_put_sync_provider: + of_node_put(sai->np_sync_provider);
return ret; } @@ -1720,6 +1727,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); + of_node_put(sai->np_sync_provider);
return ret; } @@ -1732,6 +1740,7 @@ static void stm32_sai_sub_remove(struct platform_device *pdev) snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); + of_node_put(sai->np_sync_provider); }
static int stm32_sai_sub_suspend(struct device *dev)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
[ Upstream commit efc162cbd480f1fb47d439c193ec9731bcc6c749 ]
Use the dev_err_probe() helper, instead of open-coding the same operation.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Link: https://lore.kernel.org/r/20211214020843.2225831-22-kuninori.morimoto.gx@ren... Signed-off-by: Mark Brown broonie@kernel.org Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_i2s.c | 62 ++++++++++++----------------------- sound/soc/stm/stm32_sai.c | 37 ++++++++------------- sound/soc/stm/stm32_sai_sub.c | 25 +++++--------- sound/soc/stm/stm32_spdifrx.c | 44 +++++++++---------------- 4 files changed, 57 insertions(+), 111 deletions(-)
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 717f45a83445..08db73c2ed78 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1044,36 +1044,24 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
/* Get clocks */ i2s->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(i2s->pclk)) { - if (PTR_ERR(i2s->pclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get pclk: %ld\n", - PTR_ERR(i2s->pclk)); - return PTR_ERR(i2s->pclk); - } + if (IS_ERR(i2s->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->pclk), + "Could not get pclk\n");
i2s->i2sclk = devm_clk_get(&pdev->dev, "i2sclk"); - if (IS_ERR(i2s->i2sclk)) { - if (PTR_ERR(i2s->i2sclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get i2sclk: %ld\n", - PTR_ERR(i2s->i2sclk)); - return PTR_ERR(i2s->i2sclk); - } + if (IS_ERR(i2s->i2sclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->i2sclk), + "Could not get i2sclk\n");
i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(i2s->x8kclk)) { - if (PTR_ERR(i2s->x8kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get x8k parent clock: %ld\n", - PTR_ERR(i2s->x8kclk)); - return PTR_ERR(i2s->x8kclk); - } + if (IS_ERR(i2s->x8kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x8kclk), + "Could not get x8k parent clock\n");
i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(i2s->x11kclk)) { - if (PTR_ERR(i2s->x11kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get x11k parent clock: %ld\n", - PTR_ERR(i2s->x11kclk)); - return PTR_ERR(i2s->x11kclk); - } + if (IS_ERR(i2s->x11kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x11kclk), + "Could not get x11k parent clock\n");
/* Register mclk provider if requested */ if (of_find_property(np, "#clock-cells", NULL)) { @@ -1096,12 +1084,10 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
/* Reset */ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); @@ -1143,19 +1129,13 @@ static int stm32_i2s_probe(struct platform_device *pdev)
i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", i2s->base, i2s->regmap_conf); - if (IS_ERR(i2s->regmap)) { - if (PTR_ERR(i2s->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(i2s->regmap)); - return PTR_ERR(i2s->regmap); - } + if (IS_ERR(i2s->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), + "Regmap init error\n");
ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component, i2s->dai_drv, 1); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 058757c721f0..8e21e6f886fc 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -173,29 +173,20 @@ static int stm32_sai_probe(struct platform_device *pdev)
if (!STM_SAI_IS_F4(sai)) { sai->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(sai->pclk)) { - if (PTR_ERR(sai->pclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing bus clock pclk: %ld\n", - PTR_ERR(sai->pclk)); - return PTR_ERR(sai->pclk); - } + if (IS_ERR(sai->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->pclk), + "missing bus clock pclk\n"); }
sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(sai->clk_x8k)) { - if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing x8k parent clock: %ld\n", - PTR_ERR(sai->clk_x8k)); - return PTR_ERR(sai->clk_x8k); - } + if (IS_ERR(sai->clk_x8k)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k), + "missing x8k parent clock\n");
sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(sai->clk_x11k)) { - if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing x11k parent clock: %ld\n", - PTR_ERR(sai->clk_x11k)); - return PTR_ERR(sai->clk_x11k); - } + if (IS_ERR(sai->clk_x11k)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k), + "missing x11k parent clock\n");
/* init irqs */ sai->irq = platform_get_irq(pdev, 0); @@ -204,12 +195,10 @@ static int stm32_sai_probe(struct platform_device *pdev)
/* reset */ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index d71b4aecd269..0db307cdb825 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1379,12 +1379,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, */ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, sai->regmap_config); - if (IS_ERR(sai->regmap)) { - if (PTR_ERR(sai->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(sai->regmap)); - return PTR_ERR(sai->regmap); - } + if (IS_ERR(sai->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->regmap), + "Regmap init error\n");
/* Get direction property */ if (of_property_match_string(np, "dma-names", "tx") >= 0) { @@ -1472,12 +1469,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); - if (IS_ERR(sai->sai_ck)) { - if (PTR_ERR(sai->sai_ck) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Missing kernel clock sai_ck: %ld\n", - PTR_ERR(sai->sai_ck)); - return PTR_ERR(sai->sai_ck); - } + if (IS_ERR(sai->sai_ck)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), + "Missing kernel clock sai_ck\n");
ret = clk_prepare(sai->pdata->pclk); if (ret < 0) @@ -1551,11 +1545,8 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) conf = &stm32_sai_pcm_config_spdif;
ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not register pcm dma\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n");
ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index e3d6258afbac..80f7761cbcb7 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -405,12 +405,9 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, int ret;
spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); - if (IS_ERR(spdifrx->ctrl_chan)) { - if (PTR_ERR(spdifrx->ctrl_chan) != -EPROBE_DEFER) - dev_err(dev, "dma_request_slave_channel error %ld\n", - PTR_ERR(spdifrx->ctrl_chan)); - return PTR_ERR(spdifrx->ctrl_chan); - } + if (IS_ERR(spdifrx->ctrl_chan)) + return dev_err_probe(dev, PTR_ERR(spdifrx->ctrl_chan), + "dma_request_slave_channel error\n");
spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), GFP_KERNEL); @@ -929,12 +926,9 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, spdifrx->phys_addr = res->start;
spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); - if (IS_ERR(spdifrx->kclk)) { - if (PTR_ERR(spdifrx->kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get kclk: %ld\n", - PTR_ERR(spdifrx->kclk)); - return PTR_ERR(spdifrx->kclk); - } + if (IS_ERR(spdifrx->kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(spdifrx->kclk), + "Could not get kclk\n");
spdifrx->irq = platform_get_irq(pdev, 0); if (spdifrx->irq < 0) @@ -985,12 +979,9 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", spdifrx->base, spdifrx->regmap_conf); - if (IS_ERR(spdifrx->regmap)) { - if (PTR_ERR(spdifrx->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(spdifrx->regmap)); - return PTR_ERR(spdifrx->regmap); - } + if (IS_ERR(spdifrx->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(spdifrx->regmap), + "Regmap init error\n");
ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, dev_name(&pdev->dev), spdifrx); @@ -1000,23 +991,18 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) }
rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst);
pcm_config = &stm32_spdifrx_pcm_config; ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
ret = snd_soc_register_component(&pdev->dev, &stm32_spdifrx_component,
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit a3bd37e2e2bce4fb1757a940fa985d556662ba80 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void.
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Acked-by: Takashi Iwai tiwai@suse.de Acked-by: Nicolas Ferre nicolas.ferre@microchip.com Link: https://lore.kernel.org/r/20230315150745.67084-139-u.kleine-koenig@pengutron... Signed-off-by: Mark Brown broonie@kernel.org Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_sai_sub.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 0db307cdb825..d179400b9b09 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1560,7 +1560,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) return 0; }
-static int stm32_sai_sub_remove(struct platform_device *pdev) +static void stm32_sai_sub_remove(struct platform_device *pdev) { struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
@@ -1568,8 +1568,6 @@ static int stm32_sai_sub_remove(struct platform_device *pdev) snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; }
#ifdef CONFIG_PM_SLEEP @@ -1619,7 +1617,7 @@ static struct platform_driver stm32_sai_sub_driver = { .pm = &stm32_sai_sub_pm_ops, }, .probe = stm32_sai_sub_probe, - .remove = stm32_sai_sub_remove, + .remove_new = stm32_sai_sub_remove, };
module_platform_driver(stm32_sai_sub_driver);
From: Christophe JAILLET christophe.jaillet@wanadoo.fr
[ Upstream commit 374628fb668e50b42fe81f2a63af616182415bcd ]
Use devm_clk_get_optional() instead of hand writing it. This saves some LoC and improves the semantic.
Signed-off-by: Christophe JAILLET christophe.jaillet@wanadoo.fr Link: https://lore.kernel.org/r/f7987f18dadf77bfa09969fd4c82d5a0f4e4e3b7.168459483... Signed-off-by: Mark Brown broonie@kernel.org Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_sai_sub.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index d179400b9b09..e4ee4c800275 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1486,12 +1486,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (ret < 0) return ret; } else { - sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK"); - if (IS_ERR(sai->sai_mclk)) { - if (PTR_ERR(sai->sai_mclk) != -ENOENT) - return PTR_ERR(sai->sai_mclk); - sai->sai_mclk = NULL; - } + sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); + if (IS_ERR(sai->sai_mclk)) + return PTR_ERR(sai->sai_mclk); }
return 0;
From: Johan Hovold johan@kernel.org
[ Upstream commit e26ff429eaf10c4ef1bc3dabd9bf27eb54b7e1f4 ]
Make sure to drop the reference taken when looking up the sync provider device and its driver data during DAI probe on probe failures and on unbind.
Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference.
Fixes: 7dd0d835582f ("ASoC: stm32: sai: simplify sync modes management") Fixes: 1c3816a19487 ("ASoC: stm32: sai: add missing put_device()") Cc: stable@vger.kernel.org # 4.16: 1c3816a19487 Cc: olivier moysan olivier.moysan@st.com Cc: Wen Yang yellowriver2010@hotmail.com Signed-off-by: Johan Hovold johan@kernel.org Reviewed-by: olivier moysan olivier.moysan@foss.st.com Link: https://patch.msgid.link/20251124104908.15754-2-johan@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 8e21e6f886fc..df167c389b98 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -127,6 +127,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, }
sai_provider = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); @@ -143,7 +144,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, ret = stm32_sai_sync_conf_provider(sai_provider, synco);
error: - put_device(&pdev->dev); of_node_put(np_provider); return ret; }
From: Johan Hovold johan@kernel.org
[ Upstream commit 312ec2f0d9d1a5656f76d770bbf1d967e9289aa7 ]
Make sure to unprepare the parent clock also on probe failures (e.g. probe deferral).
Fixes: a14bf98c045b ("ASoC: stm32: sai: fix possible circular locking") Cc: stable@vger.kernel.org # 5.5 Cc: Olivier Moysan olivier.moysan@st.com Signed-off-by: Johan Hovold johan@kernel.org Reviewed-by: olivier moysan olivier.moysan@foss.st.com Link: https://patch.msgid.link/20251124104908.15754-3-johan@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Stable-dep-of: 23261f0de094 ("ASoC: stm32: sai: fix OF node leak on probe") Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_sai_sub.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index e4ee4c800275..6ae1c15f3439 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1484,14 +1484,21 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (of_find_property(np, "#clock-cells", NULL)) { ret = stm32_sai_add_mclk_provider(sai); if (ret < 0) - return ret; + goto err_unprepare_pclk; } else { sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); - if (IS_ERR(sai->sai_mclk)) - return PTR_ERR(sai->sai_mclk); + if (IS_ERR(sai->sai_mclk)) { + ret = PTR_ERR(sai->sai_mclk); + goto err_unprepare_pclk; + } }
return 0; + +err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); + + return ret; }
static int stm32_sai_sub_probe(struct platform_device *pdev) @@ -1535,26 +1542,33 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) IRQF_SHARED, dev_name(&pdev->dev), sai); if (ret) { dev_err(&pdev->dev, "IRQ request returned %d\n", ret); - return ret; + goto err_unprepare_pclk; }
if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) conf = &stm32_sai_pcm_config_spdif;
ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); + if (ret) { + ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); + goto err_unprepare_pclk; + }
ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); if (ret) { snd_dmaengine_pcm_unregister(&pdev->dev); - return ret; + goto err_unprepare_pclk; }
pm_runtime_enable(&pdev->dev);
return 0; + +err_unprepare_pclk: + clk_unprepare(sai->pdata->pclk); + + return ret; }
static void stm32_sai_sub_remove(struct platform_device *pdev)
From: Johan Hovold johan@kernel.org
[ Upstream commit 23261f0de09427367e99f39f588e31e2856a690e ]
The reference taken to the sync provider OF node when probing the platform device is currently only dropped if the set_sync() callback fails during DAI probe.
Make sure to drop the reference on platform probe failures (e.g. probe deferral) and on driver unbind.
This also avoids a potential use-after-free in case the DAI is ever reprobed without first rebinding the platform driver.
Fixes: 5914d285f6b7 ("ASoC: stm32: sai: Add synchronization support") Fixes: d4180b4c02e7 ("ASoC: stm32: sai: fix set_sync service") Cc: Olivier Moysan olivier.moysan@st.com Cc: stable@vger.kernel.org # 4.16: d4180b4c02e7 Signed-off-by: Johan Hovold johan@kernel.org Reviewed-by: olivier moysan olivier.moysan@foss.st.com Link: https://patch.msgid.link/20251124104908.15754-4-johan@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/stm/stm32_sai.c | 12 +++--------- sound/soc/stm/stm32_sai_sub.c | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index df167c389b98..026321620a20 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -122,7 +122,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, "Device not found for node %pOFn\n", np_provider); - of_node_put(np_provider); return -ENODEV; }
@@ -131,21 +130,16 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); - ret = -EINVAL; - goto error; + return -EINVAL; }
/* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) - goto error; + return ret;
/* Configure sync provider */ - ret = stm32_sai_sync_conf_provider(sai_provider, synco); - -error: - of_node_put(np_provider); - return ret; + return stm32_sai_sync_conf_provider(sai_provider, synco); }
static int stm32_sai_probe(struct platform_device *pdev) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 6ae1c15f3439..c7930d8f9ded 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1436,7 +1436,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, dev_err(&pdev->dev, "External synchro not supported\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } sai->sync = SAI_SYNC_EXTERNAL;
@@ -1445,7 +1446,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) { dev_err(&pdev->dev, "Wrong SAI index\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; }
if (of_property_match_string(args.np, "compatible", @@ -1459,7 +1461,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (!sai->synco) { dev_err(&pdev->dev, "Unknown SAI sub-block\n"); of_node_put(args.np); - return -EINVAL; + ret = -EINVAL; + goto err_put_sync_provider; } }
@@ -1469,13 +1472,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); - if (IS_ERR(sai->sai_ck)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), - "Missing kernel clock sai_ck\n"); + if (IS_ERR(sai->sai_ck)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), + "Missing kernel clock sai_ck\n"); + goto err_put_sync_provider; + }
ret = clk_prepare(sai->pdata->pclk); if (ret < 0) - return ret; + goto err_put_sync_provider;
if (STM_SAI_IS_F4(sai->pdata)) return 0; @@ -1497,6 +1502,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); +err_put_sync_provider: + of_node_put(sai->np_sync_provider);
return ret; } @@ -1567,6 +1574,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
err_unprepare_pclk: clk_unprepare(sai->pdata->pclk); + of_node_put(sai->np_sync_provider);
return ret; } @@ -1579,6 +1587,7 @@ static void stm32_sai_sub_remove(struct platform_device *pdev) snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); + of_node_put(sai->np_sync_provider); }
#ifdef CONFIG_PM_SLEEP
linux-stable-mirror@lists.linaro.org