aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-broadcast.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/tick-broadcast.c')
-rw-r--r--kernel/time/tick-broadcast.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f113755695e2..7f32fe0e52cd 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -18,6 +18,7 @@
18#include <linux/percpu.h> 18#include <linux/percpu.h>
19#include <linux/profile.h> 19#include <linux/profile.h>
20#include <linux/sched.h> 20#include <linux/sched.h>
21#include <linux/smp.h>
21 22
22#include "tick-internal.h" 23#include "tick-internal.h"
23 24
@@ -66,7 +67,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
66 */ 67 */
67int tick_check_broadcast_device(struct clock_event_device *dev) 68int tick_check_broadcast_device(struct clock_event_device *dev)
68{ 69{
69 if ((tick_broadcast_device.evtdev && 70 if ((dev->features & CLOCK_EVT_FEAT_DUMMY) ||
71 (tick_broadcast_device.evtdev &&
70 tick_broadcast_device.evtdev->rating >= dev->rating) || 72 tick_broadcast_device.evtdev->rating >= dev->rating) ||
71 (dev->features & CLOCK_EVT_FEAT_C3STOP)) 73 (dev->features & CLOCK_EVT_FEAT_C3STOP))
72 return 0; 74 return 0;
@@ -86,6 +88,22 @@ int tick_is_broadcast_device(struct clock_event_device *dev)
86 return (dev && tick_broadcast_device.evtdev == dev); 88 return (dev && tick_broadcast_device.evtdev == dev);
87} 89}
88 90
91static void err_broadcast(const struct cpumask *mask)
92{
93 pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
94}
95
96static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
97{
98 if (!dev->broadcast)
99 dev->broadcast = tick_broadcast;
100 if (!dev->broadcast) {
101 pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
102 dev->name);
103 dev->broadcast = err_broadcast;
104 }
105}
106
89/* 107/*
90 * Check, if the device is disfunctional and a place holder, which 108 * Check, if the device is disfunctional and a place holder, which
91 * needs to be handled by the broadcast device. 109 * needs to be handled by the broadcast device.
@@ -105,6 +123,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
105 */ 123 */
106 if (!tick_device_is_functional(dev)) { 124 if (!tick_device_is_functional(dev)) {
107 dev->event_handler = tick_handle_periodic; 125 dev->event_handler = tick_handle_periodic;
126 tick_device_setup_broadcast_func(dev);
108 cpumask_set_cpu(cpu, tick_get_broadcast_mask()); 127 cpumask_set_cpu(cpu, tick_get_broadcast_mask());
109 tick_broadcast_start_periodic(tick_broadcast_device.evtdev); 128 tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
110 ret = 1; 129 ret = 1;
@@ -116,15 +135,33 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
116 */ 135 */
117 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { 136 if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
118 int cpu = smp_processor_id(); 137 int cpu = smp_processor_id();
119
120 cpumask_clear_cpu(cpu, tick_get_broadcast_mask()); 138 cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
121 tick_broadcast_clear_oneshot(cpu); 139 tick_broadcast_clear_oneshot(cpu);
140 } else {
141 tick_device_setup_broadcast_func(dev);
122 } 142 }
123 } 143 }
124 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); 144 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
125 return ret; 145 return ret;
126} 146}
127 147
148#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
149int tick_receive_broadcast(void)
150{
151 struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
152 struct clock_event_device *evt = td->evtdev;
153
154 if (!evt)
155 return -ENODEV;
156
157 if (!evt->event_handler)
158 return -EINVAL;
159
160 evt->event_handler(evt);
161 return 0;
162}
163#endif
164
128/* 165/*
129 * Broadcast the event to the cpus, which are set in the mask (mangled). 166 * Broadcast the event to the cpus, which are set in the mask (mangled).
130 */ 167 */