linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH query] arm: i.MX/MX1 clock event source
@ 2007-01-21  0:01 Pavel Pisa
  2007-01-22 19:59 ` Ingo Molnar
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Pisa @ 2007-01-21  0:01 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: Ingo Molnar, linux-kernel, Sascha Hauer

Hello Thomas, Sascha and Ingo

please can you find some time to review next patch
  arm: i.MX/MX1 clock event source
which has been sent to you and to the ALKML at 2007-01-13.

http://thread.gmane.org/gmane.linux.ports.arm.kernel/29510/focus=29533

There seems to be some problems, because this patch has not been
accepted to patch-2.6.20-rc5-rt7.patch, but GENERIC_CLOCKEVENTS
are set already for i.MX and this results in a problems to run
RT kernel on this architecture.

 config ARCH_IMX
        bool "IMX"
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS


Thanks for review and your time

                Pavel

-------------------------------------------------------------------------------------
Subject: arm: i.MX/MX1 clock event source

Support clock event source based on i.MX general purpose
timer in free running timer mode.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>


 arch/arm/mach-imx/time.c |   92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

Index: linux-2.6.20-rc4/arch/arm/mach-imx/time.c
===================================================================
--- linux-2.6.20-rc4.orig/arch/arm/mach-imx/time.c
+++ linux-2.6.20-rc4/arch/arm/mach-imx/time.c
@@ -15,6 +15,9 @@
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#include <linux/clockchips.h>
+#endif
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -25,6 +28,11 @@
 /* Use timer 1 as system timer */
 #define TIMER_BASE IMX_TIM1_BASE
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+static struct clock_event_device clockevent_imx;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_PERIODIC;
+#endif
+
 static unsigned long evt_diff;
 
 /*
@@ -42,9 +50,16 @@ imx_timer_interrupt(int irq, void *dev_i
 	if (tstat & TSTAT_COMP) {
 		do {
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+			if (clockevent_imx.event_handler)
+				clockevent_imx.event_handler();
+			if  (likely(clockevent_mode != CLOCK_EVT_PERIODIC))
+				break;
+#else
 			write_seqlock(&xtime_lock);
 			timer_tick();
 			write_sequnlock(&xtime_lock);
+#endif
 			IMX_TCMP(TIMER_BASE) += evt_diff;
 
 		} while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE)
@@ -99,11 +114,88 @@ static int __init imx_clocksource_init(v
 	return 0;
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+static void imx_set_next_event(unsigned long evt,
+				  struct clock_event_device *unused)
+{
+	evt_diff = evt;
+	IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) + evt;
+}
+
+static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call imx_set_next_event()
+	 */
+	local_irq_save(flags);
+	/* Disable interrupt in GPT module */
+	IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
+	if ((mode != CLOCK_EVT_PERIODIC) || (mode != clockevent_mode)) {
+		/* Set event time into far-far future */
+		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
+		/* Clear pending interrupt */
+		IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
+	}
+	/* Remember timer mode */
+	clockevent_mode = mode;
+	local_irq_restore(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_PERIODIC:
+	case CLOCK_EVT_ONESHOT:
+		/*
+		 * Do not put overhead of interrupt enable/disable into
+		 * imx_set_next_event(), the core has about 4 minutes
+		 * to call imx_set_next_event() or shutdown clock after
+		 * mode switching
+		 */
+		local_irq_save(flags);
+		IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
+		local_irq_restore(flags);
+		break;
+	case CLOCK_EVT_SHUTDOWN:
+		/* Left event sources disabled, no more interrupts appears */
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_imx = {
+	.name		= "imx_timer1",
+	.capabilities	= CLOCK_CAP_NEXTEVT | CLOCK_CAP_TICK |
+			  CLOCK_CAP_UPDATE | CLOCK_CAP_PROFILE,
+	.shift		= 32,
+	.set_mode	= imx_set_mode,
+	.set_next_event	= imx_set_next_event,
+};
+
+static int __init imx_clockevent_init(void)
+{
+	clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC,
+					clockevent_imx.shift);
+	clockevent_imx.max_delta_ns =
+		clockevent_delta2ns(0xfffffffe, &clockevent_imx);
+	clockevent_imx.min_delta_ns =
+		clockevent_delta2ns(0xf, &clockevent_imx);
+	register_local_clockevent(&clockevent_imx);
+
+	return 0;
+}
+#endif
+
+
 static void __init imx_timer_init(void)
 {
 	imx_timer_hardware_init();
 	imx_clocksource_init();
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	imx_clockevent_init();
+#endif
+
 	/*
 	 * Make irqs happen for the system timer
 	 */


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH query] arm: i.MX/MX1 clock event source
  2007-01-21  0:01 [PATCH query] arm: i.MX/MX1 clock event source Pavel Pisa
@ 2007-01-22 19:59 ` Ingo Molnar
  2007-01-23  2:52   ` Pavel Pisa
  0 siblings, 1 reply; 6+ messages in thread
From: Ingo Molnar @ 2007-01-22 19:59 UTC (permalink / raw)
  To: Pavel Pisa; +Cc: Thomas Gleixner, linux-kernel, Sascha Hauer


* Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:

> Hello Thomas, Sascha and Ingo
> 
> please can you find some time to review next patch
>   arm: i.MX/MX1 clock event source
> which has been sent to you and to the ALKML at 2007-01-13.
> 
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/29510/focus=29533
> 
> There seems to be some problems, because this patch has not been 
> accepted to patch-2.6.20-rc5-rt7.patch, but GENERIC_CLOCKEVENTS are 
> set already for i.MX and this results in a problems to run RT kernel 
> on this architecture.

i've added your patch to -rt, but note that there's a new, slightly 
incompatible clockevents code in -rt now so you'll need to do some more 
(hopefully trivial) fixups for this to build and work.

	Ingo

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH query] arm: i.MX/MX1 clock event source
  2007-01-22 19:59 ` Ingo Molnar
@ 2007-01-23  2:52   ` Pavel Pisa
  2007-01-24  2:00     ` Pavel Pisa
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Pisa @ 2007-01-23  2:52 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Thomas Gleixner, linux-kernel, Sascha Hauer

On Monday 22 January 2007 20:59, Ingo Molnar wrote:
> * Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:
> > Hello Thomas, Sascha and Ingo
> >
> > please can you find some time to review next patch
> >   arm: i.MX/MX1 clock event source
> > which has been sent to you and to the ALKML at 2007-01-13.
> >
> > http://thread.gmane.org/gmane.linux.ports.arm.kernel/29510/focus=29533
> >
> > There seems to be some problems, because this patch has not been
> > accepted to patch-2.6.20-rc5-rt7.patch, but GENERIC_CLOCKEVENTS are
> > set already for i.MX and this results in a problems to run RT kernel
> > on this architecture.
>
> i've added your patch to -rt, but note that there's a new, slightly
> incompatible clockevents code in -rt now so you'll need to do some more
> (hopefully trivial) fixups for this to build and work.
>
> 	Ingo


Hello Ingo,

thanks for reply. I am attaching updated version of the patch at the end of e-mail.
There is problem with missing include in tick-sched.c

  CC      kernel/time/tick-sched.o
/usr/src/linux-2.6.20-rc5/kernel/time/tick-sched.c: In function `tick_nohz_handler':
/usr/src/linux-2.6.20-rc5/kernel/time/tick-sched.c:330: warning: implicit declaration of function `get_irq_regs'
/usr/src/linux-2.6.20-rc5/kernel/time/tick-sched.c:330: warning: initialization makes pointer from integer without a cast
/usr/src/linux-2.6.20-rc5/kernel/time/tick-sched.c: In function `tick_sched_timer':
/usr/src/linux-2.6.20-rc5/kernel/time/tick-sched.c:425: warning: initialization makes pointer from integer without a cast
  LD      kernel/time/built-in.o

--- linux-2.6.20-rc5.orig/kernel/time/tick-sched.c
+++ linux-2.6.20-rc5/kernel/time/tick-sched.c
@@ -20,6 +20,7 @@
 #include <linux/profile.h>
 #include <linux/sched.h>
 #include <linux/tick.h>
+#include <asm/irq_regs.h>
 
 #include "tick-internal.h"

And

  CC      arch/arm/kernel/process.o
/usr/src/linux-2.6.20-rc5/arch/arm/kernel/process.c: In function `cpu_idle':
/usr/src/linux-2.6.20-rc5/arch/arm/kernel/process.c:157: warning: implicit declaration of function `hrtimer_stop_sched_tick'
/usr/src/linux-2.6.20-rc5/arch/arm/kernel/process.c:161: warning: implicit declaration of function `hrtimer_restart_sched_tick'

--- linux-2.6.20-rc5.orig/arch/arm/kernel/process.c
+++ linux-2.6.20-rc5/arch/arm/kernel/process.c
@@ -154,11 +154,11 @@ void cpu_idle(void)
 		if (!idle)
 			idle = default_idle;
 		leds_event(led_idle_start);
-		hrtimer_stop_sched_tick();
+		tick_nohz_stop_sched_tick();
 		while (!need_resched() && !need_resched_delayed())
 			idle();
 		leds_event(led_idle_end);
-		hrtimer_restart_sched_tick();
+		tick_nohz_restart_sched_tick();
 		local_irq_disable();
 		__preempt_enable_no_resched();
 		__schedule();

Unfortunately, even with these corrections boot stuck at

Memory: 18972KB available (2488K code, 358K data, 92K init)

I have not time now to start JTAG debugging session, so I look at that
tomorrow or on Friday.

It seems, that the interrupts are not coming from device.

Best wishes

            Pavel

==========================================================================
Subject: arm: i.MX/MX1 clock event source

Support clock event source based on i.MX general purpose
timer in free running timer mode.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>

 arch/arm/mach-imx/time.c |  112 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 107 insertions(+), 5 deletions(-)

Index: linux-2.6.20-rc5/arch/arm/mach-imx/time.c
===================================================================
--- linux-2.6.20-rc5.orig/arch/arm/mach-imx/time.c
+++ linux-2.6.20-rc5/arch/arm/mach-imx/time.c
@@ -15,6 +15,9 @@
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#include <linux/clockchips.h>
+#endif
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -25,6 +28,11 @@
 /* Use timer 1 as system timer */
 #define TIMER_BASE IMX_TIM1_BASE
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+static struct clock_event_device clockevent_imx;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_PERIODIC;
+#endif
+
 static unsigned long evt_diff;
 
 /*
@@ -33,6 +41,7 @@ static unsigned long evt_diff;
 static irqreturn_t
 imx_timer_interrupt(int irq, void *dev_id)
 {
+	unsigned long tcmp;
 	uint32_t tstat;
 
 	/* clear the interrupt */
@@ -42,13 +51,20 @@ imx_timer_interrupt(int irq, void *dev_i
 	if (tstat & TSTAT_COMP) {
 		do {
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+			if (clockevent_imx.event_handler)
+				clockevent_imx.event_handler(&clockevent_imx);
+			if (likely(clockevent_mode != CLOCK_EVT_MODE_PERIODIC))
+				break;
+#else
 			write_seqlock(&xtime_lock);
 			timer_tick();
 			write_sequnlock(&xtime_lock);
-			IMX_TCMP(TIMER_BASE) += evt_diff;
+#endif
+			tcmp = IMX_TCMP(TIMER_BASE) + evt_diff;
+			IMX_TCMP(TIMER_BASE) = tcmp;
 
-		} while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE)
-					- IMX_TCN(TIMER_BASE)) < 0));
+		} while (unlikely((int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0));
 	}
 
 	return IRQ_HANDLED;
@@ -70,7 +86,7 @@ static void __init imx_timer_hardware_in
 	 */
 	IMX_TCTL(TIMER_BASE) = 0;
 	IMX_TPRER(TIMER_BASE) = 0;
-	IMX_TCMP(TIMER_BASE) = LATCH - 1;
+	IMX_TCMP(TIMER_BASE) += LATCH;
 
 	IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN;
 	evt_diff = LATCH;
@@ -87,7 +103,7 @@ static struct clocksource clocksource_im
 	.read		= imx_get_cycles,
 	.mask		= 0xFFFFFFFF,
 	.shift 		= 20,
-	.is_continuous 	= 1,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static int __init imx_clocksource_init(void)
@@ -99,11 +115,97 @@ static int __init imx_clocksource_init(v
 	return 0;
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+static int imx_set_next_event(unsigned long evt,
+				  struct clock_event_device *unused)
+{
+	unsigned long tcmp;
+	evt_diff = evt;
+
+	tcmp = IMX_TCN(TIMER_BASE) + evt;
+	IMX_TCMP(TIMER_BASE) = tcmp;
+
+	return unlikely((int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0) ? -ETIME : 0;
+}
+
+static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call imx_set_next_event()
+	 */
+	local_irq_save(flags);
+	/* Disable interrupt in GPT module */
+	IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
+	if ((mode != CLOCK_EVT_MODE_PERIODIC) || (mode != clockevent_mode)) {
+		/* Set event time into far-far future */
+		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
+		/* Clear pending interrupt */
+		IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
+	}
+	/* Remember timer mode */
+	clockevent_mode = mode;
+	local_irq_restore(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* It seems, that periodic mode expects old ugly latch period */
+		evt_diff = LATCH;
+		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) + evt_diff;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/*
+		 * Do not put overhead of interrupt enable/disable into
+		 * imx_set_next_event(), the core has about 4 minutes
+		 * to call imx_set_next_event() or shutdown clock after
+		 * mode switching
+		 */
+		local_irq_save(flags);
+		IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
+		local_irq_restore(flags);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+		/* Left event sources disabled, no more interrupts appears */
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_imx = {
+	.name		= "imx_timer1",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_mode	= imx_set_mode,
+	.set_next_event	= imx_set_next_event,
+	.rating		= 200,
+};
+
+static int __init imx_clockevent_init(void)
+{
+	clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC,
+					clockevent_imx.shift);
+	clockevent_imx.max_delta_ns =
+		clockevent_delta2ns(0xfffffffe, &clockevent_imx);
+	clockevent_imx.min_delta_ns =
+		clockevent_delta2ns(0xf, &clockevent_imx);
+	clockevents_register_device(&clockevent_imx);
+
+	return 0;
+}
+#endif
+
+
 static void __init imx_timer_init(void)
 {
 	imx_timer_hardware_init();
 	imx_clocksource_init();
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	imx_clockevent_init();
+#endif
+
 	/*
 	 * Make irqs happen for the system timer
 	 */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH query] arm: i.MX/MX1 clock event source
  2007-01-23  2:52   ` Pavel Pisa
@ 2007-01-24  2:00     ` Pavel Pisa
  2007-01-24 11:37       ` Thomas Gleixner
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Pisa @ 2007-01-24  2:00 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Thomas Gleixner, linux-kernel, Sascha Hauer

On Tuesday 23 January 2007 03:52, Pavel Pisa wrote:
> > i've added your patch to -rt, but note that there's a new, slightly
> > incompatible clockevents code in -rt now so you'll need to do some more
> > (hopefully trivial) fixups for this to build and work.
> >
> > 	Ingo
>
> Hello Ingo,
>
> Unfortunately, even with these corrections boot stuck at
>
> Memory: 18972KB available (2488K code, 358K data, 92K init)
>
> I have not time now to start JTAG debugging session, so I look at that
> tomorrow or on Friday.
>
> It seems, that the interrupts are not coming from device.
>
> Best wishes
>
>             Pavel
>

Hello Ingo,

I have found some time and tried to debugg problem with
help of JTAG debugger. But I have found, that IRQs
are processed right. The plain rc5 runs flawlessly.
The rt8 doesnot start. The problem is, that handler
stays NULL after clock event registration. Interrupts
runs, but my code doesnot call any function. The notification
chain and clock events list seems to be filled correctly.
I have added 

        clockevent_imx.cpumask = cpumask_of_cpu(0);

to ensure that clock are not used for affinity
mask reasons. I have tried even exchange clock 
event forcibly at the end of clockevent_imx initialization.
But it only resulted in asking timer to switch off
into unused mode.

I have added next hack into IRQ
                                write_seqlock(&xtime_lock);
                                timer_tick();
                                write_sequnlock(&xtime_lock);
which stays enabled until imx_set_mode() is called first time,
The system boots after this modification, but imx_set_mode()
is never called and there is no switch to high resolution mode.

CONFIG_ARM=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
??? CONFIG_TICK_ONESHOT=y ???
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_RT=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_SOFTIRQS=y
CONFIG_PREEMPT_HARDIRQS=y
CONFIG_PREEMPT_BKL=y

Could I preset some handler directly during timer initialization?
Can I declare somehow, that I want to use that clock event device
as source of tick from beginning? Should I try to rebuild with CONFIG_NO_HZ=n?
I would like to keep up with changes, because I have tested
RTs for ARM already over more "stable" releases and over many rc-s.
And high resolution timers support has worked well over for me last
three months (up to 2.6.20-rc4). So I want to learn what is required
to be compatible with latest code.

Thanks for any hints to the problem

                     Pavel



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH query] arm: i.MX/MX1 clock event source
  2007-01-24  2:00     ` Pavel Pisa
@ 2007-01-24 11:37       ` Thomas Gleixner
  2007-01-26 19:34         ` [PATCH updated] " Pavel Pisa
  0 siblings, 1 reply; 6+ messages in thread
From: Thomas Gleixner @ 2007-01-24 11:37 UTC (permalink / raw)
  To: Pavel Pisa; +Cc: Ingo Molnar, linux-kernel, Sascha Hauer

On Wed, 2007-01-24 at 03:00 +0100, Pavel Pisa wrote:
> stays NULL after clock event registration. Interrupts
> runs, but my code doesnot call any function. The notification
> chain and clock events list seems to be filled correctly.
> I have added 
> 
>         clockevent_imx.cpumask = cpumask_of_cpu(0);

Correct. I probably should disable the check for UP.

> to ensure that clock are not used for affinity
> mask reasons. I have tried even exchange clock 
> event forcibly at the end of clockevent_imx initialization.
> But it only resulted in asking timer to switch off
> into unused mode.
> 
> I have added next hack into IRQ
>                                 write_seqlock(&xtime_lock);
>                                 timer_tick();
>                                 write_sequnlock(&xtime_lock);
> which stays enabled until imx_set_mode() is called first time,
> The system boots after this modification, but imx_set_mode()
> is never called and there is no switch to high resolution mode.

You should not set up the timer at all. The setup of the timer happens
from the registration. 

We need to know, why the timer is not picked from the tick code in the
first place and why set_mode() is not called.

	tglx





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH updated] arm: i.MX/MX1 clock event source
  2007-01-24 11:37       ` Thomas Gleixner
@ 2007-01-26 19:34         ` Pavel Pisa
  0 siblings, 0 replies; 6+ messages in thread
From: Pavel Pisa @ 2007-01-26 19:34 UTC (permalink / raw)
  To: tglx; +Cc: Ingo Molnar, linux-kernel, Sascha Hauer

On Wednesday 24 January 2007 12:37, Thomas Gleixner wrote:
> On Wed, 2007-01-24 at 03:00 +0100, Pavel Pisa wrote:
> > stays NULL after clock event registration. Interrupts
> > runs, but my code doesnot call any function. The notification
> > chain and clock events list seems to be filled correctly.
> > I have added
> >
> >         clockevent_imx.cpumask = cpumask_of_cpu(0);
>
> Correct. I probably should disable the check for UP.

I have made mistake last time on 2.6.20-rc5-rt8.
I have returned to testing today with 2.6.20-rc6-rt2.
I have added checking outputs to the tickregistration
routines, but all works correctly after right cpumask correction.
I have rechecked even without additional printks
and I have observed no problems. The clock events enabled kernels
requires next minor changes to compile on ARM still

================================================================================
================================================================================

 arch/arm/kernel/process.c |    5 +++--
 kernel/time/tick-sched.c  |    1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

Index: linux-2.6.20-rc6/kernel/time/tick-sched.c
===================================================================
--- linux-2.6.20-rc6.orig/kernel/time/tick-sched.c
+++ linux-2.6.20-rc6/kernel/time/tick-sched.c
@@ -20,6 +20,7 @@
 #include <linux/profile.h>
 #include <linux/sched.h>
 #include <linux/tick.h>
+#include <asm/irq_regs.h>
 
 #include "tick-internal.h"
 
Index: linux-2.6.20-rc6/arch/arm/kernel/process.c
===================================================================
--- linux-2.6.20-rc6.orig/arch/arm/kernel/process.c
+++ linux-2.6.20-rc6/arch/arm/kernel/process.c
@@ -28,6 +28,7 @@
 #include <linux/cpu.h>
 #include <linux/elfcore.h>
 #include <linux/pm.h>
+#include <linux/tick.h>
 
 #include <asm/leds.h>
 #include <asm/processor.h>
@@ -154,11 +155,11 @@ void cpu_idle(void)
 		if (!idle)
 			idle = default_idle;
 		leds_event(led_idle_start);
-		hrtimer_stop_sched_tick();
+		tick_nohz_stop_sched_tick();
 		while (!need_resched() && !need_resched_delayed())
 			idle();
 		leds_event(led_idle_end);
-		hrtimer_restart_sched_tick();
+		tick_nohz_restart_sched_tick();
 		local_irq_disable();
 		__preempt_enable_no_resched();
 		__schedule();

================================================================================
================================================================================

Updated version of i.MX patch follows. If somebody wants it,
I can send patch to revert code of previous version from
full 2.6.20-rc6-rt2 patch.

Ingo, please, can you replace i.MX1 patch in your series?

Thanks

          Pavel

================================================================================
================================================================================
Subject: arm: i.MX/MX1 clock event source

Support clock event source based on i.MX general purpose
timer in free running timer mode.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>

 arch/arm/mach-imx/time.c |  130 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 125 insertions(+), 5 deletions(-)

Index: linux-2.6.20-rc6/arch/arm/mach-imx/time.c
===================================================================
--- linux-2.6.20-rc6.orig/arch/arm/mach-imx/time.c
+++ linux-2.6.20-rc6/arch/arm/mach-imx/time.c
@@ -15,6 +15,9 @@
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#include <linux/clockchips.h>
+#endif
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -25,6 +28,11 @@
 /* Use timer 1 as system timer */
 #define TIMER_BASE IMX_TIM1_BASE
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+static struct clock_event_device clockevent_imx;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_PERIODIC;
+#endif
+
 static unsigned long evt_diff;
 
 /*
@@ -33,6 +41,7 @@ static unsigned long evt_diff;
 static irqreturn_t
 imx_timer_interrupt(int irq, void *dev_id)
 {
+	unsigned long tcmp;
 	uint32_t tstat;
 
 	/* clear the interrupt */
@@ -42,13 +51,20 @@ imx_timer_interrupt(int irq, void *dev_i
 	if (tstat & TSTAT_COMP) {
 		do {
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+			if (clockevent_imx.event_handler)
+				clockevent_imx.event_handler(&clockevent_imx);
+			if (likely(clockevent_mode != CLOCK_EVT_MODE_PERIODIC))
+				break;
+#else
 			write_seqlock(&xtime_lock);
 			timer_tick();
 			write_sequnlock(&xtime_lock);
-			IMX_TCMP(TIMER_BASE) += evt_diff;
+#endif
+			tcmp = IMX_TCMP(TIMER_BASE) + evt_diff;
+			IMX_TCMP(TIMER_BASE) = tcmp;
 
-		} while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE)
-					- IMX_TCN(TIMER_BASE)) < 0));
+		} while (unlikely((int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0));
 	}
 
 	return IRQ_HANDLED;
@@ -70,7 +86,7 @@ static void __init imx_timer_hardware_in
 	 */
 	IMX_TCTL(TIMER_BASE) = 0;
 	IMX_TPRER(TIMER_BASE) = 0;
-	IMX_TCMP(TIMER_BASE) = LATCH - 1;
+	IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) + LATCH;
 
 	IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN;
 	evt_diff = LATCH;
@@ -87,7 +103,7 @@ static struct clocksource clocksource_im
 	.read		= imx_get_cycles,
 	.mask		= 0xFFFFFFFF,
 	.shift 		= 20,
-	.is_continuous 	= 1,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static int __init imx_clocksource_init(void)
@@ -99,11 +115,115 @@ static int __init imx_clocksource_init(v
 	return 0;
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+static int imx_set_next_event(unsigned long evt,
+				  struct clock_event_device *unused)
+{
+	unsigned long tcmp;
+	evt_diff = evt;
+
+	tcmp = IMX_TCN(TIMER_BASE) + evt;
+	IMX_TCMP(TIMER_BASE) = tcmp;
+
+	return unlikely((int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0) ? -ETIME : 0;
+}
+
+#ifdef DEBUG
+static const char *clock_event_mode_label[]={
+	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
+	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
+	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
+	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
+};
+#endif /*DEBUG*/
+
+static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call imx_set_next_event()
+	 */
+	local_irq_save(flags);
+	/* Disable interrupt in GPT module */
+	IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
+	if ((mode != CLOCK_EVT_MODE_PERIODIC) || (mode != clockevent_mode)) {
+		/* Set event time into far-far future */
+		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
+		/* Clear pending interrupt */
+		IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
+	}
+
+#ifdef DEBUG
+	printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n",
+		clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]);
+#endif /*DEBUG*/
+
+	/* Remember timer mode */
+	clockevent_mode = mode;
+	local_irq_restore(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* It seems, that periodic mode expects old ugly latch period */
+		evt_diff = LATCH;
+		IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) + evt_diff;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/*
+		 * Do not put overhead of interrupt enable/disable into
+		 * imx_set_next_event(), the core has about 4 minutes
+		 * to call imx_set_next_event() or shutdown clock after
+		 * mode switching
+		 */
+		local_irq_save(flags);
+		IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
+		local_irq_restore(flags);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+		/* Left event sources disabled, no more interrupts appears */
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_imx = {
+	.name		= "imx_timer1",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_mode	= imx_set_mode,
+	.set_next_event	= imx_set_next_event,
+	.rating		= 200,
+};
+
+static int __init imx_clockevent_init(void)
+{
+	clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC,
+					clockevent_imx.shift);
+	clockevent_imx.max_delta_ns =
+		clockevent_delta2ns(0xfffffffe, &clockevent_imx);
+	clockevent_imx.min_delta_ns =
+		clockevent_delta2ns(0xf, &clockevent_imx);
+
+	clockevent_imx.cpumask = cpumask_of_cpu(0);
+
+	clockevents_register_device(&clockevent_imx);
+
+	return 0;
+}
+#endif
+
+
 static void __init imx_timer_init(void)
 {
 	imx_timer_hardware_init();
 	imx_clocksource_init();
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	imx_clockevent_init();
+#endif
+
 	/*
 	 * Make irqs happen for the system timer
 	 */

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-01-26 19:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-01-21  0:01 [PATCH query] arm: i.MX/MX1 clock event source Pavel Pisa
2007-01-22 19:59 ` Ingo Molnar
2007-01-23  2:52   ` Pavel Pisa
2007-01-24  2:00     ` Pavel Pisa
2007-01-24 11:37       ` Thomas Gleixner
2007-01-26 19:34         ` [PATCH updated] " Pavel Pisa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).