2 * SVC Greybus "watchdog" driver.
4 * Copyright 2016 Google Inc.
6 * Released under the GPLv2 only.
9 #include <linux/delay.h>
10 #include <linux/suspend.h>
11 #include <linux/workqueue.h>
14 #define SVC_WATCHDOG_PERIOD (2 * HZ)
16 struct gb_svc_watchdog
{
17 struct delayed_work work
;
20 struct notifier_block pm_notifier
;
23 static struct delayed_work reset_work
;
25 static int svc_watchdog_pm_notifier(struct notifier_block
*notifier
,
26 unsigned long pm_event
, void *unused
)
28 struct gb_svc_watchdog
*watchdog
=
29 container_of(notifier
, struct gb_svc_watchdog
, pm_notifier
);
32 case PM_SUSPEND_PREPARE
:
33 gb_svc_watchdog_disable(watchdog
->svc
);
36 gb_svc_watchdog_enable(watchdog
->svc
);
45 static void greybus_reset(struct work_struct
*work
)
47 static char const start_path
[] = "/system/bin/start";
48 static char *envp
[] = {
50 "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
53 static char *argv
[] = {
59 pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
61 call_usermodehelper(start_path
, argv
, envp
, UMH_WAIT_EXEC
);
64 static void do_work(struct work_struct
*work
)
66 struct gb_svc_watchdog
*watchdog
;
70 watchdog
= container_of(work
, struct gb_svc_watchdog
, work
.work
);
73 dev_dbg(&svc
->dev
, "%s: ping.\n", __func__
);
74 retval
= gb_svc_ping(svc
);
77 * Something went really wrong, let's warn userspace and then
78 * pull the plug and reset the whole greybus network.
79 * We need to do this outside of this workqueue as we will be
80 * tearing down the svc device itself. So queue up
81 * yet-another-callback to do that.
84 "SVC ping has returned %d, something is wrong!!!\n",
87 if (svc
->action
== GB_SVC_WATCHDOG_BITE_PANIC_KERNEL
) {
88 panic("SVC is not responding\n");
89 } else if (svc
->action
== GB_SVC_WATCHDOG_BITE_RESET_UNIPRO
) {
90 dev_err(&svc
->dev
, "Resetting the greybus network, watch out!!!\n");
92 INIT_DELAYED_WORK(&reset_work
, greybus_reset
);
93 schedule_delayed_work(&reset_work
, HZ
/ 2);
96 * Disable ourselves, we don't want to trip again unless
97 * userspace wants us to.
99 watchdog
->enabled
= false;
103 /* resubmit our work to happen again, if we are still "alive" */
104 if (watchdog
->enabled
)
105 schedule_delayed_work(&watchdog
->work
, SVC_WATCHDOG_PERIOD
);
108 int gb_svc_watchdog_create(struct gb_svc
*svc
)
110 struct gb_svc_watchdog
*watchdog
;
116 watchdog
= kmalloc(sizeof(*watchdog
), GFP_KERNEL
);
120 watchdog
->enabled
= false;
122 INIT_DELAYED_WORK(&watchdog
->work
, do_work
);
123 svc
->watchdog
= watchdog
;
125 watchdog
->pm_notifier
.notifier_call
= svc_watchdog_pm_notifier
;
126 retval
= register_pm_notifier(&watchdog
->pm_notifier
);
128 dev_err(&svc
->dev
, "error registering pm notifier(%d)\n",
130 goto svc_watchdog_create_err
;
133 retval
= gb_svc_watchdog_enable(svc
);
135 dev_err(&svc
->dev
, "error enabling watchdog (%d)\n", retval
);
136 unregister_pm_notifier(&watchdog
->pm_notifier
);
137 goto svc_watchdog_create_err
;
141 svc_watchdog_create_err
:
142 svc
->watchdog
= NULL
;
148 void gb_svc_watchdog_destroy(struct gb_svc
*svc
)
150 struct gb_svc_watchdog
*watchdog
= svc
->watchdog
;
155 unregister_pm_notifier(&watchdog
->pm_notifier
);
156 gb_svc_watchdog_disable(svc
);
157 svc
->watchdog
= NULL
;
161 bool gb_svc_watchdog_enabled(struct gb_svc
*svc
)
163 if (!svc
|| !svc
->watchdog
)
165 return svc
->watchdog
->enabled
;
168 int gb_svc_watchdog_enable(struct gb_svc
*svc
)
170 struct gb_svc_watchdog
*watchdog
;
175 watchdog
= svc
->watchdog
;
176 if (watchdog
->enabled
)
179 watchdog
->enabled
= true;
180 schedule_delayed_work(&watchdog
->work
, SVC_WATCHDOG_PERIOD
);
184 int gb_svc_watchdog_disable(struct gb_svc
*svc
)
186 struct gb_svc_watchdog
*watchdog
;
191 watchdog
= svc
->watchdog
;
192 if (!watchdog
->enabled
)
195 watchdog
->enabled
= false;
196 cancel_delayed_work_sync(&watchdog
->work
);