ptimer.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * General purpose implementation of a simple periodic countdown timer.
  3. *
  4. * Copyright (c) 2007 CodeSourcery.
  5. *
  6. * This code is licensed under the GNU LGPL.
  7. */
  8. #include "hw.h"
  9. #include "qemu/timer.h"
  10. #include "ptimer.h"
  11. #include "qemu/host-utils.h"
  12. struct ptimer_state
  13. {
  14. uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */
  15. uint64_t limit;
  16. uint64_t delta;
  17. uint32_t period_frac;
  18. int64_t period;
  19. int64_t last_event;
  20. int64_t next_event;
  21. QEMUBH *bh;
  22. QEMUTimer *timer;
  23. };
  24. /* Use a bottom-half routine to avoid reentrancy issues. */
  25. static void ptimer_trigger(ptimer_state *s)
  26. {
  27. if (s->bh) {
  28. qemu_bh_schedule(s->bh);
  29. }
  30. }
  31. static void ptimer_reload(ptimer_state *s)
  32. {
  33. if (s->delta == 0) {
  34. ptimer_trigger(s);
  35. s->delta = s->limit;
  36. }
  37. if (s->delta == 0 || s->period == 0) {
  38. fprintf(stderr, "Timer with period zero, disabling\n");
  39. s->enabled = 0;
  40. return;
  41. }
  42. s->last_event = s->next_event;
  43. s->next_event = s->last_event + s->delta * s->period;
  44. if (s->period_frac) {
  45. s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
  46. }
  47. qemu_mod_timer(s->timer, s->next_event);
  48. }
  49. static void ptimer_tick(void *opaque)
  50. {
  51. ptimer_state *s = (ptimer_state *)opaque;
  52. ptimer_trigger(s);
  53. s->delta = 0;
  54. if (s->enabled == 2) {
  55. s->enabled = 0;
  56. } else {
  57. ptimer_reload(s);
  58. }
  59. }
  60. uint64_t ptimer_get_count(ptimer_state *s)
  61. {
  62. int64_t now;
  63. uint64_t counter;
  64. if (s->enabled) {
  65. now = qemu_get_clock_ns(vm_clock);
  66. /* Figure out the current counter value. */
  67. if (now - s->next_event > 0
  68. || s->period == 0) {
  69. /* Prevent timer underflowing if it should already have
  70. triggered. */
  71. counter = 0;
  72. } else {
  73. uint64_t rem;
  74. uint64_t div;
  75. int clz1, clz2;
  76. int shift;
  77. /* We need to divide time by period, where time is stored in
  78. rem (64-bit integer) and period is stored in period/period_frac
  79. (64.32 fixed point).
  80. Doing full precision division is hard, so scale values and
  81. do a 64-bit division. The result should be rounded down,
  82. so that the rounding error never causes the timer to go
  83. backwards.
  84. */
  85. rem = s->next_event - now;
  86. div = s->period;
  87. clz1 = clz64(rem);
  88. clz2 = clz64(div);
  89. shift = clz1 < clz2 ? clz1 : clz2;
  90. rem <<= shift;
  91. div <<= shift;
  92. if (shift >= 32) {
  93. div |= ((uint64_t)s->period_frac << (shift - 32));
  94. } else {
  95. if (shift != 0)
  96. div |= (s->period_frac >> (32 - shift));
  97. /* Look at remaining bits of period_frac and round div up if
  98. necessary. */
  99. if ((uint32_t)(s->period_frac << shift))
  100. div += 1;
  101. }
  102. counter = rem / div;
  103. }
  104. } else {
  105. counter = s->delta;
  106. }
  107. return counter;
  108. }
  109. void ptimer_set_count(ptimer_state *s, uint64_t count)
  110. {
  111. s->delta = count;
  112. if (s->enabled) {
  113. s->next_event = qemu_get_clock_ns(vm_clock);
  114. ptimer_reload(s);
  115. }
  116. }
  117. void ptimer_run(ptimer_state *s, int oneshot)
  118. {
  119. if (s->enabled) {
  120. return;
  121. }
  122. if (s->period == 0) {
  123. fprintf(stderr, "Timer with period zero, disabling\n");
  124. return;
  125. }
  126. s->enabled = oneshot ? 2 : 1;
  127. s->next_event = qemu_get_clock_ns(vm_clock);
  128. ptimer_reload(s);
  129. }
  130. /* Pause a timer. Note that this may cause it to "lose" time, even if it
  131. is immediately restarted. */
  132. void ptimer_stop(ptimer_state *s)
  133. {
  134. if (!s->enabled)
  135. return;
  136. s->delta = ptimer_get_count(s);
  137. qemu_del_timer(s->timer);
  138. s->enabled = 0;
  139. }
  140. /* Set counter increment interval in nanoseconds. */
  141. void ptimer_set_period(ptimer_state *s, int64_t period)
  142. {
  143. s->period = period;
  144. s->period_frac = 0;
  145. if (s->enabled) {
  146. s->next_event = qemu_get_clock_ns(vm_clock);
  147. ptimer_reload(s);
  148. }
  149. }
  150. /* Set counter frequency in Hz. */
  151. void ptimer_set_freq(ptimer_state *s, uint32_t freq)
  152. {
  153. s->period = 1000000000ll / freq;
  154. s->period_frac = (1000000000ll << 32) / freq;
  155. if (s->enabled) {
  156. s->next_event = qemu_get_clock_ns(vm_clock);
  157. ptimer_reload(s);
  158. }
  159. }
  160. /* Set the initial countdown value. If reload is nonzero then also set
  161. count = limit. */
  162. void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
  163. {
  164. /*
  165. * Artificially limit timeout rate to something
  166. * achievable under QEMU. Otherwise, QEMU spends all
  167. * its time generating timer interrupts, and there
  168. * is no forward progress.
  169. * About ten microseconds is the fastest that really works
  170. * on the current generation of host machines.
  171. */
  172. if (limit * s->period < 10000 && s->period) {
  173. limit = 10000 / s->period;
  174. }
  175. s->limit = limit;
  176. if (reload)
  177. s->delta = limit;
  178. if (s->enabled && reload) {
  179. s->next_event = qemu_get_clock_ns(vm_clock);
  180. ptimer_reload(s);
  181. }
  182. }
  183. const VMStateDescription vmstate_ptimer = {
  184. .name = "ptimer",
  185. .version_id = 1,
  186. .minimum_version_id = 1,
  187. .minimum_version_id_old = 1,
  188. .fields = (VMStateField[]) {
  189. VMSTATE_UINT8(enabled, ptimer_state),
  190. VMSTATE_UINT64(limit, ptimer_state),
  191. VMSTATE_UINT64(delta, ptimer_state),
  192. VMSTATE_UINT32(period_frac, ptimer_state),
  193. VMSTATE_INT64(period, ptimer_state),
  194. VMSTATE_INT64(last_event, ptimer_state),
  195. VMSTATE_INT64(next_event, ptimer_state),
  196. VMSTATE_TIMER(timer, ptimer_state),
  197. VMSTATE_END_OF_LIST()
  198. }
  199. };
  200. ptimer_state *ptimer_init(QEMUBH *bh)
  201. {
  202. ptimer_state *s;
  203. s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
  204. s->bh = bh;
  205. s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s);
  206. return s;
  207. }