1 /* 2 * linux/kernel/time/tick-oneshot.c 3 * 4 * This file contains functions which manage high resolution 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/interrupt.h> 18 #include <linux/percpu.h> 19 #include <linux/profile.h> 20 #include <linux/sched.h> 21 22 #include "tick-internal.h" 23 24 /* Limit min_delta to a jiffie */ 25 #define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) 26 27 static int tick_increase_min_delta(struct clock_event_device *dev) 28 { 29 /* Nothing to do if we already reached the limit */ 30 if (dev->min_delta_ns >= MIN_DELTA_LIMIT) 31 return -ETIME; 32 33 if (dev->min_delta_ns < 5000) 34 dev->min_delta_ns = 5000; 35 else 36 dev->min_delta_ns += dev->min_delta_ns >> 1; 37 38 if (dev->min_delta_ns > MIN_DELTA_LIMIT) 39 dev->min_delta_ns = MIN_DELTA_LIMIT; 40 41 printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", 42 dev->name ? dev->name : "?", 43 (unsigned long long) dev->min_delta_ns); 44 return 0; 45 } 46 47 /** 48 * tick_program_event internal worker function 49 */ 50 int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, 51 int force) 52 { 53 ktime_t now = ktime_get(); 54 int i; 55 56 for (i = 0;;) { 57 int ret = clockevents_program_event(dev, expires, now); 58 59 if (!ret || !force) 60 return ret; 61 62 dev->retries++; 63 /* 64 * We tried 3 times to program the device with the given 65 * min_delta_ns. If that's not working then we increase it 66 * and emit a warning. 67 */ 68 if (++i > 2) { 69 /* Increase the min. delta and try again */ 70 if (tick_increase_min_delta(dev)) { 71 /* 72 * Get out of the loop if min_delta_ns 73 * hit the limit already. That's 74 * better than staying here forever. 75 * 76 * We clear next_event so we have a 77 * chance that the box survives. 78 */ 79 printk(KERN_WARNING 80 "CE: Reprogramming failure. Giving up\n"); 81 dev->next_event.tv64 = KTIME_MAX; 82 return -ETIME; 83 } 84 i = 0; 85 } 86 87 now = ktime_get(); 88 expires = ktime_add_ns(now, dev->min_delta_ns); 89 } 90 } 91 92 /** 93 * tick_program_event 94 */ 95 int tick_program_event(ktime_t expires, int force) 96 { 97 struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); 98 99 return tick_dev_program_event(dev, expires, force); 100 } 101 102 /** 103 * tick_resume_onshot - resume oneshot mode 104 */ 105 void tick_resume_oneshot(void) 106 { 107 struct tick_device *td = &__get_cpu_var(tick_cpu_device); 108 struct clock_event_device *dev = td->evtdev; 109 110 clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); 111 tick_program_event(ktime_get(), 1); 112 } 113 114 /** 115 * tick_setup_oneshot - setup the event device for oneshot mode (hres or nohz) 116 */ 117 void tick_setup_oneshot(struct clock_event_device *newdev, 118 void (*handler)(struct clock_event_device *), 119 ktime_t next_event) 120 { 121 newdev->event_handler = handler; 122 clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); 123 tick_dev_program_event(newdev, next_event, 1); 124 } 125 126 /** 127 * tick_switch_to_oneshot - switch to oneshot mode 128 */ 129 int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) 130 { 131 struct tick_device *td = &__get_cpu_var(tick_cpu_device); 132 struct clock_event_device *dev = td->evtdev; 133 134 if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || 135 !tick_device_is_functional(dev)) { 136 137 printk(KERN_INFO "Clockevents: " 138 "could not switch to one-shot mode:"); 139 if (!dev) { 140 printk(" no tick device\n"); 141 } else { 142 if (!tick_device_is_functional(dev)) 143 printk(" %s is not functional.\n", dev->name); 144 else 145 printk(" %s does not support one-shot mode.\n", 146 dev->name); 147 } 148 return -EINVAL; 149 } 150 151 td->mode = TICKDEV_MODE_ONESHOT; 152 dev->event_handler = handler; 153 clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); 154 tick_broadcast_switch_to_oneshot(); 155 return 0; 156 } 157 158 /** 159 * tick_check_oneshot_mode - check whether the system is in oneshot mode 160 * 161 * returns 1 when either nohz or highres are enabled. otherwise 0. 162 */ 163 int tick_oneshot_mode_active(void) 164 { 165 unsigned long flags; 166 int ret; 167 168 local_irq_save(flags); 169 ret = __this_cpu_read(tick_cpu_device.mode) == TICKDEV_MODE_ONESHOT; 170 local_irq_restore(flags); 171 172 return ret; 173 } 174 175 #ifdef CONFIG_HIGH_RES_TIMERS 176 /** 177 * tick_init_highres - switch to high resolution mode 178 * 179 * Called with interrupts disabled. 180 */ 181 int tick_init_highres(void) 182 { 183 return tick_switch_to_oneshot(hrtimer_interrupt); 184 } 185 #endif 186