CINXE.COM
LKML: john stultz: [PATCH 3/11] Time: Clocksource Infrastructure
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>LKML: john stultz: [PATCH 3/11] Time: Clocksource Infrastructure</title><link href="/css/message.css" rel="stylesheet" type="text/css" /><link href="/css/wrap.css" rel="alternate stylesheet" type="text/css" title="wrap" /><link href="/css/nowrap.css" rel="stylesheet" type="text/css" title="nowrap" /><link href="/favicon.ico" rel="shortcut icon" /><script src="/js/simple-calendar.js" type="text/javascript"></script><script src="/js/styleswitcher.js" type="text/javascript"></script><link rel="alternate" type="application/rss+xml" title="lkml.org : last 100 messages" href="/rss.php" /><link rel="alternate" type="application/rss+xml" title="lkml.org : last messages by john stultz" href="/groupie.php?aid=1263" /><!--Matomo--><script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDoNotTrack", true]); _paq.push(["disableCookies"]); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//m.lkml.org/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script><!--End Matomo Code--></head><body onload="es.jasper.simpleCalendar.init();" itemscope="itemscope" itemtype="http://schema.org/BlogPosting"><table border="0" cellpadding="0" cellspacing="0"><tr><td width="180" align="center"><a href="/"><img style="border:0;width:135px;height:32px" src="/images/toprowlk.gif" alt="lkml.org" /></a></td><td width="32">聽</td><td class="nb"><div><a class="nb" href="/lkml"> [lkml]</a> 聽 <a class="nb" href="/lkml/2005"> [2005]</a> 聽 <a class="nb" href="/lkml/2005/12"> [Dec]</a> 聽 <a class="nb" href="/lkml/2005/12/15"> [15]</a> 聽 <a class="nb" href="/lkml/last100"> [last100]</a> 聽 <a href="/rss.php"><img src="/images/rss-or.gif" border="0" alt="RSS Feed" /></a></div><div>Views: <a href="#" class="nowrap" onclick="setActiveStyleSheet('wrap');return false;">[wrap]</a><a href="#" class="wrap" onclick="setActiveStyleSheet('nowrap');return false;">[no wrap]</a> 聽 <a class="nb" href="/lkml/mheaders/2005/12/15/412" onclick="this.href='/lkml/headers'+'/2005/12/15/412';">[headers]</a>聽 <a href="/lkml/bounce/2005/12/15/412">[forward]</a>聽 </div></td><td width="32">聽</td></tr><tr><td valign="top"><div class="es-jasper-simpleCalendar" baseurl="/lkml/"></div><div class="threadlist">Messages in this thread</div><ul class="threadlist"><li class="root"><a href="/lkml/2005/12/15/405">First message in thread</a></li><li><a href="/lkml/2005/12/15/405">john stultz</a><ul><li><a href="/lkml/2005/12/15/404">john stultz</a></li><li><a href="/lkml/2005/12/15/406">john stultz</a></li><li><a href="/lkml/2005/12/15/407">john stultz</a><ul><li><a href="/lkml/2006/1/3/509">Andrew Morton</a><ul><li><a href="/lkml/2006/1/4/72">john stultz</a><ul><li><a href="/lkml/2006/1/4/76">Andrew Morton</a></li></ul></li></ul></li></ul></li><li><a href="/lkml/2005/12/15/408">john stultz</a></li><li><a href="/lkml/2005/12/15/409">john stultz</a></li><li><a href="/lkml/2005/12/15/410">john stultz</a></li><li><a href="/lkml/2005/12/15/411">john stultz</a></li><li class="origin"><a href="">john stultz</a></li><li><a href="/lkml/2005/12/15/413">john stultz</a></li><li><a href="/lkml/2005/12/15/414">john stultz</a></li><li><a href="/lkml/2005/12/15/415">john stultz</a></li></ul></li></ul><div class="threadlist">Patch in this message</div><ul class="threadlist"><li><a href="/lkml/diff/2005/12/15/412/1">Get diff 1</a></li></ul></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerl.gif" width="32" height="32" alt="/" /></td><td class="c" rowspan="2" valign="top" style="padding-top: 1em"><table><tr><td><table><tr><td class="lp">Date</td><td class="rp" itemprop="datePublished">Thu, 15 Dec 2005 18:07:20 -0700</td></tr><tr><td class="lp">From</td><td class="rp" itemprop="author">john stultz <></td></tr><tr><td class="lp">Subject</td><td class="rp" itemprop="name">[PATCH 3/11] Time: Clocksource Infrastructure</td></tr></table></td><td></td></tr></table><pre itemprop="articleBody">Andrew, All,<br /> This patch introduces the clocksource management <br />infrastructure. A clocksource is a driver-like architecture generic <br />abstraction of a freerunning counter. This patch defines the <br />clocksource structure, and provides management code for registering, <br />selecting, accessing and scaling clocksources. The clocksource <br />structure is influenced by the time_interpolator code, although I feel <br />it has a cleaner interface and avoids preserving system state in the <br />clocksource structure.<br /><br />Additionally, this patch includes the trivial jiffies clocksource, a <br />lowest common denominator clocksource, provided mainly for use as an <br />example.<br /><br />This patch applies on top of my ntp cleanup patchset.<br /><br />Since this patch provides the groundwork for the generic timeofday <br />core, it will not function without the generic timeofday patches to <br />follow.<br /><br />Andrew, please consider for inclusion into your tree.<br /><br />thanks<br />-john<br /><br />Signed-off-by: John Stultz <johnstul@us.ibm.com><br /><br /> Documentation/kernel-parameters.txt | 14 +<br /> include/linux/clocksource.h | 304 ++++++++++++++++++++++++++++++++++<br /> kernel/Makefile | 1 <br /> kernel/time/Makefile | 1 <br /> kernel/time/clocksource.c | 313 ++++++++++++++++++++++++++++++++++++<br /> kernel/time/jiffies.c | 75 ++++++++<br /> 6 files changed, 704 insertions(+), 4 deletions(-)<br /><br />linux-2.6.15-rc5_timeofday-clocksource-core_B14.patch<br />============================================<br />diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt<br />index 5dffcfe..e41505c 100644<br />--- a/Documentation/kernel-parameters.txt<br />+++ b/Documentation/kernel-parameters.txt<br />@@ -52,6 +52,7 @@ restrictions referred to are that the re<br /> MTD MTD support is enabled.<br /> NET Appropriate network support is enabled.<br /> NUMA NUMA support is enabled.<br />+ GENERIC_TIME The generic timeofday code is enabled.<br /> NFS Appropriate NFS support is enabled.<br /> OSS OSS sound support is enabled.<br /> PARIDE The ParIDE subsystem is enabled.<br />@@ -329,10 +330,11 @@ running once the system is up.<br /> Value can be changed at runtime via<br /> /selinux/checkreqprot.<br /> <br />- clock= [BUGS=IA-32,HW] gettimeofday timesource override.<br />- Forces specified timesource (if avaliable) to be used<br />- when calculating gettimeofday(). If specicified<br />- timesource is not avalible, it defaults to PIT.<br />+ clock= [BUGS=IA-32, HW] gettimeofday clocksource override.<br />+ [Deprecated]<br />+ Forces specified clocksource (if avaliable) to be used<br />+ when calculating gettimeofday(). If specified<br />+ clocksource is not avalible, it defaults to PIT.<br /> Format: { pit | tsc | cyclone | pmtmr }<br /> <br /> hpet= [IA-32,HPET] option to disable HPET and use PIT.<br />@@ -1477,6 +1479,10 @@ running once the system is up.<br /> <br /> time Show timing data prefixed to each printk message line<br /> <br />+ clocksource= [GENERIC_TIME] Override the default clocksource<br />+ Override the default clocksource and use the clocksource<br />+ with the name specified.<br />+<br /> tipar.timeout= [HW,PPT]<br /> Set communications timeout in tenths of a second<br /> (default 15).<br />diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h<br />new file mode 100644<br />index 0000000..5a3d6c3<br />--- /dev/null<br />+++ b/include/linux/clocksource.h<br />@@ -0,0 +1,304 @@<br />+/* linux/include/linux/clocksource.h<br />+ *<br />+ * This file contains the structure definitions for clocksources.<br />+ *<br />+ * If you are not a clocksource, or the time of day code, you should<br />+ * not be including this file!<br />+ */<br />+#ifndef _LINUX_CLOCKSOURCE_H<br />+#define _LINUX_CLOCKSOURCE_H<br />+<br />+#include <linux/types.h><br />+#include <linux/timex.h><br />+#include <linux/time.h><br />+#include <linux/list.h><br />+#include <asm/div64.h><br />+#include <asm/io.h><br />+<br />+/**<br />+ * struct clocksource - hardware abstraction for a free running counter<br />+ * Provides mostly state-free accessors to the underlying hardware.<br />+ *<br />+ * @name: ptr to clocksource name<br />+ * @list: list head for registration<br />+ * @rating: rating value for selection (higher is better)<br />+ * To avoid rating inflation the following<br />+ * list should give you a guide as to how<br />+ * to assign your clocksource a rating<br />+ * 1-99: Unfit for real use<br />+ * Only available for bootup and testing purposes.<br />+ * 100-199: Base level usability.<br />+ * Functional for real use, but not desired.<br />+ * 200-299: Good.<br />+ * A correct and usable clocksource.<br />+ * 300-399: Desired.<br />+ * A reasonably fast and accurate clocksource.<br />+ * 400-499: Perfect<br />+ * The ideal clocksource. A must-use where<br />+ * available.<br />+ * @read: returns a cycle value<br />+ * @mask: bitmask for two's complement<br />+ * subtraction of non 64 bit counters<br />+ * @mult: cycle to nanosecond multiplier<br />+ * @shift: cycle to nanosecond divisor (power of two)<br />+ * @update_callback: called when safe to alter clocksource values<br />+ * @is_continuous: defines if clocksource is free-running.<br />+ * @vread: vsyscall read function<br />+ * @vdata: vsyscall data value passed to read function<br />+ */<br />+struct clocksource {<br />+ char *name;<br />+ struct list_head list;<br />+ int rating;<br />+ cycle_t (*read)(void);<br />+ cycle_t mask;<br />+ u32 mult;<br />+ u32 shift;<br />+ int (*update_callback)(void);<br />+ int is_continuous;<br />+ cycle_t (*vread)(void *);<br />+ void *vdata;<br />+};<br />+<br />+<br />+/**<br />+ * clocksource_khz2mult - calculates mult from khz and shift<br />+ * @khz: Clocksource frequency in KHz<br />+ * @shift_constant: Clocksource shift factor<br />+ *<br />+ * Helper functions that converts a khz counter frequency to a timsource<br />+ * multiplier, given the clocksource shift value<br />+ */<br />+static inline u32 clocksource_khz2mult(u32 khz, u32 shift_constant)<br />+{<br />+ /* khz = cyc/(Million ns)<br />+ * mult/2^shift = ns/cyc<br />+ * mult = ns/cyc * 2^shift<br />+ * mult = 1Million/khz * 2^shift<br />+ * mult = 1000000 * 2^shift / khz<br />+ * mult = (1000000<<shift) / khz<br />+ */<br />+ u64 tmp = ((u64)1000000) << shift_constant;<br />+<br />+ tmp += khz/2; /* round for do_div */<br />+ do_div(tmp, khz);<br />+<br />+ return (u32)tmp;<br />+}<br />+<br />+/**<br />+ * clocksource_hz2mult - calculates mult from hz and shift<br />+ * @hz: Clocksource frequency in Hz<br />+ * @shift_constant: Clocksource shift factor<br />+ *<br />+ * Helper functions that converts a hz counter<br />+ * frequency to a timsource multiplier, given the<br />+ * clocksource shift value<br />+ */<br />+static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant)<br />+{<br />+ /* hz = cyc/(Billion ns)<br />+ * mult/2^shift = ns/cyc<br />+ * mult = ns/cyc * 2^shift<br />+ * mult = 1Billion/hz * 2^shift<br />+ * mult = 1000000000 * 2^shift / hz<br />+ * mult = (1000000000<<shift) / hz<br />+ */<br />+ u64 tmp = ((u64)1000000000) << shift_constant;<br />+<br />+ tmp += hz/2; /* round for do_div */<br />+ do_div(tmp, hz);<br />+<br />+ return (u32)tmp;<br />+}<br />+<br />+/**<br />+ * read_clocksource: - Access the clocksource's current cycle value<br />+ * @cs: pointer to clocksource being read<br />+ *<br />+ * Uses the clocksource to return the current cycle_t value<br />+ */<br />+static inline cycle_t read_clocksource(struct clocksource *cs)<br />+{<br />+ return cs->read();<br />+}<br />+<br />+/**<br />+ * ppm_to_mult_adj - Converts shifted ppm values to mult adjustment<br />+ * @cs: Pointer to clocksource<br />+ * @ppm: Shifted PPM value<br />+ *<br />+ * Helper which converts a shifted ppm value to clocksource mult_adj value.<br />+ *<br />+ * XXX - this could use some optimization<br />+ */<br />+static inline int ppm_to_mult_adj(struct clocksource *cs, int ppm)<br />+{<br />+ u64 mult_adj;<br />+ int ret_adj;<br />+<br />+ /* The basic math is as follows:<br />+ * cyc * mult/2^shift * (1 + ppm/MILL) = scaled ns<br />+ * We want to precalculate the ppm factor so it can be added<br />+ * to the multiplyer saving the extra multiplication step.<br />+ * cyc * (mult/2^shift + (mult/2^shift) * (ppm/MILL)) =<br />+ * cyc * (mult/2^shift + (mult*ppm/MILL)/2^shift) =<br />+ * cyc * (mult + (mult*ppm/MILL))/2^shift =<br />+ * Thus we want to calculate the value of:<br />+ * mult*ppm/MILL<br />+ */<br />+ mult_adj = abs(ppm);<br />+ mult_adj = (mult_adj * cs->mult)>>SHIFT_USEC;<br />+ mult_adj += 1000000/2; /* round for div*/<br />+ do_div(mult_adj, 1000000);<br />+ if (ppm < 0)<br />+ ret_adj = -(int)mult_adj;<br />+ else<br />+ ret_adj = (int)mult_adj;<br />+<br />+ return ret_adj;<br />+}<br />+<br />+/**<br />+ * cyc2ns - converts clocksource cycles to nanoseconds<br />+ * @cs: Pointer to clocksource<br />+ * @ntp_adj: Multiplier adjustment value<br />+ * @cycles: Cycles<br />+ *<br />+ * Uses the clocksource and ntp ajdustment to convert cycle_ts to nanoseconds.<br />+ *<br />+ * XXX - This could use some mult_lxl_ll() asm optimization<br />+ */<br />+static inline nsec_t cyc2ns(struct clocksource *cs, int ntp_adj, cycle_t cycles)<br />+{<br />+ u64 ret = (u64)cycles;<br />+<br />+ ret *= (cs->mult + ntp_adj);<br />+ ret >>= cs->shift;<br />+<br />+ return (nsec_t)ret;<br />+}<br />+<br />+/**<br />+ * cyc2ns_rem - converts clocksource cycles to nanoseconds w/ remainder<br />+ * @cs: Pointer to clocksource<br />+ * @ntp_adj: Multiplier adjustment value<br />+ * @cycles: Cycles<br />+ * @rem: Remainder<br />+ *<br />+ * Uses the clocksource and ntp ajdustment interval to convert cycle_t to<br />+ * nanoseconds. Add in remainder portion which is stored in (ns<<cs->shift)<br />+ * units and save the new remainder off.<br />+ *<br />+ * XXX - This could use some mult_lxl_ll() asm optimization.<br />+ */<br />+static inline nsec_t cyc2ns_rem(struct clocksource *cs, int ntp_adj,<br />+ cycle_t cycles, u64* rem)<br />+{<br />+ u64 ret = (u64)cycles;<br />+<br />+ ret *= (cs->mult + ntp_adj);<br />+ if (rem) {<br />+ ret += *rem;<br />+ *rem = ret & ((1<<cs->shift)-1);<br />+ }<br />+ ret >>= cs->shift;<br />+<br />+ return (nsec_t)ret;<br />+}<br />+<br />+<br />+/**<br />+ * struct clocksource_interval - Fixed interval conversion structure<br />+ *<br />+ * @cycles: A specified number of cycles<br />+ * @nsecs: The number of nanoseconds equivalent to the cycles value<br />+ * @remainder: Non-integer nanosecond remainder stored in (ns<<cs->shift) units<br />+ * @remainder_ns_overflow: Value at which the remainder is equal to<br />+ * one second<br />+ *<br />+ * This is a optimization structure used by cyc2ns_fixed_rem() to avoid the<br />+ * multiply in cyc2ns().<br />+ *<br />+ * Unless you're the timeofday_periodic_hook, you should not be using this!<br />+ */<br />+struct clocksource_interval {<br />+ cycle_t cycles;<br />+ nsec_t nsecs;<br />+ u64 remainder;<br />+ u64 remainder_ns_overflow;<br />+};<br />+<br />+/**<br />+ * calculate_clocksource_interval - Calculates a clocksource interval struct<br />+ *<br />+ * @c: Pointer to clocksource.<br />+ * @adj: Multiplyer adjustment.<br />+ * @length_nsec: Desired interval length in nanoseconds.<br />+ *<br />+ * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment<br />+ * pair and interval request.<br />+ *<br />+ * Unless you're the timeofday_periodic_hook, you should not be using this!<br />+ */<br />+static inline struct clocksource_interval<br />+calculate_clocksource_interval(struct clocksource *c, long adj,<br />+ unsigned long length_nsec)<br />+{<br />+ struct clocksource_interval ret;<br />+ u64 tmp;<br />+<br />+ /* XXX - All of this could use a whole lot of optimization */<br />+ tmp = length_nsec;<br />+ tmp <<= c->shift;<br />+ do_div(tmp, c->mult+adj);<br />+<br />+ ret.cycles = (cycle_t)tmp;<br />+ if(ret.cycles == 0)<br />+ ret.cycles = 1;<br />+<br />+ ret.remainder = 0;<br />+ ret.remainder_ns_overflow = 1 << c->shift;<br />+ ret.nsecs = cyc2ns_rem(c, adj, ret.cycles, &ret.remainder);<br />+<br />+ return ret;<br />+}<br />+<br />+/**<br />+ * cyc2ns_fixed_rem -<br />+ * converts clocksource cycles to nanoseconds using fixed intervals<br />+ *<br />+ * @interval: precalculated clocksource_interval structure<br />+ * @cycles: Number of clocksource cycles<br />+ * @rem: Remainder<br />+ *<br />+ * Uses a precalculated fixed cycle/nsec interval to convert cycles to<br />+ * nanoseconds. Returns the unaccumulated cycles in the cycles pointer as<br />+ * well as uses and updates the value at the remainder pointer<br />+ *<br />+ * Unless you're the timeofday_periodic_hook, you should not be using this!<br />+ */<br />+static inline nsec_t cyc2ns_fixed_rem(struct clocksource_interval interval,<br />+ cycle_t *cycles, u64* rem)<br />+{<br />+ nsec_t delta_nsec = 0;<br />+<br />+ while (*cycles > interval.cycles) {<br />+ delta_nsec += interval.nsecs;<br />+ *cycles -= interval.cycles;<br />+ *rem += interval.remainder;<br />+ while(*rem > interval.remainder_ns_overflow) {<br />+ *rem -= interval.remainder_ns_overflow;<br />+ delta_nsec += 1;<br />+ }<br />+ }<br />+<br />+ return delta_nsec;<br />+}<br />+<br />+/* used to install a new clocksource */<br />+void register_clocksource(struct clocksource*);<br />+void reselect_clocksource(void);<br />+struct clocksource* get_next_clocksource(void);<br />+<br />+#endif /* _LINUX_CLOCKSOURCE_H */<br />diff --git a/kernel/Makefile b/kernel/Makefile<br />index 6c0ebf9..20d9365 100644<br />--- a/kernel/Makefile<br />+++ b/kernel/Makefile<br />@@ -10,6 +10,7 @@ obj-y = sched.o fork.o exec_domain.o<br /> kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o \<br /> hrtimer.o<br /> <br />+obj-$(CONFIG_GENERIC_TIME) += time/<br /> obj-$(CONFIG_FUTEX) += futex.o<br /> obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o<br /> obj-$(CONFIG_SMP) += cpu.o spinlock.o<br />diff --git a/kernel/time/Makefile b/kernel/time/Makefile<br />new file mode 100644<br />index 0000000..e1dfd8e<br />--- /dev/null<br />+++ b/kernel/time/Makefile<br />@@ -0,0 +1 @@<br />+obj-y += clocksource.o jiffies.o<br />diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c<br />new file mode 100644<br />index 0000000..dafa4e5<br />--- /dev/null<br />+++ b/kernel/time/clocksource.c<br />@@ -0,0 +1,313 @@<br />+/*<br />+ * linux/kernel/time/clocksource.c<br />+ *<br />+ * This file contains the functions which manage clocksource drivers.<br />+ *<br />+ * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)<br />+ *<br />+ * This program is free software; you can redistribute it and/or modify<br />+ * it under the terms of the GNU General Public License as published by<br />+ * the Free Software Foundation; either version 2 of the License, or<br />+ * (at your option) any later version.<br />+ *<br />+ * This program is distributed in the hope that it will be useful,<br />+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br />+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />+ * GNU General Public License for more details.<br />+ *<br />+ * You should have received a copy of the GNU General Public License<br />+ * along with this program; if not, write to the Free Software<br />+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.<br />+ *<br />+ * TODO WishList:<br />+ * o Allow clocksource drivers to be unregistered<br />+ * o get rid of clocksource_jiffies extern<br />+ */<br />+<br />+#include <linux/clocksource.h><br />+#include <linux/sysdev.h><br />+#include <linux/init.h><br />+#include <linux/module.h><br />+<br />+/* XXX - Would like a better way for initializing curr_clocksource */<br />+extern struct clocksource clocksource_jiffies;<br />+<br />+/*[Clocksource internal variables]---------<br />+ * curr_clocksource:<br />+ * currently selected clocksource. Initialized to clocksource_jiffies.<br />+ * next_clocksource:<br />+ * pending next selected clocksource.<br />+ * clocksource_list:<br />+ * linked list with the registered clocksources<br />+ * clocksource_lock:<br />+ * protects manipulations to curr_clocksource and next_clocksource<br />+ * and the clocksource_list<br />+ * override_name:<br />+ * Name of the user-specified clocksource.<br />+ */<br />+static struct clocksource *curr_clocksource = &clocksource_jiffies;<br />+static struct clocksource *next_clocksource;<br />+static LIST_HEAD(clocksource_list);<br />+static DEFINE_SPINLOCK(clocksource_lock);<br />+static char override_name[32];<br />+<br />+/**<br />+ * get_next_clocksource - Returns the selected clocksource<br />+ */<br />+struct clocksource *get_next_clocksource(void)<br />+{<br />+ spin_lock(&clocksource_lock);<br />+ if (next_clocksource) {<br />+ curr_clocksource = next_clocksource;<br />+ next_clocksource = NULL;<br />+ }<br />+ spin_unlock(&clocksource_lock);<br />+<br />+ return curr_clocksource;<br />+}<br />+<br />+/**<br />+ * select_clocksource - Finds the best registered clocksource.<br />+ *<br />+ * Private function. Must hold clocksource_lock when called.<br />+ */<br />+static struct clocksource *select_clocksource(void)<br />+{<br />+ struct clocksource *best = NULL;<br />+ struct list_head *tmp;<br />+<br />+ list_for_each(tmp, &clocksource_list) {<br />+ struct clocksource *src;<br />+<br />+ src = list_entry(tmp, struct clocksource, list);<br />+ if (!best)<br />+ best = src;<br />+<br />+ /* check for override: */<br />+ if (strlen(src->name) == strlen(override_name) &&<br />+ !strcmp(src->name, override_name)) {<br />+ best = src;<br />+ break;<br />+ }<br />+ /* pick the highest rating: */<br />+ if (src->rating > best->rating)<br />+ best = src;<br />+ }<br />+<br />+ return best;<br />+}<br />+<br />+/**<br />+ * is_registered_source - Checks if clocksource is registered<br />+ * @c: pointer to a clocksource<br />+ *<br />+ * Private helper function. Must hold clocksource_lock when called.<br />+ *<br />+ * Returns one if the clocksource is already registered, zero otherwise.<br />+ */<br />+static inline int is_registered_source(struct clocksource *c)<br />+{<br />+ int len = strlen(c->name);<br />+ struct list_head *tmp;<br />+<br />+ list_for_each(tmp, &clocksource_list) {<br />+ struct clocksource *src;<br />+<br />+ src = list_entry(tmp, struct clocksource, list);<br />+ if (strlen(src->name) == len && !strcmp(src->name, c->name))<br />+ return 1;<br />+ }<br />+<br />+ return 0;<br />+}<br />+<br />+/**<br />+ * register_clocksource - Used to install new clocksources<br />+ * @t: clocksource to be registered<br />+ */<br />+void register_clocksource(struct clocksource *c)<br />+{<br />+ spin_lock(&clocksource_lock);<br />+<br />+ /* check if clocksource is already registered */<br />+ if (is_registered_source(c)) {<br />+ printk("register_clocksource: Cannot register %s. Already registered!",<br />+ c->name);<br />+ } else {<br />+ list_add(&c->list, &clocksource_list);<br />+ /* select next clocksource */<br />+ next_clocksource = select_clocksource();<br />+ }<br />+ spin_unlock(&clocksource_lock);<br />+}<br />+<br />+EXPORT_SYMBOL(register_clocksource);<br />+<br />+/**<br />+ * reselect_clocksource - Rescan list for next clocksource<br />+ *<br />+ * A quick helper function to be used if a clocksource changes its<br />+ * rating. Forces the clocksource list to be re-scaned for the best<br />+ * clocksource.<br />+ */<br />+void reselect_clocksource(void)<br />+{<br />+ spin_lock(&clocksource_lock);<br />+ next_clocksource = select_clocksource();<br />+ spin_unlock(&clocksource_lock);<br />+}<br />+<br />+/**<br />+ * sysfs_show_current_clocksources - sysfs interface for current clocksource<br />+ * @dev: unused<br />+ * @buf: char buffer to be filled with clocksource list<br />+ *<br />+ * Provides sysfs interface for listing current clocksource.<br />+ */<br />+static ssize_t<br />+sysfs_show_current_clocksources(struct sys_device *dev, char *buf)<br />+{<br />+ char *curr = buf;<br />+<br />+ spin_lock(&clocksource_lock);<br />+ curr += sprintf(curr, "%s ", curr_clocksource->name);<br />+ spin_unlock(&clocksource_lock);<br />+<br />+ curr += sprintf(curr, "\n");<br />+<br />+ return curr - buf;<br />+}<br />+<br />+/**<br />+ * sysfs_override_clocksource - interface for manually overriding clocksource<br />+ * @dev: unused<br />+ * @buf: name of override clocksource<br />+ * @count: length of buffer<br />+ *<br />+ * Takes input from sysfs interface for manually overriding the default<br />+ * clocksource selction.<br />+ */<br />+static ssize_t sysfs_override_clocksource(struct sys_device *dev,<br />+ const char *buf, size_t count)<br />+{<br />+ /* strings from sysfs write are not 0 terminated! */<br />+ if (count >= sizeof(override_name))<br />+ return -EINVAL;<br />+<br />+ /* strip of \n: */<br />+ if (buf[count-1] == '\n')<br />+ count--;<br />+ if (count < 1)<br />+ return -EINVAL;<br />+<br />+ spin_lock(&clocksource_lock);<br />+<br />+ /* copy the name given: */<br />+ memcpy(override_name, buf, count);<br />+ override_name[count] = 0;<br />+<br />+ /* try to select it: */<br />+ next_clocksource = select_clocksource();<br />+<br />+ spin_unlock(&clocksource_lock);<br />+<br />+ return count;<br />+}<br />+<br />+/**<br />+ * sysfs_show_available_clocksources - sysfs interface for listing clocksource<br />+ * @dev: unused<br />+ * @buf: char buffer to be filled with clocksource list<br />+ *<br />+ * Provides sysfs interface for listing registered clocksources<br />+ */<br />+static ssize_t<br />+sysfs_show_available_clocksources(struct sys_device *dev, char *buf)<br />+{<br />+ struct list_head *tmp;<br />+ char *curr = buf;<br />+<br />+ spin_lock(&clocksource_lock);<br />+ list_for_each(tmp, &clocksource_list) {<br />+ struct clocksource *src;<br />+<br />+ src = list_entry(tmp, struct clocksource, list);<br />+ curr += sprintf(curr, "%s ", src->name);<br />+ }<br />+ spin_unlock(&clocksource_lock);<br />+<br />+ curr += sprintf(curr, "\n");<br />+<br />+ return curr - buf;<br />+}<br />+<br />+/*<br />+ * Sysfs setup bits:<br />+ */<br />+static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,<br />+ sysfs_override_clocksource);<br />+<br />+static SYSDEV_ATTR(available_clocksource, 0600,<br />+ sysfs_show_available_clocksources, NULL);<br />+<br />+static struct sysdev_class clocksource_sysclass = {<br />+ set_kset_name("clocksource"),<br />+};<br />+<br />+static struct sys_device device_clocksource = {<br />+ .id = 0,<br />+ .cls = &clocksource_sysclass,<br />+};<br />+<br />+static int init_clocksource_sysfs(void)<br />+{<br />+ int error = sysdev_class_register(&clocksource_sysclass);<br />+<br />+ if (!error)<br />+ error = sysdev_register(&device_clocksource);<br />+ if (!error)<br />+ error = sysdev_create_file(<br />+ &device_clocksource,<br />+ &attr_current_clocksource);<br />+ if (!error)<br />+ error = sysdev_create_file(<br />+ &device_clocksource,<br />+ &attr_available_clocksource);<br />+ return error;<br />+}<br />+<br />+device_initcall(init_clocksource_sysfs);<br />+<br />+/**<br />+ * boot_override_clocksource - boot clock override<br />+ * @str: override name<br />+ *<br />+ * Takes a clocksource= boot argument and uses it<br />+ * as the clocksource override name.<br />+ */<br />+static int __init boot_override_clocksource(char* str)<br />+{<br />+ spin_lock(&clocksource_lock);<br />+ if (str)<br />+ strlcpy(override_name, str, sizeof(override_name));<br />+ spin_unlock(&clocksource_lock);<br />+ return 1;<br />+}<br />+<br />+__setup("clocksource=", boot_override_clocksource);<br />+<br />+/**<br />+ * boot_override_clock - Compatibility layer for deprecated boot option<br />+ * @str: override name<br />+ *<br />+ * DEPRECATED! Takes a clock= boot argument and uses it<br />+ * as the clocksource override name<br />+ */<br />+static int __init boot_override_clock(char* str)<br />+{<br />+ printk("Warning! clock= boot option is deprecated.\n");<br />+<br />+ return boot_override_clocksource(str);<br />+}<br />+<br />+__setup("clock=", boot_override_clock);<br />diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c<br />new file mode 100644<br />index 0000000..4f0bdd4<br />--- /dev/null<br />+++ b/kernel/time/jiffies.c<br />@@ -0,0 +1,75 @@<br />+/***********************************************************************<br />+* linux/kernel/time/jiffies.c<br />+*<br />+* This file contains the jiffies based clocksource.<br />+*<br />+* Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)<br />+*<br />+* This program is free software; you can redistribute it and/or modify<br />+* it under the terms of the GNU General Public License as published by<br />+* the Free Software Foundation; either version 2 of the License, or<br />+* (at your option) any later version.<br />+*<br />+* This program is distributed in the hope that it will be useful,<br />+* but WITHOUT ANY WARRANTY; without even the implied warranty of<br />+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />+* GNU General Public License for more details.<br />+*<br />+* You should have received a copy of the GNU General Public License<br />+* along with this program; if not, write to the Free Software<br />+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.<br />+*<br />+************************************************************************/<br />+#include <linux/clocksource.h><br />+#include <linux/jiffies.h><br />+#include <linux/init.h><br />+<br />+/* The Jiffies based clocksource is the lowest common<br />+ * denominator clock source which should function on<br />+ * all systems. It has the same coarse resolution as<br />+ * the timer interrupt frequency HZ and it suffers<br />+ * inaccuracies caused by missed or lost timer<br />+ * interrupts and the inability for the timer<br />+ * interrupt hardware to accuratly tick at the<br />+ * requested HZ value. It is also not reccomended<br />+ * for "tick-less" systems.<br />+ */<br />+#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ))<br />+<br />+/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier<br />+ * conversion, the .shift value could be zero. However<br />+ * this would make NTP adjustments impossible as they are<br />+ * in units of 1/2^.shift. Thus we use JIFFIES_SHIFT to<br />+ * shift both the nominator and denominator the same<br />+ * amount, and give ntp adjustments in units of 1/2^8<br />+ *<br />+ * The value 8 is somewhat carefully chosen, as anything<br />+ * larger can result in overflows. NSEC_PER_JIFFY grows as<br />+ * HZ shrinks, so values greater then 8 overflow 32bits when<br />+ * HZ=100.<br />+ */<br />+#define JIFFIES_SHIFT 8<br />+<br />+static cycle_t jiffies_read(void)<br />+{<br />+ return (cycle_t) get_jiffies_64();<br />+}<br />+<br />+struct clocksource clocksource_jiffies = {<br />+ .name = "jiffies",<br />+ .rating = 0, /* lowest rating*/<br />+ .read = jiffies_read,<br />+ .mask = (cycle_t)-1,<br />+ .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */<br />+ .shift = JIFFIES_SHIFT,<br />+ .is_continuous = 0, /* tick based, not free running */<br />+};<br />+<br />+static int __init init_jiffies_clocksource(void)<br />+{<br />+ register_clocksource(&clocksource_jiffies);<br />+<br />+ return 0;<br />+}<br />+<br />+module_init(init_jiffies_clocksource);<br />-<br />To unsubscribe from this list: send the line "unsubscribe linux-kernel" in<br />the body of a message to majordomo@vger.kernel.org<br />More majordomo info at <a href="http://vger.kernel.org/majordomo-info.html">http://vger.kernel.org/majordomo-info.html</a><br />Please read the FAQ at <a href="http://www.tux.org/lkml/">http://www.tux.org/lkml/</a><br /></pre></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerr.gif" width="32" height="32" alt="\" /></td></tr><tr><td align="right" valign="bottom"> 聽 </td></tr><tr><td align="right" valign="bottom">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerl.gif" width="32" height="32" alt="\" /></td><td class="c">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerr.gif" width="32" height="32" alt="/" /></td></tr><tr><td align="right" valign="top" colspan="2"> 聽 </td><td class="lm">Last update: 2005-12-16 02:14 聽聽 [from the cache]<br />漏2003-2020 <a href="http://blog.jasper.es/"><span itemprop="editor">Jasper Spaans</span></a>|hosted at <a href="https://www.digitalocean.com/?refcode=9a8e99d24cf9">Digital Ocean</a> and my Meterkast|<a href="http://blog.jasper.es/categories.html#lkml-ref">Read the blog</a></td><td>聽</td></tr></table><script language="javascript" src="/js/styleswitcher.js" type="text/javascript"></script></body></html>