| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: swwdog.c,v 1.10 2010/07/22 14:10:15 pgoyette Exp $ */ | | 1 | /* $NetBSD: swwdog.c,v 1.11 2010/08/06 16:02:56 pooka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2004, 2005 Steven M. Bellovin | | 4 | * Copyright (c) 2004, 2005 Steven M. Bellovin |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -23,27 +23,27 @@ | | | @@ -23,27 +23,27 @@ |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS | | 25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | * POSSIBILITY OF SUCH DAMAGE. | | 32 | * POSSIBILITY OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1.10 2010/07/22 14:10:15 pgoyette Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1.11 2010/08/06 16:02:56 pooka Exp $"); |
37 | | | 37 | |
38 | /* | | 38 | /* |
39 | * | | 39 | * |
40 | * Software watchdog timer | | 40 | * Software watchdog timer |
41 | * | | 41 | * |
42 | */ | | 42 | */ |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/callout.h> | | 44 | #include <sys/callout.h> |
45 | #include <sys/device.h> | | 45 | #include <sys/device.h> |
46 | #include <sys/kernel.h> | | 46 | #include <sys/kernel.h> |
47 | #include <sys/kmem.h> | | 47 | #include <sys/kmem.h> |
48 | #include <sys/reboot.h> | | 48 | #include <sys/reboot.h> |
49 | #include <sys/systm.h> | | 49 | #include <sys/systm.h> |
| @@ -72,26 +72,29 @@ static int swwdog_tickle(struct sysmon_w | | | @@ -72,26 +72,29 @@ static int swwdog_tickle(struct sysmon_w |
72 | | | 72 | |
73 | static int swwdog_arm(struct swwdog_softc *); | | 73 | static int swwdog_arm(struct swwdog_softc *); |
74 | static int swwdog_disarm(struct swwdog_softc *); | | 74 | static int swwdog_disarm(struct swwdog_softc *); |
75 | | | 75 | |
76 | static void swwdog_panic(void *); | | 76 | static void swwdog_panic(void *); |
77 | | | 77 | |
78 | bool swwdog_reboot = false; /* set for panic instead of reboot */ | | 78 | bool swwdog_reboot = false; /* set for panic instead of reboot */ |
79 | | | 79 | |
80 | #define SWDOG_DEFAULT 60 /* 60-second default period */ | | 80 | #define SWDOG_DEFAULT 60 /* 60-second default period */ |
81 | | | 81 | |
82 | CFATTACH_DECL_NEW(swwdog, sizeof(struct swwdog_softc), | | 82 | CFATTACH_DECL_NEW(swwdog, sizeof(struct swwdog_softc), |
83 | swwdog_match, swwdog_attach, swwdog_detach, NULL); | | 83 | swwdog_match, swwdog_attach, swwdog_detach, NULL); |
84 | | | 84 | |
| | | 85 | static void swwdog_sysctl_setup(void); |
| | | 86 | static struct sysctllog *swwdog_sysctllog; |
| | | 87 | |
85 | void | | 88 | void |
86 | swwdogattach(int n __unused) | | 89 | swwdogattach(int n __unused) |
87 | { | | 90 | { |
88 | int err; | | 91 | int err; |
89 | static struct cfdata cf; | | 92 | static struct cfdata cf; |
90 | | | 93 | |
91 | err = config_cfattach_attach(swwdog_cd.cd_name, &swwdog_ca); | | 94 | err = config_cfattach_attach(swwdog_cd.cd_name, &swwdog_ca); |
92 | if (err) { | | 95 | if (err) { |
93 | aprint_error("%s: couldn't register cfattach: %d\n", | | 96 | aprint_error("%s: couldn't register cfattach: %d\n", |
94 | swwdog_cd.cd_name, err); | | 97 | swwdog_cd.cd_name, err); |
95 | config_cfdriver_detach(&swwdog_cd); | | 98 | config_cfdriver_detach(&swwdog_cd); |
96 | return; | | 99 | return; |
97 | } | | 100 | } |
| @@ -124,35 +127,38 @@ swwdog_attach(device_t parent, device_t | | | @@ -124,35 +127,38 @@ swwdog_attach(device_t parent, device_t |
124 | sc->sc_smw.smw_tickle = swwdog_tickle; | | 127 | sc->sc_smw.smw_tickle = swwdog_tickle; |
125 | sc->sc_smw.smw_period = SWDOG_DEFAULT; | | 128 | sc->sc_smw.smw_period = SWDOG_DEFAULT; |
126 | callout_init(&sc->sc_c, 0); | | 129 | callout_init(&sc->sc_c, 0); |
127 | callout_setfunc(&sc->sc_c, swwdog_panic, sc); | | 130 | callout_setfunc(&sc->sc_c, swwdog_panic, sc); |
128 | | | 131 | |
129 | if (sysmon_wdog_register(&sc->sc_smw) == 0) | | 132 | if (sysmon_wdog_register(&sc->sc_smw) == 0) |
130 | aprint_normal_dev(self, "software watchdog initialized\n"); | | 133 | aprint_normal_dev(self, "software watchdog initialized\n"); |
131 | else | | 134 | else |
132 | aprint_error_dev(self, "unable to register software " | | 135 | aprint_error_dev(self, "unable to register software " |
133 | "watchdog with sysmon\n"); | | 136 | "watchdog with sysmon\n"); |
134 | | | 137 | |
135 | if (!pmf_device_register(self, swwdog_suspend, NULL)) | | 138 | if (!pmf_device_register(self, swwdog_suspend, NULL)) |
136 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 139 | aprint_error_dev(self, "couldn't establish power handler\n"); |
| | | 140 | |
| | | 141 | swwdog_sysctl_setup(); |
137 | } | | 142 | } |
138 | | | 143 | |
139 | static int | | 144 | static int |
140 | swwdog_detach(device_t self, int flags) | | 145 | swwdog_detach(device_t self, int flags) |
141 | { | | 146 | { |
142 | struct swwdog_softc *sc = device_private(self); | | 147 | struct swwdog_softc *sc = device_private(self); |
143 | | | 148 | |
144 | swwdog_disarm(sc); | | 149 | swwdog_disarm(sc); |
145 | callout_destroy(&sc->sc_c); | | 150 | callout_destroy(&sc->sc_c); |
| | | 151 | sysctl_teardown(&swwdog_sysctllog); |
146 | | | 152 | |
147 | return 1; | | 153 | return 1; |
148 | } | | 154 | } |
149 | | | 155 | |
150 | static bool | | 156 | static bool |
151 | swwdog_suspend(device_t dev, const pmf_qual_t *qual) | | 157 | swwdog_suspend(device_t dev, const pmf_qual_t *qual) |
152 | { | | 158 | { |
153 | struct swwdog_softc *sc = device_private(dev); | | 159 | struct swwdog_softc *sc = device_private(dev); |
154 | | | 160 | |
155 | /* Don't allow suspend if watchdog is armed */ | | 161 | /* Don't allow suspend if watchdog is armed */ |
156 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED) | | 162 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED) |
157 | return false; | | 163 | return false; |
158 | return true; | | 164 | return true; |
| @@ -197,48 +203,42 @@ static int | | | @@ -197,48 +203,42 @@ static int |
197 | swwdog_disarm(struct swwdog_softc *sc) | | 203 | swwdog_disarm(struct swwdog_softc *sc) |
198 | { | | 204 | { |
199 | | | 205 | |
200 | callout_stop(&sc->sc_c); | | 206 | callout_stop(&sc->sc_c); |
201 | return 0; | | 207 | return 0; |
202 | } | | 208 | } |
203 | | | 209 | |
204 | static void | | 210 | static void |
205 | swwdog_panic(void *vsc) | | 211 | swwdog_panic(void *vsc) |
206 | { | | 212 | { |
207 | struct swwdog_softc *sc = vsc; | | 213 | struct swwdog_softc *sc = vsc; |
208 | bool do_panic; | | 214 | bool do_panic; |
209 | | | 215 | |
210 | do_panic = swwdog_reboot; | | 216 | do_panic = !swwdog_reboot; |
211 | swwdog_reboot = 1; | | 217 | swwdog_reboot = false; |
212 | callout_schedule(&sc->sc_c, 60 * hz); /* deliberate double-panic */ | | 218 | callout_schedule(&sc->sc_c, 60 * hz); /* deliberate double-panic */ |
213 | | | 219 | |
214 | printf("%s: %d second timer expired\n", device_xname(sc->sc_dev), | | 220 | printf("%s: %d second timer expired\n", device_xname(sc->sc_dev), |
215 | sc->sc_smw.smw_period); | | 221 | sc->sc_smw.smw_period); |
216 | | | 222 | |
217 | if (do_panic) | | 223 | if (do_panic) |
218 | panic("watchdog timer expired"); | | 224 | panic("watchdog timer expired"); |
219 | else | | 225 | else |
220 | cpu_reboot(0, NULL); | | 226 | cpu_reboot(0, NULL); |
221 | } | | 227 | } |
222 | | | 228 | |
223 | SYSCTL_SETUP(sysctl_swwdog, "swwdog subtree setup") | | 229 | static void |
| | | 230 | swwdog_sysctl_setup(void) |
224 | { | | 231 | { |
225 | int err; | | | |
226 | const struct sysctlnode *me; | | 232 | const struct sysctlnode *me; |
227 | | | 233 | |
228 | err = sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT, | | 234 | KASSERT(swwdog_sysctllog == NULL); |
229 | CTLTYPE_NODE, "machdep", NULL, | | | |
230 | NULL, 0, NULL, 0, | | | |
231 | CTL_HW, CTL_EOL); | | | |
232 | | | 235 | |
233 | if (err == 0) | | 236 | sysctl_createv(&swwdog_sysctllog, 0, NULL, &me, CTLFLAG_READWRITE, |
234 | err = sysctl_createv(NULL, 0, NULL, &me, CTLFLAG_READWRITE, | | 237 | CTLTYPE_NODE, "swwdog", NULL, |
235 | CTLTYPE_NODE, "swwdog", NULL, | | 238 | NULL, 0, NULL, 0, |
236 | NULL, 0, NULL, 0, | | 239 | CTL_HW, CTL_CREATE, CTL_EOL); |
237 | CTL_HW, CTL_CREATE, CTL_EOL); | | 240 | sysctl_createv(&swwdog_sysctllog, 0, NULL, NULL, CTLFLAG_READWRITE, |
238 | | | 241 | CTLTYPE_BOOL, "reboot", "reboot if timer expires", |
239 | if (err == 0) | | 242 | NULL, 0, &swwdog_reboot, sizeof(bool), |
240 | err = sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE, | | 243 | CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); |
241 | CTLTYPE_BOOL, "reboot", "reboot if timer expires", | | | |
242 | NULL, 0, &swwdog_reboot, sizeof(bool), | | | |
243 | CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); | | | |
244 | } | | 244 | } |