On Wed, Apr 19, 2006 at 06:44:26PM +0200, Lennert Buytenhek wrote:
> I was being lazy when I implemented this, and so the 983040/HZ division
> error will still cause some drift, but this should be easy enough to
> compensate for -- just do the TIMER4_TICKS_PER_JIFFY division as a round-
> to-zero instead of round-nearest division, and increment a separate
> accumulator by 983040 % HZ on every timer tick, and when that accumulator
> goes >= HZ, increment next_jiffy_time by one. I'll just code that up
> right now and see if it works.
Sorry, didn't have much time today. The patch below (against
2.6.17-rc2) should in theory (untested) make linux timekeeping as
accurate as possible, limited only by accuracy of the hardware.
Attached to this email is a small simulation program (blah.c) that
kind of sort of demonstrates that the algorithm is correct. But of
course, someone will still have to verify it in practise. :-)
cheers,
Lennert
diff -urN linux-2.6.17-rc2.orig/arch/arm/mach-ep93xx/core.c
linux-2.6.17-rc2/arch/arm/mach-ep93xx/core.c
--- linux-2.6.17-rc2.orig/arch/arm/mach-ep93xx/core.c 2006-04-19
21:54:41.000000000 +0200
+++ linux-2.6.17-rc2/arch/arm/mach-ep93xx/core.c 2006-04-20
00:10:49.000000000 +0200
@@ -95,18 +95,32 @@
* track of lost jiffies.
*/
static unsigned int last_jiffy_time;
+static unsigned int next_jiffy_time;
+static unsigned int accumulator;
-#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
+#define TIMER4_TICKS_PER_JIFFY (CLOCK_TICK_RATE / HZ)
+#define TIMER4_TICKS_MOD_JIFFY (CLOCK_TICK_RATE % HZ)
+
+static int after_eq(unsigned long a, unsigned long b)
+{
+ return ((signed long)(a - b)) >= 0;
+}
static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
write_seqlock(&xtime_lock);
__raw_writel(1, EP93XX_TIMER1_CLEAR);
- while (__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time
- >= TIMER4_TICKS_PER_JIFFY) {
- last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
+ while (after_eq(__raw_readl(EP93XX_TIMER4_VALUE_LOW), next_jiffy_time))
{
timer_tick(regs);
+
+ last_jiffy_time = next_jiffy_time;
+ next_jiffy_time += TIMER4_TICKS_PER_JIFFY;
+ accumulator += TIMER4_TICKS_MOD_JIFFY;
+ if (accumulator >= HZ) {
+ next_jiffy_time++;
+ accumulator -= HZ;
+ }
}
write_sequnlock(&xtime_lock);
@@ -124,7 +138,7 @@
{
/* Enable periodic HZ timer. */
__raw_writel(0x48, EP93XX_TIMER1_CONTROL);
- __raw_writel((508000 / HZ) - 1, EP93XX_TIMER1_LOAD);
+ __raw_writel((508469 / HZ) - 1, EP93XX_TIMER1_LOAD);
__raw_writel(0xc8, EP93XX_TIMER1_CONTROL);
/* Enable lost jiffy timer. */
Yahoo! Groups Links
<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/ts-7000/
<*> To unsubscribe from this group, send an email to:
<*> Your use of Yahoo! Groups is subject to:
http://docs.yahoo.com/info/terms/
blah.c
Description: Text document
|