mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-05-21 14:44:09 +00:00
watchdog: watchdog_core: Add watchdog registration deferral mechanism
Currently, watchdog subsystem require the misc subsystem to register a watchdog. This may not be the case in case of an early registration of a watchdog, which can be required when the watchdog cannot be disabled. This patch introduces a deferral mechanism to remove this requirement. Signed-off-by: Jean-Baptiste Theou <jtheou@adeneo-embedded.us> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
This commit is contained in:
parent
b9be9660ba
commit
ef90174f82
3 changed files with 110 additions and 18 deletions
|
@ -36,6 +36,10 @@ The watchdog_unregister_device routine deregisters a registered watchdog timer
|
||||||
device. The parameter of this routine is the pointer to the registered
|
device. The parameter of this routine is the pointer to the registered
|
||||||
watchdog_device structure.
|
watchdog_device structure.
|
||||||
|
|
||||||
|
The watchdog subsystem includes an registration deferral mechanism,
|
||||||
|
which allows you to register an watchdog as early as you wish during
|
||||||
|
the boot process.
|
||||||
|
|
||||||
The watchdog device structure looks like this:
|
The watchdog device structure looks like this:
|
||||||
|
|
||||||
struct watchdog_device {
|
struct watchdog_device {
|
||||||
|
@ -52,6 +56,7 @@ struct watchdog_device {
|
||||||
void *driver_data;
|
void *driver_data;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
unsigned long status;
|
unsigned long status;
|
||||||
|
struct list_head deferred;
|
||||||
};
|
};
|
||||||
|
|
||||||
It contains following fields:
|
It contains following fields:
|
||||||
|
@ -80,6 +85,8 @@ It contains following fields:
|
||||||
information about the status of the device (Like: is the watchdog timer
|
information about the status of the device (Like: is the watchdog timer
|
||||||
running/active, is the nowayout bit set, is the device opened via
|
running/active, is the nowayout bit set, is the device opened via
|
||||||
the /dev/watchdog interface or not, ...).
|
the /dev/watchdog interface or not, ...).
|
||||||
|
* deferred: entry in wtd_deferred_reg_list which is used to
|
||||||
|
register early initialized watchdogs.
|
||||||
|
|
||||||
The list of watchdog operations is defined as:
|
The list of watchdog operations is defined as:
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,45 @@
|
||||||
static DEFINE_IDA(watchdog_ida);
|
static DEFINE_IDA(watchdog_ida);
|
||||||
static struct class *watchdog_class;
|
static struct class *watchdog_class;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 int watchdog_deferred_registration_add(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
list_add_tail(&wdd->deferred,
|
||||||
|
&wtd_deferred_reg_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void watchdog_deferred_registration_del(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
struct list_head *p, *n;
|
||||||
|
struct watchdog_device *wdd_tmp;
|
||||||
|
|
||||||
|
list_for_each_safe(p, n, &wtd_deferred_reg_list) {
|
||||||
|
wdd_tmp = list_entry(p, struct watchdog_device,
|
||||||
|
deferred);
|
||||||
|
if (wdd_tmp == wdd) {
|
||||||
|
list_del(&wdd_tmp->deferred);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
|
static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -98,17 +137,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(watchdog_init_timeout);
|
EXPORT_SYMBOL_GPL(watchdog_init_timeout);
|
||||||
|
|
||||||
/**
|
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)
|
|
||||||
{
|
{
|
||||||
int ret, id, devno;
|
int ret, id, devno;
|
||||||
|
|
||||||
|
@ -164,16 +193,33 @@ int watchdog_register_device(struct watchdog_device *wdd)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(watchdog_register_device);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* watchdog_unregister_device() - unregister a watchdog device
|
* watchdog_register_device() - register a watchdog device
|
||||||
* @wdd: watchdog device to unregister
|
* @wdd: watchdog device
|
||||||
*
|
*
|
||||||
* Unregister a watchdog device that was previously successfully
|
* Register a watchdog device with the kernel so that the
|
||||||
* registered with watchdog_register_device().
|
* watchdog timer can be accessed from userspace.
|
||||||
|
*
|
||||||
|
* A zero is returned on success and a negative errno code for
|
||||||
|
* failure.
|
||||||
*/
|
*/
|
||||||
void watchdog_unregister_device(struct watchdog_device *wdd)
|
|
||||||
|
int watchdog_register_device(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&wtd_deferred_reg_mutex);
|
||||||
|
if (wtd_deferred_reg_done)
|
||||||
|
ret = __watchdog_register_device(wdd);
|
||||||
|
else
|
||||||
|
ret = watchdog_deferred_registration_add(wdd);
|
||||||
|
mutex_unlock(&wtd_deferred_reg_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(watchdog_register_device);
|
||||||
|
|
||||||
|
static void __watchdog_unregister_device(struct watchdog_device *wdd)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int devno;
|
int devno;
|
||||||
|
@ -189,8 +235,43 @@ void watchdog_unregister_device(struct watchdog_device *wdd)
|
||||||
ida_simple_remove(&watchdog_ida, wdd->id);
|
ida_simple_remove(&watchdog_ida, wdd->id);
|
||||||
wdd->dev = NULL;
|
wdd->dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
mutex_lock(&wtd_deferred_reg_mutex);
|
||||||
|
if (wtd_deferred_reg_done)
|
||||||
|
__watchdog_unregister_device(wdd);
|
||||||
|
else
|
||||||
|
watchdog_deferred_registration_del(wdd);
|
||||||
|
mutex_unlock(&wtd_deferred_reg_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(watchdog_unregister_device);
|
EXPORT_SYMBOL_GPL(watchdog_unregister_device);
|
||||||
|
|
||||||
|
static int __init watchdog_deferred_registration(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&wtd_deferred_reg_mutex);
|
||||||
|
wtd_deferred_reg_done = true;
|
||||||
|
while (!list_empty(&wtd_deferred_reg_list)) {
|
||||||
|
struct watchdog_device *wdd;
|
||||||
|
|
||||||
|
wdd = list_first_entry(&wtd_deferred_reg_list,
|
||||||
|
struct watchdog_device, deferred);
|
||||||
|
list_del(&wdd->deferred);
|
||||||
|
__watchdog_register_device(wdd);
|
||||||
|
}
|
||||||
|
mutex_unlock(&wtd_deferred_reg_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init watchdog_init(void)
|
static int __init watchdog_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -207,6 +288,7 @@ static int __init watchdog_init(void)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watchdog_deferred_registration();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +299,7 @@ static void __exit watchdog_exit(void)
|
||||||
ida_destroy(&watchdog_ida);
|
ida_destroy(&watchdog_ida);
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(watchdog_init);
|
subsys_initcall_sync(watchdog_init);
|
||||||
module_exit(watchdog_exit);
|
module_exit(watchdog_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
|
MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
|
||||||
|
|
|
@ -65,6 +65,8 @@ struct watchdog_ops {
|
||||||
* @driver-data:Pointer to the drivers private data.
|
* @driver-data:Pointer to the drivers private data.
|
||||||
* @lock: Lock for watchdog core internal use only.
|
* @lock: Lock for watchdog core internal use only.
|
||||||
* @status: Field that contains the devices internal status bits.
|
* @status: Field that contains the devices internal status bits.
|
||||||
|
* @deferred: entry in wtd_deferred_reg_list which is used to
|
||||||
|
* register early initialized watchdogs.
|
||||||
*
|
*
|
||||||
* The watchdog_device structure contains all information about a
|
* The watchdog_device structure contains all information about a
|
||||||
* watchdog timer device.
|
* watchdog timer device.
|
||||||
|
@ -95,6 +97,7 @@ struct watchdog_device {
|
||||||
#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
|
#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
|
||||||
#define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
|
#define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
|
||||||
#define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
|
#define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
|
||||||
|
struct list_head deferred;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WATCHDOG_NOWAYOUT IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
|
#define WATCHDOG_NOWAYOUT IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
|
||||||
|
|
Loading…
Add table
Reference in a new issue