Blame view
drivers/greybus/svc_watchdog.c
4.37 KB
eb50fd3a2 staging: greybus:... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
ed7279ae3 greybus: svc: add... |
2 3 4 5 |
/* * SVC Greybus "watchdog" driver. * * Copyright 2016 Google Inc. |
ed7279ae3 greybus: svc: add... |
6 7 8 |
*/ #include <linux/delay.h> |
192c70dcf greybus: svc watc... |
9 |
#include <linux/suspend.h> |
ed7279ae3 greybus: svc: add... |
10 |
#include <linux/workqueue.h> |
ec0ad8681 staging: greybus:... |
11 |
#include <linux/greybus.h> |
ed7279ae3 greybus: svc: add... |
12 |
|
28cf20352 staging: greybus:... |
13 |
#define SVC_WATCHDOG_PERIOD (2 * HZ) |
ed7279ae3 greybus: svc: add... |
14 15 16 17 |
struct gb_svc_watchdog { struct delayed_work work; struct gb_svc *svc; |
d562853d3 greybus: svc watc... |
18 |
bool enabled; |
192c70dcf greybus: svc watc... |
19 |
struct notifier_block pm_notifier; |
ed7279ae3 greybus: svc: add... |
20 21 22 |
}; static struct delayed_work reset_work; |
192c70dcf greybus: svc watc... |
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
static int svc_watchdog_pm_notifier(struct notifier_block *notifier, unsigned long pm_event, void *unused) { struct gb_svc_watchdog *watchdog = container_of(notifier, struct gb_svc_watchdog, pm_notifier); switch (pm_event) { case PM_SUSPEND_PREPARE: gb_svc_watchdog_disable(watchdog->svc); break; case PM_POST_SUSPEND: gb_svc_watchdog_enable(watchdog->svc); break; default: break; } return NOTIFY_DONE; } |
ed7279ae3 greybus: svc: add... |
42 43 |
static void greybus_reset(struct work_struct *work) { |
377e7a27c Make static userm... |
44 |
static char const start_path[] = "/system/bin/start"; |
ed7279ae3 greybus: svc: add... |
45 46 47 48 49 50 |
static char *envp[] = { "HOME=/", "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin", NULL, }; static char *argv[] = { |
377e7a27c Make static userm... |
51 |
(char *)start_path, |
ed7279ae3 greybus: svc: add... |
52 53 54 |
"unipro_reset", NULL, }; |
62730c957 staging: greybus:... |
55 56 |
pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network! ", |
ed7279ae3 greybus: svc: add... |
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
argv[0], argv[1]); call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC); } static void do_work(struct work_struct *work) { struct gb_svc_watchdog *watchdog; struct gb_svc *svc; int retval; watchdog = container_of(work, struct gb_svc_watchdog, work.work); svc = watchdog->svc; dev_dbg(&svc->dev, "%s: ping. ", __func__); retval = gb_svc_ping(svc); if (retval) { /* * Something went really wrong, let's warn userspace and then * pull the plug and reset the whole greybus network. * We need to do this outside of this workqueue as we will be * tearing down the svc device itself. So queue up * yet-another-callback to do that. */ dev_err(&svc->dev, "SVC ping has returned %d, something is wrong!!! ", retval); |
ed7279ae3 greybus: svc: add... |
85 |
|
7c4a0edb3 greybus: svc_watc... |
86 87 88 89 90 91 |
if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL) { panic("SVC is not responding "); } else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO) { dev_err(&svc->dev, "Resetting the greybus network, watch out!!! "); |
d562853d3 greybus: svc watc... |
92 |
|
7c4a0edb3 greybus: svc_watc... |
93 |
INIT_DELAYED_WORK(&reset_work, greybus_reset); |
b6fc2876a greybus: svc_watc... |
94 |
schedule_delayed_work(&reset_work, HZ / 2); |
7c4a0edb3 greybus: svc_watc... |
95 96 97 98 99 100 101 |
/* * Disable ourselves, we don't want to trip again unless * userspace wants us to. */ watchdog->enabled = false; } |
ed7279ae3 greybus: svc: add... |
102 103 104 |
} /* resubmit our work to happen again, if we are still "alive" */ |
d562853d3 greybus: svc watc... |
105 |
if (watchdog->enabled) |
b6fc2876a greybus: svc_watc... |
106 |
schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD); |
ed7279ae3 greybus: svc: add... |
107 108 109 110 111 |
} int gb_svc_watchdog_create(struct gb_svc *svc) { struct gb_svc_watchdog *watchdog; |
192c70dcf greybus: svc watc... |
112 |
int retval; |
ed7279ae3 greybus: svc: add... |
113 114 115 116 117 118 119 |
if (svc->watchdog) return 0; watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL); if (!watchdog) return -ENOMEM; |
d562853d3 greybus: svc watc... |
120 |
watchdog->enabled = false; |
ed7279ae3 greybus: svc: add... |
121 122 123 |
watchdog->svc = svc; INIT_DELAYED_WORK(&watchdog->work, do_work); svc->watchdog = watchdog; |
192c70dcf greybus: svc watc... |
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier; retval = register_pm_notifier(&watchdog->pm_notifier); if (retval) { dev_err(&svc->dev, "error registering pm notifier(%d) ", retval); goto svc_watchdog_create_err; } retval = gb_svc_watchdog_enable(svc); if (retval) { dev_err(&svc->dev, "error enabling watchdog (%d) ", retval); unregister_pm_notifier(&watchdog->pm_notifier); goto svc_watchdog_create_err; } return retval; svc_watchdog_create_err: svc->watchdog = NULL; kfree(watchdog); return retval; |
ed7279ae3 greybus: svc: add... |
147 148 149 150 151 152 153 154 |
} void gb_svc_watchdog_destroy(struct gb_svc *svc) { struct gb_svc_watchdog *watchdog = svc->watchdog; if (!watchdog) return; |
192c70dcf greybus: svc watc... |
155 |
unregister_pm_notifier(&watchdog->pm_notifier); |
d562853d3 greybus: svc watc... |
156 |
gb_svc_watchdog_disable(svc); |
ed7279ae3 greybus: svc: add... |
157 158 159 |
svc->watchdog = NULL; kfree(watchdog); } |
d562853d3 greybus: svc watc... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
bool gb_svc_watchdog_enabled(struct gb_svc *svc) { if (!svc || !svc->watchdog) return false; return svc->watchdog->enabled; } int gb_svc_watchdog_enable(struct gb_svc *svc) { struct gb_svc_watchdog *watchdog; if (!svc->watchdog) return -ENODEV; watchdog = svc->watchdog; if (watchdog->enabled) return 0; watchdog->enabled = true; |
b6fc2876a greybus: svc_watc... |
180 |
schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD); |
d562853d3 greybus: svc watc... |
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
return 0; } int gb_svc_watchdog_disable(struct gb_svc *svc) { struct gb_svc_watchdog *watchdog; if (!svc->watchdog) return -ENODEV; watchdog = svc->watchdog; if (!watchdog->enabled) return 0; watchdog->enabled = false; cancel_delayed_work_sync(&watchdog->work); return 0; } |