From 2e5cc9051b5daf0b164f0454e28e08c2b952089a Mon Sep 17 00:00:00 2001
From: Atish Patra <atish.patra@wdc.com>
Date: Thu, 29 Aug 2019 15:19:11 -0700
Subject: lib: Fix timer for 32 bit

To read 64bit time in 32 bit we have to read lower & upper half
separately and 'or' them together. However, upper half time may
have changed by the time we read lower half. Thus, the resultant
64 bit time may not be accurate.

Consider lower half time value only if upper half time value has
not changed.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
---
 lib/utils/sys/clint.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

(limited to 'lib/utils/sys')

diff --git a/lib/utils/sys/clint.c b/lib/utils/sys/clint.c
index d58e4e6..802d419 100644
--- a/lib/utils/sys/clint.c
+++ b/lib/utils/sys/clint.c
@@ -62,16 +62,24 @@ static volatile void *clint_time_base;
 static volatile u64 *clint_time_val;
 static volatile u64 *clint_time_cmp;
 
+static inline u32 clint_time_read_hi()
+{
+	return readl_relaxed((u32 *)clint_time_val + 1);
+}
+
 u64 clint_timer_value(void)
 {
 #if __riscv_xlen == 64
 	return readq_relaxed(clint_time_val);
 #else
-	u64 tmp;
-	tmp = readl_relaxed((void *)clint_time_val + 0x04);
-	tmp <<= 32;
-	tmp |= readl_relaxed(clint_time_val);
-	return tmp;
+	u32 lo, hi;
+
+	do {
+		hi = clint_time_read_hi();
+		lo = readl_relaxed(clint_time_val);
+	} while (hi != clint_time_read_hi());
+
+	return ((u64)hi << 32) | (u64)lo;
 #endif
 }
 
-- 
cgit v1.2.3