This adds basic NO_IDLE_HZ support to the SH timer API so timers are able to wire it up. Taken from the ARM version, as it fit in to our API with very few changes needed.
···423423 default "140" if CPU_SUBTYPE_SH7206424424 default "16"425425426426+config NO_IDLE_HZ427427+ bool "Dynamic tick timer"428428+ help429429+ Select this option if you want to disable continuous timer ticks430430+ and have them programmed to occur as required. This option saves431431+ power as the system can remain in idle state for longer.432432+433433+ By default dynamic tick is disabled during the boot, and can be434434+ manually enabled with:435435+436436+ echo 1 > /sys/devices/system/timer/timer0/dyn_tick437437+438438+ Alternatively, if you want dynamic tick automatically enabled439439+ during boot, pass "dyntick=enable" via the kernel command string.440440+441441+ Please note that dynamic tick may affect the accuracy of442442+ timekeeping on some platforms depending on the implementation.443443+426444config SH_PCLK_FREQ427445 int "Peripheral clock frequency (in Hz)"428446 default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
+123-1
arch/sh/kernel/time.c
···174174 .resume = timer_resume,175175};176176177177+#ifdef CONFIG_NO_IDLE_HZ178178+static int timer_dyn_tick_enable(void)179179+{180180+ struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;181181+ unsigned long flags;182182+ int ret = -ENODEV;183183+184184+ if (dyn_tick) {185185+ spin_lock_irqsave(&dyn_tick->lock, flags);186186+ ret = 0;187187+ if (!(dyn_tick->state & DYN_TICK_ENABLED)) {188188+ ret = dyn_tick->enable();189189+190190+ if (ret == 0)191191+ dyn_tick->state |= DYN_TICK_ENABLED;192192+ }193193+ spin_unlock_irqrestore(&dyn_tick->lock, flags);194194+ }195195+196196+ return ret;197197+}198198+199199+static int timer_dyn_tick_disable(void)200200+{201201+ struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;202202+ unsigned long flags;203203+ int ret = -ENODEV;204204+205205+ if (dyn_tick) {206206+ spin_lock_irqsave(&dyn_tick->lock, flags);207207+ ret = 0;208208+ if (dyn_tick->state & DYN_TICK_ENABLED) {209209+ ret = dyn_tick->disable();210210+211211+ if (ret == 0)212212+ dyn_tick->state &= ~DYN_TICK_ENABLED;213213+ }214214+ spin_unlock_irqrestore(&dyn_tick->lock, flags);215215+ }216216+217217+ return ret;218218+}219219+220220+/*221221+ * Reprogram the system timer for at least the calculated time interval.222222+ * This function should be called from the idle thread with IRQs disabled,223223+ * immediately before sleeping.224224+ */225225+void timer_dyn_reprogram(void)226226+{227227+ struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;228228+ unsigned long next, seq, flags;229229+230230+ if (!dyn_tick)231231+ return;232232+233233+ spin_lock_irqsave(&dyn_tick->lock, flags);234234+ if (dyn_tick->state & DYN_TICK_ENABLED) {235235+ next = next_timer_interrupt();236236+ do {237237+ seq = read_seqbegin(&xtime_lock);238238+ dyn_tick->reprogram(next - jiffies);239239+ } while (read_seqretry(&xtime_lock, seq));240240+ }241241+ spin_unlock_irqrestore(&dyn_tick->lock, flags);242242+}243243+244244+static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)245245+{246246+ return sprintf(buf, "%i\n",247247+ (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);248248+}249249+250250+static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,251251+ size_t count)252252+{253253+ unsigned int enable = simple_strtoul(buf, NULL, 2);254254+255255+ if (enable)256256+ timer_dyn_tick_enable();257257+ else258258+ timer_dyn_tick_disable();259259+260260+ return count;261261+}262262+static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);263263+264264+/*265265+ * dyntick=enable|disable266266+ */267267+static char dyntick_str[4] __initdata = "";268268+269269+static int __init dyntick_setup(char *str)270270+{271271+ if (str)272272+ strlcpy(dyntick_str, str, sizeof(dyntick_str));273273+ return 1;274274+}275275+276276+__setup("dyntick=", dyntick_setup);277277+#endif278278+177279static int __init timer_init_sysfs(void)178280{179281 int ret = sysdev_class_register(&timer_sysclass);···283181 return ret;284182285183 sys_timer->dev.cls = &timer_sysclass;286286- return sysdev_register(&sys_timer->dev);184184+ ret = sysdev_register(&sys_timer->dev);185185+186186+#ifdef CONFIG_NO_IDLE_HZ187187+ if (ret == 0 && sys_timer->dyn_tick) {188188+ ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);189189+190190+ /*191191+ * Turn on dynamic tick after calibrate delay192192+ * for correct bogomips193193+ */194194+ if (ret == 0 && dyntick_str[0] == 'e')195195+ ret = timer_dyn_tick_enable();196196+ }197197+#endif198198+199199+ return ret;287200}288201device_initcall(timer_init_sysfs);289202···321204 */322205 sys_timer = get_sys_timer();323206 printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);207207+208208+#ifdef CONFIG_NO_IDLE_HZ209209+ if (sys_timer->dyn_tick)210210+ spin_lock_init(&sys_timer->dyn_tick->lock);211211+#endif324212325213#if defined(CONFIG_SH_KGDB)326214 /*
+21
include/asm-sh/timer.h
···18181919 struct sys_device dev;2020 struct sys_timer_ops *ops;2121+2222+#ifdef CONFIG_NO_IDLE_HZ2323+ struct dyn_tick_timer *dyn_tick;2424+#endif2125};2626+2727+#ifdef CONFIG_NO_IDLE_HZ2828+#define DYN_TICK_ENABLED (1 << 1)2929+3030+struct dyn_tick_timer {3131+ spinlock_t lock;3232+ unsigned int state; /* Current state */3333+ int (*enable)(void); /* Enables dynamic tick */3434+ int (*disable)(void); /* Disables dynamic tick */3535+ void (*reprogram)(unsigned long); /* Reprograms the timer */3636+ int (*handler)(int, void *);3737+};3838+3939+void timer_dyn_reprogram(void);4040+#else4141+#define timer_dyn_reprogram() do { } while (0)4242+#endif22432344#define TICK_SIZE (tick_nsec / 1000)2445