Skip to content

Commit 694921a

Browse files
Stephen Eta Zhoudlezcano
authored andcommitted
clocksource/drivers/timer-sp804: Fix an Oops when read_current_timer is called on ARM32 platforms where the SP804 is not registered as the sched_clock.
On SP804, the delay timer shares the same clkevt instance with sched_clock. On some platforms, when sp804_clocksource_and_sched_clock_init is called with use_sched_clock not set to 1, sched_clkevt is not properly initialized. However, sp804_register_delay_timer is invoked unconditionally, and read_current_timer() subsequently calls sp804_read on an uninitialized sched_clkevt, leading to a kernel Oops when accessing sched_clkevt->value. Declare a dedicated clkevt instance exclusively for delay timer, instead of sharing the same clkevt with sched_clock. This ensures that read_current_timer continues to work correctly regardless of whether SP804 is selected as the sched_clock. Fixes: 640594a ("clocksource/drivers/timer-sp804: Fix read_current_timer() issue when clock source is not registered") Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202512250520.APOMkYRQ-lkp@intel.com/ Signed-off-by: Stephen Eta Zhou <stephen.eta.zhou@gmail.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Link: https://patch.msgid.link/20251225-fix_timersp804-v2-1-a366d7157f58@gmail.com
1 parent f555fd9 commit 694921a

1 file changed

Lines changed: 9 additions & 5 deletions

File tree

drivers/clocksource/timer-sp804.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,25 @@ static u64 notrace sp804_read(void)
106106
return ~readl_relaxed(sched_clkevt->value);
107107
}
108108

109+
/* Register delay timer backed by the hardware counter */
109110
#ifdef CONFIG_ARM
110111
static struct delay_timer delay;
112+
static struct sp804_clkevt *delay_clkevt;
113+
111114
static unsigned long sp804_read_delay_timer_read(void)
112115
{
113-
return sp804_read();
116+
return ~readl_relaxed(delay_clkevt->value);
114117
}
115118

116-
static void sp804_register_delay_timer(int freq)
119+
static void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq)
117120
{
121+
delay_clkevt = clk;
118122
delay.freq = freq;
119123
delay.read_current_timer = sp804_read_delay_timer_read;
120124
register_current_timer_delay(&delay);
121125
}
122126
#else
123-
static inline void sp804_register_delay_timer(int freq) {}
127+
static inline void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) {}
124128
#endif
125129

126130
static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
@@ -135,8 +139,6 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
135139
if (rate < 0)
136140
return -EINVAL;
137141

138-
sp804_register_delay_timer(rate);
139-
140142
clkevt = sp804_clkevt_get(base);
141143

142144
writel(0, clkevt->ctrl);
@@ -152,6 +154,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
152154
clocksource_mmio_init(clkevt->value, name,
153155
rate, 200, 32, clocksource_mmio_readl_down);
154156

157+
sp804_register_delay_timer(clkevt, rate);
158+
155159
if (use_sched_clock) {
156160
sched_clkevt = clkevt;
157161
sched_clock_register(sp804_read, 32, rate);

0 commit comments

Comments
 (0)