[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