On 9/11/21 2:37 PM, Samuel Holland wrote:
On 9/11/21 1:31 PM, Sean Anderson wrote:
+CC Heinrich

Did you ever try booting with WDT on k210?

On 9/11/21 12:43 PM, Samuel Holland wrote:
Hello,

I am porting U-Boot to the Allwinner D1 SoC, and I ran into an issue
where the board fails to boot if I enable watchdog auto-start.

The call to get_timer() -> get_ticks() panics because no timer is
available. And since panic_finish() calls udelay(), this causes infinite
recursion of trying and failing to get the timer.

The issue is that the RISC-V architectural timer driver is bound in
arch_early_init_r, which is only called _after_ the first instance of
INIT_FUNC_WATCHDOG_RESET in the initcall list.

Below is a boot log where I commented out the calls to get_timer() and
time_after_eq() in watchdog_reset() in order to illustrate the problem.

I modified the log to add the initcall symbol names for clarity.

U-Boot 2021.10-rc2-00278-ge2be1a426d6-dirty (Jan 01 1970 - 00:00:00
+0000)

DRAM:  512 MiB
initcall: 000000005ff63916
initcall: 000000005ff6391a
initcall: 000000004a012a4e (initr_reloc_global_data)
initcall: 000000004a012a88 (initr_barrier)
initcall: 000000004a012a1c (initr_malloc)
Pre-reloc malloc() used 0x720 bytes (1 KB)
initcall: 000000004a01290e (log_init)
initcall: 000000004a012a94 (initr_bootstage)
initcall: 000000004a012a8c (initr_of_live)
initcall: 000000004a012a06 (initr_dm)
Binding device root_driver to driver root_driver
Probing device root_driver with driver root_driver
Binding device osc24M_clk to driver fixed_clock
Binding device soc to driver simple_bus
Binding device pinctrl@2000000 to driver sunxi-pinctrl
Binding device pinctrl@2000000 to driver gpio_sunxi
Binding device PA to driver gpio_sunxi
Binding device PB to driver gpio_sunxi
Binding device PC to driver gpio_sunxi
Binding device PD to driver gpio_sunxi
Binding device PE to driver gpio_sunxi
Binding device PF to driver gpio_sunxi
Binding device PG to driver gpio_sunxi
Binding device i2c0-pb10-pins to driver pinconfig
Binding device i2c2-pb0-pins to driver pinconfig
Binding device mmc0-pins to driver pinconfig
Binding device mmc1-pins to driver pinconfig
Binding device rgmii-pe-pins to driver pinconfig
Binding device spi0-pins to driver pinconfig
Binding device spi1-pd-pins to driver pinconfig
Binding device uart0-pb8-pins to driver pinconfig
Binding device uart1-pg6-pins to driver pinconfig
Binding device uart1-pg8-rts-cts-pins to driver pinconfig
Binding device i2s2-pb-pins to driver pinconfig
Binding device i2s2-pb3-din-pin to driver pinconfig
Binding device i2s2-pb4-dout-pin to driver pinconfig
Binding device ledc-pc0-pin to driver pinconfig
Binding device pwm0-pd16-pin to driver pinconfig
Binding device pwm2-pd18-pin to driver pinconfig
Binding device pwm7-pd22-pin to driver pinconfig
Binding device spdif-pd22-pin to driver pinconfig
Binding device clock-controller@2001000 to driver sun50i_d1_ccu
Binding device reset to driver sunxi_reset
Binding device serial@2500000 to driver ns16550_serial
Binding device serial@2500400 to driver ns16550_serial
Binding device i2c@2502000 to driver i2c_mvtwsi
Binding device i2c@2502800 to driver i2c_mvtwsi
Binding device mmc@4020000 to driver sunxi_mmc
Binding device m...@4020000.blk to driver mmc_blk
Binding device mmc@4021000 to driver sunxi_mmc
Binding device m...@4021000.blk to driver mmc_blk
Binding device usb@4100000 to driver sunxi-musb
Binding device phy@4100400 to driver sun4i_usb_phy
Binding device usb@4101000 to driver ehci_generic
Binding device usb@4101400 to driver ohci_generic
Binding device usb@4200000 to driver ehci_generic
Binding device usb@4200400 to driver ohci_generic
Binding device ethernet@4500000 to driver eth_sun8i_emac
Binding device watchdog@6011000 to driver sunxi_wdt
initcall: 000000004a001914 (board_init)
initcall: 000000004a04d814 (efi_memory_init)
initcall: 000000004a012a9c (initr_binman)
initcall: 000000004a012a90 (initr_dm_devices)

Here's where dm_timer_init() would be called if CONFIG_TIMER_EARLY was
enabled, but that still doesn't help because the timer is not bound yet.
In fact, CONFIG_TIMER_EARLY actually makes the situation worse, because
the board hangs if dm_timer_init() fails:

initcall sequence 000000005ffdac78 failed at call 000000004a012a06
(err=-19)
### ERROR ### Please RESET the board ###

I'm not sure what's going on here. Why does dm_timer_init get called
from initr_dm?

dm_timer_init gets called from initr_dm_devices (not initr_dm) if

Ah, 000000004a012a06 earlier referred to initr_dm.

CONFIG_TIMER_EARLY is enabled.

Hmm. It looks like this came up before and was addressed by 84b2416b6a
("board_r: move initr_watchdog to be called after initr_serial"). That
commit suggests just moving watchdog init later.

Perhaps it would be better to introduce a generic "bind_timer"
initcall?

We could also do something like

diff --git i/lib/time.c w/lib/time.c
index 38a9758292..3fccffc010 100644
--- i/lib/time.c
+++ w/lib/time.c
@@ -86,15 +86,15 @@ uint64_t notrace get_ticks(void)
        int ret;
if (!gd->timer) {
-#ifdef CONFIG_TIMER_EARLY
-               return timer_early_get_count();
-#else
                int ret;
ret = dm_timer_init();
-               if (ret)
-                       panic("Could not initialize timer (err %d)\n", ret);
-#endif
+               if (ret) {
+                       if (IS_ENABLED(CONFIG_TIMER_EARLY))
+                               return timer_early_get_count();
+                       else
+                               panic("Could not initialize timer (err %d)\n", 
ret);
+               }
        }
ret = timer_get_count(gd->timer, &count);
--

which would probably keep this from coming up again.

--Sean


Why does it fail?

It fails because at this point there are no devices bound for the timer
uclass, so uclass_first_device_err returns -ENODEV.

Regards,
Samuel

--Sean

initcall: 000000004a01c4f4 (stdio_init_tables)
initcall: 000000004a039ff8 (serial_initialize)
Probing device pinctrl@2000000 with driver sunxi-pinctrl
Probing device soc with driver simple_bus
Probing device clock-controller@2001000 with driver sun50i_d1_ccu
Probing device osc24M_clk with driver fixed_clock
Probing device uart0-pb8-pins with driver pinconfig
Probing device serial@2500000 with driver ns16550_serial
Probing device reset with driver sunxi_reset
initcall: 000000004a0129ea (initr_announce)
Now running in RAM - U-Boot at: 5ff51000
initcall: 000000004a0367ce (initr_watchdog)
Probing device watchdog@6011000 with driver sunxi_wdt
WDT:   Started with servicing (16s timeout)
initcall: 000000004a012610 (init_func_watchdog_reset)

Here's where the timer needs to be available for watchdog auto-start to
work. An unpatched U-Boot would panic here.

initcall: 000000004a012a84 (arch_initr_trap)
initcall: 000000004a012610 (init_func_watchdog_reset)
initcall: 000000004a012610 (init_func_watchdog_reset)
initcall: 000000004a000ed4 (arch_early_init_r)
Binding device cpus to driver cpu_bus
Binding device cpu@0 to driver riscv_cpu
Binding device riscv_timer to driver riscv_timer

But here is where the timer device is actually bound.

Do you have any suggestions for how best to fix this?

Some things I can think of:
   - Add an option to probe the CPU device early in initr_dm_devices()
   - Require the board to probe the CPU device from board_init()
   - Move arch_early_init_r() earlier in the initcall list
   - Skip restarting the watchdog until a timer is available (but this
     would not fix CONFIG_TIMER_EARLY)

Thanks,
Samuel

Probing device cpus with driver cpu_bus
Probing device cpu@0 with driver riscv_cpu
Binding device sbi-sysreset to driver sbi-sysreset
initcall: 000000004a012a98 (power_init_board)
initcall: 000000004a012610 (init_func_watchdog_reset)
initcall: 000000004a0129ca (initr_mmc)
MMC:   Probing device mmc0-pins with driver pinconfig
Probing device mmc@4020000 with driver sunxi_mmc
Probing device pinctrl@2000000 with driver gpio_sunxi
Probing device PF with driver gpio_sunxi
Need to init timer!
Probing device riscv_timer with driver riscv_timer
Timer is 000000005df34f80
Read timer, got 0x17dacfb
Timer is 000000005df34f80
Read timer, got 0x17f63b8
Probing device mmc1-pins with driver pinconfig
Probing device mmc@4021000 with driver sunxi_mmc
Timer is 000000005df34f80
Read timer, got 0x186be7e
Timer is 000000005df34f80
Read timer, got 0x188752e
mmc@4020000: 0, mmc@4021000: 1
initcall: 000000004a012970 (relocated to 000000005ff63970)
Loading Environment from nowhere... OK
initcall: 000000004a012610 (relocated to 000000005ff63610)
initcall: 000000004a012912 (relocated to 000000005ff63912)
initcall: 000000004a012610 (relocated to 000000005ff63610)
initcall: 000000004a01c50c (relocated to 000000005ff6d50c)
initcall: 000000004a010938 (relocated to 000000005ff61938)
initcall: 000000004a0188bc (relocated to 000000005ff698bc)
In:    serial@2500000
Out:   serial@2500000
Err:   serial@2500000
initcall: 000000004a012610 (relocated to 000000005ff63610)
initcall: 000000004a0012dc (relocated to 000000005ff522dc)
initcall: 000000004a012950 (relocated to 000000005ff63950)
initcall: 000000004a012610 (relocated to 000000005ff63610)
initcall: 000000004a012934 (relocated to 000000005ff63934)
Net:   phy interface8
Probing device rgmii-pe-pins with driver pinconfig
Probing device ethernet@4500000 with driver eth_sun8i_emac
Timer is 000000005df34f80
Read timer, got 0x1ae9538
Timer is 000000005df34f80
Read timer, got 0x1b04bed
Timer is 000000005df34f80
Read timer, got 0x1b202af
Timer is 000000005df34f80
Read timer, got 0x1b3b96e
Timer is 000000005df34f80
Read timer, got 0x1b5702c
Timer is 000000005df34f80
Read timer, got 0x1b726ec

Warning: ethernet@4500000 (eth0) using random MAC address -
62:69:97:68:19:04
eth0: ethernet@4500000
initcall: 000000004a01292a (relocated to 000000005ff6392a)
Hit any key to stop autoboot:  0





Reply via email to