vsyscall_gtod.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. /*
  2. * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
  3. * Copyright 2003 Andi Kleen, SuSE Labs.
  4. *
  5. * Modified for x86 32 bit architecture by
  6. * Stefani Seibold <stefani@seibold.net>
  7. * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
  8. *
  9. * Thanks to hpa@transmeta.com for some useful hint.
  10. * Special thanks to Ingo Molnar for his early experience with
  11. * a different vsyscall implementation for Linux/IA32 and for the name.
  12. *
  13. */
  14. #include <linux/timekeeper_internal.h>
  15. #include <asm/vgtod.h>
  16. #include <asm/vvar.h>
  17. int vclocks_used __read_mostly;
  18. DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
  19. void update_vsyscall_tz(void)
  20. {
  21. vsyscall_gtod_data.tz_minuteswest = sys_tz.tz_minuteswest;
  22. vsyscall_gtod_data.tz_dsttime = sys_tz.tz_dsttime;
  23. }
  24. void update_vsyscall(struct timekeeper *tk)
  25. {
  26. int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
  27. struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
  28. /* Mark the new vclock used. */
  29. BUILD_BUG_ON(VCLOCK_MAX >= 32);
  30. WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode));
  31. gtod_write_begin(vdata);
  32. /* copy vsyscall data */
  33. vdata->vclock_mode = vclock_mode;
  34. vdata->cycle_last = tk->tkr_mono.cycle_last;
  35. vdata->mask = tk->tkr_mono.mask;
  36. vdata->mult = tk->tkr_mono.mult;
  37. vdata->shift = tk->tkr_mono.shift;
  38. vdata->wall_time_sec = tk->xtime_sec;
  39. vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec;
  40. vdata->monotonic_time_sec = tk->xtime_sec
  41. + tk->wall_to_monotonic.tv_sec;
  42. vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec
  43. + ((u64)tk->wall_to_monotonic.tv_nsec
  44. << tk->tkr_mono.shift);
  45. while (vdata->monotonic_time_snsec >=
  46. (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
  47. vdata->monotonic_time_snsec -=
  48. ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
  49. vdata->monotonic_time_sec++;
  50. }
  51. vdata->wall_time_coarse_sec = tk->xtime_sec;
  52. vdata->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >>
  53. tk->tkr_mono.shift);
  54. vdata->monotonic_time_coarse_sec =
  55. vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
  56. vdata->monotonic_time_coarse_nsec =
  57. vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec;
  58. while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) {
  59. vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC;
  60. vdata->monotonic_time_coarse_sec++;
  61. }
  62. gtod_write_end(vdata);
  63. }