summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjchandra <jchandra@FreeBSD.org>2010-08-25 07:33:35 +0000
committerjchandra <jchandra@FreeBSD.org>2010-08-25 07:33:35 +0000
commit4e8095717392ce27912dea6bcc9615cbbafa643a (patch)
tree645a45487aa85c180b61c4e6bada79e71d261f2f
parent86cb0861ef42c36a3d32b54c00c4fabfab729298 (diff)
downloadFreeBSD-src-4e8095717392ce27912dea6bcc9615cbbafa643a.zip
FreeBSD-src-4e8095717392ce27912dea6bcc9615cbbafa643a.tar.gz
Sync up XLR tick.c with the new MIPS tick.c
-rw-r--r--sys/mips/rmi/tick.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/sys/mips/rmi/tick.c b/sys/mips/rmi/tick.c
index 7520cac..3b83a5c 100644
--- a/sys/mips/rmi/tick.c
+++ b/sys/mips/rmi/tick.c
@@ -62,8 +62,8 @@ struct timecounter *platform_timecounter;
static DPCPU_DEFINE(uint32_t, cycles_per_tick);
static uint32_t cycles_per_usec;
-static DPCPU_DEFINE(uint32_t, counter_upper);
-static DPCPU_DEFINE(uint32_t, counter_lower_last);
+static DPCPU_DEFINE(volatile uint32_t, counter_upper);
+static DPCPU_DEFINE(volatile uint32_t, counter_lower_last);
static DPCPU_DEFINE(uint32_t, compare_ticks);
static DPCPU_DEFINE(uint32_t, lost_ticks);
@@ -108,23 +108,32 @@ tick_ticker(void)
uint32_t t_lower_last, t_upper;
/*
- * XXX: MIPS64 platforms can read 64-bits of counter directly.
- * Also: the tc code is supposed to cope with things wrapping
- * from the time counter, so I'm not sure why all these hoops
- * are even necessary.
+ * Disable preemption because we are working with cpu specific data.
*/
- ticktock = mips_rd_count();
critical_enter();
- t_lower_last = DPCPU_GET(counter_lower_last);
- t_upper = DPCPU_GET(counter_upper);
+
+ /*
+ * Note that even though preemption is disabled, interrupts are
+ * still enabled. In particular there is a race with clock_intr()
+ * reading the values of 'counter_upper' and 'counter_lower_last'.
+ *
+ * XXX this depends on clock_intr() being executed periodically
+ * so that 'counter_upper' and 'counter_lower_last' are not stale.
+ */
+ do {
+ t_upper = DPCPU_GET(counter_upper);
+ t_lower_last = DPCPU_GET(counter_lower_last);
+ } while (t_upper != DPCPU_GET(counter_upper));
+
+ ticktock = mips_rd_count();
+
+ critical_exit();
+
+ /* COUNT register wrapped around */
if (ticktock < t_lower_last)
t_upper++;
- t_lower_last = ticktock;
- DPCPU_SET(counter_upper, t_upper);
- DPCPU_SET(counter_lower_last, t_lower_last);
- critical_exit();
- ret = ((uint64_t)t_upper << 32) | t_lower_last;
+ ret = ((uint64_t)t_upper << 32) | ticktock;
return (ret);
}
@@ -268,11 +277,11 @@ clock_intr(void *arg)
} else /* In one-shot mode timer should be stopped after the event. */
mips_wr_compare(0xffffffff);
- critical_enter();
+ /* COUNT register wrapped around */
if (count < DPCPU_GET(counter_lower_last)) {
DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1);
- DPCPU_SET(counter_lower_last, count);
}
+ DPCPU_SET(counter_lower_last, count);
if (cycles_per_tick > 0) {
@@ -302,7 +311,6 @@ clock_intr(void *arg)
}
if (sc->et.et_active)
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
- critical_exit();
return (FILTER_HANDLED);
}
OpenPOWER on IntegriCloud