xref: /openbmc/linux/kernel/time/tick-common.c (revision f8381cba04ba8173fd5a2b8e5cd8b3290ee13a98)
1906568c9SThomas Gleixner /*
2906568c9SThomas Gleixner  * linux/kernel/time/tick-common.c
3906568c9SThomas Gleixner  *
4906568c9SThomas Gleixner  * This file contains the base functions to manage periodic tick
5906568c9SThomas Gleixner  * related events.
6906568c9SThomas Gleixner  *
7906568c9SThomas Gleixner  * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de>
8906568c9SThomas Gleixner  * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar
9906568c9SThomas Gleixner  * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner
10906568c9SThomas Gleixner  *
11906568c9SThomas Gleixner  * This code is licenced under the GPL version 2. For details see
12906568c9SThomas Gleixner  * kernel-base/COPYING.
13906568c9SThomas Gleixner  */
14906568c9SThomas Gleixner #include <linux/cpu.h>
15906568c9SThomas Gleixner #include <linux/err.h>
16906568c9SThomas Gleixner #include <linux/hrtimer.h>
17906568c9SThomas Gleixner #include <linux/irq.h>
18906568c9SThomas Gleixner #include <linux/percpu.h>
19906568c9SThomas Gleixner #include <linux/profile.h>
20906568c9SThomas Gleixner #include <linux/sched.h>
21906568c9SThomas Gleixner #include <linux/tick.h>
22906568c9SThomas Gleixner 
23*f8381cbaSThomas Gleixner #include "tick-internal.h"
24*f8381cbaSThomas Gleixner 
25906568c9SThomas Gleixner /*
26906568c9SThomas Gleixner  * Tick devices
27906568c9SThomas Gleixner  */
28*f8381cbaSThomas Gleixner DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
29906568c9SThomas Gleixner /*
30906568c9SThomas Gleixner  * Tick next event: keeps track of the tick time
31906568c9SThomas Gleixner  */
32*f8381cbaSThomas Gleixner ktime_t tick_next_period;
33*f8381cbaSThomas Gleixner ktime_t tick_period;
34906568c9SThomas Gleixner static int tick_do_timer_cpu = -1;
35*f8381cbaSThomas Gleixner DEFINE_SPINLOCK(tick_device_lock);
36906568c9SThomas Gleixner 
37906568c9SThomas Gleixner /*
38906568c9SThomas Gleixner  * Periodic tick
39906568c9SThomas Gleixner  */
40906568c9SThomas Gleixner static void tick_periodic(int cpu)
41906568c9SThomas Gleixner {
42906568c9SThomas Gleixner 	if (tick_do_timer_cpu == cpu) {
43906568c9SThomas Gleixner 		write_seqlock(&xtime_lock);
44906568c9SThomas Gleixner 
45906568c9SThomas Gleixner 		/* Keep track of the next tick event */
46906568c9SThomas Gleixner 		tick_next_period = ktime_add(tick_next_period, tick_period);
47906568c9SThomas Gleixner 
48906568c9SThomas Gleixner 		do_timer(1);
49906568c9SThomas Gleixner 		write_sequnlock(&xtime_lock);
50906568c9SThomas Gleixner 	}
51906568c9SThomas Gleixner 
52906568c9SThomas Gleixner 	update_process_times(user_mode(get_irq_regs()));
53906568c9SThomas Gleixner 	profile_tick(CPU_PROFILING);
54906568c9SThomas Gleixner }
55906568c9SThomas Gleixner 
56906568c9SThomas Gleixner /*
57906568c9SThomas Gleixner  * Event handler for periodic ticks
58906568c9SThomas Gleixner  */
59906568c9SThomas Gleixner void tick_handle_periodic(struct clock_event_device *dev)
60906568c9SThomas Gleixner {
61906568c9SThomas Gleixner 	int cpu = smp_processor_id();
62906568c9SThomas Gleixner 
63906568c9SThomas Gleixner 	tick_periodic(cpu);
64906568c9SThomas Gleixner 
65906568c9SThomas Gleixner 	if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
66906568c9SThomas Gleixner 		return;
67906568c9SThomas Gleixner 	/*
68906568c9SThomas Gleixner 	 * Setup the next period for devices, which do not have
69906568c9SThomas Gleixner 	 * periodic mode:
70906568c9SThomas Gleixner 	 */
71906568c9SThomas Gleixner 	for (;;) {
72906568c9SThomas Gleixner 		ktime_t next = ktime_add(dev->next_event, tick_period);
73906568c9SThomas Gleixner 
74906568c9SThomas Gleixner 		if (!clockevents_program_event(dev, next, ktime_get()))
75906568c9SThomas Gleixner 			return;
76906568c9SThomas Gleixner 		tick_periodic(cpu);
77906568c9SThomas Gleixner 	}
78906568c9SThomas Gleixner }
79906568c9SThomas Gleixner 
80906568c9SThomas Gleixner /*
81906568c9SThomas Gleixner  * Setup the device for a periodic tick
82906568c9SThomas Gleixner  */
83*f8381cbaSThomas Gleixner void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
84906568c9SThomas Gleixner {
85*f8381cbaSThomas Gleixner 	tick_set_periodic_handler(dev, broadcast);
86*f8381cbaSThomas Gleixner 
87*f8381cbaSThomas Gleixner 	/* Broadcast setup ? */
88*f8381cbaSThomas Gleixner 	if (!tick_device_is_functional(dev))
89*f8381cbaSThomas Gleixner 		return;
90906568c9SThomas Gleixner 
91906568c9SThomas Gleixner 	if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
92906568c9SThomas Gleixner 		clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
93906568c9SThomas Gleixner 	} else {
94906568c9SThomas Gleixner 		unsigned long seq;
95906568c9SThomas Gleixner 		ktime_t next;
96906568c9SThomas Gleixner 
97906568c9SThomas Gleixner 		do {
98906568c9SThomas Gleixner 			seq = read_seqbegin(&xtime_lock);
99906568c9SThomas Gleixner 			next = tick_next_period;
100906568c9SThomas Gleixner 		} while (read_seqretry(&xtime_lock, seq));
101906568c9SThomas Gleixner 
102906568c9SThomas Gleixner 		clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
103906568c9SThomas Gleixner 
104906568c9SThomas Gleixner 		for (;;) {
105906568c9SThomas Gleixner 			if (!clockevents_program_event(dev, next, ktime_get()))
106906568c9SThomas Gleixner 				return;
107906568c9SThomas Gleixner 			next = ktime_add(next, tick_period);
108906568c9SThomas Gleixner 		}
109906568c9SThomas Gleixner 	}
110906568c9SThomas Gleixner }
111906568c9SThomas Gleixner 
112906568c9SThomas Gleixner /*
113906568c9SThomas Gleixner  * Setup the tick device
114906568c9SThomas Gleixner  */
115906568c9SThomas Gleixner static void tick_setup_device(struct tick_device *td,
116906568c9SThomas Gleixner 			      struct clock_event_device *newdev, int cpu,
117906568c9SThomas Gleixner 			      cpumask_t cpumask)
118906568c9SThomas Gleixner {
119906568c9SThomas Gleixner 	ktime_t next_event;
120906568c9SThomas Gleixner 	void (*handler)(struct clock_event_device *) = NULL;
121906568c9SThomas Gleixner 
122906568c9SThomas Gleixner 	/*
123906568c9SThomas Gleixner 	 * First device setup ?
124906568c9SThomas Gleixner 	 */
125906568c9SThomas Gleixner 	if (!td->evtdev) {
126906568c9SThomas Gleixner 		/*
127906568c9SThomas Gleixner 		 * If no cpu took the do_timer update, assign it to
128906568c9SThomas Gleixner 		 * this cpu:
129906568c9SThomas Gleixner 		 */
130906568c9SThomas Gleixner 		if (tick_do_timer_cpu == -1) {
131906568c9SThomas Gleixner 			tick_do_timer_cpu = cpu;
132906568c9SThomas Gleixner 			tick_next_period = ktime_get();
133906568c9SThomas Gleixner 			tick_period = ktime_set(0, NSEC_PER_SEC / HZ);
134906568c9SThomas Gleixner 		}
135906568c9SThomas Gleixner 
136906568c9SThomas Gleixner 		/*
137906568c9SThomas Gleixner 		 * Startup in periodic mode first.
138906568c9SThomas Gleixner 		 */
139906568c9SThomas Gleixner 		td->mode = TICKDEV_MODE_PERIODIC;
140906568c9SThomas Gleixner 	} else {
141906568c9SThomas Gleixner 		handler = td->evtdev->event_handler;
142906568c9SThomas Gleixner 		next_event = td->evtdev->next_event;
143906568c9SThomas Gleixner 	}
144906568c9SThomas Gleixner 
145906568c9SThomas Gleixner 	td->evtdev = newdev;
146906568c9SThomas Gleixner 
147906568c9SThomas Gleixner 	/*
148906568c9SThomas Gleixner 	 * When the device is not per cpu, pin the interrupt to the
149906568c9SThomas Gleixner 	 * current cpu:
150906568c9SThomas Gleixner 	 */
151906568c9SThomas Gleixner 	if (!cpus_equal(newdev->cpumask, cpumask))
152906568c9SThomas Gleixner 		irq_set_affinity(newdev->irq, cpumask);
153906568c9SThomas Gleixner 
154*f8381cbaSThomas Gleixner 	/*
155*f8381cbaSThomas Gleixner 	 * When global broadcasting is active, check if the current
156*f8381cbaSThomas Gleixner 	 * device is registered as a placeholder for broadcast mode.
157*f8381cbaSThomas Gleixner 	 * This allows us to handle this x86 misfeature in a generic
158*f8381cbaSThomas Gleixner 	 * way.
159*f8381cbaSThomas Gleixner 	 */
160*f8381cbaSThomas Gleixner 	if (tick_device_uses_broadcast(newdev, cpu))
161*f8381cbaSThomas Gleixner 		return;
162*f8381cbaSThomas Gleixner 
163906568c9SThomas Gleixner 	if (td->mode == TICKDEV_MODE_PERIODIC)
164906568c9SThomas Gleixner 		tick_setup_periodic(newdev, 0);
165906568c9SThomas Gleixner }
166906568c9SThomas Gleixner 
167906568c9SThomas Gleixner /*
168906568c9SThomas Gleixner  * Check, if the new registered device should be used.
169906568c9SThomas Gleixner  */
170906568c9SThomas Gleixner static int tick_check_new_device(struct clock_event_device *newdev)
171906568c9SThomas Gleixner {
172906568c9SThomas Gleixner 	struct clock_event_device *curdev;
173906568c9SThomas Gleixner 	struct tick_device *td;
174906568c9SThomas Gleixner 	int cpu, ret = NOTIFY_OK;
175906568c9SThomas Gleixner 	unsigned long flags;
176906568c9SThomas Gleixner 	cpumask_t cpumask;
177906568c9SThomas Gleixner 
178906568c9SThomas Gleixner 	spin_lock_irqsave(&tick_device_lock, flags);
179906568c9SThomas Gleixner 
180906568c9SThomas Gleixner 	cpu = smp_processor_id();
181906568c9SThomas Gleixner 	if (!cpu_isset(cpu, newdev->cpumask))
182906568c9SThomas Gleixner 		goto out;
183906568c9SThomas Gleixner 
184906568c9SThomas Gleixner 	td = &per_cpu(tick_cpu_device, cpu);
185906568c9SThomas Gleixner 	curdev = td->evtdev;
186906568c9SThomas Gleixner 	cpumask = cpumask_of_cpu(cpu);
187906568c9SThomas Gleixner 
188906568c9SThomas Gleixner 	/* cpu local device ? */
189906568c9SThomas Gleixner 	if (!cpus_equal(newdev->cpumask, cpumask)) {
190906568c9SThomas Gleixner 
191906568c9SThomas Gleixner 		/*
192906568c9SThomas Gleixner 		 * If the cpu affinity of the device interrupt can not
193906568c9SThomas Gleixner 		 * be set, ignore it.
194906568c9SThomas Gleixner 		 */
195906568c9SThomas Gleixner 		if (!irq_can_set_affinity(newdev->irq))
196906568c9SThomas Gleixner 			goto out_bc;
197906568c9SThomas Gleixner 
198906568c9SThomas Gleixner 		/*
199906568c9SThomas Gleixner 		 * If we have a cpu local device already, do not replace it
200906568c9SThomas Gleixner 		 * by a non cpu local device
201906568c9SThomas Gleixner 		 */
202906568c9SThomas Gleixner 		if (curdev && cpus_equal(curdev->cpumask, cpumask))
203906568c9SThomas Gleixner 			goto out_bc;
204906568c9SThomas Gleixner 	}
205906568c9SThomas Gleixner 
206906568c9SThomas Gleixner 	/*
207906568c9SThomas Gleixner 	 * If we have an active device, then check the rating and the oneshot
208906568c9SThomas Gleixner 	 * feature.
209906568c9SThomas Gleixner 	 */
210906568c9SThomas Gleixner 	if (curdev) {
211906568c9SThomas Gleixner 		/*
212906568c9SThomas Gleixner 		 * Check the rating
213906568c9SThomas Gleixner 		 */
214906568c9SThomas Gleixner 		if (curdev->rating >= newdev->rating)
215*f8381cbaSThomas Gleixner 			goto out_bc;
216906568c9SThomas Gleixner 	}
217906568c9SThomas Gleixner 
218906568c9SThomas Gleixner 	/*
219906568c9SThomas Gleixner 	 * Replace the eventually existing device by the new
220*f8381cbaSThomas Gleixner 	 * device. If the current device is the broadcast device, do
221*f8381cbaSThomas Gleixner 	 * not give it back to the clockevents layer !
222906568c9SThomas Gleixner 	 */
223*f8381cbaSThomas Gleixner 	if (tick_is_broadcast_device(curdev)) {
224*f8381cbaSThomas Gleixner 		clockevents_set_mode(curdev, CLOCK_EVT_MODE_SHUTDOWN);
225*f8381cbaSThomas Gleixner 		curdev = NULL;
226*f8381cbaSThomas Gleixner 	}
227906568c9SThomas Gleixner 	clockevents_exchange_device(curdev, newdev);
228906568c9SThomas Gleixner 	tick_setup_device(td, newdev, cpu, cpumask);
229906568c9SThomas Gleixner 
230*f8381cbaSThomas Gleixner 	spin_unlock_irqrestore(&tick_device_lock, flags);
231*f8381cbaSThomas Gleixner 	return NOTIFY_STOP;
232*f8381cbaSThomas Gleixner 
233*f8381cbaSThomas Gleixner out_bc:
234*f8381cbaSThomas Gleixner 	/*
235*f8381cbaSThomas Gleixner 	 * Can the new device be used as a broadcast device ?
236*f8381cbaSThomas Gleixner 	 */
237*f8381cbaSThomas Gleixner 	if (tick_check_broadcast_device(newdev))
238*f8381cbaSThomas Gleixner 		ret = NOTIFY_STOP;
239906568c9SThomas Gleixner out:
240906568c9SThomas Gleixner 	spin_unlock_irqrestore(&tick_device_lock, flags);
241*f8381cbaSThomas Gleixner 
242906568c9SThomas Gleixner 	return ret;
243906568c9SThomas Gleixner }
244906568c9SThomas Gleixner 
245906568c9SThomas Gleixner /*
246906568c9SThomas Gleixner  * Shutdown an event device on a given cpu:
247906568c9SThomas Gleixner  *
248906568c9SThomas Gleixner  * This is called on a life CPU, when a CPU is dead. So we cannot
249906568c9SThomas Gleixner  * access the hardware device itself.
250906568c9SThomas Gleixner  * We just set the mode and remove it from the lists.
251906568c9SThomas Gleixner  */
252906568c9SThomas Gleixner static void tick_shutdown(unsigned int *cpup)
253906568c9SThomas Gleixner {
254906568c9SThomas Gleixner 	struct tick_device *td = &per_cpu(tick_cpu_device, *cpup);
255906568c9SThomas Gleixner 	struct clock_event_device *dev = td->evtdev;
256906568c9SThomas Gleixner 	unsigned long flags;
257906568c9SThomas Gleixner 
258906568c9SThomas Gleixner 	spin_lock_irqsave(&tick_device_lock, flags);
259906568c9SThomas Gleixner 	td->mode = TICKDEV_MODE_PERIODIC;
260906568c9SThomas Gleixner 	if (dev) {
261906568c9SThomas Gleixner 		/*
262906568c9SThomas Gleixner 		 * Prevent that the clock events layer tries to call
263906568c9SThomas Gleixner 		 * the set mode function!
264906568c9SThomas Gleixner 		 */
265906568c9SThomas Gleixner 		dev->mode = CLOCK_EVT_MODE_UNUSED;
266906568c9SThomas Gleixner 		clockevents_exchange_device(dev, NULL);
267906568c9SThomas Gleixner 		td->evtdev = NULL;
268906568c9SThomas Gleixner 	}
269906568c9SThomas Gleixner 	spin_unlock_irqrestore(&tick_device_lock, flags);
270906568c9SThomas Gleixner }
271906568c9SThomas Gleixner 
272906568c9SThomas Gleixner /*
273906568c9SThomas Gleixner  * Notification about clock event devices
274906568c9SThomas Gleixner  */
275906568c9SThomas Gleixner static int tick_notify(struct notifier_block *nb, unsigned long reason,
276906568c9SThomas Gleixner 			       void *dev)
277906568c9SThomas Gleixner {
278906568c9SThomas Gleixner 	switch (reason) {
279906568c9SThomas Gleixner 
280906568c9SThomas Gleixner 	case CLOCK_EVT_NOTIFY_ADD:
281906568c9SThomas Gleixner 		return tick_check_new_device(dev);
282906568c9SThomas Gleixner 
283*f8381cbaSThomas Gleixner 	case CLOCK_EVT_NOTIFY_BROADCAST_ON:
284*f8381cbaSThomas Gleixner 	case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
285*f8381cbaSThomas Gleixner 		tick_broadcast_on_off(reason, dev);
286*f8381cbaSThomas Gleixner 		break;
287*f8381cbaSThomas Gleixner 
288906568c9SThomas Gleixner 	case CLOCK_EVT_NOTIFY_CPU_DEAD:
289*f8381cbaSThomas Gleixner 		tick_shutdown_broadcast(dev);
290906568c9SThomas Gleixner 		tick_shutdown(dev);
291906568c9SThomas Gleixner 		break;
292906568c9SThomas Gleixner 
293906568c9SThomas Gleixner 	default:
294906568c9SThomas Gleixner 		break;
295906568c9SThomas Gleixner 	}
296906568c9SThomas Gleixner 
297906568c9SThomas Gleixner 	return NOTIFY_OK;
298906568c9SThomas Gleixner }
299906568c9SThomas Gleixner 
300906568c9SThomas Gleixner static struct notifier_block tick_notifier = {
301906568c9SThomas Gleixner 	.notifier_call = tick_notify,
302906568c9SThomas Gleixner };
303906568c9SThomas Gleixner 
304906568c9SThomas Gleixner /**
305906568c9SThomas Gleixner  * tick_init - initialize the tick control
306906568c9SThomas Gleixner  *
307906568c9SThomas Gleixner  * Register the notifier with the clockevents framework
308906568c9SThomas Gleixner  */
309906568c9SThomas Gleixner void __init tick_init(void)
310906568c9SThomas Gleixner {
311906568c9SThomas Gleixner 	clockevents_register_notifier(&tick_notifier);
312906568c9SThomas Gleixner }
313