comparison vordog.c @ 6:76ce6e6624b8

Make vordog compatible with watchdog(9).
author Thinker K.F. Li <thinker@branda.to>
date Tue, 08 Jul 2008 14:41:47 +0800
parents e59963b503cb
children 5a281ce7453c
comparison
equal deleted inserted replaced
5:e59963b503cb 6:76ce6e6624b8
31 #include <sys/systm.h> 31 #include <sys/systm.h>
32 #include <sys/proc.h> 32 #include <sys/proc.h>
33 #include <sys/ioccom.h> 33 #include <sys/ioccom.h>
34 #include <sys/types.h> 34 #include <sys/types.h>
35 #include <sys/malloc.h> 35 #include <sys/malloc.h>
36 #include <sys/watchdog.h>
36 #include "vordog.h" 37 #include "vordog.h"
37 38
38 #if 0 39 #if 0
39 #undef __FreeBSD_version 40 #undef __FreeBSD_version
40 #define __FreeBSD_version 800029 41 #define __FreeBSD_version 800029
41 #endif 42 #endif
42 43
43 #define VD_STATUS 0x841 44 #define VD_STATUS 0x841
44 #define VD_INITVAL 0x84a 45 #define VD_INITVAL 0x84a
45 #define VD_CTR 0x84b 46 #define VD_CTR 0x84b
47 /* trigger PCIRST */
48 #define VD_TIMER_RST 0xc
46 49
47 typedef struct vd_softc { 50 typedef struct vd_softc {
48 struct cdev *_cdev; 51 struct cdev *_cdev;
49 device_t dev; 52 device_t dev;
50 int open_cnt; 53 int open_cnt;
51 int init_val; 54 u_int init_val;
55 eventhandler_tag wd9_tag;
52 } *vd_softc_t; 56 } *vd_softc_t;
53 57
54 #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) 58 #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1)
55 59
56 static int 60 static int
96 } 100 }
97 101
98 static void 102 static void
99 setup_timer(vordog_cfg_t cfg) { 103 setup_timer(vordog_cfg_t cfg) {
100 int val; 104 int val;
101 #define VD_TIMER_RST 0xc
102 105
103 val = cfg->init_val & 0xff; 106 val = cfg->init_val & 0xff;
104 outb(VD_INITVAL, val); 107 outb(VD_INITVAL, val);
105 val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST; 108 val = 0x80 | ((cfg->unit & 0x3) << 4) | VD_TIMER_RST;
106 outb(VD_CTR, val); 109 outb(VD_CTR, val);
107 } 110 }
108 111
109 static void 112 static void
110 reset_timer(int init_val) { 113 reset_timer(void) {
111 outb(VD_STATUS, 0xc0); 114 outb(VD_STATUS, 0xc0);
112 } 115 }
113 116
114 static void 117 static void
115 disable_timer(void) { 118 disable_timer(void) {
121 vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 124 vordog_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
122 int fflag, struct thread *td) { 125 int fflag, struct thread *td) {
123 int r = 0; 126 int r = 0;
124 vd_softc_t sc; 127 vd_softc_t sc;
125 vordog_cfg_t cfg; 128 vordog_cfg_t cfg;
129 static const u_int unit_factors[] = {0, 1, 60, 360};
126 130
127 sc = CDEV_2_SOFTC(dev); 131 sc = CDEV_2_SOFTC(dev);
128 switch(cmd) { 132 switch(cmd) {
129 case VDCTL_ENABLE: 133 case VDCTL_ENABLE:
130 cfg = (vordog_cfg_t)data; 134 cfg = (vordog_cfg_t)data;
131 sc->init_val = cfg->init_val & 0xff; 135 sc->init_val = (cfg->init_val & 0xff) * unit_factors[cfg->unit];
132 setup_timer(cfg); 136 setup_timer(cfg);
133 break; 137 break;
134 case VDCTL_RESET: 138 case VDCTL_RESET:
135 reset_timer(sc->init_val); 139 reset_timer();
136 break; 140 break;
137 case VDCTL_DISABLE: 141 case VDCTL_DISABLE:
138 disable_timer(); 142 disable_timer();
139 break; 143 break;
140 default: 144 default:
148 .d_open = vordog_open, 152 .d_open = vordog_open,
149 .d_close = vordog_close, 153 .d_close = vordog_close,
150 .d_ioctl = vordog_ioctl, 154 .d_ioctl = vordog_ioctl,
151 .d_name = "vordog", 155 .d_name = "vordog",
152 }; 156 };
157
158 /* Implements watchdog(9) compatible driver. */
159 static int
160 vordog_wd9_init(int timeout) {
161 int val;
162
163 if(timeout < 0 || timeout > 255)
164 return EINVAL;
165
166 outb(VD_INITVAL, timeout & 0xff);
167 val = 0x80 | (VDT_1S << 4) | VD_TIMER_RST;
168 outb(VD_CTR, val);
169 return 0;
170 }
171
172 static void
173 vordog_wd9_reset(void) {
174 outb(VD_STATUS, 0xc0);
175 }
176
177 static void
178 vordog_wd9_disable(void) {
179 outb(VD_CTR, 0);
180 outb(VD_STATUS, 0xc0);
181 }
182
183 static void
184 vordog_wd9_evh(void *private, u_int cmd, int *error) {
185 vd_softc_t sc;
186 u_int timeout, u;
187 static const int timeouts[] = { 1, 2, 3, 5, 9, 18, 35, 69, 138};
188
189 sc = (vd_softc_t)private;
190
191 u = cmd & WD_INTERVAL;
192 if(u < 31 || u > 39) {
193 vordog_wd9_disable();
194 sc->init_val = 0;
195 return;
196 }
197
198 timeout = timeouts[u - 31];
199 if(timeout != sc->init_val) {
200 vordog_wd9_init(timeout);
201 sc->init_val = timeout;
202 } else {
203 vordog_wd9_reset();
204 }
205 }
206
207 static void
208 vordog_wd9_register(vd_softc_t sc) {
209 sc->wd9_tag = \
210 EVENTHANDLER_REGISTER(watchdog_list, vordog_wd9_evh, sc, 0);
211 }
212
213 static void
214 vordog_wd9_unregister(vd_softc_t sc) {
215 EVENTHANDLER_DEREGISTER(watchdog_list, sc->wd9_tag);
216 }
217
153 218
154 /* Following implements a new bus device. 219 /* Following implements a new bus device.
155 * It is attached under nexus bus, an on board device as `vordog0'. 220 * It is attached under nexus bus, an on board device as `vordog0'.
156 */ 221 */
157 222
200 device_set_softc(dev, sc); 265 device_set_softc(dev, sc);
201 CDEV_2_SOFTC(_cdev) = sc; 266 CDEV_2_SOFTC(_cdev) = sc;
202 267
203 sc->open_cnt = 0; 268 sc->open_cnt = 0;
204 sc->init_val = 0; 269 sc->init_val = 0;
270 sc->wd9_tag = NULL;
205 271
206 device_set_desc(dev, "Watchdog of Vortex86 SoC"); 272 device_set_desc(dev, "Watchdog of Vortex86 SoC");
207 device_printf(dev, "<Vortex86 SoC watchdog> at port 0x%x\n", VD_STATUS); 273 device_printf(dev, "<Vortex86 SoC watchdog> at port 0x%x\n", VD_STATUS);
274
275 vordog_wd9_register(sc);
208 276
209 return 0; 277 return 0;
210 } 278 }
211 279
212 static int vordog_detach(device_t dev) { 280 static int vordog_detach(device_t dev) {
215 283
216 sc = device_get_softc(dev); 284 sc = device_get_softc(dev);
217 if(sc->open_cnt != 0) 285 if(sc->open_cnt != 0)
218 return EBUSY; 286 return EBUSY;
219 287
288 disable_timer();
289
290 vordog_wd9_unregister(sc);
291
220 _cdev = sc->_cdev; 292 _cdev = sc->_cdev;
221 293
222 destroy_dev(_cdev); 294 destroy_dev(_cdev);
223 295
224 free(sc, M_TEMP); 296 free(sc, M_TEMP);