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

clocksource/drivers/dw_apb_timer_of: Add error handling if no clock available

commit ("b0fc70ce1f02 arm64: berlin: Select DW_APB_TIMER_OF") added the
support for the dw_apb_timer into the arm64 defconfig. However, for some
platforms like the Intel Stratix10 and Agilex, the clock manager doesn't
get loaded until after the timer driver get loaded. Thus, the driver hits
the panic "No clock nor clock-frequency property for" because it cannot
properly get the clock.

This patch adds the error handling needed for the timer driver so that
the kernel can continue booting instead of just hitting the panic.

Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20201205105223.208604-1-dinguyen@kernel.org

authored by

Dinh Nguyen and committed by
Daniel Lezcano
5d9814df fef92cd2

+39 -18
+39 -18
drivers/clocksource/dw_apb_timer_of.c
··· 14 14 #include <linux/reset.h> 15 15 #include <linux/sched_clock.h> 16 16 17 - static void __init timer_get_base_and_rate(struct device_node *np, 17 + static int __init timer_get_base_and_rate(struct device_node *np, 18 18 void __iomem **base, u32 *rate) 19 19 { 20 20 struct clk *timer_clk; 21 21 struct clk *pclk; 22 22 struct reset_control *rstc; 23 + int ret; 23 24 24 25 *base = of_iomap(np, 0); 25 26 ··· 47 46 pr_warn("pclk for %pOFn is present, but could not be activated\n", 48 47 np); 49 48 49 + if (!of_property_read_u32(np, "clock-freq", rate) && 50 + !of_property_read_u32(np, "clock-frequency", rate)) 51 + return 0; 52 + 50 53 timer_clk = of_clk_get_by_name(np, "timer"); 51 54 if (IS_ERR(timer_clk)) 52 - goto try_clock_freq; 55 + return PTR_ERR(timer_clk); 53 56 54 - if (!clk_prepare_enable(timer_clk)) { 55 - *rate = clk_get_rate(timer_clk); 56 - return; 57 - } 57 + ret = clk_prepare_enable(timer_clk); 58 + if (ret) 59 + return ret; 58 60 59 - try_clock_freq: 60 - if (of_property_read_u32(np, "clock-freq", rate) && 61 - of_property_read_u32(np, "clock-frequency", rate)) 62 - panic("No clock nor clock-frequency property for %pOFn", np); 61 + *rate = clk_get_rate(timer_clk); 62 + if (!(*rate)) 63 + return -EINVAL; 64 + 65 + return 0; 63 66 } 64 67 65 - static void __init add_clockevent(struct device_node *event_timer) 68 + static int __init add_clockevent(struct device_node *event_timer) 66 69 { 67 70 void __iomem *iobase; 68 71 struct dw_apb_clock_event_device *ced; 69 72 u32 irq, rate; 73 + int ret = 0; 70 74 71 75 irq = irq_of_parse_and_map(event_timer, 0); 72 76 if (irq == 0) 73 77 panic("No IRQ for clock event timer"); 74 78 75 - timer_get_base_and_rate(event_timer, &iobase, &rate); 79 + ret = timer_get_base_and_rate(event_timer, &iobase, &rate); 80 + if (ret) 81 + return ret; 76 82 77 83 ced = dw_apb_clockevent_init(-1, event_timer->name, 300, iobase, irq, 78 84 rate); 79 85 if (!ced) 80 - panic("Unable to initialise clockevent device"); 86 + return -EINVAL; 81 87 82 88 dw_apb_clockevent_register(ced); 89 + 90 + return 0; 83 91 } 84 92 85 93 static void __iomem *sched_io_base; 86 94 static u32 sched_rate; 87 95 88 - static void __init add_clocksource(struct device_node *source_timer) 96 + static int __init add_clocksource(struct device_node *source_timer) 89 97 { 90 98 void __iomem *iobase; 91 99 struct dw_apb_clocksource *cs; 92 100 u32 rate; 101 + int ret; 93 102 94 - timer_get_base_and_rate(source_timer, &iobase, &rate); 103 + ret = timer_get_base_and_rate(source_timer, &iobase, &rate); 104 + if (ret) 105 + return ret; 95 106 96 107 cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate); 97 108 if (!cs) 98 - panic("Unable to initialise clocksource device"); 109 + return -EINVAL; 99 110 100 111 dw_apb_clocksource_start(cs); 101 112 dw_apb_clocksource_register(cs); ··· 119 106 */ 120 107 sched_io_base = iobase + 0x04; 121 108 sched_rate = rate; 109 + 110 + return 0; 122 111 } 123 112 124 113 static u64 notrace read_sched_clock(void) ··· 161 146 static int num_called; 162 147 static int __init dw_apb_timer_init(struct device_node *timer) 163 148 { 149 + int ret = 0; 150 + 164 151 switch (num_called) { 165 152 case 1: 166 153 pr_debug("%s: found clocksource timer\n", __func__); 167 - add_clocksource(timer); 154 + ret = add_clocksource(timer); 155 + if (ret) 156 + return ret; 168 157 init_sched_clock(); 169 158 #ifdef CONFIG_ARM 170 159 dw_apb_delay_timer.freq = sched_rate; ··· 177 158 break; 178 159 default: 179 160 pr_debug("%s: found clockevent timer\n", __func__); 180 - add_clockevent(timer); 161 + ret = add_clockevent(timer); 162 + if (ret) 163 + return ret; 181 164 break; 182 165 } 183 166