|
|
@@ -89,6 +89,7 @@ static struct device *watchdog_device = NULL;
|
|
|
|
|
|
/* Watchdog state: 0 = OFF, 1 = ON */
|
|
|
static int watchdog_state = 0;
|
|
|
+static int watchdog_running = 0;
|
|
|
static DEFINE_MUTEX(watchdog_mutex);
|
|
|
|
|
|
/* Software timer for servicing watchdog */
|
|
|
@@ -197,11 +198,16 @@ static int wdt_round_time(int t)
|
|
|
/* Software timer callback - service the watchdog */
|
|
|
static void watchdog_timer_callback(struct timer_list *t)
|
|
|
{
|
|
|
- /* Re-trigger the hardware watchdog by writing timeout again */
|
|
|
- wdt_update_timeout(timeout);
|
|
|
+ watchdog_running++;
|
|
|
+ if(watchdog_running >= (timeout/2))
|
|
|
+ {
|
|
|
+ /* Re-trigger the hardware watchdog by writing timeout again */
|
|
|
+ wdt_update_timeout(timeout);
|
|
|
+ watchdog_running = 0;
|
|
|
+ }
|
|
|
|
|
|
/* Restart timer (periodic servicing, e.g., every half timeout) */
|
|
|
- mod_timer(&watchdog_timer, jiffies + (timeout * HZ / 2));
|
|
|
+ mod_timer(&watchdog_timer, jiffies + HZ);
|
|
|
}
|
|
|
|
|
|
/* Enable watchdog - start hardware and software timer */
|
|
|
@@ -219,7 +225,7 @@ static int watchdog_enable(void)
|
|
|
|
|
|
/* Start periodic software timer to service watchdog */
|
|
|
timer_setup(&watchdog_timer, watchdog_timer_callback, 0);
|
|
|
- mod_timer(&watchdog_timer, jiffies + (timeout * HZ / 2));
|
|
|
+ mod_timer(&watchdog_timer, jiffies + HZ);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -231,11 +237,13 @@ static int watchdog_disable(void)
|
|
|
|
|
|
/* Stop and delete software timer */
|
|
|
del_timer_sync(&watchdog_timer);
|
|
|
+ watchdog_running = 0;
|
|
|
|
|
|
/* Disable hardware watchdog by setting timeout to 0 */
|
|
|
return wdt_update_timeout(0);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/* Parse user command: supports "ON", "OFF", "1", "0" */
|
|
|
static int parse_watchdog_command(const char *buf, size_t count)
|
|
|
{
|
|
|
@@ -389,7 +397,7 @@ static char *my_devnode(struct device *dev, umode_t *mode) {
|
|
|
static ssize_t watchdog_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
char *buf)
|
|
|
{
|
|
|
- return 0;
|
|
|
+ return sprintf(buf, "%d\n", watchdog_state);
|
|
|
}
|
|
|
|
|
|
static ssize_t watchdog_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
@@ -442,10 +450,50 @@ static ssize_t watchdog_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d\n", watchdog_state);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t timeleft_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ if(watchdog_state == 1)
|
|
|
+ {
|
|
|
+ return sprintf(buf, "%d\n", timeout - watchdog_running);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return sprintf(buf, "%d\n", 0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t timeleft_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static struct kobj_attribute state_attr =
|
|
|
+ __ATTR(state, 0444, state_show, state_store);
|
|
|
+
|
|
|
+static struct kobj_attribute timeleft_attr =
|
|
|
+ __ATTR(timeleft, 0444, timeleft_show, timeleft_store);
|
|
|
+
|
|
|
static struct kobj_attribute watchdog_attr =
|
|
|
__ATTR(watchdog, 0644, watchdog_show, watchdog_store);
|
|
|
|
|
|
static struct attribute *watchdog_attrs[] = {
|
|
|
+ &state_attr.attr,
|
|
|
+ &timeleft_attr.attr,
|
|
|
&watchdog_attr.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
@@ -454,14 +502,25 @@ static struct attribute_group watchdog_attr_group = {
|
|
|
.attrs = watchdog_attrs,
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+static struct kobject *watchdog_kobj;
|
|
|
+
|
|
|
int watchdog_init(void)
|
|
|
{
|
|
|
u8 chip_rev;
|
|
|
int rc;
|
|
|
|
|
|
- rc = sysfs_create_group(vfiec_kobj, &watchdog_attr_group);
|
|
|
+ watchdog_kobj = kobject_create_and_add("watchdog", vfiec_kobj);
|
|
|
+ if (!watchdog_kobj)
|
|
|
+ {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = sysfs_create_group(watchdog_kobj, &watchdog_attr_group);
|
|
|
if (rc)
|
|
|
{
|
|
|
+ kobject_put(watchdog_kobj);
|
|
|
pr_err("Faiec_version to create sysfs group: %d\n", rc);
|
|
|
return -1;
|
|
|
}
|
|
|
@@ -585,7 +644,8 @@ void watchdog_exit(void)
|
|
|
|
|
|
/* Delete timer */
|
|
|
del_timer_sync(&watchdog_timer);
|
|
|
- sysfs_remove_group(vfiec_kobj, &watchdog_attr_group);
|
|
|
+ sysfs_remove_group(watchdog_kobj, &watchdog_attr_group);
|
|
|
+ kobject_put(watchdog_kobj);
|
|
|
|
|
|
/* Remove device */
|
|
|
device_destroy(watchdog_class, MKDEV(major_number, 0));
|