summaryrefslogtreecommitdiffstats
path: root/arch/mips/include/asm/vdso.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/include/asm/vdso.h')
-rw-r--r--arch/mips/include/asm/vdso.h68
1 files changed, 67 insertions, 1 deletions
diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h
index db2d45be8f2e..8f4ca5dd992b 100644
--- a/arch/mips/include/asm/vdso.h
+++ b/arch/mips/include/asm/vdso.h
@@ -13,6 +13,8 @@
#include <linux/mm_types.h>
+#include <asm/barrier.h>
+
/**
* struct mips_vdso_image - Details of a VDSO image.
* @data: Pointer to VDSO image data (page-aligned).
@@ -53,18 +55,82 @@ extern struct mips_vdso_image vdso_image_n32;
/**
* union mips_vdso_data - Data provided by the kernel for the VDSO.
+ * @xtime_sec: Current real time (seconds part).
+ * @xtime_nsec: Current real time (nanoseconds part, shifted).
+ * @wall_to_mono_sec: Wall-to-monotonic offset (seconds part).
+ * @wall_to_mono_nsec: Wall-to-monotonic offset (nanoseconds part).
+ * @seq_count: Counter to synchronise updates (odd = updating).
+ * @cs_shift: Clocksource shift value.
+ * @clock_mode: Clocksource to use for time functions.
+ * @cs_mult: Clocksource multiplier value.
+ * @cs_cycle_last: Clock cycle value at last update.
+ * @cs_mask: Clocksource mask value.
+ * @tz_minuteswest: Minutes west of Greenwich (from timezone).
+ * @tz_dsttime: Type of DST correction (from timezone).
*
* This structure contains data needed by functions within the VDSO. It is
- * populated by the kernel and mapped read-only into user memory.
+ * populated by the kernel and mapped read-only into user memory. The time
+ * fields are mirrors of internal data from the timekeeping infrastructure.
*
* Note: Care should be taken when modifying as the layout must remain the same
* for both 64- and 32-bit (for 32-bit userland on 64-bit kernel).
*/
union mips_vdso_data {
struct {
+ u64 xtime_sec;
+ u64 xtime_nsec;
+ u32 wall_to_mono_sec;
+ u32 wall_to_mono_nsec;
+ u32 seq_count;
+ u32 cs_shift;
+ u8 clock_mode;
+ u32 cs_mult;
+ u64 cs_cycle_last;
+ u64 cs_mask;
+ s32 tz_minuteswest;
+ s32 tz_dsttime;
};
u8 page[PAGE_SIZE];
};
+static inline u32 vdso_data_read_begin(const union mips_vdso_data *data)
+{
+ u32 seq;
+
+ while (true) {
+ seq = ACCESS_ONCE(data->seq_count);
+ if (likely(!(seq & 1))) {
+ /* Paired with smp_wmb() in vdso_data_write_*(). */
+ smp_rmb();
+ return seq;
+ }
+
+ cpu_relax();
+ }
+}
+
+static inline bool vdso_data_read_retry(const union mips_vdso_data *data,
+ u32 start_seq)
+{
+ /* Paired with smp_wmb() in vdso_data_write_*(). */
+ smp_rmb();
+ return unlikely(data->seq_count != start_seq);
+}
+
+static inline void vdso_data_write_begin(union mips_vdso_data *data)
+{
+ ++data->seq_count;
+
+ /* Ensure sequence update is written before other data page values. */
+ smp_wmb();
+}
+
+static inline void vdso_data_write_end(union mips_vdso_data *data)
+{
+ /* Ensure data values are written before updating sequence again. */
+ smp_wmb();
+ ++data->seq_count;
+}
+
#endif /* __ASM_VDSO_H */