diff options
Diffstat (limited to 'zephyr/shim/src/watchdog.c')
-rw-r--r-- | zephyr/shim/src/watchdog.c | 180 |
1 files changed, 129 insertions, 51 deletions
diff --git a/zephyr/shim/src/watchdog.c b/zephyr/shim/src/watchdog.c index 208930f5ea..0b96cbaa0e 100644 --- a/zephyr/shim/src/watchdog.c +++ b/zephyr/shim/src/watchdog.c @@ -14,81 +14,159 @@ LOG_MODULE_REGISTER(watchdog_shim, LOG_LEVEL_ERR); -#define wdt DEVICE_DT_GET(DT_CHOSEN(cros_ec_watchdog)) +struct watchdog_info { + const struct device *wdt_dev; + struct wdt_timeout_cfg config; +}; + +__maybe_unused static void wdt_warning_handler(const struct device *wdt_dev, + int channel_id); + +const struct watchdog_info wdt_info[] = { + { + .wdt_dev = DEVICE_DT_GET(DT_CHOSEN(cros_ec_watchdog)), + .config = { +#if DT_NODE_HAS_COMPAT(DT_CHOSEN(cros_ec_watchdog), st_stm32_watchdog) + .flags = WDT_FLAG_RESET_SOC, + .window.min = 0U, + .window.max = CONFIG_WATCHDOG_PERIOD_MS, + .callback = NULL, +#else + .flags = WDT_FLAG_RESET_SOC, + .window.min = 0U, + .window.max = CONFIG_AUX_TIMER_PERIOD_MS, + .callback = wdt_warning_handler, +#endif + }, + }, +#ifdef CONFIG_PLATFORM_EC_WATCHDOG_HELPER + { + .wdt_dev = DEVICE_DT_GET(DT_CHOSEN(cros_ec_watchdog_helper)), + .config = { + .flags = 0U, + .window.min = 0U, + .window.max = CONFIG_AUX_TIMER_PERIOD_MS, + .callback = wdt_warning_handler, + }, + }, +#endif +}; + +/* Array to keep channel used to implement watchdog */ +int wdt_chan[ARRAY_SIZE(wdt_info)]; +bool watchdog_initialized; #ifdef TEST_BUILD -extern bool wdt_warning_triggered; +bool wdt_warning_triggered; #endif /* TEST_BUILD */ -static void wdt_warning_handler(const struct device *wdt_dev, int channel_id) +static int watchdog_config(const struct watchdog_info *info) { - const char *thread_name = k_thread_name_get(k_current_get()); + const struct device *wdt_dev = info->wdt_dev; + const struct wdt_timeout_cfg *config = &info->config; + int chan; -#ifdef CONFIG_RISCV - printk("WDT pre-warning MEPC:%p THREAD_NAME:%s\n", - (void *)csr_read(mepc), thread_name); -#else - /* TODO(b/176523207): watchdog warning message */ - printk("Watchdog deadline is close! THREAD_NAME:%s\n", thread_name); -#endif -#ifdef TEST_BUILD - wdt_warning_triggered = true; -#endif -#ifdef CONFIG_SOC_SERIES_MEC172X - extern void cros_chip_wdt_handler(const struct device *wdt_dev, - int channel_id); - cros_chip_wdt_handler(wdt_dev, channel_id); -#endif + chan = wdt_install_timeout(wdt_dev, config); + + /* If watchdog is running, reinstall it. */ + if (chan == -EBUSY) { + wdt_disable(wdt_dev); + chan = wdt_install_timeout(wdt_dev, config); + } + + if (chan < 0) { + LOG_ERR("Watchdog install error: %d", chan); + } + + return chan; } -int watchdog_init(void) +static int watchdog_enable(const struct device *wdt_dev) { int err; - struct wdt_timeout_cfg wdt_config; - - if (!device_is_ready(wdt)) { - LOG_ERR("Error: device %s is not ready", wdt->name); - return -1; - } - /* Reset SoC when watchdog timer expires. */ - wdt_config.flags = WDT_FLAG_RESET_SOC; + err = wdt_setup(wdt_dev, 0); + if (err < 0) + LOG_ERR("Watchdog %s setup error: %d", wdt_dev->name, err); - /* - * Set the Warning timer as CONFIG_AUX_TIMER_PERIOD_MS. - * Then the watchdog reset time = CONFIG_WATCHDOG_PERIOD_MS. - */ - wdt_config.window.min = 0U; - wdt_config.window.max = CONFIG_AUX_TIMER_PERIOD_MS; - wdt_config.callback = wdt_warning_handler; + return err; +} - err = wdt_install_timeout(wdt, &wdt_config); +static int watchdog_init_device(const struct watchdog_info *info) +{ + const struct device *wdt_dev = info->wdt_dev; + int chan, err; - /* If watchdog is running, reinstall it. */ - if (err == -EBUSY) { - wdt_disable(wdt); - err = wdt_install_timeout(wdt, &wdt_config); + if (!device_is_ready(wdt_dev)) { + LOG_ERR("Error: device %s is not ready", wdt_dev->name); + return -ENODEV; } - if (err < 0) { - LOG_ERR("Watchdog install error"); - return err; - } + chan = watchdog_config(info); + if (chan < 0) + return chan; - err = wdt_setup(wdt, 0); - if (err < 0) { - LOG_ERR("Watchdog setup error"); + err = watchdog_enable(wdt_dev); + if (err < 0) return err; + + return chan; +} + +int watchdog_init(void) +{ + int err = EC_SUCCESS; + + if (watchdog_initialized) + return -EBUSY; + + for (int i = 0; i < ARRAY_SIZE(wdt_info); i++) { + wdt_chan[i] = watchdog_init_device(&wdt_info[i]); + if (wdt_chan[i] < 0 && err == EC_SUCCESS) + err = wdt_chan[i]; } - return EC_SUCCESS; + watchdog_initialized = true; + watchdog_reload(); + + return err; } void watchdog_reload(void) { - if (!device_is_ready(wdt)) - LOG_ERR("Error: device %s is not ready", wdt->name); + if (!watchdog_initialized) + return; + + for (int i = 0; i < ARRAY_SIZE(wdt_info); i++) { + if (wdt_chan[i] < 0) + continue; - wdt_feed(wdt, 0); + wdt_feed(wdt_info[i].wdt_dev, wdt_chan[i]); + } } DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT); + +__maybe_unused static void wdt_warning_handler(const struct device *wdt_dev, + int channel_id) +{ + const char *thread_name = k_thread_name_get(k_current_get()); + +#ifdef CONFIG_RISCV + printk("WDT pre-warning MEPC:%p THREAD_NAME:%s\n", + (void *)csr_read(mepc), thread_name); +#else + /* TODO(b/176523207): watchdog warning message */ + printk("Watchdog deadline is close! THREAD_NAME:%s\n", thread_name); +#endif +#ifdef TEST_BUILD + wdt_warning_triggered = true; +#endif +#ifdef CONFIG_SOC_SERIES_MEC172X + extern void cros_chip_wdt_handler(const struct device *wdt_dev, + int channel_id); + cros_chip_wdt_handler(wdt_dev, channel_id); +#endif + + /* Watchdog is disabled after calling handler. Re-enable it now. */ + watchdog_enable(wdt_dev); +} |