diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-04-25 16:31:50 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-05-16 05:09:17 -0400 |
commit | 45cb8e01b2ecef1c2afb18333e95793fa1a90281 (patch) | |
tree | 9528babbf50046bffca4270952af0b5a38f56895 /kernel/time | |
parent | 501f867064e95f9a6f540e60705be0937280e7ec (diff) |
clockevents: Split out selection logic
Split out the clockevent device selection logic. Preparatory patch to
allow unbinding active clockevent devices.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Magnus Damm <magnus.damm@gmail.com>
Link: http://lkml.kernel.org/r/20130425143436.431796247@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/tick-broadcast.c | 25 | ||||
-rw-r--r-- | kernel/time/tick-common.c | 69 |
2 files changed, 56 insertions, 38 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 0e374cd2e0ef..d067c01586f5 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
@@ -65,19 +65,34 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) | |||
65 | /* | 65 | /* |
66 | * Check, if the device can be utilized as broadcast device: | 66 | * Check, if the device can be utilized as broadcast device: |
67 | */ | 67 | */ |
68 | static bool tick_check_broadcast_device(struct clock_event_device *curdev, | ||
69 | struct clock_event_device *newdev) | ||
70 | { | ||
71 | if ((newdev->features & CLOCK_EVT_FEAT_DUMMY) || | ||
72 | (newdev->features & CLOCK_EVT_FEAT_C3STOP)) | ||
73 | return false; | ||
74 | |||
75 | if (tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT && | ||
76 | !(newdev->features & CLOCK_EVT_FEAT_ONESHOT)) | ||
77 | return false; | ||
78 | |||
79 | return !curdev || newdev->rating > curdev->rating; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Conditionally install/replace broadcast device | ||
84 | */ | ||
68 | void tick_install_broadcast_device(struct clock_event_device *dev) | 85 | void tick_install_broadcast_device(struct clock_event_device *dev) |
69 | { | 86 | { |
70 | struct clock_event_device *cur = tick_broadcast_device.evtdev; | 87 | struct clock_event_device *cur = tick_broadcast_device.evtdev; |
71 | 88 | ||
72 | if ((dev->features & CLOCK_EVT_FEAT_DUMMY) || | 89 | if (!tick_check_broadcast_device(cur, dev)) |
73 | (tick_broadcast_device.evtdev && | ||
74 | tick_broadcast_device.evtdev->rating >= dev->rating) || | ||
75 | (dev->features & CLOCK_EVT_FEAT_C3STOP)) | ||
76 | return; | 90 | return; |
91 | |||
77 | if (!try_module_get(dev->owner)) | 92 | if (!try_module_get(dev->owner)) |
78 | return; | 93 | return; |
79 | 94 | ||
80 | clockevents_exchange_device(tick_broadcast_device.evtdev, dev); | 95 | clockevents_exchange_device(cur, dev); |
81 | if (cur) | 96 | if (cur) |
82 | cur->event_handler = clockevents_handle_noop; | 97 | cur->event_handler = clockevents_handle_noop; |
83 | tick_broadcast_device.evtdev = dev; | 98 | tick_broadcast_device.evtdev = dev; |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 433a1e11d13b..c34021650348 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
@@ -205,6 +205,37 @@ static void tick_setup_device(struct tick_device *td, | |||
205 | tick_setup_oneshot(newdev, handler, next_event); | 205 | tick_setup_oneshot(newdev, handler, next_event); |
206 | } | 206 | } |
207 | 207 | ||
208 | static bool tick_check_percpu(struct clock_event_device *curdev, | ||
209 | struct clock_event_device *newdev, int cpu) | ||
210 | { | ||
211 | if (!cpumask_test_cpu(cpu, newdev->cpumask)) | ||
212 | return false; | ||
213 | if (cpumask_equal(newdev->cpumask, cpumask_of(cpu))) | ||
214 | return true; | ||
215 | /* Check if irq affinity can be set */ | ||
216 | if (newdev->irq >= 0 && !irq_can_set_affinity(newdev->irq)) | ||
217 | return false; | ||
218 | /* Prefer an existing cpu local device */ | ||
219 | if (curdev && cpumask_equal(curdev->cpumask, cpumask_of(cpu))) | ||
220 | return false; | ||
221 | return true; | ||
222 | } | ||
223 | |||
224 | static bool tick_check_preferred(struct clock_event_device *curdev, | ||
225 | struct clock_event_device *newdev) | ||
226 | { | ||
227 | /* Prefer oneshot capable device */ | ||
228 | if (!(newdev->features & CLOCK_EVT_FEAT_ONESHOT)) { | ||
229 | if (curdev && (curdev->features & CLOCK_EVT_FEAT_ONESHOT)) | ||
230 | return false; | ||
231 | if (tick_oneshot_mode_active()) | ||
232 | return false; | ||
233 | } | ||
234 | |||
235 | /* Use the higher rated one */ | ||
236 | return !curdev || newdev->rating > curdev->rating; | ||
237 | } | ||
238 | |||
208 | /* | 239 | /* |
209 | * Check, if the new registered device should be used. Called with | 240 | * Check, if the new registered device should be used. Called with |
210 | * clockevents_lock held and interrupts disabled. | 241 | * clockevents_lock held and interrupts disabled. |
@@ -223,40 +254,12 @@ void tick_check_new_device(struct clock_event_device *newdev) | |||
223 | curdev = td->evtdev; | 254 | curdev = td->evtdev; |
224 | 255 | ||
225 | /* cpu local device ? */ | 256 | /* cpu local device ? */ |
226 | if (!cpumask_equal(newdev->cpumask, cpumask_of(cpu))) { | 257 | if (!tick_check_percpu(curdev, newdev, cpu)) |
227 | 258 | goto out_bc; | |
228 | /* | ||
229 | * If the cpu affinity of the device interrupt can not | ||
230 | * be set, ignore it. | ||
231 | */ | ||
232 | if (!irq_can_set_affinity(newdev->irq)) | ||
233 | goto out_bc; | ||
234 | |||
235 | /* | ||
236 | * If we have a cpu local device already, do not replace it | ||
237 | * by a non cpu local device | ||
238 | */ | ||
239 | if (curdev && cpumask_equal(curdev->cpumask, cpumask_of(cpu))) | ||
240 | goto out_bc; | ||
241 | } | ||
242 | 259 | ||
243 | /* | 260 | /* Preference decision */ |
244 | * If we have an active device, then check the rating and the oneshot | 261 | if (!tick_check_preferred(curdev, newdev)) |
245 | * feature. | 262 | goto out_bc; |
246 | */ | ||
247 | if (curdev) { | ||
248 | /* | ||
249 | * Prefer one shot capable devices ! | ||
250 | */ | ||
251 | if ((curdev->features & CLOCK_EVT_FEAT_ONESHOT) && | ||
252 | !(newdev->features & CLOCK_EVT_FEAT_ONESHOT)) | ||
253 | goto out_bc; | ||
254 | /* | ||
255 | * Check the rating | ||
256 | */ | ||
257 | if (curdev->rating >= newdev->rating) | ||
258 | goto out_bc; | ||
259 | } | ||
260 | 263 | ||
261 | if (!try_module_get(newdev->owner)) | 264 | if (!try_module_get(newdev->owner)) |
262 | return; | 265 | return; |