summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-10-11 10:45:27 +0200
committerMoyano, Gabriel <gabriel.moyano@dlr.de>2021-11-16 09:48:22 +0100
commit1c378f1a9887956e51d51b7d63479a61c8b4e602 (patch)
tree315b9a82a31a74757a8624a5ad8c6dd058e57c10
parentscore: Initialize timehand generation to UINT_MAX (diff)
downloadrtems-1c378f1a9887956e51d51b7d63479a61c8b4e602.tar.bz2
score: Port large time delta support to RTEMS
-rw-r--r--cpukit/score/src/kern_tc.c25
-rw-r--r--testsuites/sptests/sptimecounter01/init.c4
2 files changed, 24 insertions, 5 deletions
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 52ae6aa034..00645600a1 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -158,7 +158,7 @@ struct timehands {
struct timecounter *th_counter;
int64_t th_adjustment;
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;
@@ -218,6 +218,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 },
@@ -373,7 +374,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;
@@ -536,17 +542,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__ */
diff --git a/testsuites/sptests/sptimecounter01/init.c b/testsuites/sptests/sptimecounter01/init.c
index 81b705473e..12d5a7820d 100644
--- a/testsuites/sptests/sptimecounter01/init.c
+++ b/testsuites/sptests/sptimecounter01/init.c
@@ -196,11 +196,11 @@ void boot_card(const char *cmdline)
assert(bt.sec == 1);
assert(bt.frac == 18446744073708);
- /* Ensure that the fraction overflows and the second remains constant */
+ /* Check that a large delta yields a correct time */
ctx->counter = (0xf0000000 | 1) + TEST_FREQ;
rtems_bsd_binuptime(&bt);
assert(ctx->counter == (0xf0000000 | 2) + TEST_FREQ);
- assert(bt.sec == 1);
+ assert(bt.sec == 2);
assert(bt.frac == 18446742522092);
test_install(ctx);