[PATCH v2 04/39] xen/riscv: introduce csr_read64()

Oleksii Kurochko <[email protected]>
Newsgroups gmane.comp.emulators.xen.devel
Message-ID <0f7080ea4dc86a8bb3dae39d94e5b03e95d010c0.1787838835.git.oleksii.kurochko@gmail.com>
csr_write64() already hides the RV32 split of a 64-bit CSR into a low and
a high half; add the read counterpart.

Reading the two halves isn't simply the mirror of writing them. A CSR which
hardware increments can carry from the low half into the high one between
the two reads, so a plain pair of reads can produce a value the CSR never
held. Therefore the high half is re-read and the sequence retried if it
changed in the meantime.

Use it for CSR_TIME, which is exactly such a counter, and widen cycles_t to
uint64_t. Otherwise get_cycles() would still truncate the time counter to
32 bits on RV32.

Fixes: a541ddadec0a ("xen/riscv: introduce time.h")
Signed-off-by: Oleksii Kurochko <[email protected]>
---
Changes in v2:
 - New patch.
---
---
 xen/arch/riscv/include/asm/csr.h  | 24 ++++++++++++++++++++++++
 xen/arch/riscv/include/asm/time.h |  4 ++--
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/xen/arch/riscv/include/asm/csr.h b/xen/arch/riscv/include/asm/csr.h
index 888d6a2a86d6..a5cdd6f99c8e 100644
--- a/xen/arch/riscv/include/asm/csr.h
+++ b/xen/arch/riscv/include/asm/csr.h
@@ -39,12 +39,36 @@
     csr_write(csr, v_);             \
     csr_write(csr ## H, v_ >> 32);  \
 })
+
+/*
+ * The two halves are read by separate instructions, so a CSR which hardware
+ * increments can carry from the low half into the high one in between,
+ * yielding a value the CSR never held. Re-read the high half and retry the
+ * sequence if it changed.
+ */
+#define csr_read64(csr)                         \
+({                                              \
+    uint32_t hi_, lo_;                          \
+                                                \
+    do {                                        \
+        hi_ = csr_read(csr ## H);               \
+        lo_ = csr_read(csr);                    \
+    } while ( hi_ != csr_read(csr ## H) );      \
+                                                \
+    ((uint64_t)hi_ << 32) | lo_;                \
+})
 #else
 #define csr_write64(csr, val)       \
 ({                                  \
     csr_write(csr, val);            \
     (void)csr ## H;                 \
 })
+
+#define csr_read64(csr)             \
+({                                  \
+    (void)csr ## H;                 \
+    csr_read(csr);                  \
+})
 #endif
 
 #define csr_swap(csr, val)                                      \
diff --git a/xen/arch/riscv/include/asm/time.h b/xen/arch/riscv/include/asm/time.h
index 4d68900151a7..ec771c3fe80f 100644
--- a/xen/arch/riscv/include/asm/time.h
+++ b/xen/arch/riscv/include/asm/time.h
@@ -18,11 +18,11 @@ static inline void force_update_vcpu_system_time(struct vcpu *v)
     BUG_ON("unimplemented");
 }
 
-typedef unsigned long cycles_t;
+typedef uint64_t cycles_t;
 
 static inline cycles_t get_cycles(void)
 {
-    return csr_read(CSR_TIME);
+    return csr_read64(CSR_TIME);
 }
 
 void preinit_xen_time(void);
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.