summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-10-11 10:45:27 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-10-12 13:54:23 +0200
commit9c21cfc1dc6f5c2980a692fdfc87f4e7cb3e8222 (patch)
tree0214efea120b49bca6d276f70719f5f602e20093
parent07a8c91dff15c78dff4cb6eddc0fe52181b9e0ee (diff)
score: Port large time delta support to RTEMS
-rw-r--r--cpukit/score/src/kern_tc.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 096de85880..c013c16f87 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -170,7 +170,7 @@ struct timehands {
int64_t th_adjustment;
#endif /* __rtems__ */
uint64_t th_scale;
- u_int th_large_delta;
+ uint32_t th_large_delta;
uint32_t th_offset_count;
struct bintime th_offset;
struct bintime th_bintime;
@@ -226,6 +226,7 @@ static struct timehands th0 = {
.th_counter = &dummy_timecounter,
.th_scale = (uint64_t)-1 / 1000000,
.th_offset = { .sec = 1 },
+ .th_large_delta = 1000000,
.th_generation = UINT_MAX,
#ifdef __rtems__
.th_bintime = { .sec = TOD_SECONDS_1970_THROUGH_1988 },
@@ -381,7 +382,12 @@ bintime_off(struct bintime *bt, u_int off)
struct timehands *th;
struct bintime *btp;
uint64_t scale, x;
+#ifndef __rtems__
u_int delta, gen, large_delta;
+#else /* __rtems__ */
+ uint32_t delta, large_delta;
+ u_int gen;
+#endif /* __rtems__ */
do {
th = timehands;
@@ -544,17 +550,30 @@ sbintime_t
_Timecounter_Sbinuptime(void)
{
struct timehands *th;
- uint32_t gen;
sbintime_t sbt;
+ uint64_t scale;
+ uint32_t delta;
+ uint32_t large_delta;
+ u_int gen;
do {
th = timehands;
gen = atomic_load_acq_int(&th->th_generation);
sbt = bttosbt(th->th_offset);
- sbt += (th->th_scale * tc_delta(th)) >> 32;
+ scale = th->th_scale;
+ delta = tc_delta(th);
+ large_delta = th->th_large_delta;
atomic_thread_fence_acq();
} while (gen == 0 || gen != th->th_generation);
+ if (__predict_false(delta >= large_delta)) {
+ /* Avoid overflow for scale * delta. */
+ sbt += (scale >> 32) * delta;
+ sbt += ((scale & 0xffffffff) * delta) >> 32;
+ } else {
+ sbt += (scale * delta) >> 32;
+ }
+
return (sbt);
}
#endif /* __rtems__ */
@@ -1649,12 +1668,24 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
#ifndef __rtems__
tc_min_ticktock_freq = max(1, timecounter->tc_frequency /
(((uint64_t)timecounter->tc_counter_mask + 1) / 3));
+#else /* __rtems__ */
+ /*
+ * For RTEMS, we can do the scale and large delta calculation
+ * here, since we do not support th_adjustment. It is
+ * condsidered to be zero.
+ */
+ scale = (uint64_t)1 << 63;
+ scale /= th->th_counter->tc_frequency;
+ th->th_scale = scale * 2;
+ th->th_large_delta = MIN(((uint64_t)1 << 63) / scale,
+ UINT_MAX);
#endif /* __rtems__ */
#ifdef FFCLOCK
ffclock_change_tc(th);
#endif
}
+#ifndef __rtems__
/*-
* Recalculate the scaling factor. We want the number of 1/2^64
* fractions of a second per period of the hardware counter, taking
@@ -1679,12 +1710,13 @@ _Timecounter_Windup(struct bintime *new_boottimebin,
*
*/
scale = (uint64_t)1 << 63;
-#ifndef __rtems__
scale += (th->th_adjustment / 1024) * 2199;
-#endif /* __rtems__ */
scale /= th->th_counter->tc_frequency;
th->th_scale = scale * 2;
th->th_large_delta = MIN(((uint64_t)1 << 63) / scale, UINT_MAX);
+#else
+ /* See above "Now is a good time to change timecounters." */
+#endif /* __rtems__ */
/*
* Now that the struct timehands is again consistent, set the new