1 // SPDX-License-Identifier: GPL-2.0
3 * SVC Greybus "watchdog" driver.
5 * Copyright 2016 Google Inc.
8 #include <linux/delay.h>
9 #include <linux/suspend.h>
10 #include <linux/workqueue.h>
11 #include <linux/greybus.h>
13 #define SVC_WATCHDOG_PERIOD (2 * HZ)
15 struct gb_svc_watchdog
{
16 struct delayed_work work
;
19 struct notifier_block pm_notifier
;
22 static struct delayed_work reset_work
;
24 static int svc_watchdog_pm_notifier(struct notifier_block
*notifier
,
25 unsigned long pm_event
, void *unused
)
27 struct gb_svc_watchdog
*watchdog
=
28 container_of(notifier
, struct gb_svc_watchdog
, pm_notifier
);
31 case PM_SUSPEND_PREPARE
:
32 gb_svc_watchdog_disable(watchdog
->svc
);
35 gb_svc_watchdog_enable(watchdog
->svc
);
44 static void greybus_reset(struct work_struct
*work
)
46 static char const start_path
[] = "/system/bin/start";
47 static char *envp
[] = {
49 "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
52 static char *argv
[] = {
58 pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
60 call_usermodehelper(start_path
, argv
, envp
, UMH_WAIT_EXEC
);
63 static void do_work(struct work_struct
*work
)
65 struct gb_svc_watchdog
*watchdog
;
69 watchdog
= container_of(work
, struct gb_svc_watchdog
, work
.work
);
72 dev_dbg(&svc
->dev
, "%s: ping.\n", __func__
);
73 retval
= gb_svc_ping(svc
);
76 * Something went really wrong, let's warn userspace and then
77 * pull the plug and reset the whole greybus network.
78 * We need to do this outside of this workqueue as we will be
79 * tearing down the svc device itself. So queue up
80 * yet-another-callback to do that.
83 "SVC ping has returned %d, something is wrong!!!\n",
86 if (svc
->action
== GB_SVC_WATCHDOG_BITE_PANIC_KERNEL
) {
87 panic("SVC is not responding\n");
88 } else if (svc
->action
== GB_SVC_WATCHDOG_BITE_RESET_UNIPRO
) {
89 dev_err(&svc
->dev
, "Resetting the greybus network, watch out!!!\n");
91 INIT_DELAYED_WORK(&reset_work
, greybus_reset
);
92 schedule_delayed_work(&reset_work
, HZ
/ 2);
95 * Disable ourselves, we don't want to trip again unless
96 * userspace wants us to.
98 watchdog
->enabled
= false;
102 /* resubmit our work to happen again, if we are still "alive" */
103 if (watchdog
->enabled
)
104 schedule_delayed_work(&watchdog
->work
, SVC_WATCHDOG_PERIOD
);
107 int gb_svc_watchdog_create(struct gb_svc
*svc
)
109 struct gb_svc_watchdog
*watchdog
;
115 watchdog
= kmalloc(sizeof(*watchdog
), GFP_KERNEL
);
119 watchdog
->enabled
= false;
121 INIT_DELAYED_WORK(&watchdog
->work
, do_work
);
122 svc
->watchdog
= watchdog
;
124 watchdog
->pm_notifier
.notifier_call
= svc_watchdog_pm_notifier
;
125 retval
= register_pm_notifier(&watchdog
->pm_notifier
);
127 dev_err(&svc
->dev
, "error registering pm notifier(%d)\n",
129 goto svc_watchdog_create_err
;
132 retval
= gb_svc_watchdog_enable(svc
);
134 dev_err(&svc
->dev
, "error enabling watchdog (%d)\n", retval
);
135 unregister_pm_notifier(&watchdog
->pm_notifier
);
136 goto svc_watchdog_create_err
;
140 svc_watchdog_create_err
:
141 svc
->watchdog
= NULL
;
147 void gb_svc_watchdog_destroy(struct gb_svc
*svc
)
149 struct gb_svc_watchdog
*watchdog
= svc
->watchdog
;
154 unregister_pm_notifier(&watchdog
->pm_notifier
);
155 gb_svc_watchdog_disable(svc
);
156 svc
->watchdog
= NULL
;
160 bool gb_svc_watchdog_enabled(struct gb_svc
*svc
)
162 if (!svc
|| !svc
->watchdog
)
164 return svc
->watchdog
->enabled
;
167 int gb_svc_watchdog_enable(struct gb_svc
*svc
)
169 struct gb_svc_watchdog
*watchdog
;
174 watchdog
= svc
->watchdog
;
175 if (watchdog
->enabled
)
178 watchdog
->enabled
= true;
179 schedule_delayed_work(&watchdog
->work
, SVC_WATCHDOG_PERIOD
);
183 int gb_svc_watchdog_disable(struct gb_svc
*svc
)
185 struct gb_svc_watchdog
*watchdog
;
190 watchdog
= svc
->watchdog
;
191 if (!watchdog
->enabled
)
194 watchdog
->enabled
= false;
195 cancel_delayed_work_sync(&watchdog
->work
);