1734efb46Sjohn stultz /* 2734efb46Sjohn stultz * linux/kernel/time/clocksource.c 3734efb46Sjohn stultz * 4734efb46Sjohn stultz * This file contains the functions which manage clocksource drivers. 5734efb46Sjohn stultz * 6734efb46Sjohn stultz * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com) 7734efb46Sjohn stultz * 8734efb46Sjohn stultz * This program is free software; you can redistribute it and/or modify 9734efb46Sjohn stultz * it under the terms of the GNU General Public License as published by 10734efb46Sjohn stultz * the Free Software Foundation; either version 2 of the License, or 11734efb46Sjohn stultz * (at your option) any later version. 12734efb46Sjohn stultz * 13734efb46Sjohn stultz * This program is distributed in the hope that it will be useful, 14734efb46Sjohn stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 15734efb46Sjohn stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16734efb46Sjohn stultz * GNU General Public License for more details. 17734efb46Sjohn stultz * 18734efb46Sjohn stultz * You should have received a copy of the GNU General Public License 19734efb46Sjohn stultz * along with this program; if not, write to the Free Software 20734efb46Sjohn stultz * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21734efb46Sjohn stultz * 22734efb46Sjohn stultz * TODO WishList: 23734efb46Sjohn stultz * o Allow clocksource drivers to be unregistered 24734efb46Sjohn stultz * o get rid of clocksource_jiffies extern 25734efb46Sjohn stultz */ 26734efb46Sjohn stultz 27734efb46Sjohn stultz #include <linux/clocksource.h> 28734efb46Sjohn stultz #include <linux/sysdev.h> 29734efb46Sjohn stultz #include <linux/init.h> 30734efb46Sjohn stultz #include <linux/module.h> 31dc29a365SMathieu Desnoyers #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ 3279bf2bb3SThomas Gleixner #include <linux/tick.h> 33734efb46Sjohn stultz 34734efb46Sjohn stultz /* XXX - Would like a better way for initializing curr_clocksource */ 35734efb46Sjohn stultz extern struct clocksource clocksource_jiffies; 36734efb46Sjohn stultz 37734efb46Sjohn stultz /*[Clocksource internal variables]--------- 38734efb46Sjohn stultz * curr_clocksource: 39734efb46Sjohn stultz * currently selected clocksource. Initialized to clocksource_jiffies. 40734efb46Sjohn stultz * next_clocksource: 41734efb46Sjohn stultz * pending next selected clocksource. 42734efb46Sjohn stultz * clocksource_list: 43734efb46Sjohn stultz * linked list with the registered clocksources 44734efb46Sjohn stultz * clocksource_lock: 45734efb46Sjohn stultz * protects manipulations to curr_clocksource and next_clocksource 46734efb46Sjohn stultz * and the clocksource_list 47734efb46Sjohn stultz * override_name: 48734efb46Sjohn stultz * Name of the user-specified clocksource. 49734efb46Sjohn stultz */ 50734efb46Sjohn stultz static struct clocksource *curr_clocksource = &clocksource_jiffies; 51734efb46Sjohn stultz static struct clocksource *next_clocksource; 5292c7e002SThomas Gleixner static struct clocksource *clocksource_override; 53734efb46Sjohn stultz static LIST_HEAD(clocksource_list); 54734efb46Sjohn stultz static DEFINE_SPINLOCK(clocksource_lock); 55734efb46Sjohn stultz static char override_name[32]; 56734efb46Sjohn stultz static int finished_booting; 57734efb46Sjohn stultz 586bb74df4Sjohn stultz /* clocksource_done_booting - Called near the end of core bootup 59734efb46Sjohn stultz * 606bb74df4Sjohn stultz * Hack to avoid lots of clocksource churn at boot time. 616bb74df4Sjohn stultz * We use fs_initcall because we want this to start before 626bb74df4Sjohn stultz * device_initcall but after subsys_initcall. 63734efb46Sjohn stultz */ 64ad596171Sjohn stultz static int __init clocksource_done_booting(void) 65734efb46Sjohn stultz { 66734efb46Sjohn stultz finished_booting = 1; 67734efb46Sjohn stultz return 0; 68734efb46Sjohn stultz } 696bb74df4Sjohn stultz fs_initcall(clocksource_done_booting); 70734efb46Sjohn stultz 715d8b34fdSThomas Gleixner #ifdef CONFIG_CLOCKSOURCE_WATCHDOG 725d8b34fdSThomas Gleixner static LIST_HEAD(watchdog_list); 735d8b34fdSThomas Gleixner static struct clocksource *watchdog; 745d8b34fdSThomas Gleixner static struct timer_list watchdog_timer; 755d8b34fdSThomas Gleixner static DEFINE_SPINLOCK(watchdog_lock); 765d8b34fdSThomas Gleixner static cycle_t watchdog_last; 775d8b34fdSThomas Gleixner /* 785d8b34fdSThomas Gleixner * Interval: 0.5sec Treshold: 0.0625s 795d8b34fdSThomas Gleixner */ 805d8b34fdSThomas Gleixner #define WATCHDOG_INTERVAL (HZ >> 1) 815d8b34fdSThomas Gleixner #define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4) 825d8b34fdSThomas Gleixner 835d8b34fdSThomas Gleixner static void clocksource_ratewd(struct clocksource *cs, int64_t delta) 845d8b34fdSThomas Gleixner { 855d8b34fdSThomas Gleixner if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD) 865d8b34fdSThomas Gleixner return; 875d8b34fdSThomas Gleixner 885d8b34fdSThomas Gleixner printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", 895d8b34fdSThomas Gleixner cs->name, delta); 905d8b34fdSThomas Gleixner cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); 915d8b34fdSThomas Gleixner clocksource_change_rating(cs, 0); 925d8b34fdSThomas Gleixner cs->flags &= ~CLOCK_SOURCE_WATCHDOG; 935d8b34fdSThomas Gleixner list_del(&cs->wd_list); 945d8b34fdSThomas Gleixner } 955d8b34fdSThomas Gleixner 965d8b34fdSThomas Gleixner static void clocksource_watchdog(unsigned long data) 975d8b34fdSThomas Gleixner { 985d8b34fdSThomas Gleixner struct clocksource *cs, *tmp; 995d8b34fdSThomas Gleixner cycle_t csnow, wdnow; 1005d8b34fdSThomas Gleixner int64_t wd_nsec, cs_nsec; 1015d8b34fdSThomas Gleixner 1025d8b34fdSThomas Gleixner spin_lock(&watchdog_lock); 1035d8b34fdSThomas Gleixner 1045d8b34fdSThomas Gleixner wdnow = watchdog->read(); 1055d8b34fdSThomas Gleixner wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask); 1065d8b34fdSThomas Gleixner watchdog_last = wdnow; 1075d8b34fdSThomas Gleixner 1085d8b34fdSThomas Gleixner list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { 1095d8b34fdSThomas Gleixner csnow = cs->read(); 1105d8b34fdSThomas Gleixner /* Initialized ? */ 1115d8b34fdSThomas Gleixner if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) { 1125d8b34fdSThomas Gleixner if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && 1135d8b34fdSThomas Gleixner (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { 1145d8b34fdSThomas Gleixner cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; 11579bf2bb3SThomas Gleixner /* 11679bf2bb3SThomas Gleixner * We just marked the clocksource as 11779bf2bb3SThomas Gleixner * highres-capable, notify the rest of the 11879bf2bb3SThomas Gleixner * system as well so that we transition 11979bf2bb3SThomas Gleixner * into high-res mode: 12079bf2bb3SThomas Gleixner */ 12179bf2bb3SThomas Gleixner tick_clock_notify(); 1225d8b34fdSThomas Gleixner } 1235d8b34fdSThomas Gleixner cs->flags |= CLOCK_SOURCE_WATCHDOG; 1245d8b34fdSThomas Gleixner cs->wd_last = csnow; 1255d8b34fdSThomas Gleixner } else { 1265d8b34fdSThomas Gleixner cs_nsec = cyc2ns(cs, (csnow - cs->wd_last) & cs->mask); 1275d8b34fdSThomas Gleixner cs->wd_last = csnow; 1285d8b34fdSThomas Gleixner /* Check the delta. Might remove from the list ! */ 1295d8b34fdSThomas Gleixner clocksource_ratewd(cs, cs_nsec - wd_nsec); 1305d8b34fdSThomas Gleixner } 1315d8b34fdSThomas Gleixner } 1325d8b34fdSThomas Gleixner 1335d8b34fdSThomas Gleixner if (!list_empty(&watchdog_list)) { 1345d8b34fdSThomas Gleixner __mod_timer(&watchdog_timer, 1355d8b34fdSThomas Gleixner watchdog_timer.expires + WATCHDOG_INTERVAL); 1365d8b34fdSThomas Gleixner } 1375d8b34fdSThomas Gleixner spin_unlock(&watchdog_lock); 1385d8b34fdSThomas Gleixner } 1395d8b34fdSThomas Gleixner static void clocksource_check_watchdog(struct clocksource *cs) 1405d8b34fdSThomas Gleixner { 1415d8b34fdSThomas Gleixner struct clocksource *cse; 1425d8b34fdSThomas Gleixner unsigned long flags; 1435d8b34fdSThomas Gleixner 1445d8b34fdSThomas Gleixner spin_lock_irqsave(&watchdog_lock, flags); 1455d8b34fdSThomas Gleixner if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { 1465d8b34fdSThomas Gleixner int started = !list_empty(&watchdog_list); 1475d8b34fdSThomas Gleixner 1485d8b34fdSThomas Gleixner list_add(&cs->wd_list, &watchdog_list); 1495d8b34fdSThomas Gleixner if (!started && watchdog) { 1505d8b34fdSThomas Gleixner watchdog_last = watchdog->read(); 1515d8b34fdSThomas Gleixner watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL; 1525d8b34fdSThomas Gleixner add_timer(&watchdog_timer); 1535d8b34fdSThomas Gleixner } 1545d8b34fdSThomas Gleixner } else if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) { 1555d8b34fdSThomas Gleixner cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; 1565d8b34fdSThomas Gleixner 1575d8b34fdSThomas Gleixner if (!watchdog || cs->rating > watchdog->rating) { 1585d8b34fdSThomas Gleixner if (watchdog) 1595d8b34fdSThomas Gleixner del_timer(&watchdog_timer); 1605d8b34fdSThomas Gleixner watchdog = cs; 1615d8b34fdSThomas Gleixner init_timer(&watchdog_timer); 1625d8b34fdSThomas Gleixner watchdog_timer.function = clocksource_watchdog; 1635d8b34fdSThomas Gleixner 1645d8b34fdSThomas Gleixner /* Reset watchdog cycles */ 1655d8b34fdSThomas Gleixner list_for_each_entry(cse, &watchdog_list, wd_list) 1665d8b34fdSThomas Gleixner cse->flags &= ~CLOCK_SOURCE_WATCHDOG; 1675d8b34fdSThomas Gleixner /* Start if list is not empty */ 1685d8b34fdSThomas Gleixner if (!list_empty(&watchdog_list)) { 1695d8b34fdSThomas Gleixner watchdog_last = watchdog->read(); 1705d8b34fdSThomas Gleixner watchdog_timer.expires = 1715d8b34fdSThomas Gleixner jiffies + WATCHDOG_INTERVAL; 1725d8b34fdSThomas Gleixner add_timer(&watchdog_timer); 1735d8b34fdSThomas Gleixner } 1745d8b34fdSThomas Gleixner } 1755d8b34fdSThomas Gleixner } 1765d8b34fdSThomas Gleixner spin_unlock_irqrestore(&watchdog_lock, flags); 1775d8b34fdSThomas Gleixner } 1785d8b34fdSThomas Gleixner #else 1795d8b34fdSThomas Gleixner static void clocksource_check_watchdog(struct clocksource *cs) 1805d8b34fdSThomas Gleixner { 1815d8b34fdSThomas Gleixner if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) 1825d8b34fdSThomas Gleixner cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; 1835d8b34fdSThomas Gleixner } 1845d8b34fdSThomas Gleixner #endif 1855d8b34fdSThomas Gleixner 186734efb46Sjohn stultz /** 187a2752549Sjohn stultz * clocksource_get_next - Returns the selected clocksource 188734efb46Sjohn stultz * 189734efb46Sjohn stultz */ 190a2752549Sjohn stultz struct clocksource *clocksource_get_next(void) 191734efb46Sjohn stultz { 192734efb46Sjohn stultz unsigned long flags; 193734efb46Sjohn stultz 194734efb46Sjohn stultz spin_lock_irqsave(&clocksource_lock, flags); 195734efb46Sjohn stultz if (next_clocksource && finished_booting) { 196734efb46Sjohn stultz curr_clocksource = next_clocksource; 197734efb46Sjohn stultz next_clocksource = NULL; 198734efb46Sjohn stultz } 199734efb46Sjohn stultz spin_unlock_irqrestore(&clocksource_lock, flags); 200734efb46Sjohn stultz 201734efb46Sjohn stultz return curr_clocksource; 202734efb46Sjohn stultz } 203734efb46Sjohn stultz 204734efb46Sjohn stultz /** 20592c7e002SThomas Gleixner * select_clocksource - Selects the best registered clocksource. 206734efb46Sjohn stultz * 207734efb46Sjohn stultz * Private function. Must hold clocksource_lock when called. 208734efb46Sjohn stultz * 20992c7e002SThomas Gleixner * Select the clocksource with the best rating, or the clocksource, 21092c7e002SThomas Gleixner * which is selected by userspace override. 211734efb46Sjohn stultz */ 212734efb46Sjohn stultz static struct clocksource *select_clocksource(void) 213734efb46Sjohn stultz { 2145d8b34fdSThomas Gleixner struct clocksource *next; 2155d8b34fdSThomas Gleixner 21692c7e002SThomas Gleixner if (list_empty(&clocksource_list)) 21792c7e002SThomas Gleixner return NULL; 218734efb46Sjohn stultz 21992c7e002SThomas Gleixner if (clocksource_override) 2205d8b34fdSThomas Gleixner next = clocksource_override; 2215d8b34fdSThomas Gleixner else 2225d8b34fdSThomas Gleixner next = list_entry(clocksource_list.next, struct clocksource, 2235d8b34fdSThomas Gleixner list); 224734efb46Sjohn stultz 2255d8b34fdSThomas Gleixner if (next == curr_clocksource) 2265d8b34fdSThomas Gleixner return NULL; 2275d8b34fdSThomas Gleixner 2285d8b34fdSThomas Gleixner return next; 229734efb46Sjohn stultz } 230734efb46Sjohn stultz 23192c7e002SThomas Gleixner /* 23292c7e002SThomas Gleixner * Enqueue the clocksource sorted by rating 233734efb46Sjohn stultz */ 23492c7e002SThomas Gleixner static int clocksource_enqueue(struct clocksource *c) 235734efb46Sjohn stultz { 23692c7e002SThomas Gleixner struct list_head *tmp, *entry = &clocksource_list; 237734efb46Sjohn stultz 238734efb46Sjohn stultz list_for_each(tmp, &clocksource_list) { 23992c7e002SThomas Gleixner struct clocksource *cs; 240734efb46Sjohn stultz 24192c7e002SThomas Gleixner cs = list_entry(tmp, struct clocksource, list); 24292c7e002SThomas Gleixner if (cs == c) 24392c7e002SThomas Gleixner return -EBUSY; 24492c7e002SThomas Gleixner /* Keep track of the place, where to insert */ 24592c7e002SThomas Gleixner if (cs->rating >= c->rating) 24692c7e002SThomas Gleixner entry = tmp; 247734efb46Sjohn stultz } 24892c7e002SThomas Gleixner list_add(&c->list, entry); 24992c7e002SThomas Gleixner 25092c7e002SThomas Gleixner if (strlen(c->name) == strlen(override_name) && 25192c7e002SThomas Gleixner !strcmp(c->name, override_name)) 25292c7e002SThomas Gleixner clocksource_override = c; 253734efb46Sjohn stultz 254734efb46Sjohn stultz return 0; 255734efb46Sjohn stultz } 256734efb46Sjohn stultz 257734efb46Sjohn stultz /** 258a2752549Sjohn stultz * clocksource_register - Used to install new clocksources 259734efb46Sjohn stultz * @t: clocksource to be registered 260734efb46Sjohn stultz * 261734efb46Sjohn stultz * Returns -EBUSY if registration fails, zero otherwise. 262734efb46Sjohn stultz */ 263a2752549Sjohn stultz int clocksource_register(struct clocksource *c) 264734efb46Sjohn stultz { 265734efb46Sjohn stultz unsigned long flags; 2665d8b34fdSThomas Gleixner int ret; 267734efb46Sjohn stultz 268734efb46Sjohn stultz spin_lock_irqsave(&clocksource_lock, flags); 26992c7e002SThomas Gleixner ret = clocksource_enqueue(c); 27092c7e002SThomas Gleixner if (!ret) 271734efb46Sjohn stultz next_clocksource = select_clocksource(); 272734efb46Sjohn stultz spin_unlock_irqrestore(&clocksource_lock, flags); 2735d8b34fdSThomas Gleixner if (!ret) 2745d8b34fdSThomas Gleixner clocksource_check_watchdog(c); 275734efb46Sjohn stultz return ret; 276734efb46Sjohn stultz } 277a2752549Sjohn stultz EXPORT_SYMBOL(clocksource_register); 278734efb46Sjohn stultz 279734efb46Sjohn stultz /** 28092c7e002SThomas Gleixner * clocksource_change_rating - Change the rating of a registered clocksource 281734efb46Sjohn stultz * 282734efb46Sjohn stultz */ 28392c7e002SThomas Gleixner void clocksource_change_rating(struct clocksource *cs, int rating) 284734efb46Sjohn stultz { 285734efb46Sjohn stultz unsigned long flags; 286734efb46Sjohn stultz 287734efb46Sjohn stultz spin_lock_irqsave(&clocksource_lock, flags); 28892c7e002SThomas Gleixner list_del(&cs->list); 2895d8b34fdSThomas Gleixner cs->rating = rating; 29092c7e002SThomas Gleixner clocksource_enqueue(cs); 291734efb46Sjohn stultz next_clocksource = select_clocksource(); 292734efb46Sjohn stultz spin_unlock_irqrestore(&clocksource_lock, flags); 293734efb46Sjohn stultz } 294734efb46Sjohn stultz 2952b013700SDaniel Walker #ifdef CONFIG_SYSFS 296734efb46Sjohn stultz /** 297734efb46Sjohn stultz * sysfs_show_current_clocksources - sysfs interface for current clocksource 298734efb46Sjohn stultz * @dev: unused 299734efb46Sjohn stultz * @buf: char buffer to be filled with clocksource list 300734efb46Sjohn stultz * 301734efb46Sjohn stultz * Provides sysfs interface for listing current clocksource. 302734efb46Sjohn stultz */ 303734efb46Sjohn stultz static ssize_t 304734efb46Sjohn stultz sysfs_show_current_clocksources(struct sys_device *dev, char *buf) 305734efb46Sjohn stultz { 306734efb46Sjohn stultz char *curr = buf; 307734efb46Sjohn stultz 308734efb46Sjohn stultz spin_lock_irq(&clocksource_lock); 309734efb46Sjohn stultz curr += sprintf(curr, "%s ", curr_clocksource->name); 310734efb46Sjohn stultz spin_unlock_irq(&clocksource_lock); 311734efb46Sjohn stultz 312734efb46Sjohn stultz curr += sprintf(curr, "\n"); 313734efb46Sjohn stultz 314734efb46Sjohn stultz return curr - buf; 315734efb46Sjohn stultz } 316734efb46Sjohn stultz 317734efb46Sjohn stultz /** 318734efb46Sjohn stultz * sysfs_override_clocksource - interface for manually overriding clocksource 319734efb46Sjohn stultz * @dev: unused 320734efb46Sjohn stultz * @buf: name of override clocksource 321734efb46Sjohn stultz * @count: length of buffer 322734efb46Sjohn stultz * 323734efb46Sjohn stultz * Takes input from sysfs interface for manually overriding the default 324734efb46Sjohn stultz * clocksource selction. 325734efb46Sjohn stultz */ 326734efb46Sjohn stultz static ssize_t sysfs_override_clocksource(struct sys_device *dev, 327734efb46Sjohn stultz const char *buf, size_t count) 328734efb46Sjohn stultz { 32992c7e002SThomas Gleixner struct clocksource *ovr = NULL; 33092c7e002SThomas Gleixner struct list_head *tmp; 331734efb46Sjohn stultz size_t ret = count; 33292c7e002SThomas Gleixner int len; 33392c7e002SThomas Gleixner 334734efb46Sjohn stultz /* strings from sysfs write are not 0 terminated! */ 335734efb46Sjohn stultz if (count >= sizeof(override_name)) 336734efb46Sjohn stultz return -EINVAL; 337734efb46Sjohn stultz 338734efb46Sjohn stultz /* strip of \n: */ 339734efb46Sjohn stultz if (buf[count-1] == '\n') 340734efb46Sjohn stultz count--; 341734efb46Sjohn stultz 342734efb46Sjohn stultz spin_lock_irq(&clocksource_lock); 343734efb46Sjohn stultz 34492c7e002SThomas Gleixner if (count > 0) 345734efb46Sjohn stultz memcpy(override_name, buf, count); 346734efb46Sjohn stultz override_name[count] = 0; 347734efb46Sjohn stultz 34892c7e002SThomas Gleixner len = strlen(override_name); 34992c7e002SThomas Gleixner if (len) { 35092c7e002SThomas Gleixner ovr = clocksource_override; 351734efb46Sjohn stultz /* try to select it: */ 35292c7e002SThomas Gleixner list_for_each(tmp, &clocksource_list) { 35392c7e002SThomas Gleixner struct clocksource *cs; 35492c7e002SThomas Gleixner 35592c7e002SThomas Gleixner cs = list_entry(tmp, struct clocksource, list); 35692c7e002SThomas Gleixner if (strlen(cs->name) == len && 35792c7e002SThomas Gleixner !strcmp(cs->name, override_name)) 35892c7e002SThomas Gleixner ovr = cs; 35992c7e002SThomas Gleixner } 36092c7e002SThomas Gleixner } 36192c7e002SThomas Gleixner 36292c7e002SThomas Gleixner /* Reselect, when the override name has changed */ 36392c7e002SThomas Gleixner if (ovr != clocksource_override) { 36492c7e002SThomas Gleixner clocksource_override = ovr; 365734efb46Sjohn stultz next_clocksource = select_clocksource(); 36692c7e002SThomas Gleixner } 367734efb46Sjohn stultz 368734efb46Sjohn stultz spin_unlock_irq(&clocksource_lock); 369734efb46Sjohn stultz 370734efb46Sjohn stultz return ret; 371734efb46Sjohn stultz } 372734efb46Sjohn stultz 373734efb46Sjohn stultz /** 374734efb46Sjohn stultz * sysfs_show_available_clocksources - sysfs interface for listing clocksource 375734efb46Sjohn stultz * @dev: unused 376734efb46Sjohn stultz * @buf: char buffer to be filled with clocksource list 377734efb46Sjohn stultz * 378734efb46Sjohn stultz * Provides sysfs interface for listing registered clocksources 379734efb46Sjohn stultz */ 380734efb46Sjohn stultz static ssize_t 381734efb46Sjohn stultz sysfs_show_available_clocksources(struct sys_device *dev, char *buf) 382734efb46Sjohn stultz { 383734efb46Sjohn stultz struct list_head *tmp; 384734efb46Sjohn stultz char *curr = buf; 385734efb46Sjohn stultz 386734efb46Sjohn stultz spin_lock_irq(&clocksource_lock); 387734efb46Sjohn stultz list_for_each(tmp, &clocksource_list) { 388734efb46Sjohn stultz struct clocksource *src; 389734efb46Sjohn stultz 390734efb46Sjohn stultz src = list_entry(tmp, struct clocksource, list); 391734efb46Sjohn stultz curr += sprintf(curr, "%s ", src->name); 392734efb46Sjohn stultz } 393734efb46Sjohn stultz spin_unlock_irq(&clocksource_lock); 394734efb46Sjohn stultz 395734efb46Sjohn stultz curr += sprintf(curr, "\n"); 396734efb46Sjohn stultz 397734efb46Sjohn stultz return curr - buf; 398734efb46Sjohn stultz } 399734efb46Sjohn stultz 400734efb46Sjohn stultz /* 401734efb46Sjohn stultz * Sysfs setup bits: 402734efb46Sjohn stultz */ 403734efb46Sjohn stultz static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources, 404734efb46Sjohn stultz sysfs_override_clocksource); 405734efb46Sjohn stultz 406734efb46Sjohn stultz static SYSDEV_ATTR(available_clocksource, 0600, 407734efb46Sjohn stultz sysfs_show_available_clocksources, NULL); 408734efb46Sjohn stultz 409734efb46Sjohn stultz static struct sysdev_class clocksource_sysclass = { 410734efb46Sjohn stultz set_kset_name("clocksource"), 411734efb46Sjohn stultz }; 412734efb46Sjohn stultz 413734efb46Sjohn stultz static struct sys_device device_clocksource = { 414734efb46Sjohn stultz .id = 0, 415734efb46Sjohn stultz .cls = &clocksource_sysclass, 416734efb46Sjohn stultz }; 417734efb46Sjohn stultz 418ad596171Sjohn stultz static int __init init_clocksource_sysfs(void) 419734efb46Sjohn stultz { 420734efb46Sjohn stultz int error = sysdev_class_register(&clocksource_sysclass); 421734efb46Sjohn stultz 422734efb46Sjohn stultz if (!error) 423734efb46Sjohn stultz error = sysdev_register(&device_clocksource); 424734efb46Sjohn stultz if (!error) 425734efb46Sjohn stultz error = sysdev_create_file( 426734efb46Sjohn stultz &device_clocksource, 427734efb46Sjohn stultz &attr_current_clocksource); 428734efb46Sjohn stultz if (!error) 429734efb46Sjohn stultz error = sysdev_create_file( 430734efb46Sjohn stultz &device_clocksource, 431734efb46Sjohn stultz &attr_available_clocksource); 432734efb46Sjohn stultz return error; 433734efb46Sjohn stultz } 434734efb46Sjohn stultz 435734efb46Sjohn stultz device_initcall(init_clocksource_sysfs); 4362b013700SDaniel Walker #endif /* CONFIG_SYSFS */ 437734efb46Sjohn stultz 438734efb46Sjohn stultz /** 439734efb46Sjohn stultz * boot_override_clocksource - boot clock override 440734efb46Sjohn stultz * @str: override name 441734efb46Sjohn stultz * 442734efb46Sjohn stultz * Takes a clocksource= boot argument and uses it 443734efb46Sjohn stultz * as the clocksource override name. 444734efb46Sjohn stultz */ 445734efb46Sjohn stultz static int __init boot_override_clocksource(char* str) 446734efb46Sjohn stultz { 447734efb46Sjohn stultz unsigned long flags; 448734efb46Sjohn stultz spin_lock_irqsave(&clocksource_lock, flags); 449734efb46Sjohn stultz if (str) 450734efb46Sjohn stultz strlcpy(override_name, str, sizeof(override_name)); 451734efb46Sjohn stultz spin_unlock_irqrestore(&clocksource_lock, flags); 452734efb46Sjohn stultz return 1; 453734efb46Sjohn stultz } 454734efb46Sjohn stultz 455734efb46Sjohn stultz __setup("clocksource=", boot_override_clocksource); 456734efb46Sjohn stultz 457734efb46Sjohn stultz /** 458734efb46Sjohn stultz * boot_override_clock - Compatibility layer for deprecated boot option 459734efb46Sjohn stultz * @str: override name 460734efb46Sjohn stultz * 461734efb46Sjohn stultz * DEPRECATED! Takes a clock= boot argument and uses it 462734efb46Sjohn stultz * as the clocksource override name 463734efb46Sjohn stultz */ 464734efb46Sjohn stultz static int __init boot_override_clock(char* str) 465734efb46Sjohn stultz { 4665d0cf410Sjohn stultz if (!strcmp(str, "pmtmr")) { 4675d0cf410Sjohn stultz printk("Warning: clock=pmtmr is deprecated. " 4685d0cf410Sjohn stultz "Use clocksource=acpi_pm.\n"); 4695d0cf410Sjohn stultz return boot_override_clocksource("acpi_pm"); 4705d0cf410Sjohn stultz } 4715d0cf410Sjohn stultz printk("Warning! clock= boot option is deprecated. " 4725d0cf410Sjohn stultz "Use clocksource=xyz\n"); 473734efb46Sjohn stultz return boot_override_clocksource(str); 474734efb46Sjohn stultz } 475734efb46Sjohn stultz 476734efb46Sjohn stultz __setup("clock=", boot_override_clock); 477