vgettimeofday.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright 2012 Tilera Corporation. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, version 2.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11. * NON INFRINGEMENT. See the GNU General Public License for
  12. * more details.
  13. */
  14. #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */
  15. #include <linux/time.h>
  16. #include <asm/timex.h>
  17. #include <asm/vdso.h>
  18. #if CHIP_HAS_SPLIT_CYCLE()
  19. static inline cycles_t get_cycles_inline(void)
  20. {
  21. unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
  22. unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
  23. unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
  24. while (unlikely(high != high2)) {
  25. low = __insn_mfspr(SPR_CYCLE_LOW);
  26. high = high2;
  27. high2 = __insn_mfspr(SPR_CYCLE_HIGH);
  28. }
  29. return (((cycles_t)high) << 32) | low;
  30. }
  31. #define get_cycles get_cycles_inline
  32. #endif
  33. /*
  34. * Find out the vDSO data page address in the process address space.
  35. */
  36. inline unsigned long get_datapage(void)
  37. {
  38. unsigned long ret;
  39. /* vdso data page located in the 2nd vDSO page. */
  40. asm volatile ("lnk %0" : "=r"(ret));
  41. ret &= ~(PAGE_SIZE - 1);
  42. ret += PAGE_SIZE;
  43. return ret;
  44. }
  45. int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
  46. {
  47. cycles_t cycles;
  48. unsigned long count, sec, ns;
  49. volatile struct vdso_data *vdso_data;
  50. vdso_data = (struct vdso_data *)get_datapage();
  51. /* The use of the timezone is obsolete, normally tz is NULL. */
  52. if (unlikely(tz != NULL)) {
  53. while (1) {
  54. /* Spin until the update finish. */
  55. count = vdso_data->tz_update_count;
  56. if (count & 1)
  57. continue;
  58. tz->tz_minuteswest = vdso_data->tz_minuteswest;
  59. tz->tz_dsttime = vdso_data->tz_dsttime;
  60. /* Check whether updated, read again if so. */
  61. if (count == vdso_data->tz_update_count)
  62. break;
  63. }
  64. }
  65. if (unlikely(tv == NULL))
  66. return 0;
  67. while (1) {
  68. /* Spin until the update finish. */
  69. count = vdso_data->tb_update_count;
  70. if (count & 1)
  71. continue;
  72. cycles = (get_cycles() - vdso_data->xtime_tod_stamp);
  73. ns = (cycles * vdso_data->mult) >> vdso_data->shift;
  74. sec = vdso_data->xtime_clock_sec;
  75. ns += vdso_data->xtime_clock_nsec;
  76. if (ns >= NSEC_PER_SEC) {
  77. ns -= NSEC_PER_SEC;
  78. sec += 1;
  79. }
  80. /* Check whether updated, read again if so. */
  81. if (count == vdso_data->tb_update_count)
  82. break;
  83. }
  84. tv->tv_sec = sec;
  85. tv->tv_usec = ns / 1000;
  86. return 0;
  87. }
  88. int gettimeofday(struct timeval *tv, struct timezone *tz)
  89. __attribute__((weak, alias("__vdso_gettimeofday")));