Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Dec 2012 01:38:43 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r244758 - head/sys/arm/broadcom/bcm2835
Message-ID:  <201212280138.qBS1chFm022181@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Fri Dec 28 01:38:43 2012
New Revision: 244758
URL: http://svnweb.freebsd.org/changeset/base/244758

Log:
  Fix event timer on Raspberry Pi
  
  - Disable interrupt when updating compare value in order to
     make this operation atomical
  
  - Increase minimum period for event timer. Systimer on BCM2835
      is compare timer, so if minimum period is too small it might
      be less then fraction of time between "read current value" and
      "set compare timer" operations. It means that when timer is armed
      actual counter value is more then compare value and it will take
      whole cycle (~32sec for 1MHz timer) to fire interrupt.
  
  Submitted by:	Daisuke Aoyama <aoyama at peach.ne.jp>

Modified:
  head/sys/arm/broadcom/bcm2835/bcm2835_systimer.c

Modified: head/sys/arm/broadcom/bcm2835/bcm2835_systimer.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_systimer.c	Fri Dec 28 01:23:12 2012	(r244757)
+++ head/sys/arm/broadcom/bcm2835/bcm2835_systimer.c	Fri Dec 28 01:38:43 2012	(r244758)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 
 #define	DEFAULT_TIMER		3
 #define	DEFAULT_FREQUENCY	1000000
+#define	MIN_PERIOD		100LLU
 
 #define	SYSTIMER_CS	0x00
 #define	SYSTIMER_CLO	0x04
@@ -123,17 +124,24 @@ bcm_systimer_start(struct eventtimer *et
 	struct systimer *st = et->et_priv;
 	uint32_t clo;
 	uint32_t count;
+	register_t s;
 
 	if (first != NULL) {
-		st->enabled = 1;
 
 		count = (st->et.et_frequency * (first->frac >> 32)) >> 32;
 		if (first->sec != 0)
 			count += st->et.et_frequency * first->sec;
 
+		s = intr_disable();
 		clo = bcm_systimer_tc_read_4(SYSTIMER_CLO);
 		clo += count;
+		/*
+		 * Clear pending interrupts
+		 */
+		bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index));
 		bcm_systimer_tc_write_4(SYSTIMER_C0 + st->index*4, clo);
+		st->enabled = 1;
+		intr_restore(s);
 
 		return (0);
 	} 
@@ -154,7 +162,13 @@ static int
 bcm_systimer_intr(void *arg)
 {
 	struct systimer *st = (struct systimer *)arg;
+	uint32_t cs;
+
+ 	cs = bcm_systimer_tc_read_4(SYSTIMER_CS);
+	if ((cs & (1 << st->index)) == 0)
+		return (FILTER_STRAY);
 
+	/* ACK interrupt */
 	bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index));
 	if (st->enabled) {
 		if (st->et.et_active) {
@@ -226,7 +240,7 @@ bcm_systimer_attach(device_t dev)
 	sc->st[DEFAULT_TIMER].et.et_frequency = sc->sysclk_freq;
 	sc->st[DEFAULT_TIMER].et.et_min_period.sec = 0;
 	sc->st[DEFAULT_TIMER].et.et_min_period.frac =
-	    ((0x00000002LLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
+	    ((MIN_PERIOD << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;
 	sc->st[DEFAULT_TIMER].et.et_max_period.sec = 0xfffffff0U / sc->st[DEFAULT_TIMER].et.et_frequency;
 	sc->st[DEFAULT_TIMER].et.et_max_period.frac =
 	    ((0xfffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency) << 32;



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