Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 640594a04f11 ("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

authored by

Stephen Eta Zhou and committed by
Daniel Lezcano
694921a9 f555fd9e

+9 -5
+9 -5
drivers/clocksource/timer-sp804.c
··· 106 106 return ~readl_relaxed(sched_clkevt->value); 107 107 } 108 108 109 + /* Register delay timer backed by the hardware counter */ 109 110 #ifdef CONFIG_ARM 110 111 static struct delay_timer delay; 112 + static struct sp804_clkevt *delay_clkevt; 113 + 111 114 static unsigned long sp804_read_delay_timer_read(void) 112 115 { 113 - return sp804_read(); 116 + return ~readl_relaxed(delay_clkevt->value); 114 117 } 115 118 116 - static void sp804_register_delay_timer(int freq) 119 + static void sp804_register_delay_timer(struct sp804_clkevt *clk, int freq) 117 120 { 121 + delay_clkevt = clk; 118 122 delay.freq = freq; 119 123 delay.read_current_timer = sp804_read_delay_timer_read; 120 124 register_current_timer_delay(&delay); 121 125 } 122 126 #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) {} 124 128 #endif 125 129 126 130 static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, ··· 138 134 rate = sp804_get_clock_rate(clk, name); 139 135 if (rate < 0) 140 136 return -EINVAL; 141 - 142 - sp804_register_delay_timer(rate); 143 137 144 138 clkevt = sp804_clkevt_get(base); 145 139 ··· 153 151 154 152 clocksource_mmio_init(clkevt->value, name, 155 153 rate, 200, 32, clocksource_mmio_readl_down); 154 + 155 + sp804_register_delay_timer(clkevt, rate); 156 156 157 157 if (use_sched_clock) { 158 158 sched_clkevt = clkevt;