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