[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-arm-kernel
Subject:    [RFC] decouple ixp4xx timer interval calculation from
From:       Lennert Buytenhek <buytenh () wantstofly ! org>
Date:       2005-09-29 14:59:40
Message-ID: 20050929145940.GA13486 () xi ! wantstofly ! org
[Download RAW message or body]

Hi!

ixp4xx currenty uses the compile-time define CLOCK_TICK_RATE for
calculating the HZ timer interval at kernel boot time.  This is
slightly unfortunate as it doesn't allow for compiling in support
for multiple different board types with different core clock
frequencies.

CLOCK_TICK_RATE is also used (indirectly) by kernel/timer.c for
precision timekeeping, and there are reasons (see previous threads)
not to do the arithmetic depending on CLOCK_TICK_RATE at run time.

So, as a first step, the patch below decouples CLOCK_TICK_RATE from
the ixp4xx timer code just like it's done on ixp2000.  This allows
us to choose the timer interval at run time.  (Otherwise totally
untested and probably will not compile.)  How does that look?


This patch still leaves the problem of CLOCK_TICK_RATE being wrong.

The value of CLOCK_TICK_RATE and that of HZ are used to calculate
how many nanoseconds one timer interval really takes.  For HZ=100
and CLOCK_TICK_RATE=1000000, each timer interval really does take
1/100 of a second, but for CLOCK_TICK_RATE=1234567 and HZ=100 for
example, the timer interval will end up as 1234567 / 100 ~ 12346
clocks, which is then 267ns per timer interval too long, and so
the timekeeping code will account for that.

However, the arithmetic for the two values of CLOCK_TICK_RATE
currently out in the wild (66666666 and 66000000) with the default
value of HZ=100 works out to give the exact the same value for
TICK_NSEC, 10000000, so it doesn't really matter whether we put
66666666 or 66000000 in here, which means we don't have to deal
with this yet.  (Besides, some archs put totally bogus values in
CLOCK_TICK_RATE and get away with it too.)

Comments?


cheers,
Lennert


--- linux-2.6.13/arch/arm/mach-ixp4xx/common.c.orig	2005-09-28 13:18:10.000000000 +0200
+++ linux-2.6.13/arch/arm/mach-ixp4xx/common.c	2005-09-28 15:06:40.000000000 +0200
@@ -261,19 +261,18 @@
  * We use OS timer1 on the CPU for the timer tick and the timestamp 
  * counter as a source of real clock ticks to account for missed jiffies.
  *************************************************************************/
-
-static unsigned volatile last_jiffy_time;
-
-#define CLOCK_TICKS_PER_USEC	((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
+static unsigned ticks_per_jiffy;
+static unsigned ticks_per_usec;
+static unsigned last_jiffy_time;
 
 /* IRQs are disabled before entering here from do_gettimeofday() */
-static unsigned long ixp4xx_gettimeoffset(void)
+unsigned long ixp4xx_gettimeoffset(void)
 {
-	u32 elapsed;
+	unsigned long offset;
 
-	elapsed = *IXP4XX_OSTS - last_jiffy_time;
+	offset = *IXP4XX_OSTS - last_jiffy_time;
 
-	return elapsed / CLOCK_TICKS_PER_USEC;
+	return offset / ticks_per_usec;
 }
 
 static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -286,9 +285,9 @@
 	/*
 	 * Catch up with the real idea of time
 	 */
-	while ((*IXP4XX_OSTS - last_jiffy_time) > LATCH) {
+	while ((*IXP4XX_OSTS - last_jiffy_time) > ticks_per_jiffy) {
 		timer_tick(regs);
-		last_jiffy_time += LATCH;
+		last_jiffy_time += ticks_per_jiffy;
 	}
 
 	write_sequnlock(&xtime_lock);
@@ -302,13 +301,16 @@
 	.handler	= ixp4xx_timer_interrupt,
 };
 
-static void __init ixp4xx_timer_init(void)
+static void __init ixp4xx_init_time(unsigned long tick_rate)
 {
+	ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
+	ticks_per_usec = tick_rate / 1000000;
+
 	/* Clear Pending Interrupt by writing '1' to it */
 	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
 
 	/* Setup the Timer counter value */
-	*IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
+	*IXP4XX_OSRT1 = ((ticks_per_jiffy - 1) & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
 
 	/* Reset time-stamp counter */
 	*IXP4XX_OSTS = 0;
@@ -318,11 +320,6 @@
 	setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
 }
 
-struct sys_timer ixp4xx_timer = {
-	.init		= ixp4xx_timer_init,
-	.offset		= ixp4xx_gettimeoffset,
-};
-
 static struct resource ixp46x_i2c_resources[] = {
 	[0] = {
 		.start 	= 0xc8011000,
--- linux-2.6.13/arch/arm/mach-ixp4xx/coyote-setup.c.orig	2005-09-28 13:27:44.000000000 +0200
+++ linux-2.6.13/arch/arm/mach-ixp4xx/coyote-setup.c	2005-09-28 13:39:50.000000000 +0200
@@ -29,6 +29,16 @@
 	ixp4xx_map_io();
 }
 
+static void __init coyote_timer_init(void)
+{
+	ixp4xx_init_time(66666666);
+}
+
+static struct sys_timer coyote_timer = {
+	.init		= coyote_timer_init,
+	.offset		= ixp4xx_gettimeoffset,
+};
+
 static struct flash_platform_data coyote_flash_data = {
 	.map_name	= "cfi_probe",
 	.width		= 2,
@@ -109,7 +119,7 @@
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= coyote_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &coyote_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= coyote_init,
 MACHINE_END
--- linux-2.6.13/arch/arm/mach-ixp4xx/gtwx5715-setup.c.orig	2005-09-28 13:27:49.000000000 +0200
+++ linux-2.6.13/arch/arm/mach-ixp4xx/gtwx5715-setup.c	2005-09-28 14:19:12.000000000 +0200
@@ -107,6 +107,16 @@
 	ixp4xx_map_io();
 }
 
+static void __init gtwx5715_timer_init(void)
+{
+	ixp4xx_init_time(66666666);
+}
+
+static struct sys_timer gtwx5715_timer = {
+	.init		= gtwx5715_timer_init,
+	.offset		= ixp4xx_gettimeoffset,
+};
+
 static struct flash_platform_data gtwx5715_flash_data = {
 	.map_name	= "cfi_probe",
 	.width		= 2,
@@ -146,7 +156,7 @@
 	.io_pg_offst	= ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= gtwx5715_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &gtwx5715_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= gtwx5715_init,
 MACHINE_END
--- linux-2.6.13/arch/arm/mach-ixp4xx/ixdp425-setup.c.orig	2005-09-28 13:27:55.000000000 +0200
+++ linux-2.6.13/arch/arm/mach-ixp4xx/ixdp425-setup.c	2005-09-28 14:29:33.000000000 +0200
@@ -29,6 +29,16 @@
 	ixp4xx_map_io();
 }
 
+static void __init ixdp425_timer_init(void)
+{
+	ixp4xx_init_time(66666666);
+}
+
+static struct sys_timer ixdp425_timer = {
+	.init		= ixdp425_timer_init,
+	.offset		= ixp4xx_gettimeoffset,
+};
+
 static struct flash_platform_data ixdp425_flash_data = {
 	.map_name	= "cfi_probe",
 	.width		= 2,
@@ -135,7 +145,7 @@
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &ixdp425_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= ixdp425_init,
 MACHINE_END
@@ -147,7 +157,7 @@
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &ixdp425_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= ixdp425_init,
 MACHINE_END
@@ -159,7 +169,7 @@
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &ixdp425_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= ixdp425_init,
 MACHINE_END
@@ -178,7 +188,7 @@
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
-	.timer		= &ixp4xx_timer,
+	.timer		= &ixdp425_timer,
 	.boot_params	= 0x0100,
 	.init_machine	= ixdp425_init,
 MACHINE_END

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic