tick-broadcast.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * linux/kernel/time/tick-broadcast.c
  3. *
  4. * This file contains functions which emulate a local clock-event
  5. * device via a broadcast event source.
  6. *
  7. * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de>
  8. * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar
  9. * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner
  10. *
  11. * This code is licenced under the GPL version 2. For details see
  12. * kernel-base/COPYING.
  13. */
  14. #include <linux/cpu.h>
  15. #include <linux/err.h>
  16. #include <linux/hrtimer.h>
  17. #include <linux/irq.h>
  18. #include <linux/percpu.h>
  19. #include <linux/profile.h>
  20. #include <linux/sched.h>
  21. #include <linux/tick.h>
  22. #include "tick-internal.h"
  23. /*
  24. * Broadcast support for broken x86 hardware, where the local apic
  25. * timer stops in C3 state.
  26. */
  27. struct tick_device tick_broadcast_device;
  28. static cpumask_t tick_broadcast_mask;
  29. DEFINE_SPINLOCK(tick_broadcast_lock);
  30. /*
  31. * Start the device in periodic mode
  32. */
  33. static void tick_broadcast_start_periodic(struct clock_event_device *bc)
  34. {
  35. if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
  36. tick_setup_periodic(bc, 1);
  37. }
  38. /*
  39. * Check, if the device can be utilized as broadcast device:
  40. */
  41. int tick_check_broadcast_device(struct clock_event_device *dev)
  42. {
  43. if (tick_broadcast_device.evtdev ||
  44. (dev->features & CLOCK_EVT_FEAT_C3STOP))
  45. return 0;
  46. clockevents_exchange_device(NULL, dev);
  47. tick_broadcast_device.evtdev = dev;
  48. if (!cpus_empty(tick_broadcast_mask))
  49. tick_broadcast_start_periodic(dev);
  50. return 1;
  51. }
  52. /*
  53. * Check, if the device is the broadcast device
  54. */
  55. int tick_is_broadcast_device(struct clock_event_device *dev)
  56. {
  57. return (dev && tick_broadcast_device.evtdev == dev);
  58. }
  59. /*
  60. * Check, if the device is disfunctional and a place holder, which
  61. * needs to be handled by the broadcast device.
  62. */
  63. int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
  64. {
  65. unsigned long flags;
  66. int ret = 0;
  67. spin_lock_irqsave(&tick_broadcast_lock, flags);
  68. /*
  69. * Devices might be registered with both periodic and oneshot
  70. * mode disabled. This signals, that the device needs to be
  71. * operated from the broadcast device and is a placeholder for
  72. * the cpu local device.
  73. */
  74. if (!tick_device_is_functional(dev)) {
  75. dev->event_handler = tick_handle_periodic;
  76. cpu_set(cpu, tick_broadcast_mask);
  77. tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
  78. ret = 1;
  79. }
  80. spin_unlock_irqrestore(&tick_broadcast_lock, flags);
  81. return ret;
  82. }
  83. /*
  84. * Broadcast the event to the cpus, which are set in the mask
  85. */
  86. int tick_do_broadcast(cpumask_t mask)
  87. {
  88. int ret = 0, cpu = smp_processor_id();
  89. struct tick_device *td;
  90. /*
  91. * Check, if the current cpu is in the mask
  92. */
  93. if (cpu_isset(cpu, mask)) {
  94. cpu_clear(cpu, mask);
  95. td = &per_cpu(tick_cpu_device, cpu);
  96. td->evtdev->event_handler(td->evtdev);
  97. ret = 1;
  98. }
  99. if (!cpus_empty(mask)) {
  100. /*
  101. * It might be necessary to actually check whether the devices
  102. * have different broadcast functions. For now, just use the
  103. * one of the first device. This works as long as we have this
  104. * misfeature only on x86 (lapic)
  105. */
  106. cpu = first_cpu(mask);
  107. td = &per_cpu(tick_cpu_device, cpu);
  108. td->evtdev->broadcast(mask);
  109. ret = 1;
  110. }
  111. return ret;
  112. }
  113. /*
  114. * Periodic broadcast:
  115. * - invoke the broadcast handlers
  116. */
  117. static void tick_do_periodic_broadcast(void)
  118. {
  119. cpumask_t mask;
  120. spin_lock(&tick_broadcast_lock);
  121. cpus_and(mask, cpu_online_map, tick_broadcast_mask);
  122. tick_do_broadcast(mask);
  123. spin_unlock(&tick_broadcast_lock);
  124. }
  125. /*
  126. * Event handler for periodic broadcast ticks
  127. */
  128. static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
  129. {
  130. dev->next_event.tv64 = KTIME_MAX;
  131. tick_do_periodic_broadcast();
  132. /*
  133. * The device is in periodic mode. No reprogramming necessary:
  134. */
  135. if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
  136. return;
  137. /*
  138. * Setup the next period for devices, which do not have
  139. * periodic mode:
  140. */
  141. for (;;) {
  142. ktime_t next = ktime_add(dev->next_event, tick_period);
  143. if (!clockevents_program_event(dev, next, ktime_get()))
  144. return;
  145. tick_do_periodic_broadcast();
  146. }
  147. }
  148. /*
  149. * Powerstate information: The system enters/leaves a state, where
  150. * affected devices might stop
  151. */
  152. static void tick_do_broadcast_on_off(void *why)
  153. {
  154. struct clock_event_device *bc, *dev;
  155. struct tick_device *td;
  156. unsigned long flags, *reason = why;
  157. int cpu;
  158. spin_lock_irqsave(&tick_broadcast_lock, flags);
  159. cpu = smp_processor_id();
  160. td = &per_cpu(tick_cpu_device, cpu);
  161. dev = td->evtdev;
  162. bc = tick_broadcast_device.evtdev;
  163. /*
  164. * Is the device in broadcast mode forever or is it not
  165. * affected by the powerstate ?
  166. */
  167. if (!dev || !tick_device_is_functional(dev) ||
  168. !(dev->features & CLOCK_EVT_FEAT_C3STOP))
  169. goto out;
  170. if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_ON) {
  171. if (!cpu_isset(cpu, tick_broadcast_mask)) {
  172. cpu_set(cpu, tick_broadcast_mask);
  173. if (td->mode == TICKDEV_MODE_PERIODIC)
  174. clockevents_set_mode(dev,
  175. CLOCK_EVT_MODE_SHUTDOWN);
  176. }
  177. } else {
  178. if (cpu_isset(cpu, tick_broadcast_mask)) {
  179. cpu_clear(cpu, tick_broadcast_mask);
  180. if (td->mode == TICKDEV_MODE_PERIODIC)
  181. tick_setup_periodic(dev, 0);
  182. }
  183. }
  184. if (cpus_empty(tick_broadcast_mask))
  185. clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
  186. else {
  187. if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
  188. tick_broadcast_start_periodic(bc);
  189. }
  190. out:
  191. spin_unlock_irqrestore(&tick_broadcast_lock, flags);
  192. }
  193. /*
  194. * Powerstate information: The system enters/leaves a state, where
  195. * affected devices might stop.
  196. */
  197. void tick_broadcast_on_off(unsigned long reason, int *oncpu)
  198. {
  199. int cpu = get_cpu();
  200. if (cpu == *oncpu)
  201. tick_do_broadcast_on_off(&reason);
  202. else
  203. smp_call_function_single(*oncpu, tick_do_broadcast_on_off,
  204. &reason, 1, 1);
  205. put_cpu();
  206. }
  207. /*
  208. * Set the periodic handler depending on broadcast on/off
  209. */
  210. void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
  211. {
  212. if (!broadcast)
  213. dev->event_handler = tick_handle_periodic;
  214. else
  215. dev->event_handler = tick_handle_periodic_broadcast;
  216. }
  217. /*
  218. * Remove a CPU from broadcasting
  219. */
  220. void tick_shutdown_broadcast(unsigned int *cpup)
  221. {
  222. struct clock_event_device *bc;
  223. unsigned long flags;
  224. unsigned int cpu = *cpup;
  225. spin_lock_irqsave(&tick_broadcast_lock, flags);
  226. bc = tick_broadcast_device.evtdev;
  227. cpu_clear(cpu, tick_broadcast_mask);
  228. if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
  229. if (bc && cpus_empty(tick_broadcast_mask))
  230. clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
  231. }
  232. spin_unlock_irqrestore(&tick_broadcast_lock, flags);
  233. }