0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/suspend.h>
0010 #include <linux/workqueue.h>
0011 #include <linux/greybus.h>
0012
0013 #define SVC_WATCHDOG_PERIOD (2 * HZ)
0014
0015 struct gb_svc_watchdog {
0016 struct delayed_work work;
0017 struct gb_svc *svc;
0018 bool enabled;
0019 struct notifier_block pm_notifier;
0020 };
0021
0022 static struct delayed_work reset_work;
0023
0024 static int svc_watchdog_pm_notifier(struct notifier_block *notifier,
0025 unsigned long pm_event, void *unused)
0026 {
0027 struct gb_svc_watchdog *watchdog =
0028 container_of(notifier, struct gb_svc_watchdog, pm_notifier);
0029
0030 switch (pm_event) {
0031 case PM_SUSPEND_PREPARE:
0032 gb_svc_watchdog_disable(watchdog->svc);
0033 break;
0034 case PM_POST_SUSPEND:
0035 gb_svc_watchdog_enable(watchdog->svc);
0036 break;
0037 default:
0038 break;
0039 }
0040
0041 return NOTIFY_DONE;
0042 }
0043
0044 static void greybus_reset(struct work_struct *work)
0045 {
0046 static char const start_path[] = "/system/bin/start";
0047 static char *envp[] = {
0048 "HOME=/",
0049 "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
0050 NULL,
0051 };
0052 static char *argv[] = {
0053 (char *)start_path,
0054 "unipro_reset",
0055 NULL,
0056 };
0057
0058 pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
0059 argv[0], argv[1]);
0060 call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC);
0061 }
0062
0063 static void do_work(struct work_struct *work)
0064 {
0065 struct gb_svc_watchdog *watchdog;
0066 struct gb_svc *svc;
0067 int retval;
0068
0069 watchdog = container_of(work, struct gb_svc_watchdog, work.work);
0070 svc = watchdog->svc;
0071
0072 dev_dbg(&svc->dev, "%s: ping.\n", __func__);
0073 retval = gb_svc_ping(svc);
0074 if (retval) {
0075
0076
0077
0078
0079
0080
0081
0082 dev_err(&svc->dev,
0083 "SVC ping has returned %d, something is wrong!!!\n",
0084 retval);
0085
0086 if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL) {
0087 panic("SVC is not responding\n");
0088 } else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO) {
0089 dev_err(&svc->dev, "Resetting the greybus network, watch out!!!\n");
0090
0091 INIT_DELAYED_WORK(&reset_work, greybus_reset);
0092 schedule_delayed_work(&reset_work, HZ / 2);
0093
0094
0095
0096
0097
0098 watchdog->enabled = false;
0099 }
0100 }
0101
0102
0103 if (watchdog->enabled)
0104 schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
0105 }
0106
0107 int gb_svc_watchdog_create(struct gb_svc *svc)
0108 {
0109 struct gb_svc_watchdog *watchdog;
0110 int retval;
0111
0112 if (svc->watchdog)
0113 return 0;
0114
0115 watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL);
0116 if (!watchdog)
0117 return -ENOMEM;
0118
0119 watchdog->enabled = false;
0120 watchdog->svc = svc;
0121 INIT_DELAYED_WORK(&watchdog->work, do_work);
0122 svc->watchdog = watchdog;
0123
0124 watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier;
0125 retval = register_pm_notifier(&watchdog->pm_notifier);
0126 if (retval) {
0127 dev_err(&svc->dev, "error registering pm notifier(%d)\n",
0128 retval);
0129 goto svc_watchdog_create_err;
0130 }
0131
0132 retval = gb_svc_watchdog_enable(svc);
0133 if (retval) {
0134 dev_err(&svc->dev, "error enabling watchdog (%d)\n", retval);
0135 unregister_pm_notifier(&watchdog->pm_notifier);
0136 goto svc_watchdog_create_err;
0137 }
0138 return retval;
0139
0140 svc_watchdog_create_err:
0141 svc->watchdog = NULL;
0142 kfree(watchdog);
0143
0144 return retval;
0145 }
0146
0147 void gb_svc_watchdog_destroy(struct gb_svc *svc)
0148 {
0149 struct gb_svc_watchdog *watchdog = svc->watchdog;
0150
0151 if (!watchdog)
0152 return;
0153
0154 unregister_pm_notifier(&watchdog->pm_notifier);
0155 gb_svc_watchdog_disable(svc);
0156 svc->watchdog = NULL;
0157 kfree(watchdog);
0158 }
0159
0160 bool gb_svc_watchdog_enabled(struct gb_svc *svc)
0161 {
0162 if (!svc || !svc->watchdog)
0163 return false;
0164 return svc->watchdog->enabled;
0165 }
0166
0167 int gb_svc_watchdog_enable(struct gb_svc *svc)
0168 {
0169 struct gb_svc_watchdog *watchdog;
0170
0171 if (!svc->watchdog)
0172 return -ENODEV;
0173
0174 watchdog = svc->watchdog;
0175 if (watchdog->enabled)
0176 return 0;
0177
0178 watchdog->enabled = true;
0179 schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD);
0180 return 0;
0181 }
0182
0183 int gb_svc_watchdog_disable(struct gb_svc *svc)
0184 {
0185 struct gb_svc_watchdog *watchdog;
0186
0187 if (!svc->watchdog)
0188 return -ENODEV;
0189
0190 watchdog = svc->watchdog;
0191 if (!watchdog->enabled)
0192 return 0;
0193
0194 watchdog->enabled = false;
0195 cancel_delayed_work_sync(&watchdog->work);
0196 return 0;
0197 }