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 start_path[256] = "/system/bin/start";
48 static char *envp[] = {
50 "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
53 static char *argv[] = {
59 printk(KERN_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",
86 dev_err(&svc->dev, "Resetting the greybus network, watch out!!!\n");
88 INIT_DELAYED_WORK(&reset_work, greybus_reset);
89 queue_delayed_work(system_wq, &reset_work, HZ/2);
92 * Disable ourselves, we don't want to trip again unless
93 * userspace wants us to.
95 watchdog->enabled = false;
98 /* resubmit our work to happen again, if we are still "alive" */
99 if (watchdog->enabled)
100 queue_delayed_work(system_wq, &watchdog->work,
101 SVC_WATCHDOG_PERIOD);
104 int gb_svc_watchdog_create(struct gb_svc *svc)
106 struct gb_svc_watchdog *watchdog;
112 watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL);
116 watchdog->enabled = false;
118 INIT_DELAYED_WORK(&watchdog->work, do_work);
119 svc->watchdog = watchdog;
121 watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier;
122 retval = register_pm_notifier(&watchdog->pm_notifier);
124 dev_err(&svc->dev, "error registering pm notifier(%d)\n",
126 goto svc_watchdog_create_err;
129 retval = gb_svc_watchdog_enable(svc);
131 dev_err(&svc->dev, "error enabling watchdog (%d)\n", retval);
132 unregister_pm_notifier(&watchdog->pm_notifier);
133 goto svc_watchdog_create_err;
137 svc_watchdog_create_err:
138 svc->watchdog = NULL;
144 void gb_svc_watchdog_destroy(struct gb_svc *svc)
146 struct gb_svc_watchdog *watchdog = svc->watchdog;
151 unregister_pm_notifier(&watchdog->pm_notifier);
152 gb_svc_watchdog_disable(svc);
153 svc->watchdog = NULL;
157 bool gb_svc_watchdog_enabled(struct gb_svc *svc)
159 if (!svc || !svc->watchdog)
161 return svc->watchdog->enabled;
164 int gb_svc_watchdog_enable(struct gb_svc *svc)
166 struct gb_svc_watchdog *watchdog;
171 watchdog = svc->watchdog;
172 if (watchdog->enabled)
175 watchdog->enabled = true;
176 queue_delayed_work(system_wq, &watchdog->work,
177 SVC_WATCHDOG_PERIOD);
181 int gb_svc_watchdog_disable(struct gb_svc *svc)
183 struct gb_svc_watchdog *watchdog;
188 watchdog = svc->watchdog;
189 if (!watchdog->enabled)
192 watchdog->enabled = false;
193 cancel_delayed_work_sync(&watchdog->work);