Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Aug 2006 19:54:06 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 103394 for review
Message-ID:  <200608071954.k77Js6aS057291@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=103394

Change 103394 by imp@imp_bugs on 2006/08/07 19:53:09

	
	implement actual watchdog device, when present.  This implementation
	stretches the spec a little to match the #defines in
	sys/watchdog.h.  I think this is acceptible given the size
	constraints of the kernel and how watchdogs are generally
	used.  Likely not a big deal either way...

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_st.c#12 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_st.c#12 (text+ko) ====

@@ -34,6 +34,7 @@
 #include <sys/resource.h>
 #include <sys/rman.h>
 #include <sys/timetc.h>
+#include <sys/watchdog.h>
 
 #include <machine/bus.h>
 #include <machine/cpu.h>
@@ -48,7 +49,8 @@
 static struct at91st_softc {
 	bus_space_tag_t		sc_st;
 	bus_space_handle_t	sc_sh;
-	device_t		dev;
+	device_t		sc_dev;
+	eventhandler_tag	sc_wet;	/* watchdog event handler tag */
 } *timer_softc;
 
 #define RD4(off) \
@@ -56,6 +58,8 @@
 #define WR4(off, val) \
 	bus_space_write_4(timer_softc->sc_st, timer_softc->sc_sh, (off), (val))
 
+static watchdog_fn at91st_watchdog;
+
 static inline int
 st_crtr(void)
 {
@@ -97,7 +101,7 @@
 
 	timer_softc = device_get_softc(dev);
 	timer_softc->sc_st = sc->sc_st;
-	timer_softc->dev = dev;
+	timer_softc->sc_dev = dev;
 	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_ST_BASE,
 	    AT91RM92_ST_SIZE, &timer_softc->sc_sh) != 0)
 		panic("couldn't subregion timer registers");
@@ -110,6 +114,11 @@
 	WR4(ST_IDR, 0xffffffff);
 	/* disable watchdog timer */
 	WR4(ST_WDMR, 0);
+
+	timer_softc->sc_wet = EVENTHANDLER_REGISTER(watchdog_list,
+	  at91st_watchdog, dev, 0);
+	device_printf(dev,
+	  "watchdog registered, timeout intervall max. 64 sec\n");
 	return (0);
 }
 
@@ -142,7 +151,34 @@
 #endif
 }
 
+/*
+ * t below is in a weird unit.  The watchdog is set to 2^t
+ * nanoseconds.  Since our watchdog timer can't really do that too
+ * well, we approximate it by assuming that the timeout interval for
+ * the lsb is 2^22 ns, which is 4.194ms.  This is an overestimation of
+ * the actual time (3.906ms), but close enough for watchdogging.
+ * These approximations, though a violation of the spec, improve the
+ * performance of the application which typically specifies things as
+ * WD_TO_32SEC.  In that last case, we'd wait 32s before the wdog
+ * reset.  The spec says we should wait closer to 34s, but given how
+ * it is likely to be used, and the extremely coarse nature time
+ * interval, I think this is the best solution.
+ */
 static void
+at91st_watchdog(void *argp, u_int cmd, int *error)
+{
+	uint32_t wdog;
+	int t;
+
+	wdog = 0;
+	t = cmd & WD_INTERVAL;
+	if (cmd != 0 && t >= 22 && t <= 37)
+		wdog = (1 << (t - 22)) | ST_WDMR_RSTEN;
+	WR4(ST_WDMR, wdog);
+	WR4(ST_CR, ST_CR_WDRST);
+}
+
+static void
 clock_intr(void *arg)
 {
 	struct trapframe *fp = arg;
@@ -163,7 +199,7 @@
 	struct resource *irq;
 	int rid = 0;
 	void *ih;
-	device_t dev = timer_softc->dev;
+	device_t dev = timer_softc->sc_dev;
 
 	if (32768 % hz) {
 		printf("Cannot get %d Hz clock; using 128Hz\n", hz);
@@ -231,4 +267,3 @@
 cpu_stopprofclock(void)
 {
 }
-



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200608071954.k77Js6aS057291>