[PATCH 2/6] clocksource/drivers/mxs_timer: Fix clock reference leak in mxs_timer_init

From: Wentao Liang

Date: Tue Sep 15 2026 - 01:19:54 EST


mxs_timer_init() looks up the timer clock with of_clk_get(), which takes
a reference on the clock, but no clk_put() exists anywhere in the
driver. The reference is leaked on every return path after the clock
has been obtained:

- clk_prepare_enable() failure,
- mxs_clocksource_init() failure,
- mxs_clockevent_init() failure,
- irq_of_parse_and_map() failure,
- request_irq() failure,
- and on success, where the clock is intentionally left enabled for the
timer but the local timer_clk pointer is lost.

Add proper error unwinding: on failure of clk_prepare_enable() only the
reference is dropped, on the later error paths the clock is disabled and
unprepared before the reference is dropped, and on success the reference
is dropped while keeping the clock enabled.

Fixes: 2efb950465e9 ("ARM: mxs: look up timrot clock from device tree")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/clocksource/mxs_timer.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c
index e52e12d27d2a..dd58d7505797 100644
--- a/drivers/clocksource/mxs_timer.c
+++ b/drivers/clocksource/mxs_timer.c
@@ -215,8 +215,10 @@ static int __init mxs_timer_init(struct device_node *np)
}

ret = clk_prepare_enable(timer_clk);
- if (ret)
+ if (ret) {
+ clk_put(timer_clk);
return ret;
+ }

/*
* Initialize timers to a known state
@@ -256,18 +258,32 @@ static int __init mxs_timer_init(struct device_node *np)
/* init and register the timer to the framework */
ret = mxs_clocksource_init(timer_clk);
if (ret)
- return ret;
+ goto err_clk_disable;

ret = mxs_clockevent_init(timer_clk);
if (ret)
- return ret;
+ goto err_clk_disable;

/* Make irqs happen */
irq = irq_of_parse_and_map(np, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq <= 0) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ ret = request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+ "MXS Timer Tick", &mxs_clockevent_device);
+ if (ret)
+ goto err_clk_disable;
+
+ clk_put(timer_clk);
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(timer_clk);
+ clk_put(timer_clk);

- return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
- "MXS Timer Tick", &mxs_clockevent_device);
+ return ret;
}
TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
--
2.34.1