timer_hpet.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * This code largely moved from arch/i386/kernel/time.c.
  3. * See comments there for proper credits.
  4. */
  5. #include <linux/spinlock.h>
  6. #include <linux/init.h>
  7. #include <linux/timex.h>
  8. #include <linux/errno.h>
  9. #include <linux/string.h>
  10. #include <linux/jiffies.h>
  11. #include <asm/timer.h>
  12. #include <asm/io.h>
  13. #include <asm/processor.h>
  14. #include "io_ports.h"
  15. #include "mach_timer.h"
  16. #include <asm/hpet.h>
  17. static unsigned long hpet_usec_quotient __read_mostly; /* convert hpet clks to usec */
  18. static unsigned long tsc_hpet_quotient __read_mostly; /* convert tsc to hpet clks */
  19. static unsigned long hpet_last; /* hpet counter value at last tick*/
  20. static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
  21. static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
  22. static unsigned long long monotonic_base;
  23. static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
  24. /* convert from cycles(64bits) => nanoseconds (64bits)
  25. * basic equation:
  26. * ns = cycles / (freq / ns_per_sec)
  27. * ns = cycles * (ns_per_sec / freq)
  28. * ns = cycles * (10^9 / (cpu_khz * 10^3))
  29. * ns = cycles * (10^6 / cpu_khz)
  30. *
  31. * Then we use scaling math (suggested by george@mvista.com) to get:
  32. * ns = cycles * (10^6 * SC / cpu_khz) / SC
  33. * ns = cycles * cyc2ns_scale / SC
  34. *
  35. * And since SC is a constant power of two, we can convert the div
  36. * into a shift.
  37. *
  38. * We can use khz divisor instead of mhz to keep a better percision, since
  39. * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
  40. * (mathieu.desnoyers@polymtl.ca)
  41. *
  42. * -johnstul@us.ibm.com "math is hard, lets go shopping!"
  43. */
  44. static unsigned long cyc2ns_scale __read_mostly;
  45. #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
  46. static inline void set_cyc2ns_scale(unsigned long cpu_khz)
  47. {
  48. cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
  49. }
  50. static inline unsigned long long cycles_2_ns(unsigned long long cyc)
  51. {
  52. return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
  53. }
  54. static unsigned long long monotonic_clock_hpet(void)
  55. {
  56. unsigned long long last_offset, this_offset, base;
  57. unsigned seq;
  58. /* atomically read monotonic base & last_offset */
  59. do {
  60. seq = read_seqbegin(&monotonic_lock);
  61. last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
  62. base = monotonic_base;
  63. } while (read_seqretry(&monotonic_lock, seq));
  64. /* Read the Time Stamp Counter */
  65. rdtscll(this_offset);
  66. /* return the value in ns */
  67. return base + cycles_2_ns(this_offset - last_offset);
  68. }
  69. static unsigned long get_offset_hpet(void)
  70. {
  71. register unsigned long eax, edx;
  72. eax = hpet_readl(HPET_COUNTER);
  73. eax -= hpet_last; /* hpet delta */
  74. eax = min(hpet_tick, eax);
  75. /*
  76. * Time offset = (hpet delta) * ( usecs per HPET clock )
  77. * = (hpet delta) * ( usecs per tick / HPET clocks per tick)
  78. * = (hpet delta) * ( hpet_usec_quotient ) / (2^32)
  79. *
  80. * Where,
  81. * hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick
  82. *
  83. * Using a mull instead of a divl saves some cycles in critical path.
  84. */
  85. ASM_MUL64_REG(eax, edx, hpet_usec_quotient, eax);
  86. /* our adjusted time offset in microseconds */
  87. return edx;
  88. }
  89. static void mark_offset_hpet(void)
  90. {
  91. unsigned long long this_offset, last_offset;
  92. unsigned long offset;
  93. write_seqlock(&monotonic_lock);
  94. last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
  95. rdtsc(last_tsc_low, last_tsc_high);
  96. if (hpet_use_timer)
  97. offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
  98. else
  99. offset = hpet_readl(HPET_COUNTER);
  100. if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {
  101. int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;
  102. jiffies_64 += lost_ticks;
  103. }
  104. hpet_last = offset;
  105. /* update the monotonic base value */
  106. this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
  107. monotonic_base += cycles_2_ns(this_offset - last_offset);
  108. write_sequnlock(&monotonic_lock);
  109. }
  110. static void delay_hpet(unsigned long loops)
  111. {
  112. unsigned long hpet_start, hpet_end;
  113. unsigned long eax;
  114. /* loops is the number of cpu cycles. Convert it to hpet clocks */
  115. ASM_MUL64_REG(eax, loops, tsc_hpet_quotient, loops);
  116. hpet_start = hpet_readl(HPET_COUNTER);
  117. do {
  118. rep_nop();
  119. hpet_end = hpet_readl(HPET_COUNTER);
  120. } while ((hpet_end - hpet_start) < (loops));
  121. }
  122. static struct timer_opts timer_hpet;
  123. static int __init init_hpet(char* override)
  124. {
  125. unsigned long result, remain;
  126. /* check clock override */
  127. if (override[0] && strncmp(override,"hpet",4))
  128. return -ENODEV;
  129. if (!is_hpet_enabled())
  130. return -ENODEV;
  131. printk("Using HPET for gettimeofday\n");
  132. if (cpu_has_tsc) {
  133. unsigned long tsc_quotient = calibrate_tsc_hpet(&tsc_hpet_quotient);
  134. if (tsc_quotient) {
  135. /* report CPU clock rate in Hz.
  136. * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
  137. * clock/second. Our precision is about 100 ppm.
  138. */
  139. { unsigned long eax=0, edx=1000;
  140. ASM_DIV64_REG(cpu_khz, edx, tsc_quotient,
  141. eax, edx);
  142. printk("Detected %u.%03u MHz processor.\n",
  143. cpu_khz / 1000, cpu_khz % 1000);
  144. }
  145. set_cyc2ns_scale(cpu_khz);
  146. }
  147. /* set this only when cpu_has_tsc */
  148. timer_hpet.read_timer = read_timer_tsc;
  149. }
  150. /*
  151. * Math to calculate hpet to usec multiplier
  152. * Look for the comments at get_offset_hpet()
  153. */
  154. ASM_DIV64_REG(result, remain, hpet_tick, 0, KERNEL_TICK_USEC);
  155. if (remain > (hpet_tick >> 1))
  156. result++; /* rounding the result */
  157. hpet_usec_quotient = result;
  158. return 0;
  159. }
  160. static int hpet_resume(void)
  161. {
  162. write_seqlock(&monotonic_lock);
  163. /* Assume this is the last mark offset time */
  164. rdtsc(last_tsc_low, last_tsc_high);
  165. if (hpet_use_timer)
  166. hpet_last = hpet_readl(HPET_T0_CMP) - hpet_tick;
  167. else
  168. hpet_last = hpet_readl(HPET_COUNTER);
  169. write_sequnlock(&monotonic_lock);
  170. return 0;
  171. }
  172. /************************************************************/
  173. /* tsc timer_opts struct */
  174. static struct timer_opts timer_hpet __read_mostly = {
  175. .name = "hpet",
  176. .mark_offset = mark_offset_hpet,
  177. .get_offset = get_offset_hpet,
  178. .monotonic_clock = monotonic_clock_hpet,
  179. .delay = delay_hpet,
  180. .resume = hpet_resume,
  181. };
  182. struct init_timer_opts __initdata timer_hpet_init = {
  183. .init = init_hpet,
  184. .opts = &timer_hpet,
  185. };