[PATCH] tick-management: core functionality
[powerpc.git] / kernel / time / tick-common.c
1 /*
2  * linux/kernel/time/tick-common.c
3  *
4  * This file contains the base functions to manage periodic tick
5  * related events.
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
23 /*
24  * Tick devices
25  */
26 static DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
27 /*
28  * Tick next event: keeps track of the tick time
29  */
30 static ktime_t tick_next_period;
31 static ktime_t tick_period;
32 static int tick_do_timer_cpu = -1;
33 static DEFINE_SPINLOCK(tick_device_lock);
34
35 /*
36  * Periodic tick
37  */
38 static void tick_periodic(int cpu)
39 {
40         if (tick_do_timer_cpu == cpu) {
41                 write_seqlock(&xtime_lock);
42
43                 /* Keep track of the next tick event */
44                 tick_next_period = ktime_add(tick_next_period, tick_period);
45
46                 do_timer(1);
47                 write_sequnlock(&xtime_lock);
48         }
49
50         update_process_times(user_mode(get_irq_regs()));
51         profile_tick(CPU_PROFILING);
52 }
53
54 /*
55  * Event handler for periodic ticks
56  */
57 void tick_handle_periodic(struct clock_event_device *dev)
58 {
59         int cpu = smp_processor_id();
60
61         tick_periodic(cpu);
62
63         if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
64                 return;
65         /*
66          * Setup the next period for devices, which do not have
67          * periodic mode:
68          */
69         for (;;) {
70                 ktime_t next = ktime_add(dev->next_event, tick_period);
71
72                 if (!clockevents_program_event(dev, next, ktime_get()))
73                         return;
74                 tick_periodic(cpu);
75         }
76 }
77
78 /*
79  * Setup the device for a periodic tick
80  */
81 void tick_setup_periodic(struct clock_event_device *dev)
82 {
83         dev->event_handler = tick_handle_periodic;
84
85         if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
86                 clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
87         } else {
88                 unsigned long seq;
89                 ktime_t next;
90
91                 do {
92                         seq = read_seqbegin(&xtime_lock);
93                         next = tick_next_period;
94                 } while (read_seqretry(&xtime_lock, seq));
95
96                 clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
97
98                 for (;;) {
99                         if (!clockevents_program_event(dev, next, ktime_get()))
100                                 return;
101                         next = ktime_add(next, tick_period);
102                 }
103         }
104 }
105
106 /*
107  * Setup the tick device
108  */
109 static void tick_setup_device(struct tick_device *td,
110                               struct clock_event_device *newdev, int cpu,
111                               cpumask_t cpumask)
112 {
113         ktime_t next_event;
114         void (*handler)(struct clock_event_device *) = NULL;
115
116         /*
117          * First device setup ?
118          */
119         if (!td->evtdev) {
120                 /*
121                  * If no cpu took the do_timer update, assign it to
122                  * this cpu:
123                  */
124                 if (tick_do_timer_cpu == -1) {
125                         tick_do_timer_cpu = cpu;
126                         tick_next_period = ktime_get();
127                         tick_period = ktime_set(0, NSEC_PER_SEC / HZ);
128                 }
129
130                 /*
131                  * Startup in periodic mode first.
132                  */
133                 td->mode = TICKDEV_MODE_PERIODIC;
134         } else {
135                 handler = td->evtdev->event_handler;
136                 next_event = td->evtdev->next_event;
137         }
138
139         td->evtdev = newdev;
140
141         /*
142          * When the device is not per cpu, pin the interrupt to the
143          * current cpu:
144          */
145         if (!cpus_equal(newdev->cpumask, cpumask))
146                 irq_set_affinity(newdev->irq, cpumask);
147
148         if (td->mode == TICKDEV_MODE_PERIODIC)
149                 tick_setup_periodic(newdev, 0);
150 }
151
152 /*
153  * Check, if the new registered device should be used.
154  */
155 static int tick_check_new_device(struct clock_event_device *newdev)
156 {
157         struct clock_event_device *curdev;
158         struct tick_device *td;
159         int cpu, ret = NOTIFY_OK;
160         unsigned long flags;
161         cpumask_t cpumask;
162
163         spin_lock_irqsave(&tick_device_lock, flags);
164
165         cpu = smp_processor_id();
166         if (!cpu_isset(cpu, newdev->cpumask))
167                 goto out;
168
169         td = &per_cpu(tick_cpu_device, cpu);
170         curdev = td->evtdev;
171         cpumask = cpumask_of_cpu(cpu);
172
173         /* cpu local device ? */
174         if (!cpus_equal(newdev->cpumask, cpumask)) {
175
176                 /*
177                  * If the cpu affinity of the device interrupt can not
178                  * be set, ignore it.
179                  */
180                 if (!irq_can_set_affinity(newdev->irq))
181                         goto out_bc;
182
183                 /*
184                  * If we have a cpu local device already, do not replace it
185                  * by a non cpu local device
186                  */
187                 if (curdev && cpus_equal(curdev->cpumask, cpumask))
188                         goto out_bc;
189         }
190
191         /*
192          * If we have an active device, then check the rating and the oneshot
193          * feature.
194          */
195         if (curdev) {
196                 /*
197                  * Check the rating
198                  */
199                 if (curdev->rating >= newdev->rating)
200                         goto out;
201         }
202
203         /*
204          * Replace the eventually existing device by the new
205          * device.
206          */
207         clockevents_exchange_device(curdev, newdev);
208         tick_setup_device(td, newdev, cpu, cpumask);
209         ret = NOTIFY_STOP;
210
211 out:
212         spin_unlock_irqrestore(&tick_device_lock, flags);
213         return ret;
214 }
215
216 /*
217  * Shutdown an event device on a given cpu:
218  *
219  * This is called on a life CPU, when a CPU is dead. So we cannot
220  * access the hardware device itself.
221  * We just set the mode and remove it from the lists.
222  */
223 static void tick_shutdown(unsigned int *cpup)
224 {
225         struct tick_device *td = &per_cpu(tick_cpu_device, *cpup);
226         struct clock_event_device *dev = td->evtdev;
227         unsigned long flags;
228
229         spin_lock_irqsave(&tick_device_lock, flags);
230         td->mode = TICKDEV_MODE_PERIODIC;
231         if (dev) {
232                 /*
233                  * Prevent that the clock events layer tries to call
234                  * the set mode function!
235                  */
236                 dev->mode = CLOCK_EVT_MODE_UNUSED;
237                 clockevents_exchange_device(dev, NULL);
238                 td->evtdev = NULL;
239         }
240         spin_unlock_irqrestore(&tick_device_lock, flags);
241 }
242
243 /*
244  * Notification about clock event devices
245  */
246 static int tick_notify(struct notifier_block *nb, unsigned long reason,
247                                void *dev)
248 {
249         switch (reason) {
250
251         case CLOCK_EVT_NOTIFY_ADD:
252                 return tick_check_new_device(dev);
253
254         case CLOCK_EVT_NOTIFY_CPU_DEAD:
255                 tick_shutdown(dev);
256                 break;
257
258         default:
259                 break;
260         }
261
262         return NOTIFY_OK;
263 }
264
265 static struct notifier_block tick_notifier = {
266         .notifier_call = tick_notify,
267 };
268
269 /**
270  * tick_init - initialize the tick control
271  *
272  * Register the notifier with the clockevents framework
273  */
274 void __init tick_init(void)
275 {
276         clockevents_register_notifier(&tick_notifier);
277 }