forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
watchdog: add watchdog pretimeout governor framework
The change adds a simple watchdog pretimeout framework infrastructure, its purpose is to allow users to select a desired handling of watchdog pretimeout events, which may be generated by some watchdog devices. A user selects a default watchdog pretimeout governor during compilation stage. Watchdogs with WDIOF_PRETIMEOUT capability now have one more device attribute in sysfs, pretimeout_governor attribute is intended to display the selected watchdog pretimeout governor. The framework has no impact at runtime on watchdog devices with no WDIOF_PRETIMEOUT capability set. Signed-off-by: Vladimir Zapolskiy <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Reviewed-by: Wolfram Sang <[email protected]> Tested-by: Wolfram Sang <[email protected]> Signed-off-by: Guenter Roeck <[email protected]> Signed-off-by: Wim Van Sebroeck <[email protected]>
- Loading branch information
Vladimir Zapolskiy
authored and
Wim Van Sebroeck
committed
Oct 8, 2016
1 parent
fc113d5
commit ff84136
Showing
7 changed files
with
231 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
* Copyright (C) 2015-2016 Mentor Graphics | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
*/ | ||
|
||
#include <linux/list.h> | ||
#include <linux/slab.h> | ||
#include <linux/spinlock.h> | ||
#include <linux/watchdog.h> | ||
|
||
#include "watchdog_pretimeout.h" | ||
|
||
/* Default watchdog pretimeout governor */ | ||
static struct watchdog_governor *default_gov; | ||
|
||
/* The spinlock protects default_gov, wdd->gov and pretimeout_list */ | ||
static DEFINE_SPINLOCK(pretimeout_lock); | ||
|
||
/* List of watchdog devices, which can generate a pretimeout event */ | ||
static LIST_HEAD(pretimeout_list); | ||
|
||
struct watchdog_pretimeout { | ||
struct watchdog_device *wdd; | ||
struct list_head entry; | ||
}; | ||
|
||
int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf) | ||
{ | ||
int count = 0; | ||
|
||
spin_lock_irq(&pretimeout_lock); | ||
if (wdd->gov) | ||
count = sprintf(buf, "%s\n", wdd->gov->name); | ||
spin_unlock_irq(&pretimeout_lock); | ||
|
||
return count; | ||
} | ||
|
||
void watchdog_notify_pretimeout(struct watchdog_device *wdd) | ||
{ | ||
unsigned long flags; | ||
|
||
spin_lock_irqsave(&pretimeout_lock, flags); | ||
if (!wdd->gov) { | ||
spin_unlock_irqrestore(&pretimeout_lock, flags); | ||
return; | ||
} | ||
|
||
wdd->gov->pretimeout(wdd); | ||
spin_unlock_irqrestore(&pretimeout_lock, flags); | ||
} | ||
EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout); | ||
|
||
int watchdog_register_governor(struct watchdog_governor *gov) | ||
{ | ||
struct watchdog_pretimeout *p; | ||
|
||
if (!default_gov) { | ||
spin_lock_irq(&pretimeout_lock); | ||
default_gov = gov; | ||
|
||
list_for_each_entry(p, &pretimeout_list, entry) | ||
if (!p->wdd->gov) | ||
p->wdd->gov = default_gov; | ||
spin_unlock_irq(&pretimeout_lock); | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL(watchdog_register_governor); | ||
|
||
void watchdog_unregister_governor(struct watchdog_governor *gov) | ||
{ | ||
struct watchdog_pretimeout *p; | ||
|
||
spin_lock_irq(&pretimeout_lock); | ||
if (gov == default_gov) | ||
default_gov = NULL; | ||
|
||
list_for_each_entry(p, &pretimeout_list, entry) | ||
if (p->wdd->gov == gov) | ||
p->wdd->gov = default_gov; | ||
spin_unlock_irq(&pretimeout_lock); | ||
} | ||
EXPORT_SYMBOL(watchdog_unregister_governor); | ||
|
||
int watchdog_register_pretimeout(struct watchdog_device *wdd) | ||
{ | ||
struct watchdog_pretimeout *p; | ||
|
||
if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
return 0; | ||
|
||
p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
if (!p) | ||
return -ENOMEM; | ||
|
||
spin_lock_irq(&pretimeout_lock); | ||
list_add(&p->entry, &pretimeout_list); | ||
p->wdd = wdd; | ||
wdd->gov = default_gov; | ||
spin_unlock_irq(&pretimeout_lock); | ||
|
||
return 0; | ||
} | ||
|
||
void watchdog_unregister_pretimeout(struct watchdog_device *wdd) | ||
{ | ||
struct watchdog_pretimeout *p, *t; | ||
|
||
if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
return; | ||
|
||
spin_lock_irq(&pretimeout_lock); | ||
wdd->gov = NULL; | ||
|
||
list_for_each_entry_safe(p, t, &pretimeout_list, entry) { | ||
if (p->wdd == wdd) { | ||
list_del(&p->entry); | ||
break; | ||
} | ||
} | ||
spin_unlock_irq(&pretimeout_lock); | ||
|
||
kfree(p); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#ifndef __WATCHDOG_PRETIMEOUT_H | ||
#define __WATCHDOG_PRETIMEOUT_H | ||
|
||
#define WATCHDOG_GOV_NAME_MAXLEN 20 | ||
|
||
struct watchdog_device; | ||
|
||
struct watchdog_governor { | ||
const char name[WATCHDOG_GOV_NAME_MAXLEN]; | ||
void (*pretimeout)(struct watchdog_device *wdd); | ||
}; | ||
|
||
#if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV) | ||
/* Interfaces to watchdog pretimeout governors */ | ||
int watchdog_register_governor(struct watchdog_governor *gov); | ||
void watchdog_unregister_governor(struct watchdog_governor *gov); | ||
|
||
/* Interfaces to watchdog_dev.c */ | ||
int watchdog_register_pretimeout(struct watchdog_device *wdd); | ||
void watchdog_unregister_pretimeout(struct watchdog_device *wdd); | ||
int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf); | ||
|
||
#else | ||
static inline int watchdog_register_pretimeout(struct watchdog_device *wdd) | ||
{ | ||
return 0; | ||
} | ||
|
||
static inline void watchdog_unregister_pretimeout(struct watchdog_device *wdd) | ||
{ | ||
} | ||
|
||
static inline int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, | ||
char *buf) | ||
{ | ||
return -EINVAL; | ||
} | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters