xref: /openbsd/sys/dev/pci/mbg.c (revision 3cab2bb3)
1 /*	$OpenBSD: mbg.c,v 1.30 2017/09/08 05:36:52 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/kernel.h>
22 #include <sys/timeout.h>
23 #include <sys/systm.h>
24 #include <sys/sensors.h>
25 #include <sys/syslog.h>
26 #include <sys/time.h>
27 
28 #include <machine/bus.h>
29 
30 #include <dev/pci/pcivar.h>
31 #include <dev/pci/pcireg.h>
32 #include <dev/pci/pcidevs.h>
33 
34 struct mbg_softc {
35 	struct device		sc_dev;
36 	bus_space_tag_t		sc_iot;
37 	bus_space_handle_t	sc_ioh;
38 
39 	/*
40 	 * I/O region used by the AMCC S5920 found on the PCI509 card
41 	 * used to access the data.
42 	 */
43 	bus_space_tag_t		sc_iot_s5920;
44 	bus_space_handle_t	sc_ioh_s5920;
45 
46 	struct ksensor		sc_timedelta;
47 	struct ksensor		sc_signal;
48 	struct ksensordev	sc_sensordev;
49 	struct timeout		sc_timeout;	/* invalidate sensor */
50 	int			sc_trust;	/* trust time in seconds */
51 
52 	int			(*sc_read)(struct mbg_softc *, int cmd,
53 				    char *buf, size_t len,
54 				    struct timespec *tstamp);
55 };
56 
57 struct mbg_time {
58 	u_int8_t		hundreds;
59 	u_int8_t		sec;
60 	u_int8_t		min;
61 	u_int8_t		hour;
62 	u_int8_t		mday;
63 	u_int8_t		wday;	/* 1 (monday) - 7 (sunday) */
64 	u_int8_t		mon;
65 	u_int8_t		year;	/* 0 - 99 */
66 	u_int8_t		status;
67 	u_int8_t		signal;
68 	int8_t			utc_off;
69 };
70 
71 struct mbg_time_hr {
72 	u_int32_t		sec;		/* always UTC */
73 	u_int32_t		frac;		/* fractions of second */
74 	int32_t			utc_off;	/* informal only, in seconds */
75 	u_int16_t		status;
76 	u_int8_t		signal;
77 };
78 
79 /* mbg_time.status bits */
80 #define MBG_FREERUN		0x01	/* clock running on xtal */
81 #define MBG_DST_ENA		0x02	/* DST enabled */
82 #define MBG_SYNC		0x04	/* clock synced at least once */
83 #define MBG_DST_CHG		0x08	/* DST change announcement */
84 #define MBG_UTC			0x10	/* special UTC firmware is installed */
85 #define MBG_LEAP		0x20	/* announcement of a leap second */
86 #define MBG_IFTM		0x40	/* current time was set from host */
87 #define MBG_INVALID		0x80	/* time invalid, batt. was disconn. */
88 
89 /* AMCC S5920 registers */
90 #define AMCC_DATA		0x00	/* data register, on 2nd IO region */
91 #define AMCC_OMB		0x0c	/* outgoing mailbox */
92 #define AMCC_IMB		0x1c	/* incoming mailbox */
93 
94 /* AMCC S5933 registers */
95 #define AMCC_OMB1		0x00	/* outgoing mailbox 1 */
96 #define AMCC_IMB4		0x1c	/* incoming mailbox 4 */
97 #define AMCC_FIFO		0x20	/* FIFO register */
98 #define AMCC_INTCSR		0x38	/* interrupt control/status register */
99 #define AMCC_MCSR		0x3c	/* master control/status register */
100 
101 /* ASIC registers */
102 #define ASIC_CFG		0x00
103 #define ASIC_FEATURES		0x08	/* r/o */
104 #define ASIC_STATUS		0x10
105 #define ASIC_CTLSTATUS		0x14
106 #define ASIC_DATA		0x18
107 #define ASIC_RES1		0x1c
108 #define ASIC_ADDON		0x20
109 
110 /* commands */
111 #define MBG_GET_TIME		0x00
112 #define MBG_GET_SYNC_TIME	0x02
113 #define MBG_GET_TIME_HR		0x03
114 #define MBG_SET_TIME		0x10
115 #define MBG_GET_TZCODE		0x32
116 #define MBG_SET_TZCODE		0x33
117 #define MBG_GET_FW_ID_1		0x40
118 #define MBG_GET_FW_ID_2		0x41
119 #define MBG_GET_SERNUM		0x42
120 
121 /* timezone codes (for MBG_{GET|SET}_TZCODE) */
122 #define MBG_TZCODE_CET_CEST	0x00
123 #define MBG_TZCODE_CET		0x01
124 #define MBG_TZCODE_UTC		0x02
125 #define MBG_TZCODE_EET_EEST	0x03
126 
127 /* misc. constants */
128 #define MBG_FIFO_LEN		16
129 #define MBG_ID_LEN		(2 * MBG_FIFO_LEN + 1)
130 #define MBG_BUSY		0x01
131 #define MBG_SIG_BIAS		55
132 #define MBG_SIG_MAX		68
133 #define NSECPERSEC		1000000000LL	/* nanoseconds per second */
134 #define HRDIVISOR		0x100000000LL	/* for hi-res timestamp */
135 
136 int	mbg_probe(struct device *, void *, void *);
137 void	mbg_attach(struct device *, struct device *, void *);
138 void	mbg_task(void *);
139 void	mbg_task_hr(void *);
140 void	mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp,
141 	    int64_t timedelta, u_int8_t rsignal, u_int16_t status);
142 int	mbg_read_amcc_s5920(struct mbg_softc *, int cmd, char *buf, size_t len,
143 	    struct timespec *tstamp);
144 int	mbg_read_amcc_s5933(struct mbg_softc *, int cmd, char *buf, size_t len,
145 	    struct timespec *tstamp);
146 int	mbg_read_asic(struct mbg_softc *, int cmd, char *buf, size_t len,
147 	    struct timespec *tstamp);
148 void	mbg_timeout(void *);
149 
150 struct cfattach mbg_ca = {
151 	sizeof(struct mbg_softc), mbg_probe, mbg_attach
152 };
153 
154 struct cfdriver mbg_cd = {
155 	NULL, "mbg", DV_DULL
156 };
157 
158 const struct pci_matchid mbg_devices[] = {
159 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_GPS170PCI },
160 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 },
161 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI509 },
162 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 },
163 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PEX511 }
164 };
165 
166 int
167 mbg_probe(struct device *parent, void *match, void *aux)
168 {
169 	return pci_matchbyid((struct pci_attach_args *)aux, mbg_devices,
170 	    nitems(mbg_devices));
171 }
172 
173 void
174 mbg_attach(struct device *parent, struct device *self, void *aux)
175 {
176 	struct mbg_softc *sc = (struct mbg_softc *)self;
177 	struct pci_attach_args *const pa = (struct pci_attach_args *)aux;
178 	struct mbg_time tframe;
179 	pcireg_t memtype;
180 	bus_size_t iosize, iosize2;
181 	int bar = PCI_MAPREG_START, signal, t_trust;
182 	const char *desc;
183 #ifdef MBG_DEBUG
184 	char fw_id[MBG_ID_LEN];
185 #endif
186 
187 	timeout_set(&sc->sc_timeout, mbg_timeout, sc);
188 
189 	/* for the PEX511 use BAR2 instead of BAR0*/
190 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MEINBERG_PEX511)
191 		bar += 0x08;
192 
193 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar);
194 	if (pci_mapreg_map(pa, bar, memtype, 0, &sc->sc_iot,
195 	    &sc->sc_ioh, NULL, &iosize, 0)) {
196 		printf(": PCI %s region not found\n",
197 		    memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
198 		return;
199 	}
200 
201 	if ((desc = pci_findproduct(pa->pa_id)) == NULL)
202 		desc = "Radio clock";
203 	strlcpy(sc->sc_timedelta.desc, desc, sizeof(sc->sc_timedelta.desc));
204 
205 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
206 	    sizeof(sc->sc_sensordev.xname));
207 
208 	sc->sc_timedelta.type = SENSOR_TIMEDELTA;
209 	sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
210 	sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
211 
212 	sc->sc_signal.type = SENSOR_PERCENT;
213 	sc->sc_signal.status = SENSOR_S_UNKNOWN;
214 	strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc));
215 	sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
216 
217 	t_trust = 12 * 60 * 60;		/* twelve hours */
218 
219 	switch (PCI_PRODUCT(pa->pa_id)) {
220 	case PCI_PRODUCT_MEINBERG_PCI32:
221 		sc->sc_read = mbg_read_amcc_s5933;
222 		sensor_task_register(sc, mbg_task, 10);
223 		break;
224 	case PCI_PRODUCT_MEINBERG_PCI509:
225 		/*
226 		 * map the second I/O region needed in addition to the first
227 		 * to get at the actual data.
228 		 */
229 		memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
230 		    PCI_MAPREG_START + 0x04);
231 		if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, memtype, 0,
232 		    &sc->sc_iot_s5920, &sc->sc_ioh_s5920, NULL, &iosize2, 0)) {
233 			printf(": PCI2 %s region not found\n",
234 			    memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
235 
236 			/* unmap first mapped region as well if we fail */
237 			bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
238 			return;
239 		}
240 		sc->sc_read = mbg_read_amcc_s5920;
241 		sensor_task_register(sc, mbg_task, 10);
242 		break;
243 	case PCI_PRODUCT_MEINBERG_PCI511:
244 	case PCI_PRODUCT_MEINBERG_PEX511:
245 		sc->sc_read = mbg_read_asic;
246 		sensor_task_register(sc, mbg_task, 10);
247 		break;
248 	case PCI_PRODUCT_MEINBERG_GPS170PCI:
249 		t_trust = 4 * 24 * 60 * 60;	/* four days */
250 		sc->sc_read = mbg_read_asic;
251 		sensor_task_register(sc, mbg_task_hr, 1);
252 		break;
253 	default:
254 		/* this can not normally happen, but then there is murphy */
255 		panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id));
256 		break;
257 	}
258 
259 	sc->sc_trust = t_trust;
260 
261 	if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe,
262 	    sizeof(struct mbg_time), NULL)) {
263 		printf(": unknown status");
264 		sc->sc_signal.status = SENSOR_S_CRIT;
265 	} else {
266 		sc->sc_signal.status = SENSOR_S_OK;
267 		signal = tframe.signal - MBG_SIG_BIAS;
268 		if (signal < 0)
269 			signal = 0;
270 		else if (signal > MBG_SIG_MAX)
271 			signal = MBG_SIG_MAX;
272 		sc->sc_signal.value = signal;
273 
274 		if (tframe.status & MBG_SYNC)
275 			printf(": synchronized");
276 		else
277 			printf(": not synchronized");
278 		if (tframe.status & MBG_FREERUN) {
279 			sc->sc_signal.status = SENSOR_S_WARN;
280 			printf(", free running");
281 		}
282 		if (tframe.status & MBG_IFTM)
283 			printf(", time set from host");
284 	}
285 #ifdef MBG_DEBUG
286 	if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
287 	    sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
288 	    NULL))
289 		printf(", firmware unknown");
290 	else {
291 		fw_id[MBG_ID_LEN - 1] = '\0';
292 		printf(", firmware %s", fw_id);
293 	}
294 #endif
295 	printf("\n");
296 	sensordev_install(&sc->sc_sensordev);
297 	timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
298 }
299 
300 /*
301  * mbg_task() reads a timestamp from cards that to not provide a high
302  * resolution timestamp.  The precision is limited to 1/100 sec.
303  */
304 void
305 mbg_task(void *arg)
306 {
307 	struct mbg_softc *sc = (struct mbg_softc *)arg;
308 	struct mbg_time tframe;
309 	struct clock_ymdhms ymdhms;
310 	struct timespec tstamp;
311 	int64_t timedelta;
312 	time_t trecv;
313 
314 	if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe),
315 	    &tstamp)) {
316 		sc->sc_signal.status = SENSOR_S_CRIT;
317 		return;
318 	}
319 	if (tframe.status & MBG_INVALID) {
320 		sc->sc_signal.status = SENSOR_S_CRIT;
321 		return;
322 	}
323 	ymdhms.dt_year = tframe.year + 2000;
324 	ymdhms.dt_mon = tframe.mon;
325 	ymdhms.dt_day = tframe.mday;
326 	ymdhms.dt_hour = tframe.hour;
327 	ymdhms.dt_min = tframe.min;
328 	ymdhms.dt_sec = tframe.sec;
329 	trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600;
330 
331 	timedelta = (int64_t)((tstamp.tv_sec - trecv) * 100
332 	    - tframe.hundreds) * 10000000LL + tstamp.tv_nsec;
333 
334 	mbg_update_sensor(sc, &tstamp, timedelta, tframe.signal,
335 	    (u_int16_t)tframe.status);
336 }
337 
338 /*
339  * mbg_task_hr() reads a timestamp from cards that do provide a high
340  * resolution timestamp.
341  */
342 void
343 mbg_task_hr(void *arg)
344 {
345 	struct mbg_softc *sc = (struct mbg_softc *)arg;
346 	struct mbg_time_hr tframe;
347 	struct timespec tstamp;
348 	int64_t tlocal, trecv;
349 
350 	if (sc->sc_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe),
351 	    &tstamp)) {
352 		sc->sc_signal.status = SENSOR_S_CRIT;
353 		return;
354 	}
355 	if (tframe.status & MBG_INVALID) {
356 		sc->sc_signal.status = SENSOR_S_CRIT;
357 		return;
358 	}
359 
360 	tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec;
361 	trecv = letoh32(tframe.sec) * NSECPERSEC +
362 	    (letoh32(tframe.frac) * NSECPERSEC >> 32);
363 
364 	mbg_update_sensor(sc, &tstamp, tlocal - trecv, tframe.signal,
365 	    letoh16(tframe.status));
366 }
367 
368 /* update the sensor value, common to all cards */
369 void
370 mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp,
371     int64_t timedelta, u_int8_t rsignal, u_int16_t status)
372 {
373 	int signal;
374 
375 	sc->sc_timedelta.value = timedelta;
376 	sc->sc_timedelta.tv.tv_sec = tstamp->tv_sec;
377 	sc->sc_timedelta.tv.tv_usec = tstamp->tv_nsec / 1000;
378 
379 	signal = rsignal - MBG_SIG_BIAS;
380 	if (signal < 0)
381 		signal = 0;
382 	else if (signal > MBG_SIG_MAX)
383 		signal = MBG_SIG_MAX;
384 
385 	sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
386 	sc->sc_signal.status = status & MBG_FREERUN ?
387 	    SENSOR_S_WARN : SENSOR_S_OK;
388 	sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
389 	sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
390 	if (!(status & MBG_FREERUN)) {
391 		sc->sc_timedelta.status = SENSOR_S_OK;
392 		timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
393 	}
394 }
395 
396 /*
397  * send a command and read back results to an AMCC S5920 based card
398  * (e.g. the PCI509 DCF77 radio clock)
399  */
400 int
401 mbg_read_amcc_s5920(struct mbg_softc *sc, int cmd, char *buf, size_t len,
402     struct timespec *tstamp)
403 {
404 	long timer, tmax;
405 	size_t quot, rem;
406 	u_int32_t ul;
407 	int n;
408 	u_int8_t status;
409 
410 	quot = len / 4;
411 	rem = len % 4;
412 
413 	/* write the command, optionally taking a timestamp */
414 	if (tstamp)
415 		nanotime(tstamp);
416 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB, cmd);
417 
418 	/* wait for the BUSY flag to go low (approx 70 us on i386) */
419 	timer = 0;
420 	tmax = cold ? 50 : hz / 10;
421 	do {
422 		if (cold)
423 			delay(20);
424 		else
425 			tsleep(tstamp, 0, "mbg", 1);
426 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
427 		    AMCC_IMB4 + 3);
428 	} while ((status & MBG_BUSY) && timer++ < tmax);
429 
430 	if (status & MBG_BUSY)
431 		return -1;
432 
433 	/* read data from the device */
434 	if (len) {
435 		for (n = 0; n < quot; n++) {
436 			*(u_int32_t *)buf = bus_space_read_4(sc->sc_iot_s5920,
437 			    sc->sc_ioh_s5920, AMCC_DATA);
438 			buf += sizeof(u_int32_t);
439 		}
440 		if (rem) {
441 			ul =  bus_space_read_4(sc->sc_iot_s5920,
442 			    sc->sc_ioh_s5920, AMCC_DATA);
443 			for (n = 0; n < rem; n++)
444 				*buf++ = *((char *)&ul + n);
445 		}
446 	} else
447 		bus_space_read_4(sc->sc_iot_s5920, sc->sc_ioh_s5920, AMCC_DATA);
448 	return 0;
449 }
450 
451 /*
452  * send a command and read back results to an AMCC S5933 based card
453  * (e.g. the PCI32 DCF77 radio clock)
454  */
455 int
456 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len,
457     struct timespec *tstamp)
458 {
459 	long timer, tmax;
460 	size_t n;
461 	u_int8_t status;
462 
463 	/* reset inbound mailbox and clear FIFO status */
464 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c);
465 
466 	/* set FIFO */
467 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c);
468 
469 	/* write the command, optionally taking a timestamp */
470 	if (tstamp)
471 		nanotime(tstamp);
472 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd);
473 
474 	/* wait for the BUSY flag to go low (approx 70 us on i386) */
475 	timer = 0;
476 	tmax = cold ? 50 : hz / 10;
477 	do {
478 		if (cold)
479 			delay(20);
480 		else
481 			tsleep(tstamp, 0, "mbg", 1);
482 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
483 		    AMCC_IMB4 + 3);
484 	} while ((status & MBG_BUSY) && timer++ < tmax);
485 
486 	if (status & MBG_BUSY)
487 		return -1;
488 
489 	/* read data from the device FIFO */
490 	for (n = 0; n < len; n++) {
491 		if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR)
492 		    & 0x20) {
493 			return -1;
494 		}
495 		buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
496 		    AMCC_FIFO + (n % 4));
497 	}
498 	return 0;
499 }
500 
501 /*
502  * send a command and read back results to an ASIC based card
503  * (e.g. the PCI511 DCF77 radio clock)
504  */
505 int
506 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len,
507     struct timespec *tstamp)
508 {
509 	long timer, tmax;
510 	size_t n;
511 	u_int32_t data;
512 	u_int16_t port;
513 	char *p = buf;
514 	u_int8_t status;
515 	int s;
516 
517 	/* write the command, optionally taking a timestamp */
518 	if (tstamp) {
519 		s = splhigh();
520 		nanotime(tstamp);
521 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
522 		splx(s);
523 	} else
524 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
525 
526 	/* wait for the BUSY flag to go low */
527 	timer = 0;
528 	tmax = cold ? 50 : hz / 10;
529 	do {
530 		if (cold)
531 			delay(20);
532 		else
533 			tsleep(tstamp, 0, "mbg", 1);
534 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS);
535 	} while ((status & MBG_BUSY) && timer++ < tmax);
536 
537 	if (status & MBG_BUSY)
538 		return -1;
539 
540 	/* read data from the device FIFO */
541 	port = ASIC_ADDON;
542 	for (n = 0; n < len / 4; n++) {
543 		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
544 		*(u_int32_t *)p = data;
545 		p += sizeof(data);
546 		port += sizeof(data);
547 	}
548 
549 	if (len % 4) {
550 		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
551 		for (n = 0; n < len % 4; n++) {
552 			*p++ = data & 0xff;
553 			data >>= 8;
554 		}
555 	}
556 	return 0;
557 }
558 
559 /*
560  * degrade the sensor state if we are feerunning for more than
561  * sc->sc_trust seconds.
562  */
563 void
564 mbg_timeout(void *xsc)
565 {
566 	struct mbg_softc *sc = xsc;
567 
568 	if (sc->sc_timedelta.status == SENSOR_S_OK) {
569 		sc->sc_timedelta.status = SENSOR_S_WARN;
570 		/*
571 		 * further degrade in sc->sc_trust seconds if no new valid
572 		 * time data can be read from the device.
573 		 */
574 		timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
575 	} else
576 		sc->sc_timedelta.status = SENSOR_S_CRIT;
577 }
578