[PATCH] mailbox: mtk-cmdq: Fix GCE clock reference leak in cmdq_get_clocks()
From: Wentao Liang <hidden>
Date: 2026-09-17 09:38:01
Also in:
linux-mediatek, lkml, stable
Subsystem:
mailbox api, the rest · Maintainers:
Jassi Brar, Linus Torvalds
of_clk_get() returns the clock with an elevated reference count, but
the references taken for the other GCE clocks are never dropped: those
clocks outlive probe and the driver calls neither clk_put() nor
clk_bulk_put(), so probing a GCE with multiple instances leaks one
reference per other GCE clock.
Let devres drop the references when the device goes away, which also
covers the probe failure paths after cmdq_get_clocks() has returned.
Fixes: 85dfdbfc13ea ("mailbox: cmdq: add multi-gce clocks support for mt8195")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <redacted>
---
drivers/mailbox/mtk-cmdq-mailbox.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index e523c84b4808..eadd340f8fee 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c@@ -633,11 +633,22 @@ static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox, return &mbox->chans[ind]; } +static void cmdq_put_clocks(void *data) +{ + struct cmdq *cmdq = data; + u32 i; + + for (i = 0; i < cmdq->pdata->gce_num; i++) + if (!IS_ERR_OR_NULL(cmdq->clocks[i].clk)) + clk_put(cmdq->clocks[i].clk); +} + static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq) { static const char * const gce_name = "gce"; struct device_node *parent = dev->of_node->parent; struct clk_bulk_data *clks; + int ret; cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num, sizeof(*cmdq->clocks), GFP_KERNEL);
@@ -660,7 +671,14 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq) * If there is more than one GCE, get the clocks for the others too, * as the clock of the main GCE must be enabled for additional IPs * to be reachable. + * + * Those clocks are not devm-managed, so keep track of their + * references and drop them when this device goes away. */ + ret = devm_add_action_or_reset(dev, cmdq_put_clocks, cmdq); + if (ret) + return ret; + for_each_child_of_node_scoped(parent, node) { int alias_id = of_alias_get_id(node, gce_name);
--
2.34.1