Commit 06985289d452ad2423145cfed8cece61a7f8cec6

Authored by Stefan Roese
1 parent 5edb9b2d71

watchdog: Implement generic watchdog_reset() version

This patch tries to implement a generic watchdog_reset() function that
can be used by all boards that want to service the watchdog device in
U-Boot. This watchdog servicing is enabled via CONFIG_WATCHDOG.

Without this approach, new boards or platforms needed to implement a
board specific version of this functionality, mostly copy'ing the same
code over and over again into their board or platforms code base.

With this new generic function, the scattered other functions are now
removed to be replaced by the generic one. The new version also enables
the configuration of the watchdog timeout via the DT "timeout-sec"
property (if enabled via CONFIG_OF_CONTROL).

This patch also adds a new flag to the GD flags, to flag that the
watchdog is ready to use and adds the pointer to the watchdog device
to the GD. This enables us to remove the global "watchdog_dev"
variable, which was prone to cause problems because of its potentially
very early use in watchdog_reset(), even before the BSS is cleared.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Heiko Schocher <hs@denx.de>
Cc: Tom Rini <trini@konsulko.com>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: "Marek Behún" <marek.behun@nic.cz>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Cc: Maxim Sloyko <maxims@google.com>
Cc: Erik van Luijk <evanluijk@interact.nl>
Cc: Ryder Lee <ryder.lee@mediatek.com>
Cc: Weijie Gao <weijie.gao@mediatek.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: "Álvaro Fernández Rojas" <noltari@gmail.com>
Cc: Philippe Reynes <philippe.reynes@softathome.com>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: Michal Simek <michal.simek@xilinx.com>
Tested-by: Michal Simek <michal.simek@xilinx.com> (on zcu100)

Showing 14 changed files with 82 additions and 259 deletions Side-by-side Diff

arch/mips/mach-mt7620/cpu.c
... ... @@ -69,28 +69,6 @@
69 69 return 0;
70 70 }
71 71  
72   -#ifdef CONFIG_WATCHDOG
73   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
74   -
75   -/* Called by macro WATCHDOG_RESET */
76   -void watchdog_reset(void)
77   -{
78   - static ulong next_reset;
79   - ulong now;
80   -
81   - if (!watchdog_dev)
82   - return;
83   -
84   - now = get_timer(0);
85   -
86   - /* Do not reset the watchdog too often */
87   - if (now > next_reset) {
88   - next_reset = now + 1000; /* reset every 1000ms */
89   - wdt_reset(watchdog_dev);
90   - }
91   -}
92   -#endif
93   -
94 72 int arch_misc_init(void)
95 73 {
96 74 /*
... ... @@ -102,20 +80,6 @@
102 80 */
103 81 flush_dcache_range(gd->bd->bi_memstart,
104 82 gd->bd->bi_memstart + gd->ram_size - 1);
105   -
106   -#ifdef CONFIG_WATCHDOG
107   - /* Init watchdog */
108   - if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
109   - debug("Watchdog: Not found by seq!\n");
110   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
111   - puts("Watchdog: Not found!\n");
112   - return 0;
113   - }
114   - }
115   -
116   - wdt_start(watchdog_dev, 60000, 0); /* 60 seconds */
117   - printf("Watchdog: Started\n");
118   -#endif
119 83  
120 84 return 0;
121 85 }
board/CZ.NIC/turris_mox/turris_mox.c
... ... @@ -119,40 +119,10 @@
119 119 }
120 120 #endif
121 121  
122   -#ifdef CONFIG_WDT_ARMADA_37XX
123   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
124   -
125   -void watchdog_reset(void)
126   -{
127   - static ulong next_reset;
128   - ulong now;
129   -
130   - if (!watchdog_dev)
131   - return;
132   -
133   - now = timer_get_us();
134   -
135   - /* Do not reset the watchdog too often */
136   - if (now > next_reset) {
137   - wdt_reset(watchdog_dev);
138   - next_reset = now + 100000;
139   - }
140   -}
141   -#endif
142   -
143 122 int board_init(void)
144 123 {
145 124 /* address of boot parameters */
146 125 gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
147   -
148   -#ifdef CONFIG_WDT_ARMADA_37XX
149   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
150   - printf("Cannot find Armada 3720 watchdog!\n");
151   - } else {
152   - printf("Enabling Armada 3720 watchdog (3 minutes timeout).\n");
153   - wdt_start(watchdog_dev, 180000, 0);
154   - }
155   -#endif
156 126  
157 127 return 0;
158 128 }
board/CZ.NIC/turris_omnia/turris_omnia.c
... ... @@ -364,25 +364,12 @@
364 364 }
365 365 #endif
366 366  
367   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
368   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
369   -#endif
370   -
371 367 int board_init(void)
372 368 {
373 369 /* adress of boot parameters */
374 370 gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
375 371  
376 372 #ifndef CONFIG_SPL_BUILD
377   -# ifdef CONFIG_WDT_ORION
378   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
379   - puts("Cannot find Armada 385 watchdog!\n");
380   - } else {
381   - puts("Enabling Armada 385 watchdog.\n");
382   - wdt_start(watchdog_dev, 120000, 0);
383   - }
384   -# endif
385   -
386 373 if (disable_mcu_watchdog())
387 374 puts("Disabled MCU startup watchdog.\n");
388 375  
... ... @@ -391,28 +378,6 @@
391 378  
392 379 return 0;
393 380 }
394   -
395   -#ifdef CONFIG_WATCHDOG
396   -/* Called by macro WATCHDOG_RESET */
397   -void watchdog_reset(void)
398   -{
399   -# if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
400   - static ulong next_reset = 0;
401   - ulong now;
402   -
403   - if (!watchdog_dev)
404   - return;
405   -
406   - now = timer_get_us();
407   -
408   - /* Do not reset the watchdog too often */
409   - if (now > next_reset) {
410   - wdt_reset(watchdog_dev);
411   - next_reset = now + 1000;
412   - }
413   -# endif
414   -}
415   -#endif
416 381  
417 382 int board_late_init(void)
418 383 {
board/alliedtelesis/x530/x530.c
... ... @@ -25,10 +25,6 @@
25 25 #define CONFIG_NVS_LOCATION 0xf4800000
26 26 #define CONFIG_NVS_SIZE (512 << 10)
27 27  
28   -#ifdef CONFIG_WATCHDOG
29   -static struct udevice *watchdog_dev;
30   -#endif
31   -
32 28 static struct serdes_map board_serdes_map[] = {
33 29 {PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0},
34 30 {DEFAULT_SERDES, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0},
... ... @@ -80,10 +76,6 @@
80 76  
81 77 int board_early_init_f(void)
82 78 {
83   -#ifdef CONFIG_WATCHDOG
84   - watchdog_dev = NULL;
85   -#endif
86   -
87 79 /* Configure MPP */
88 80 writel(0x00001111, MVEBU_MPP_BASE + 0x00);
89 81 writel(0x00000000, MVEBU_MPP_BASE + 0x04);
... ... @@ -99,13 +91,6 @@
99 91  
100 92 void spl_board_init(void)
101 93 {
102   -#ifdef CONFIG_WATCHDOG
103   - int ret;
104   -
105   - ret = uclass_get_device(UCLASS_WDT, 0, &watchdog_dev);
106   - if (!ret)
107   - wdt_start(watchdog_dev, 120000, 0);
108   -#endif
109 94 }
110 95  
111 96 int board_init(void)
112 97  
... ... @@ -128,28 +113,9 @@
128 113 void arch_preboot_os(void)
129 114 {
130 115 #ifdef CONFIG_WATCHDOG
131   - wdt_stop(watchdog_dev);
  116 + wdt_stop(gd->watchdog_dev);
132 117 #endif
133 118 }
134   -
135   -#ifdef CONFIG_WATCHDOG
136   -void watchdog_reset(void)
137   -{
138   - static ulong next_reset = 0;
139   - ulong now;
140   -
141   - if (!watchdog_dev)
142   - return;
143   -
144   - now = timer_get_us();
145   -
146   - /* Do not reset the watchdog too often */
147   - if (now > next_reset) {
148   - wdt_reset(watchdog_dev);
149   - next_reset = now + 1000;
150   - }
151   -}
152   -#endif
153 119  
154 120 static int led_7seg_init(unsigned int segments)
155 121 {
board/xilinx/microblaze-generic/microblaze-generic.c
... ... @@ -24,10 +24,6 @@
24 24  
25 25 DECLARE_GLOBAL_DATA_PTR;
26 26  
27   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
28   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
29   -#endif /* !CONFIG_SPL_BUILD && CONFIG_WDT */
30   -
31 27 ulong ram_base;
32 28  
33 29 int dram_init_banksize(void)
34 30  
... ... @@ -43,44 +39,8 @@
43 39 return 0;
44 40 };
45 41  
46   -#ifdef CONFIG_WDT
47   -/* Called by macro WATCHDOG_RESET */
48   -void watchdog_reset(void)
49   -{
50   -#if !defined(CONFIG_SPL_BUILD)
51   - ulong now;
52   - static ulong next_reset;
53   -
54   - if (!watchdog_dev)
55   - return;
56   -
57   - now = timer_get_us();
58   -
59   - /* Do not reset the watchdog too often */
60   - if (now > next_reset) {
61   - wdt_reset(watchdog_dev);
62   - next_reset = now + 1000;
63   - }
64   -#endif /* !CONFIG_SPL_BUILD */
65   -}
66   -#endif /* CONFIG_WDT */
67   -
68 42 int board_late_init(void)
69 43 {
70   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
71   - watchdog_dev = NULL;
72   -
73   - if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
74   - debug("Watchdog: Not found by seq!\n");
75   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
76   - puts("Watchdog: Not found!\n");
77   - return 0;
78   - }
79   - }
80   -
81   - wdt_start(watchdog_dev, 0, 0);
82   - puts("Watchdog: Started\n");
83   -#endif /* !CONFIG_SPL_BUILD && CONFIG_WDT */
84 44 #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SYSRESET_MICROBLAZE)
85 45 int ret;
86 46  
board/xilinx/zynq/board.c
... ... @@ -18,10 +18,6 @@
18 18  
19 19 DECLARE_GLOBAL_DATA_PTR;
20 20  
21   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
22   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
23   -#endif
24   -
25 21 #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOARD_EARLY_INIT_F)
26 22 int board_early_init_f(void)
27 23 {
... ... @@ -31,19 +27,6 @@
31 27  
32 28 int board_init(void)
33 29 {
34   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
35   - if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
36   - debug("Watchdog: Not found by seq!\n");
37   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
38   - puts("Watchdog: Not found!\n");
39   - return 0;
40   - }
41   - }
42   -
43   - wdt_start(watchdog_dev, 0, 0);
44   - puts("Watchdog: Started\n");
45   -# endif
46   -
47 30 return 0;
48 31 }
49 32  
... ... @@ -125,28 +108,6 @@
125 108 zynq_ddrc_init();
126 109  
127 110 return 0;
128   -}
129   -#endif
130   -
131   -#if defined(CONFIG_WATCHDOG)
132   -/* Called by macro WATCHDOG_RESET */
133   -void watchdog_reset(void)
134   -{
135   -# if !defined(CONFIG_SPL_BUILD)
136   - static ulong next_reset;
137   - ulong now;
138   -
139   - if (!watchdog_dev)
140   - return;
141   -
142   - now = timer_get_us();
143   -
144   - /* Do not reset the watchdog too often */
145   - if (now > next_reset) {
146   - wdt_reset(watchdog_dev);
147   - next_reset = now + 1000;
148   - }
149   -# endif
150 111 }
151 112 #endif
board/xilinx/zynqmp/zynqmp.c
... ... @@ -24,10 +24,6 @@
24 24  
25 25 DECLARE_GLOBAL_DATA_PTR;
26 26  
27   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
28   -static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;
29   -#endif
30   -
31 27 #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
32 28 !defined(CONFIG_SPL_BUILD)
33 29 static xilinx_desc zynqmppl = XILINX_ZYNQMP_DESC;
34 30  
... ... @@ -344,43 +340,8 @@
344 340 }
345 341 #endif
346 342  
347   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT)
348   - if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
349   - debug("Watchdog: Not found by seq!\n");
350   - if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
351   - puts("Watchdog: Not found!\n");
352   - return 0;
353   - }
354   - }
355   -
356   - wdt_start(watchdog_dev, 0, 0);
357   - puts("Watchdog: Started\n");
358   -#endif
359   -
360 343 return 0;
361 344 }
362   -
363   -#ifdef CONFIG_WATCHDOG
364   -/* Called by macro WATCHDOG_RESET */
365   -void watchdog_reset(void)
366   -{
367   -# if !defined(CONFIG_SPL_BUILD)
368   - static ulong next_reset;
369   - ulong now;
370   -
371   - if (!watchdog_dev)
372   - return;
373   -
374   - now = timer_get_us();
375   -
376   - /* Do not reset the watchdog too often */
377   - if (now > next_reset) {
378   - wdt_reset(watchdog_dev);
379   - next_reset = now + 1000;
380   - }
381   -# endif
382   -}
383   -#endif
384 345  
385 346 int board_early_init_r(void)
386 347 {
... ... @@ -48,6 +48,7 @@
48 48 #include <linux/compiler.h>
49 49 #include <linux/err.h>
50 50 #include <efi_loader.h>
  51 +#include <wdt.h>
51 52  
52 53 DECLARE_GLOBAL_DATA_PTR;
53 54  
... ... @@ -676,6 +677,9 @@
676 677 #endif
677 678 #ifdef CONFIG_DM
678 679 initr_dm,
  680 +#endif
  681 +#if defined(CONFIG_WDT)
  682 + initr_watchdog,
679 683 #endif
680 684 #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
681 685 defined(CONFIG_SANDBOX)
... ... @@ -22,6 +22,7 @@
22 22 #include <linux/compiler.h>
23 23 #include <fdt_support.h>
24 24 #include <bootcount.h>
  25 +#include <wdt.h>
25 26  
26 27 DECLARE_GLOBAL_DATA_PTR;
27 28  
... ... @@ -598,6 +599,10 @@
598 599  
599 600 #if CONFIG_IS_ENABLED(BOARD_INIT)
600 601 spl_board_init();
  602 +#endif
  603 +
  604 +#if defined(CONFIG_SPL_WATCHDOG_SUPPORT) && defined(CONFIG_WDT)
  605 + initr_watchdog();
601 606 #endif
602 607  
603 608 if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF))
drivers/watchdog/Kconfig
... ... @@ -51,6 +51,7 @@
51 51 config WDT
52 52 bool "Enable driver model for watchdog timer drivers"
53 53 depends on DM
  54 + imply WATCHDOG
54 55 help
55 56 Enable driver model for watchdog timer. At the moment the API
56 57 is very simple and only supports four operations:
drivers/watchdog/wdt-uclass.c
... ... @@ -10,6 +10,8 @@
10 10 #include <dm/device-internal.h>
11 11 #include <dm/lists.h>
12 12  
  13 +DECLARE_GLOBAL_DATA_PTR;
  14 +
13 15 int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
14 16 {
15 17 const struct wdt_ops *ops = device_get_ops(dev);
... ... @@ -62,6 +64,30 @@
62 64  
63 65 return ret;
64 66 }
  67 +
  68 +#if defined(CONFIG_WATCHDOG)
  69 +/*
  70 + * Called by macro WATCHDOG_RESET. This function be called *very* early,
  71 + * so we need to make sure, that the watchdog driver is ready before using
  72 + * it in this function.
  73 + */
  74 +void watchdog_reset(void)
  75 +{
  76 + static ulong next_reset;
  77 + ulong now;
  78 +
  79 + /* Exit if GD is not ready or watchdog is not initialized yet */
  80 + if (!gd || !(gd->flags & GD_FLG_WDT_READY))
  81 + return;
  82 +
  83 + /* Do not reset the watchdog too often */
  84 + now = get_timer(0);
  85 + if (now > next_reset) {
  86 + next_reset = now + 1000; /* reset every 1000ms */
  87 + wdt_reset(gd->watchdog_dev);
  88 + }
  89 +}
  90 +#endif
65 91  
66 92 static int wdt_post_bind(struct udevice *dev)
67 93 {
include/asm-generic/global_data.h
... ... @@ -137,6 +137,9 @@
137 137 #if defined(CONFIG_TRANSLATION_OFFSET)
138 138 fdt_addr_t translation_offset; /* optional translation offset */
139 139 #endif
  140 +#if defined(CONFIG_WDT)
  141 + struct udevice *watchdog_dev;
  142 +#endif
140 143 } gd_t;
141 144 #endif
142 145  
... ... @@ -165,6 +168,7 @@
165 168 #define GD_FLG_ENV_DEFAULT 0x02000 /* Default variable flag */
166 169 #define GD_FLG_SPL_EARLY_INIT 0x04000 /* Early SPL init is done */
167 170 #define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */
  171 +#define GD_FLG_WDT_READY 0x10000 /* Watchdog is ready for use */
168 172  
169 173 #endif /* __ASM_GENERIC_GBL_DATA_H */
include/configs/turris_omnia.h
... ... @@ -29,11 +29,6 @@
29 29 #define CONFIG_SPL_I2C_MUX
30 30 #define CONFIG_SYS_I2C_MVTWSI
31 31  
32   -/* Watchdog support */
33   -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION)
34   -# define CONFIG_WATCHDOG
35   -#endif
36   -
37 32 /*
38 33 * SDIO/MMC Card Configuration
39 34 */
... ... @@ -6,6 +6,9 @@
6 6 #ifndef _WDT_H_
7 7 #define _WDT_H_
8 8  
  9 +#include <dm.h>
  10 +#include <dm/read.h>
  11 +
9 12 /*
10 13 * Implement a simple watchdog uclass. Watchdog is basically a timer that
11 14 * is used to detect or recover from malfunction. During normal operation
... ... @@ -102,6 +105,44 @@
102 105 */
103 106 int (*expire_now)(struct udevice *dev, ulong flags);
104 107 };
  108 +
  109 +#if defined(CONFIG_WDT)
  110 +#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
  111 +#define CONFIG_WATCHDOG_TIMEOUT_MSECS (60 * 1000)
  112 +#endif
  113 +#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
  114 +
  115 +static inline int initr_watchdog(void)
  116 +{
  117 + u32 timeout = WATCHDOG_TIMEOUT_SECS;
  118 +
  119 + /*
  120 + * Init watchdog: This will call the probe function of the
  121 + * watchdog driver, enabling the use of the device
  122 + */
  123 + if (uclass_get_device_by_seq(UCLASS_WDT, 0,
  124 + (struct udevice **)&gd->watchdog_dev)) {
  125 + debug("WDT: Not found by seq!\n");
  126 + if (uclass_get_device(UCLASS_WDT, 0,
  127 + (struct udevice **)&gd->watchdog_dev)) {
  128 + printf("WDT: Not found!\n");
  129 + return 0;
  130 + }
  131 + }
  132 +
  133 + if (CONFIG_IS_ENABLED(OF_CONTROL)) {
  134 + timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec",
  135 + WATCHDOG_TIMEOUT_SECS);
  136 + }
  137 +
  138 + wdt_start(gd->watchdog_dev, timeout * 1000, 0);
  139 + gd->flags |= GD_FLG_WDT_READY;
  140 + printf("WDT: Started with%s servicing (%ds timeout)\n",
  141 + IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout);
  142 +
  143 + return 0;
  144 +}
  145 +#endif
105 146  
106 147 #endif /* _WDT_H_ */