xref: /openbsd/sys/dev/pci/mbg.c (revision aed994fe)
1 /*	$OpenBSD: mbg.c,v 1.36 2024/03/23 10:38:02 sthen 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 const 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_PCI510 },
163 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 },
164 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PEX511 },
165 	{ PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PZF180PEX }
166 };
167 
168 int
mbg_probe(struct device * parent,void * match,void * aux)169 mbg_probe(struct device *parent, void *match, void *aux)
170 {
171 	return pci_matchbyid((struct pci_attach_args *)aux, mbg_devices,
172 	    nitems(mbg_devices));
173 }
174 
175 void
mbg_attach(struct device * parent,struct device * self,void * aux)176 mbg_attach(struct device *parent, struct device *self, void *aux)
177 {
178 	struct mbg_softc *sc = (struct mbg_softc *)self;
179 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
180 	struct mbg_time tframe;
181 	pcireg_t memtype;
182 	bus_size_t iosize, iosize2;
183 	int bar = PCI_MAPREG_START, signal, t_trust;
184 	const char *desc;
185 #ifdef MBG_DEBUG
186 	char fw_id[MBG_ID_LEN];
187 #endif
188 
189 	timeout_set(&sc->sc_timeout, mbg_timeout, sc);
190 
191 	/* for the PEX511 use BAR2 instead of BAR0*/
192 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MEINBERG_PEX511)
193 		bar += 0x08;
194 
195 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar);
196 	if (pci_mapreg_map(pa, bar, memtype, 0, &sc->sc_iot,
197 	    &sc->sc_ioh, NULL, &iosize, 0)) {
198 		printf(": PCI %s region not found\n",
199 		    memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
200 		return;
201 	}
202 
203 	if ((desc = pci_findproduct(pa->pa_id)) == NULL)
204 		desc = "Radio clock";
205 	strlcpy(sc->sc_timedelta.desc, desc, sizeof(sc->sc_timedelta.desc));
206 
207 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
208 	    sizeof(sc->sc_sensordev.xname));
209 
210 	sc->sc_timedelta.type = SENSOR_TIMEDELTA;
211 	sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
212 	sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
213 
214 	sc->sc_signal.type = SENSOR_PERCENT;
215 	sc->sc_signal.status = SENSOR_S_UNKNOWN;
216 	strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc));
217 	sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
218 
219 	t_trust = 12 * 60 * 60;		/* twelve hours */
220 
221 	switch (PCI_PRODUCT(pa->pa_id)) {
222 	case PCI_PRODUCT_MEINBERG_PCI32:
223 		sc->sc_read = mbg_read_amcc_s5933;
224 		sensor_task_register(sc, mbg_task, 10);
225 		break;
226 	case PCI_PRODUCT_MEINBERG_PCI509:
227 		/*
228 		 * map the second I/O region needed in addition to the first
229 		 * to get at the actual data.
230 		 */
231 		memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
232 		    PCI_MAPREG_START + 0x04);
233 		if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, memtype, 0,
234 		    &sc->sc_iot_s5920, &sc->sc_ioh_s5920, NULL, &iosize2, 0)) {
235 			printf(": PCI2 %s region not found\n",
236 			    memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
237 
238 			/* unmap first mapped region as well if we fail */
239 			bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
240 			return;
241 		}
242 		sc->sc_read = mbg_read_amcc_s5920;
243 		sensor_task_register(sc, mbg_task, 10);
244 		break;
245 	case PCI_PRODUCT_MEINBERG_PCI510:
246 	case PCI_PRODUCT_MEINBERG_PCI511:
247 	case PCI_PRODUCT_MEINBERG_PEX511:
248 		sc->sc_read = mbg_read_asic;
249 		sensor_task_register(sc, mbg_task, 10);
250 		break;
251 	case PCI_PRODUCT_MEINBERG_GPS170PCI:
252 	case PCI_PRODUCT_MEINBERG_PZF180PEX:
253 		t_trust = 4 * 24 * 60 * 60;	/* four days */
254 		sc->sc_read = mbg_read_asic;
255 		sensor_task_register(sc, mbg_task_hr, 1);
256 		break;
257 	default:
258 		/* this can not normally happen, but then there is murphy */
259 		panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id));
260 		break;
261 	}
262 
263 	sc->sc_trust = t_trust;
264 
265 	if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe,
266 	    sizeof(struct mbg_time), NULL)) {
267 		printf(": unknown status");
268 		sc->sc_signal.status = SENSOR_S_CRIT;
269 	} else {
270 		sc->sc_signal.status = SENSOR_S_OK;
271 		signal = tframe.signal - MBG_SIG_BIAS;
272 		if (signal < 0)
273 			signal = 0;
274 		else if (signal > MBG_SIG_MAX)
275 			signal = MBG_SIG_MAX;
276 		sc->sc_signal.value = signal;
277 
278 		if (tframe.status & MBG_SYNC)
279 			printf(": synchronized");
280 		else
281 			printf(": not synchronized");
282 		if (tframe.status & MBG_FREERUN) {
283 			sc->sc_signal.status = SENSOR_S_WARN;
284 			printf(", free running");
285 		}
286 		if (tframe.status & MBG_IFTM)
287 			printf(", time set from host");
288 	}
289 #ifdef MBG_DEBUG
290 	if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
291 	    sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
292 	    NULL))
293 		printf(", firmware unknown");
294 	else {
295 		fw_id[MBG_ID_LEN - 1] = '\0';
296 		printf(", firmware %s", fw_id);
297 	}
298 #endif
299 	printf("\n");
300 	sensordev_install(&sc->sc_sensordev);
301 	timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
302 }
303 
304 /*
305  * mbg_task() reads a timestamp from cards that to not provide a high
306  * resolution timestamp.  The precision is limited to 1/100 sec.
307  */
308 void
mbg_task(void * arg)309 mbg_task(void *arg)
310 {
311 	struct mbg_softc *sc = (struct mbg_softc *)arg;
312 	struct mbg_time tframe;
313 	struct clock_ymdhms ymdhms;
314 	struct timespec tstamp;
315 	int64_t timedelta;
316 	time_t trecv;
317 
318 	if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe),
319 	    &tstamp)) {
320 		sc->sc_signal.status = SENSOR_S_CRIT;
321 		return;
322 	}
323 	if (tframe.status & MBG_INVALID) {
324 		sc->sc_signal.status = SENSOR_S_CRIT;
325 		return;
326 	}
327 	ymdhms.dt_year = tframe.year + 2000;
328 	ymdhms.dt_mon = tframe.mon;
329 	ymdhms.dt_day = tframe.mday;
330 	ymdhms.dt_hour = tframe.hour;
331 	ymdhms.dt_min = tframe.min;
332 	ymdhms.dt_sec = tframe.sec;
333 	trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600;
334 
335 	timedelta = (int64_t)((tstamp.tv_sec - trecv) * 100
336 	    - tframe.hundreds) * 10000000LL + tstamp.tv_nsec;
337 
338 	mbg_update_sensor(sc, &tstamp, timedelta, tframe.signal,
339 	    (u_int16_t)tframe.status);
340 }
341 
342 /*
343  * mbg_task_hr() reads a timestamp from cards that do provide a high
344  * resolution timestamp.
345  */
346 void
mbg_task_hr(void * arg)347 mbg_task_hr(void *arg)
348 {
349 	struct mbg_softc *sc = (struct mbg_softc *)arg;
350 	struct mbg_time_hr tframe;
351 	struct timespec tstamp;
352 	int64_t tlocal, trecv;
353 
354 	if (sc->sc_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe),
355 	    &tstamp)) {
356 		sc->sc_signal.status = SENSOR_S_CRIT;
357 		return;
358 	}
359 	if (tframe.status & MBG_INVALID) {
360 		sc->sc_signal.status = SENSOR_S_CRIT;
361 		return;
362 	}
363 
364 	tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec;
365 	trecv = letoh32(tframe.sec) * NSECPERSEC +
366 	    (letoh32(tframe.frac) * NSECPERSEC >> 32);
367 
368 	mbg_update_sensor(sc, &tstamp, tlocal - trecv, tframe.signal,
369 	    letoh16(tframe.status));
370 }
371 
372 /* update the sensor value, common to all cards */
373 void
mbg_update_sensor(struct mbg_softc * sc,struct timespec * tstamp,int64_t timedelta,u_int8_t rsignal,u_int16_t status)374 mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp,
375     int64_t timedelta, u_int8_t rsignal, u_int16_t status)
376 {
377 	int signal;
378 
379 	sc->sc_timedelta.value = timedelta;
380 	sc->sc_timedelta.tv.tv_sec = tstamp->tv_sec;
381 	sc->sc_timedelta.tv.tv_usec = tstamp->tv_nsec / 1000;
382 
383 	signal = rsignal - MBG_SIG_BIAS;
384 	if (signal < 0)
385 		signal = 0;
386 	else if (signal > MBG_SIG_MAX)
387 		signal = MBG_SIG_MAX;
388 
389 	sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
390 	sc->sc_signal.status = status & MBG_FREERUN ?
391 	    SENSOR_S_WARN : SENSOR_S_OK;
392 	sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
393 	sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
394 	if (!(status & MBG_FREERUN)) {
395 		sc->sc_timedelta.status = SENSOR_S_OK;
396 		timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
397 	}
398 }
399 
400 /*
401  * send a command and read back results to an AMCC S5920 based card
402  * (e.g. the PCI509 DCF77 radio clock)
403  */
404 int
mbg_read_amcc_s5920(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)405 mbg_read_amcc_s5920(struct mbg_softc *sc, int cmd, char *buf, size_t len,
406     struct timespec *tstamp)
407 {
408 	long timer, tmax;
409 	size_t quot, rem;
410 	u_int32_t ul;
411 	int n;
412 	u_int8_t status;
413 
414 	quot = len / 4;
415 	rem = len % 4;
416 
417 	/* write the command, optionally taking a timestamp */
418 	if (tstamp)
419 		nanotime(tstamp);
420 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB, cmd);
421 
422 	/* wait for the BUSY flag to go low (approx 70 us on i386) */
423 	timer = 0;
424 	tmax = cold ? 50 : 10;
425 	do {
426 		if (cold)
427 			delay(20);
428 		else
429 			tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
430 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
431 		    AMCC_IMB4 + 3);
432 	} while ((status & MBG_BUSY) && timer++ < tmax);
433 
434 	if (status & MBG_BUSY)
435 		return -1;
436 
437 	/* read data from the device */
438 	if (len) {
439 		for (n = 0; n < quot; n++) {
440 			*(u_int32_t *)buf = bus_space_read_4(sc->sc_iot_s5920,
441 			    sc->sc_ioh_s5920, AMCC_DATA);
442 			buf += sizeof(u_int32_t);
443 		}
444 		if (rem) {
445 			ul =  bus_space_read_4(sc->sc_iot_s5920,
446 			    sc->sc_ioh_s5920, AMCC_DATA);
447 			for (n = 0; n < rem; n++)
448 				*buf++ = *((char *)&ul + n);
449 		}
450 	} else
451 		bus_space_read_4(sc->sc_iot_s5920, sc->sc_ioh_s5920, AMCC_DATA);
452 	return 0;
453 }
454 
455 /*
456  * send a command and read back results to an AMCC S5933 based card
457  * (e.g. the PCI32 DCF77 radio clock)
458  */
459 int
mbg_read_amcc_s5933(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)460 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len,
461     struct timespec *tstamp)
462 {
463 	long timer, tmax;
464 	size_t n;
465 	u_int8_t status;
466 
467 	/* reset inbound mailbox and clear FIFO status */
468 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c);
469 
470 	/* set FIFO */
471 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c);
472 
473 	/* write the command, optionally taking a timestamp */
474 	if (tstamp)
475 		nanotime(tstamp);
476 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd);
477 
478 	/* wait for the BUSY flag to go low (approx 70 us on i386) */
479 	timer = 0;
480 	tmax = cold ? 50 : 10;
481 	do {
482 		if (cold)
483 			delay(20);
484 		else
485 			tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
486 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
487 		    AMCC_IMB4 + 3);
488 	} while ((status & MBG_BUSY) && timer++ < tmax);
489 
490 	if (status & MBG_BUSY)
491 		return -1;
492 
493 	/* read data from the device FIFO */
494 	for (n = 0; n < len; n++) {
495 		if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR)
496 		    & 0x20) {
497 			return -1;
498 		}
499 		buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
500 		    AMCC_FIFO + (n % 4));
501 	}
502 	return 0;
503 }
504 
505 /*
506  * send a command and read back results to an ASIC based card
507  * (e.g. the PCI511 DCF77 radio clock)
508  */
509 int
mbg_read_asic(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)510 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len,
511     struct timespec *tstamp)
512 {
513 	long timer, tmax;
514 	size_t n;
515 	u_int32_t data;
516 	u_int16_t port;
517 	char *p = buf;
518 	u_int8_t status;
519 	int s;
520 
521 	/* write the command, optionally taking a timestamp */
522 	if (tstamp) {
523 		s = splhigh();
524 		nanotime(tstamp);
525 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
526 		splx(s);
527 	} else
528 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
529 
530 	/* wait for the BUSY flag to go low */
531 	timer = 0;
532 	tmax = cold ? 50 : 10;
533 	do {
534 		if (cold)
535 			delay(20);
536 		else
537 			tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
538 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS);
539 	} while ((status & MBG_BUSY) && timer++ < tmax);
540 
541 	if (status & MBG_BUSY)
542 		return -1;
543 
544 	/* read data from the device FIFO */
545 	port = ASIC_ADDON;
546 	for (n = 0; n < len / 4; n++) {
547 		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
548 		*(u_int32_t *)p = data;
549 		p += sizeof(data);
550 		port += sizeof(data);
551 	}
552 
553 	if (len % 4) {
554 		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
555 		for (n = 0; n < len % 4; n++) {
556 			*p++ = data & 0xff;
557 			data >>= 8;
558 		}
559 	}
560 	return 0;
561 }
562 
563 /*
564  * degrade the sensor state if we are freerunning for more than
565  * sc->sc_trust seconds.
566  */
567 void
mbg_timeout(void * xsc)568 mbg_timeout(void *xsc)
569 {
570 	struct mbg_softc *sc = xsc;
571 
572 	if (sc->sc_timedelta.status == SENSOR_S_OK) {
573 		sc->sc_timedelta.status = SENSOR_S_WARN;
574 		/*
575 		 * further degrade in sc->sc_trust seconds if no new valid
576 		 * time data can be read from the device.
577 		 */
578 		timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
579 	} else
580 		sc->sc_timedelta.status = SENSOR_S_CRIT;
581 }
582