162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
362306a36Sopenharmony_ci *  Copyright 2003 Andi Kleen, SuSE Labs.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Thanks to hpa@transmeta.com for some useful hint.
662306a36Sopenharmony_ci *  Special thanks to Ingo Molnar for his early experience with
762306a36Sopenharmony_ci *  a different vsyscall implementation for Linux/IA32 and for the name.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/time.h>
1162306a36Sopenharmony_ci#include <linux/timekeeper_internal.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <asm/vvar.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_civoid update_vsyscall_tz(void)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	if (unlikely(vvar_data == NULL))
1862306a36Sopenharmony_ci		return;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	vvar_data->tz_minuteswest = sys_tz.tz_minuteswest;
2162306a36Sopenharmony_ci	vvar_data->tz_dsttime = sys_tz.tz_dsttime;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_civoid update_vsyscall(struct timekeeper *tk)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct vvar_data *vdata = vvar_data;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (unlikely(vdata == NULL))
2962306a36Sopenharmony_ci		return;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	vvar_write_begin(vdata);
3262306a36Sopenharmony_ci	vdata->vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
3362306a36Sopenharmony_ci	vdata->clock.cycle_last = tk->tkr_mono.cycle_last;
3462306a36Sopenharmony_ci	vdata->clock.mask = tk->tkr_mono.mask;
3562306a36Sopenharmony_ci	vdata->clock.mult = tk->tkr_mono.mult;
3662306a36Sopenharmony_ci	vdata->clock.shift = tk->tkr_mono.shift;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	vdata->wall_time_sec = tk->xtime_sec;
3962306a36Sopenharmony_ci	vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	vdata->monotonic_time_sec = tk->xtime_sec +
4262306a36Sopenharmony_ci				    tk->wall_to_monotonic.tv_sec;
4362306a36Sopenharmony_ci	vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec +
4462306a36Sopenharmony_ci				      (tk->wall_to_monotonic.tv_nsec <<
4562306a36Sopenharmony_ci				       tk->tkr_mono.shift);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	while (vdata->monotonic_time_snsec >=
4862306a36Sopenharmony_ci	       (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
4962306a36Sopenharmony_ci		vdata->monotonic_time_snsec -=
5062306a36Sopenharmony_ci				((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
5162306a36Sopenharmony_ci		vdata->monotonic_time_sec++;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	vdata->wall_time_coarse_sec = tk->xtime_sec;
5562306a36Sopenharmony_ci	vdata->wall_time_coarse_nsec =
5662306a36Sopenharmony_ci			(long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	vdata->monotonic_time_coarse_sec =
5962306a36Sopenharmony_ci		vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
6062306a36Sopenharmony_ci	vdata->monotonic_time_coarse_nsec =
6162306a36Sopenharmony_ci		vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) {
6462306a36Sopenharmony_ci		vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC;
6562306a36Sopenharmony_ci		vdata->monotonic_time_coarse_sec++;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	vvar_write_end(vdata);
6962306a36Sopenharmony_ci}
70