// SPDX-License-Identifier: GPL-2.0+ /* * watchdog_core.c * * (c) Copyright 2008-2011 Alan Cox <[email protected]>, * All Rights Reserved. * * (c) Copyright 2008-2011 Wim Van Sebroeck <[email protected]>. * * This source code is part of the generic code that can be used * by all the watchdog timer drivers. * * Based on source code of the following authors: * Matt Domsch <[email protected]>, * Rob Radez <[email protected]>, * Rusty Lynch <[email protected]> * Satyam Sharma <[email protected]> * Randy Dunlap <[email protected]> * * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. * admit liability nor provide warranty for any of this software. * This material is provided "AS-IS" and at no charge. */ #define pr_fmt(fmt) … #include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */ #include <linux/types.h> /* For standard types */ #include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/kernel.h> /* For printk/panic/... */ #include <linux/reboot.h> /* For restart handler */ #include <linux/watchdog.h> /* For watchdog specific items */ #include <linux/init.h> /* For __init/__exit/... */ #include <linux/idr.h> /* For ida_* macros */ #include <linux/err.h> /* For IS_ERR macros */ #include <linux/of.h> /* For of_get_timeout_sec */ #include <linux/suspend.h> #include "watchdog_core.h" /* For watchdog_dev_register/... */ #define CREATE_TRACE_POINTS #include <trace/events/watchdog.h> static DEFINE_IDA(watchdog_ida); static int stop_on_reboot = …; module_param(stop_on_reboot, int, 0444); MODULE_PARM_DESC(…) …; /* * Deferred Registration infrastructure. * * Sometimes watchdog drivers needs to be loaded as soon as possible, * for example when it's impossible to disable it. To do so, * raising the initcall level of the watchdog driver is a solution. * But in such case, the miscdev is maybe not ready (subsys_initcall), and * watchdog_core need miscdev to register the watchdog as a char device. * * The deferred registration infrastructure offer a way for the watchdog * subsystem to register a watchdog properly, even before miscdev is ready. */ static DEFINE_MUTEX(wtd_deferred_reg_mutex); static LIST_HEAD(wtd_deferred_reg_list); static bool wtd_deferred_reg_done; static void watchdog_deferred_registration_add(struct watchdog_device *wdd) { … } static void watchdog_deferred_registration_del(struct watchdog_device *wdd) { … } static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) { … } /** * watchdog_init_timeout() - initialize the timeout field * @wdd: watchdog device * @timeout_parm: timeout module parameter * @dev: Device that stores the timeout-sec property * * Initialize the timeout field of the watchdog_device struct with either the * timeout module parameter (if it is valid value) or the timeout-sec property * (only if it is a valid value and the timeout_parm is out of bounds). * If none of them are valid then we keep the old value (which should normally * be the default timeout value). Note that for the module parameter, '0' means * 'use default' while it is an invalid value for the timeout-sec property. * It should simply be dropped if you want to use the default value then. * * A zero is returned on success or -EINVAL if all provided values are out of * bounds. */ int watchdog_init_timeout(struct watchdog_device *wdd, unsigned int timeout_parm, struct device *dev) { … } EXPORT_SYMBOL_GPL(…); static int watchdog_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data) { … } static int watchdog_restart_notifier(struct notifier_block *nb, unsigned long action, void *data) { … } static int watchdog_pm_notifier(struct notifier_block *nb, unsigned long mode, void *data) { … } /** * watchdog_set_restart_priority - Change priority of restart handler * @wdd: watchdog device * @priority: priority of the restart handler, should follow these guidelines: * 0: use watchdog's restart function as last resort, has limited restart * capabilies * 128: default restart handler, use if no other handler is expected to be * available and/or if restart is sufficient to restart the entire system * 255: preempt all other handlers * * If a wdd->ops->restart function is provided when watchdog_register_device is * called, it will be registered as a restart handler with the priority given * here. */ void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority) { … } EXPORT_SYMBOL_GPL(…); static int __watchdog_register_device(struct watchdog_device *wdd) { … } /** * watchdog_register_device() - register a watchdog device * @wdd: watchdog device * * Register a watchdog device with the kernel so that the * watchdog timer can be accessed from userspace. * * A zero is returned on success and a negative errno code for * failure. */ int watchdog_register_device(struct watchdog_device *wdd) { … } EXPORT_SYMBOL_GPL(…); static void __watchdog_unregister_device(struct watchdog_device *wdd) { … } /** * watchdog_unregister_device() - unregister a watchdog device * @wdd: watchdog device to unregister * * Unregister a watchdog device that was previously successfully * registered with watchdog_register_device(). */ void watchdog_unregister_device(struct watchdog_device *wdd) { … } EXPORT_SYMBOL_GPL(…); static void devm_watchdog_unregister_device(struct device *dev, void *res) { … } /** * devm_watchdog_register_device() - resource managed watchdog_register_device() * @dev: device that is registering this watchdog device * @wdd: watchdog device * * Managed watchdog_register_device(). For watchdog device registered by this * function, watchdog_unregister_device() is automatically called on driver * detach. See watchdog_register_device() for more information. */ int devm_watchdog_register_device(struct device *dev, struct watchdog_device *wdd) { … } EXPORT_SYMBOL_GPL(…); static int __init watchdog_deferred_registration(void) { … } static int __init watchdog_init(void) { … } static void __exit watchdog_exit(void) { … } subsys_initcall_sync(watchdog_init); module_exit(watchdog_exit); MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;