Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Dec 2013 22:21:49 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r259347 - stable/10/sys/arm/freescale/imx
Message-ID:  <201312132221.rBDMLna5051040@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Fri Dec 13 22:21:49 2013
New Revision: 259347
URL: http://svnweb.freebsd.org/changeset/base/259347

Log:
  MFC r257413:
  
    Reset the timer interrupt status register at the top rather than bottom of
    the interrupt handler.  If the event callback starts a new short timeout,
    the timer can fire before returning from the event callback, and clearing
    the interrupt status after that loses the interrupt and hangs until the
    counter wraps.  Fixing all of this removes the need for the do-nothing
    loop at the top of the handler which really just waited for the counter to
    roll over and reach the one-shot count again.
  
    Also add a missing return(0) in the periodic timer start case.

Modified:
  stable/10/sys/arm/freescale/imx/imx_gpt.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/arm/freescale/imx/imx_gpt.c
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx_gpt.c	Fri Dec 13 22:21:04 2013	(r259346)
+++ stable/10/sys/arm/freescale/imx/imx_gpt.c	Fri Dec 13 22:21:49 2013	(r259347)
@@ -277,14 +277,9 @@ imx_gpt_timer_start(struct eventtimer *e
 		WRITE4(sc, IMX_GPT_OCR2, READ4(sc, IMX_GPT_CNT) + sc->sc_period);
 		/* Enable compare register 2 Interrupt */
 		SET4(sc, IMX_GPT_IR, GPT_IR_OF2);
+		return (0);
 	} else if (first != 0) {
 		ticks = ((uint32_t)et->et_frequency * first) >> 32;
-
-		/*
-		 * TODO: setupt second compare reg with time which will save
-		 * us in case correct one lost, f.e. if period to short and
-		 * setup done later than counter reach target value.
-		 */
 		/* Do not disturb, otherwise event will be lost */
 		spinlock_enter();
 		/* Set expected value */
@@ -293,7 +288,6 @@ imx_gpt_timer_start(struct eventtimer *e
 		SET4(sc, IMX_GPT_IR, GPT_IR_OF1);
 		/* Now everybody can relax */
 		spinlock_exit();
-
 		return (0);
 	}
 
@@ -341,27 +335,32 @@ imx_gpt_intr(void *arg)
 
 	sc = (struct imx_gpt_softc *)arg;
 
-	/* Sometime we not get staus bit when interrupt arrive.  Cache? */
-	while (!(status = READ4(sc, IMX_GPT_SR)))
-		;
+	status = READ4(sc, IMX_GPT_SR);
+
+	/*
+	* Clear interrupt status before invoking event callbacks.  The callback
+	* often sets up a new one-shot timer event and if the interval is short
+	* enough it can fire before we get out of this function.  If we cleared
+	* at the bottom we'd miss the interrupt and hang until the clock wraps.
+	*/
+	WRITE4(sc, IMX_GPT_SR, status);
 
+	/* Handle one-shot timer events. */
 	if (status & GPT_IR_OF1) {
 		if (sc->et.et_active) {
 			sc->et.et_event_cb(&sc->et, sc->et.et_arg);
 		}
 	}
+
+	/* Handle periodic timer events. */
 	if (status & GPT_IR_OF2) {
-		if (sc->et.et_active) {
+		if (sc->et.et_active)
 			sc->et.et_event_cb(&sc->et, sc->et.et_arg);
-			/* Set expected value */
+		if (sc->sc_period != 0)
 			WRITE4(sc, IMX_GPT_OCR2, READ4(sc, IMX_GPT_CNT) +
 			    sc->sc_period);
-		}
 	}
 
-	/* ACK */
-	WRITE4(sc, IMX_GPT_SR, status);
-
 	return (FILTER_HANDLED);
 }
 



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