CINXE.COM

LKML: john stultz: [PATCH 9/11] Time: i386 Conversion - part 5: Enable Generic Timekeeping

<?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 9/11] Time: i386 Conversion - part 5: Enable Generic Timekeeping</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/413" onclick="this.href='/lkml/headers'+'/2005/12/15/413';">[headers]</a>聽 <a href="/lkml/bounce/2005/12/15/413">[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><a href="/lkml/2005/12/15/412">john stultz</a></li><li class="origin"><a href="">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/413/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:08:19 -0700</td></tr><tr><td class="lp">From</td><td class="rp" itemprop="author">john stultz &lt;&gt;</td></tr><tr><td class="lp">Subject</td><td class="rp" itemprop="name">[PATCH 9/11] Time: i386 Conversion - part 5: Enable Generic Timekeeping</td></tr></table></td><td></td></tr></table><pre itemprop="articleBody">Andrew, All,<br /> The conversion of i386 to use the generic timeofday subsystem <br />has been split into 6 parts. This patch, the fifth of six, converts the <br />i386 arch to use the generic timeofday subsystem.<br /><br />It applies on top of my timeofday-arch-i386-part4 patch. This patch is <br />the last in the timeofday-arch-i386 patchset, so you should be able to <br />build and boot a kernel after it has been applied. <br /><br />Note that this patch does not provide any i386 clocksource, so you will <br />only have the jiffies clocksource. To get full replacements for the <br />code being removed here, the following timeofday-clocks-i386 patch will <br />need to be applied.<br /><br />Andrew, please consider for inclusion into your tree.<br /><br />thanks<br />-john<br /><br />Signed-off-by: John Stultz &lt;johnstul&#64;us.ibm.com&gt;<br /><br /> arch/i386/Kconfig | 4 <br /> arch/i386/kernel/Makefile | 1 <br /> arch/i386/kernel/time.c | 219 ++++++-------------------------------------<br /> arch/i386/kernel/tsc.c | 12 --<br /> arch/i386/lib/delay.c | 66 +++++++++++-<br /> include/asm-i386/delay.h | 2 <br /> include/asm-i386/timeofday.h | 4 <br /> include/asm-i386/timer.h | 57 -----------<br /> 8 files changed, 104 insertions(+), 261 deletions(-)<br /><br />linux-2.6.15-rc5_timeofday-arch-i386-part5_B14.patch<br />============================================<br />diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig<br />index 965cb01..1457b82 100644<br />--- a/arch/i386/Kconfig<br />+++ b/arch/i386/Kconfig<br />&#64;&#64; -14,6 +14,10 &#64;&#64; config X86_32<br /> 486, 586, Pentiums, and various instruction-set-compatible chips by<br /> AMD, Cyrix, and others.<br /> <br />+config GENERIC_TIME<br />+ bool<br />+ default y<br />+<br /> config SEMAPHORE_SLEEPERS<br /> bool<br /> default y<br />diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile<br />index 4c4e1e5..5d1d9c9 100644<br />--- a/arch/i386/kernel/Makefile<br />+++ b/arch/i386/kernel/Makefile<br />&#64;&#64; -10,7 +10,6 &#64;&#64; obj-y := process.o semaphore.o signal.o <br /> doublefault.o quirks.o i8237.o i8253.o tsc.o<br /> <br /> obj-y += cpu/<br />-obj-y += timers/<br /> obj-$(CONFIG_ACPI) += acpi/<br /> obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o<br /> obj-$(CONFIG_MCA) += mca.o<br />diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c<br />index 5a9f253..3336f43 100644<br />--- a/arch/i386/kernel/time.c<br />+++ b/arch/i386/kernel/time.c<br />&#64;&#64; -56,6 +56,7 &#64;&#64;<br /> #include &lt;asm/uaccess.h&gt;<br /> #include &lt;asm/processor.h&gt;<br /> #include &lt;asm/timer.h&gt;<br />+#include &lt;asm/timeofday.h&gt;<br /> <br /> #include "mach_time.h"<br /> <br />&#64;&#64; -82,8 +83,6 &#64;&#64; extern unsigned long wall_jiffies;<br /> DEFINE_SPINLOCK(rtc_lock);<br /> EXPORT_SYMBOL(rtc_lock);<br /> <br />-struct timer_opts *cur_timer __read_mostly = &amp;timer_none;<br />-<br /> /*<br /> * This is a special lock that is owned by the CPU and holds the index<br /> * register we are working with. It is required for NMI access to the<br />&#64;&#64; -113,99 +112,19 &#64;&#64; void rtc_cmos_write(unsigned char val, u<br /> }<br /> EXPORT_SYMBOL(rtc_cmos_write);<br /> <br />-/*<br />- * This version of gettimeofday has microsecond resolution<br />- * and better than microsecond precision on fast x86 machines with TSC.<br />- */<br />-void do_gettimeofday(struct timeval *tv)<br />-{<br />- unsigned long seq;<br />- unsigned long usec, sec;<br />- unsigned long max_ntp_tick;<br />-<br />- do {<br />- unsigned long lost;<br />-<br />- seq = read_seqbegin(&amp;xtime_lock);<br />-<br />- usec = cur_timer-&gt;get_offset();<br />- lost = jiffies - wall_jiffies;<br />-<br />- /*<br />- * If time_adjust is negative then NTP is slowing the clock<br />- * so make sure not to go into next possible interval.<br />- * Better to lose some accuracy than have time go backwards..<br />- */<br />- if (unlikely(time_adjust &lt; 0)) {<br />- max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;<br />- usec = min(usec, max_ntp_tick);<br />-<br />- if (lost)<br />- usec += lost * max_ntp_tick;<br />- }<br />- else if (unlikely(lost))<br />- usec += lost * (USEC_PER_SEC / HZ);<br />-<br />- sec = xtime.tv_sec;<br />- usec += (xtime.tv_nsec / 1000);<br />- } while (read_seqretry(&amp;xtime_lock, seq));<br />-<br />- while (usec &gt;= 1000000) {<br />- usec -= 1000000;<br />- sec++;<br />- }<br />-<br />- tv-&gt;tv_sec = sec;<br />- tv-&gt;tv_usec = usec;<br />-}<br />-<br />-EXPORT_SYMBOL(do_gettimeofday);<br />-<br />-int do_settimeofday(struct timespec *tv)<br />-{<br />- time_t wtm_sec, sec = tv-&gt;tv_sec;<br />- long wtm_nsec, nsec = tv-&gt;tv_nsec;<br />-<br />- if ((unsigned long)tv-&gt;tv_nsec &gt;= NSEC_PER_SEC)<br />- return -EINVAL;<br />-<br />- write_seqlock_irq(&amp;xtime_lock);<br />- /*<br />- * This is revolting. We need to set "xtime" correctly. However, the<br />- * value in this location is the value at the most recent update of<br />- * wall time. Discover what correction gettimeofday() would have<br />- * made, and then undo it!<br />- */<br />- nsec -= cur_timer-&gt;get_offset() * NSEC_PER_USEC;<br />- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;<br />-<br />- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);<br />- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);<br />-<br />- set_normalized_timespec(&amp;xtime, sec, nsec);<br />- set_normalized_timespec(&amp;wall_to_monotonic, wtm_sec, wtm_nsec);<br />-<br />- ntp_clear();<br />- write_sequnlock_irq(&amp;xtime_lock);<br />- clock_was_set();<br />- return 0;<br />-}<br />-<br />-EXPORT_SYMBOL(do_settimeofday);<br />-<br /> static int set_rtc_mmss(unsigned long nowtime)<br /> {<br /> int retval;<br />-<br />- WARN_ON(irqs_disabled());<br />+ unsigned long flags;<br /> <br /> /* gets recalled with irq locally disabled */<br />- spin_lock_irq(&amp;rtc_lock);<br />+ /* XXX - does irqsave resolve this? -johnstul */<br />+ spin_lock_irqsave(&amp;rtc_lock, flags);<br /> if (efi_enabled)<br /> retval = efi_set_rtc_mmss(nowtime);<br /> else<br /> retval = mach_set_rtc_mmss(nowtime);<br />- spin_unlock_irq(&amp;rtc_lock);<br />+ spin_unlock_irqrestore(&amp;rtc_lock, flags);<br /> <br /> return retval;<br /> }<br />&#64;&#64; -213,16 +132,6 &#64;&#64; static int set_rtc_mmss(unsigned long no<br /> <br /> int timer_ack;<br /> <br />-/* monotonic_clock(): returns # of nanoseconds passed since time_init()<br />- * Note: This function is required to return accurate<br />- * time even in the absence of multiple timer ticks.<br />- */<br />-unsigned long long monotonic_clock(void)<br />-{<br />- return cur_timer-&gt;monotonic_clock();<br />-}<br />-EXPORT_SYMBOL(monotonic_clock);<br />-<br /> #if defined(CONFIG_SMP) &amp;&amp; defined(CONFIG_FRAME_POINTER)<br /> unsigned long profile_pc(struct pt_regs *regs)<br /> {<br />&#64;&#64; -237,11 +146,21 &#64;&#64; EXPORT_SYMBOL(profile_pc);<br /> #endif<br /> <br /> /*<br />- * timer_interrupt() needs to keep up the real-time clock,<br />- * as well as call the "do_timer()" routine every clocktick<br />+ * This is the same as the above, except we _also_ save the current<br />+ * Time Stamp Counter value at the time of the timer interrupt, so that<br />+ * we later on can estimate the time of day more exactly.<br /> */<br />-static inline void do_timer_interrupt(int irq, struct pt_regs *regs)<br />+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)<br /> {<br />+ /*<br />+ * Here we are in the timer irq handler. We just have irqs locally<br />+ * disabled but we don't know if the timer_bh is running on the other<br />+ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need<br />+ * the irq version of write_lock because as just said we have irq<br />+ * locally disabled. -arca<br />+ */<br />+ write_seqlock(&amp;xtime_lock);<br />+<br /> #ifdef CONFIG_X86_IO_APIC<br /> if (timer_ack) {<br /> /*<br />&#64;&#64; -274,27 +193,6 &#64;&#64; static inline void do_timer_interrupt(in<br /> irq = inb_p( 0x61 ); /* read the current state */<br /> outb_p( irq|0x80, 0x61 ); /* reset the IRQ */<br /> }<br />-}<br />-<br />-/*<br />- * This is the same as the above, except we _also_ save the current<br />- * Time Stamp Counter value at the time of the timer interrupt, so that<br />- * we later on can estimate the time of day more exactly.<br />- */<br />-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)<br />-{<br />- /*<br />- * Here we are in the timer irq handler. We just have irqs locally<br />- * disabled but we don't know if the timer_bh is running on the other<br />- * CPU. We need to avoid to SMP race with it. NOTE: we don' t need<br />- * the irq version of write_lock because as just said we have irq<br />- * locally disabled. -arca<br />- */<br />- write_seqlock(&amp;xtime_lock);<br />-<br />- cur_timer-&gt;mark_offset();<br />- <br />- do_timer_interrupt(irq, regs);<br /> <br /> write_sequnlock(&amp;xtime_lock);<br /> return IRQ_HANDLED;<br />&#64;&#64; -318,58 +216,37 &#64;&#64; unsigned long get_cmos_time(void)<br /> }<br /> EXPORT_SYMBOL(get_cmos_time);<br /> <br />-static void sync_cmos_clock(unsigned long dummy);<br />-<br />-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);<br />-<br />-static void sync_cmos_clock(unsigned long dummy)<br />+/* arch specific timeofday hooks */<br />+nsec_t read_persistent_clock(void)<br /> {<br />- struct timeval now, next;<br />- int fail = 1;<br />+ return (nsec_t)get_cmos_time() * NSEC_PER_SEC;<br />+}<br /> <br />+void sync_persistent_clock(struct timespec ts)<br />+{<br />+ static unsigned long last_rtc_update;<br /> /*<br /> * If we have an externally synchronized Linux clock, then update<br /> * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be<br /> * called as close as possible to 500 ms before the new second starts.<br />- * This code is run on a timer. If the clock is set, that timer<br />- * may not expire at the correct time. Thus, we adjust...<br /> */<br />- if (!ntp_synced())<br />- /*<br />- * Not synced, exit, do not restart a timer (if one is<br />- * running, let it run out).<br />- */<br />+ if (ts.tv_sec &lt;= last_rtc_update + 660)<br /> return;<br /> <br />- do_gettimeofday(&amp;now);<br />- if (now.tv_usec &gt;= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &amp;&amp;<br />- now.tv_usec &lt;= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)<br />- fail = set_rtc_mmss(now.tv_sec);<br />-<br />- next.tv_usec = USEC_AFTER - now.tv_usec;<br />- if (next.tv_usec &lt;= 0)<br />- next.tv_usec += USEC_PER_SEC;<br />-<br />- if (!fail)<br />- next.tv_sec = 659;<br />- else<br />- next.tv_sec = 0;<br />-<br />- if (next.tv_usec &gt;= USEC_PER_SEC) {<br />- next.tv_sec++;<br />- next.tv_usec -= USEC_PER_SEC;<br />+ if((ts.tv_nsec / 1000) &gt;= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &amp;&amp;<br />+ (ts.tv_nsec / 1000) &lt;= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {<br />+ /* horrible...FIXME */<br />+ if (set_rtc_mmss(ts.tv_sec) == 0)<br />+ last_rtc_update = ts.tv_sec;<br />+ else<br />+ last_rtc_update = ts.tv_sec - 600; /* do it again in 60 s */<br /> }<br />- mod_timer(&amp;sync_cmos_timer, jiffies + timeval_to_jiffies(&amp;next));<br /> }<br /> <br />-void notify_arch_cmos_timer(void)<br />-{<br />- mod_timer(&amp;sync_cmos_timer, jiffies + 1);<br />-}<br />+<br /> <br /> static long clock_cmos_diff, sleep_start;<br /> <br />-static struct timer_opts *last_timer;<br /> static int timer_suspend(struct sys_device *dev, pm_message_t state)<br /> {<br /> /*<br />&#64;&#64; -378,16 +255,11 &#64;&#64; static int timer_suspend(struct sys_devi<br /> clock_cmos_diff = -get_cmos_time();<br /> clock_cmos_diff += get_seconds();<br /> sleep_start = get_cmos_time();<br />- last_timer = cur_timer;<br />- cur_timer = &amp;timer_none;<br />- if (last_timer-&gt;suspend)<br />- last_timer-&gt;suspend(state);<br /> return 0;<br /> }<br /> <br /> static int timer_resume(struct sys_device *dev)<br /> {<br />- unsigned long flags;<br /> unsigned long sec;<br /> unsigned long sleep_length;<br /> <br />&#64;&#64; -397,16 +269,8 &#64;&#64; static int timer_resume(struct sys_devic<br /> #endif<br /> sec = get_cmos_time() + clock_cmos_diff;<br /> sleep_length = (get_cmos_time() - sleep_start) * HZ;<br />- write_seqlock_irqsave(&amp;xtime_lock, flags);<br />- xtime.tv_sec = sec;<br />- xtime.tv_nsec = 0;<br />- write_sequnlock_irqrestore(&amp;xtime_lock, flags);<br /> jiffies += sleep_length;<br /> wall_jiffies += sleep_length;<br />- if (last_timer-&gt;resume)<br />- last_timer-&gt;resume();<br />- cur_timer = last_timer;<br />- last_timer = NULL;<br /> touch_softlockup_watchdog();<br /> return 0;<br /> }<br />&#64;&#64; -439,17 +303,10 &#64;&#64; extern void (*late_time_init)(void);<br /> /* Duplicate of time_init() below, with hpet_enable part added */<br /> static void __init hpet_time_init(void)<br /> {<br />- xtime.tv_sec = get_cmos_time();<br />- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);<br />- set_normalized_timespec(&amp;wall_to_monotonic,<br />- -xtime.tv_sec, -xtime.tv_nsec);<br />-<br /> if ((hpet_enable() &gt;= 0) &amp;&amp; hpet_use_timer) {<br /> printk("Using HPET for base-timer\n");<br /> }<br /> <br />- cur_timer = select_timer();<br />- printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer-&gt;name);<br /> <br /> time_init_hook();<br /> }<br />&#64;&#64; -467,13 +324,5 &#64;&#64; void __init time_init(void)<br /> return;<br /> }<br /> #endif<br />- xtime.tv_sec = get_cmos_time();<br />- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);<br />- set_normalized_timespec(&amp;wall_to_monotonic,<br />- -xtime.tv_sec, -xtime.tv_nsec);<br />-<br />- cur_timer = select_timer();<br />- printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer-&gt;name);<br />-<br /> time_init_hook();<br /> }<br />diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c<br />index 8345506..bd04f92 100644<br />--- a/arch/i386/kernel/tsc.c<br />+++ b/arch/i386/kernel/tsc.c<br />&#64;&#64; -10,6 +10,7 &#64;&#64;<br /> #include &lt;linux/init.h&gt;<br /> <br /> #include &lt;asm/tsc.h&gt;<br />+#include &lt;asm/delay.h&gt;<br /> #include &lt;asm/io.h&gt;<br /> <br /> #include "mach_timer.h"<br />&#64;&#64; -45,16 +46,6 &#64;&#64; static int __init tsc_setup(char *str)<br /> <br /> __setup("notsc", tsc_setup);<br /> <br />-<br />-int read_current_timer(unsigned long *timer_val)<br />-{<br />- if (!tsc_disable &amp;&amp; cpu_khz) {<br />- rdtscl(*timer_val);<br />- return 0;<br />- }<br />- return -1;<br />-}<br />-<br /> /*<br /> * code to mark and check if the TSC is unstable<br /> * due to cpufreq or due to unsynced TSCs<br />&#64;&#64; -207,6 +198,7 &#64;&#64; void tsc_init(void)<br /> (unsigned long)cpu_khz % 1000);<br /> <br /> set_cyc2ns_scale(cpu_khz);<br />+ use_tsc_delay();<br /> }<br /> <br /> #ifdef CONFIG_CPU_FREQ<br />diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c<br />index c49a6ac..bddf666 100644<br />--- a/arch/i386/lib/delay.c<br />+++ b/arch/i386/lib/delay.c<br />&#64;&#64; -10,43 +10,93 &#64;&#64;<br /> * we have to worry about.<br /> */<br /> <br />+#include &lt;linux/timeofday.h&gt;<br />+#include &lt;linux/module.h&gt;<br /> #include &lt;linux/config.h&gt;<br /> #include &lt;linux/sched.h&gt;<br /> #include &lt;linux/delay.h&gt;<br />-#include &lt;linux/module.h&gt;<br />+<br /> #include &lt;asm/processor.h&gt;<br /> #include &lt;asm/delay.h&gt;<br /> #include &lt;asm/timer.h&gt;<br /> <br /> #ifdef CONFIG_SMP<br />-#include &lt;asm/smp.h&gt;<br />+# include &lt;asm/smp.h&gt;<br /> #endif<br /> <br />-extern struct timer_opts* timer;<br />+/* simple loop based delay: */<br />+static void delay_loop(unsigned long loops)<br />+{<br />+ int d0;<br />+<br />+ __asm__ __volatile__(<br />+ "\tjmp 1f\n"<br />+ ".align 16\n"<br />+ "1:\tjmp 2f\n"<br />+ ".align 16\n"<br />+ "2:\tdecl %0\n\tjns 2b"<br />+ :"=&amp;a" (d0)<br />+ :"0" (loops));<br />+}<br />+<br />+/* TSC based delay: */<br />+static void delay_tsc(unsigned long loops)<br />+{<br />+ unsigned long bclock, now;<br />+<br />+ rdtscl(bclock);<br />+ do {<br />+ rep_nop();<br />+ rdtscl(now);<br />+ } while ((now-bclock) &lt; loops);<br />+}<br />+<br />+/*<br />+ * Since we calibrate only once at boot, this<br />+ * function should be set once at boot and not changed<br />+ */<br />+static void (*delay_fn)(unsigned long) = delay_loop;<br />+<br />+void use_tsc_delay(void)<br />+{<br />+ delay_fn = delay_tsc;<br />+}<br />+<br />+int read_current_timer(unsigned long *timer_val)<br />+{<br />+ if (delay_fn == delay_tsc) {<br />+ rdtscl(*timer_val);<br />+ return 0;<br />+ }<br />+ return -1;<br />+}<br /> <br /> void __delay(unsigned long loops)<br /> {<br />- cur_timer-&gt;delay(loops);<br />+ delay_fn(loops);<br /> }<br /> <br /> inline void __const_udelay(unsigned long xloops)<br /> {<br /> int d0;<br />+<br /> xloops *= 4;<br /> __asm__("mull %0"<br /> :"=d" (xloops), "=&amp;a" (d0)<br />- :"1" (xloops),"0" (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4)));<br />- __delay(++xloops);<br />+ :"1" (xloops), "0"<br />+ (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4)));<br />+<br />+ __delay(++xloops);<br /> }<br /> <br /> void __udelay(unsigned long usecs)<br /> {<br />- __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */<br />+ __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */<br /> }<br /> <br /> void __ndelay(unsigned long nsecs)<br /> {<br />- __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */<br />+ __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */<br /> }<br /> <br /> EXPORT_SYMBOL(__delay);<br />diff --git a/include/asm-i386/delay.h b/include/asm-i386/delay.h<br />index 456db85..b1c7650 100644<br />--- a/include/asm-i386/delay.h<br />+++ b/include/asm-i386/delay.h<br />&#64;&#64; -23,4 +23,6 &#64;&#64; extern void __delay(unsigned long loops)<br /> ((n) &gt; 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \<br /> __ndelay(n))<br /> <br />+void use_tsc_delay(void);<br />+<br /> #endif /* defined(_I386_DELAY_H) */<br />diff --git a/include/asm-i386/timeofday.h b/include/asm-i386/timeofday.h<br />new file mode 100644<br />index 0000000..315edf9<br />--- /dev/null<br />+++ b/include/asm-i386/timeofday.h<br />&#64;&#64; -0,0 +1,4 &#64;&#64;<br />+#ifndef _ASM_I386_TIMEOFDAY_H<br />+#define _ASM_I386_TIMEOFDAY_H<br />+#include &lt;asm-generic/timeofday.h&gt;<br />+#endif<br />diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h<br />index aed1643..d0ebd05 100644<br />--- a/include/asm-i386/timer.h<br />+++ b/include/asm-i386/timer.h<br />&#64;&#64; -3,68 +3,11 &#64;&#64;<br /> #include &lt;linux/init.h&gt;<br /> #include &lt;linux/pm.h&gt;<br /> <br />-/**<br />- * struct timer_ops - used to define a timer source<br />- *<br />- * &#64;name: name of the timer.<br />- * &#64;init: Probes and initializes the timer. Takes clock= override <br />- * string as an argument. Returns 0 on success, anything else<br />- * on failure.<br />- * &#64;mark_offset: called by the timer interrupt.<br />- * &#64;get_offset: called by gettimeofday(). Returns the number of microseconds<br />- * since the last timer interupt.<br />- * &#64;monotonic_clock: returns the number of nanoseconds since the init of the<br />- * timer.<br />- * &#64;delay: delays this many clock cycles.<br />- */<br />-struct timer_opts {<br />- char* name;<br />- void (*mark_offset)(void);<br />- unsigned long (*get_offset)(void);<br />- unsigned long long (*monotonic_clock)(void);<br />- void (*delay)(unsigned long);<br />- unsigned long (*read_timer)(void);<br />- int (*suspend)(pm_message_t state);<br />- int (*resume)(void);<br />-};<br />-<br />-struct init_timer_opts {<br />- int (*init)(char *override);<br />- struct timer_opts *opts;<br />-};<br />-<br /> #define TICK_SIZE (tick_nsec / 1000)<br />-<br />-extern struct timer_opts* __init select_timer(void);<br />-extern void clock_fallback(void);<br /> void setup_pit_timer(void);<br />-<br /> /* Modifiers for buggy PIT handling */<br />-<br /> extern int pit_latch_buggy;<br />-<br />-extern struct timer_opts *cur_timer;<br /> extern int timer_ack;<br />-<br />-/* list of externed timers */<br />-extern struct timer_opts timer_none;<br />-extern struct timer_opts timer_pit;<br />-extern struct init_timer_opts timer_pit_init;<br />-extern struct init_timer_opts timer_tsc_init;<br />-#ifdef CONFIG_X86_CYCLONE_TIMER<br />-extern struct init_timer_opts timer_cyclone_init;<br />-#endif<br />-<br />-extern unsigned long calibrate_tsc(void);<br />-extern unsigned long read_timer_tsc(void);<br />-extern void init_cpu_khz(void);<br /> extern int recalibrate_cpu_khz(void);<br />-#ifdef CONFIG_HPET_TIMER<br />-extern struct init_timer_opts timer_hpet_init;<br />-extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);<br />-#endif<br /> <br />-#ifdef CONFIG_X86_PM_TIMER<br />-extern struct init_timer_opts timer_pmtmr_init;<br />-#endif<br /> #endif<br />-<br />To unsubscribe from this list: send the line "unsubscribe linux-kernel" in<br />the body of a message to majordomo&#64;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:15 聽聽 [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>

Pages: 1 2 3 4 5 6 7 8 9 10