linux-rt-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* clocksource and clockevent confusion
@ 2011-04-01 17:25 Johannes Bauer
  0 siblings, 0 replies; 8+ messages in thread
From: Johannes Bauer @ 2011-04-01 17:25 UTC (permalink / raw)
  To: linux-rt-users


Hi RT Mailing List!

Im trying to implement a clocksource driver for my board, which is a mach-lpc22xx board. I downloaded linux2-6.33 and patched it with the latest RT patch in order to get a RT kernel. Then I realized that i had to enable the hrtimer support in order to gain the benefit of preempt-rt.
However, to use hrt it seems i need to use the GENERIC_CLOCKEVENT timer instead of the old one using timer_tick(). I do not find a detailed documentation on this clockevent subsystem, and i dont grasp the aspect of clocksource and clockevent, what is the difference? I also dont know what exactly the shift and mult struct entities are in specific. I have a PIT running at 72MHz, and providing a 32bit prescaler counter and a 32 bit counter register, I want to use as the tick counter.
So if i set the prescaler counter to 71 (0x47) my timer counter runs with 1Mhz (increments every us). I can configure any number in 32bit compare register in order to throw an interrupt and reseting the counter and prescaler counter. My cpu (lpc2478) runs with 288MHz.
So in thsi example, what would be the ideal configuration for my timer to achieve highest resultion for hrt and what would be the corresponding settings for shift and mult?
I hope you can help me to run the system with the PIT as jiffy tick and for hrt usage.

Thank you very much in advance
Johannes Bauer 

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

* Re: clocksource and clockevent confusion
       [not found] <4458795.11336.1301677125869.JavaMail.root@WARSBL213.highway.telekom.at>
@ 2011-04-04 18:51 ` Johannes Bauer
  2011-04-04 19:35   ` Patrice Kadionik
  0 siblings, 1 reply; 8+ messages in thread
From: Johannes Bauer @ 2011-04-04 18:51 UTC (permalink / raw)
  To: linux-rt-users

Can anybody help me to sort this out plz, since I cannot find any example I can \"copy\" it for my implementation and i urgently need it to get my testscope running. I forgot to mention that i already read the highrest.txt, but it doesnt help me since there is no detailed information on what exactly mult and shift is. \"nanoseconds to cycles multiplier\" and divisor dont make click for me either and the mask member seems to have to do something with the timeroverrun, but is it the mask for the counter register, when it throw the interrupts and starts from BOTTOM again. What if i don use a power of two number as a compare match as interrupt source (for example 0x47), can i do that or is it restricted? Im somehow in the dark here...
Any help would be highly appreciated.

Kind regards Johannes Bauer

----- Original von:  Johannes Bauer

> 
 Hi RT Mailing List!


Im trying to implement a clocksource driver for my board, which is a
mach-lpc22xx board. I downloaded linux2-6.33 and patched it with the
latest RT patch in order to get a RT kernel. Then I realized that i had
to enable the hrtimer support in order to gain the benefit of
preempt-rt.
 However, to use hrt it seems i need to use the
GENERIC_CLOCKEVENT timer instead of the old one using timer_tick(). I
do not find a detailed documentation on this clockevent subsystem, and
i dont grasp the aspect of clocksource and clockevent, what is the
difference? I also dont know what exactly the shift and mult struct
entities are in specific. I have a PIT running at 72MHz, and providing
a 32bit prescaler counter and a 32 bit counter register, I want to use
as the tick counter. 
 So if i set the prescaler counter to 71
(0x47) my timer counter runs with 1Mhz (increments every us). I can
configure any number in 32bit compare register in order to throw an
interrupt and reseting the counter and prescaler counter. My cpu
(lpc2478) runs with 288MHz.
 So in thsi example, what would be the
ideal configuration for my timer to achieve highest resultion for hrt
and what would be the corresponding settings for shift and mult?
 I hope you can help me to run the system with the PIT as jiffy tick and for hrt usage.

 Thank you very much in advance
 Jhannes Bauer


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

* Re: clocksource and clockevent confusion
  2011-04-04 18:51 ` Johannes Bauer
@ 2011-04-04 19:35   ` Patrice Kadionik
  0 siblings, 0 replies; 8+ messages in thread
From: Patrice Kadionik @ 2011-04-04 19:35 UTC (permalink / raw)
  To: linux-rt-users, hannes_bauer

Le 04/04/2011 20:51, Johannes Bauer a écrit :

Hi Johannes,

Same problem than you one year before: 
http://www.spinics.net/lists/linux-rt-users/msg05299.html

Please find below some pointers on high resolution timers:

Thomas Gleixner's & Douglas Niehaus's presentation:
http://www.linuxsymposium.org/2006/linuxsymposium_procv1.pdf from page 333
http://userweb.kernel.org/~tglx/ols2006/ols2006-hrtimers.pdf

This good report on PREEMPT-RT port on AVR32 and on hrtimer port on 
AVR32: http://ntnu.diva-portal.org/smash/get/diva2:350562/FULLTEXT01

http://lwn.net/Articles/167897/
http://public.dhe.ibm.com/software/dw/linux/l-timers-list/l-timers-list-pdf.pdf
https://rt.wiki.kernel.org/index.php/High_resolution_timer_design_notes
http://elinux.org/High_Resolution_Timers

I have implemented high resolution timer support for NIOS II softcore 
processor. You may find the source code here as example: 
http://sopc.et.ntust.edu.tw/pipermail/nios2-dev/2011-January/004543.html
For the high resolution timer port, you must have 2 timers:
- a timer that you program in one shot mode with the next event of the 
hrtimer subsystem known as a clock event.
- a timer that acts as a free running counter that gives time stamping  
generally multiple of the CPU frequency known as a clock source. A 
64-bit timer is preferable.
My work was derived from the high resolution timer port for MicroBlaze 
which is now in the arch/ directory in the vanilla Linux kernel. The 
code is easy to understand.

May this help you...

Cheers;

Pat.

> Can anybody help me to sort this out plz, since I cannot find any example I can \"copy\" it for my implementation and i urgently need it to get my testscope running. I forgot to mention that i already read the highrest.txt, but it doesnt help me since there is no detailed information on what exactly mult and shift is. \"nanoseconds to cycles multiplier\" and divisor dont make click for me either and the mask member seems to have to do something with the timeroverrun, but is it the mask for the counter register, when it throw the interrupts and starts from BOTTOM again. What if i don use a power of two number as a compare match as interrupt source (for example 0x47), can i do that or is it restricted? Im somehow in the dark here...
> Any help would be highly appreciated.
>
> Kind regards Johannes Bauer
>
> ----- Original von:  Johannes Bauer
>
>   Hi RT Mailing List!
>
>
> Im trying to implement a clocksource driver for my board, which is a
> mach-lpc22xx board. I downloaded linux2-6.33 and patched it with the
> latest RT patch in order to get a RT kernel. Then I realized that i had
> to enable the hrtimer support in order to gain the benefit of
> preempt-rt.
>   However, to use hrt it seems i need to use the
> GENERIC_CLOCKEVENT timer instead of the old one using timer_tick(). I
> do not find a detailed documentation on this clockevent subsystem, and
> i dont grasp the aspect of clocksource and clockevent, what is the
> difference? I also dont know what exactly the shift and mult struct
> entities are in specific. I have a PIT running at 72MHz, and providing
> a 32bit prescaler counter and a 32 bit counter register, I want to use
> as the tick counter.
>   So if i set the prescaler counter to 71
> (0x47) my timer counter runs with 1Mhz (increments every us). I can
> configure any number in 32bit compare register in order to throw an
> interrupt and reseting the counter and prescaler counter. My cpu
> (lpc2478) runs with 288MHz.
>   So in thsi example, what would be the
> ideal configuration for my timer to achieve highest resultion for hrt
> and what would be the corresponding settings for shift and mult?
>   I hope you can help me to run the system with the PIT as jiffy tick and for hrt usage.
>
>   Thank you very much in advance
>   Jhannes Bauer
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Patrice Kadionik. F6KQH / F4CUQ
-----------

+----------------------------------------------------------------------+
+"Tout doit etre aussi simple que possible, pas seulement plus simple" +
+----------------------------------------------------------------------+
+ Patrice Kadionik             http://www.enseirb-matmeca.fr/~kadionik +
+ IMS Laboratory               http://www.ims-bordeaux.fr/             +
+ ENSEIRB-MATMECA              http://www.enseirb-matmeca.fr           +
+ PO BOX 99                    fax   : +33 5.56.37.20.23               +
+ 33402 TALENCE Cedex          voice : +33 5.56.84.23.47               +
+ FRANCE                       mailto:patrice.kadionik@ims-bordeaux.fr +
+----------------------------------------------------------------------+

--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: clocksource and clockevent confusion
@ 2011-04-07 16:48 Johannes Bauer
  2011-04-07 17:41 ` Patrice Kadionik
  2011-04-07 18:37 ` Patrice Kadionik
  0 siblings, 2 replies; 8+ messages in thread
From: Johannes Bauer @ 2011-04-07 16:48 UTC (permalink / raw)
  To: linux-rt-users

Thank you for your help Pat!

I figured out to write a driver, thats the code:

static cycle_t read_pit_clk(struct clocksource *cs)
{

	return T0TC;	// returns the actual timer count 
}

static struct clocksource pit_clk = {
	.name		= \"pit\",
	.rating		= 175,
	.read		= read_pit_clk,
	.shift		= 28,	//is changed by init code
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

/*
 * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
 */
static void
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		/* update clocksource counter */
		T0MR0 = 720000;
		T0PR = 0;
		T0MCR &= ~0x04;	//be sure timer does not stop on compare match
		T0MCR |= 0x03;
		break;
	case CLOCK_EVT_MODE_ONESHOT:
		T0MR0 = 720000;
		T0PR = 0;
		
		T0MCR |= 0x07;
		break;
		/* FALLTHROUGH */
	case CLOCK_EVT_MODE_SHUTDOWN:
		T0MCR &= ~0x01;
		break;
	case CLOCK_EVT_MODE_UNUSED:
		/* disable irq, leaving the clocksource active */
		T0MCR &= ~0x01;
		break;
	case CLOCK_EVT_MODE_RESUME:
		break;
	}
}

static struct clock_event_device pit_clkevt = {
	.name		= \"pit\",
	.features	= CLOCK_EVT_FEAT_PERIODIC,
	.shift		= 32,	//is changed by init function
	.rating		= 100,	//dont know yet
	.set_mode	= pit_clkevt_mode,
};


unsigned long lpc2xxx_gettimeoffset (void)
{
	//CLOCKS_PER_USEC = LPC2xxx_Fpclk / 1000000;
	return (T0TC/(lpc2xxx_fcclk / 1000000));
}

static irqreturn_t
lpc2xxx_timer_interrupt(int irq, void *dev_id)
{
    if (!(T0IR & 0x01)) return IRQ_NONE;
/*    do_timer(regs);
    do_profile(regs);
*/ //timer_tick(); 
/* modified 20050608 for new version */

	pit_clkevt.event_handler(&pit_clkevt);	//handle_event
//	printk(\"Interrupt\\n\");
	
    T0IR |= 0x01;	/* reset interrupt */
    return IRQ_HANDLED;
}

static struct irqaction lpc2xxx_timer_irq = {
        .name           = \"lpc2xxx-tick\",
	.flags		= IRQF_DISABLED | IRQF_TIMER,
        .handler        = lpc2xxx_timer_interrupt
};

/*
 * Set up timer interrupt, and return the current time in seconds.
 */
/*
 Setup PCLK_TIMER0 = Fcclk (01)
 Setup T0MR0 = 10 (ms)
 Setup T0PR0 = 0
*/
void __init  lpc2xxx_time_init (void)
{
	unsigned char clkSel = 0;
	unsigned long stat = PLLSTAT;
	unsigned long M = stat & 0x7FFFF;
	unsigned long N = (stat>>16) & 0xFF;
	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
	lpc2xxx_fcclk = Fcclk;
	lpc2xxx_fpclk = Fcclk;

	/* 
  	 * Here we assume that the clock is the same for all peripherals
 	 * which of course doesn\'t have to be the case.
	 * We should be using the clk.h interface instead.
	 */
	
	clkSel = (unsigned char)(PCLKSEL0 & 0xff);
	if (clkSel == 0x00)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
	else if (clkSel == 0x55)
		lpc2xxx_fpclk = lpc2xxx_fcclk;
	else if (clkSel == 0xAA)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
	else if (clkSel == 0xFF)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;

	printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
		CONFIG_LPC22xx_Fosc,
		Fcco,
		M,
		N);
	PCLKSEL0 &= ~(3<<2);
	PCLKSEL0 |=  (1<<2);
	printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
		Fcclk, PCLKSEL0, PCLKSEL1);
	/*
	 * disable and clear timer 0, set to
	 */
	T0TCR &= ~0x01;
	/* initialize the timer period and prescaler */

	//counts with 72MHz so compare interrupt every 10ms
	T0MR0 = 720000;
	T0PR = 0;	// prescaler = 0
	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/

	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;

	/* set up the interrupt vevtor for timer 0 match */
	setup_irq(LPC2xxx_INTERRUPT_TIMER0, &lpc2xxx_timer_irq);
	
	/* enable the timer IRQ */
	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);

	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)

	pit_clk.mask = 71999;				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
	clocksource_register(&pit_clk);

	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
	clockevents_register_device(&pit_clkevt);

	/* let timer 0 run... */
	T0IR = 0x01; /* reset MR0 interrupt*/
	T0TCR = 0x02;	/* Reset timer count and prescale counter */
	T0TCR = 0x01;	/* enable timer counter and prescale counter */
}

struct sys_timer lpc22xx_timer = {
	.init		= lpc2xxx_time_init,
};



The problem is that after a minute or so the kernel freezes and hangs in the cpu_idle() function in arch/arm/kernel/process.c

the board stays in this whileloop in the else condition forever:

while (!need_resched()) {
#ifdef CONFIG_HOTPLUG_CPU
			if (cpu_is_offline(smp_processor_id()))
				cpu_die();
#endif

			local_irq_disable();
			if (hlt_counter) {
				local_irq_enable();
				cpu_relax();
			} else {
				stop_critical_timings();
				pm_idle();
				start_critical_timings();
				/*
				 * This will eventually be removed - pm_idle
				 * functions should always return with IRQs
				 * enabled.
				 */
				WARN_ON(irqs_disabled());
				local_irq_enable();
			}
		}

i dont know what exactly the problem is...
Do i have to implement a sched_clock routine myself as is saw it in a few implemetations.
When i do a cat \"/proc/timer_list\" i can see folowing:

cat timer_list
Timer List Version: v0.5
HRTIMER_MAX_CLOCK_BASES: 2
now at 960971480 nsecs

cpu: 0
 clock 0:
  .base:       a031c560
  .index:      0
  .resolution: 10000000 nsecs
  .get_time:   ktime_get_real
  .offset:     0 nsecs
active timers:
 clock 1:
  .base:       a031c594
  .index:      1
  .resolution: 10000000 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
 # expires at 1000000000-1000000000 nsecs [in 39028520 to 39028520 nsecs]
 #1: <a12fda88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
 # expires at 1960997774-1961997798 nsecs [in 1000026294 to 1001026318 nsecs]
  .expires_next   : 2147483646999999999 nsecs
  .hres_active    : 0
  .nr_events      : 0
  .nr_retries     : 0
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 960913921 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 77532270 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 4294941108


Tick Device: mode:     0
Per CPU device: 0
Clock Event Device: pit
 max_delta_ns:   0
 min_delta_ns:   0
 mult:           309237645
 shift:          32
 mode:           2
 next_event:     2147483646999999999 nsecs
 set_next_event: <(null)>
 set_mode:       pit_clkevt_mode
 event_handler:  tick_handle_periodic


I enabled some tracing and debuging in the kernel and then the following message was printed when the processor froze:

\"sched: RT throttling activated\"

What does it mean? IS it a problem of my timer implementation or is something else wrong with the system?

I hope somebody can help me on this.

Kind regards
Johannes Bauer


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

* Re: clocksource and clockevent confusion
  2011-04-07 16:48 Johannes Bauer
@ 2011-04-07 17:41 ` Patrice Kadionik
  2011-04-07 18:37 ` Patrice Kadionik
  1 sibling, 0 replies; 8+ messages in thread
From: Patrice Kadionik @ 2011-04-07 17:41 UTC (permalink / raw)
  To: linux-rt-users

Le 07/04/2011 18:48, Johannes Bauer a écrit :
Hi Johannes,

Take example to my source code or to the MicroBlaze source code.

> Thank you for your help Pat!
>
> I figured out to write a driver, thats the code:
>
> static cycle_t read_pit_clk(struct clocksource *cs)
> {
>
> 	return T0TC;	// returns the actual timer count
> }
>
> static struct clocksource pit_clk = {
> 	.name		= \"pit\",
> 	.rating		= 175,
> 	.read		= read_pit_clk,
> 	.shift		= 28,	//is changed by init code
> 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
> /*
>   * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
>   */
> static void
> pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
> {
> 	switch (mode) {
> 	case CLOCK_EVT_MODE_PERIODIC:
> 		/* update clocksource counter */
> 		T0MR0 = 720000;
> 		T0PR = 0;
> 		T0MCR&= ~0x04;	//be sure timer does not stop on compare match
> 		T0MCR |= 0x03;
> 		break;
> 	case CLOCK_EVT_MODE_ONESHOT:
> 		T0MR0 = 720000;
> 		T0PR = 0;
> 		
> 		T0MCR |= 0x07;
I don't think so... nothing to do here.

> 		break;
> 		/* FALLTHROUGH */
> 	case CLOCK_EVT_MODE_SHUTDOWN:
> 		T0MCR&= ~0x01;
> 		break;
> 	case CLOCK_EVT_MODE_UNUSED:
> 		/* disable irq, leaving the clocksource active */
> 		T0MCR&= ~0x01;
> 		break;
> 	case CLOCK_EVT_MODE_RESUME:
> 		break;
> 	}
> }
>
> static struct clock_event_device pit_clkevt = {
> 	.name		= \"pit\",
> 	.features	= CLOCK_EVT_FEAT_PERIODIC,
> 	.shift		= 32,	//is changed by init function
> 	.rating		= 100,	//dont know yet
> 	.set_mode	= pit_clkevt_mode,
BE CAREFUL!
no  .set_next_event here. So the the clock event is never reprogrammed 
with the next event. See my example derived form the hrtimer support for 
MicroBlaze.
In my example:
.set_next_event = nios2_timer_set_next_event,

The prototype of the function is for me:

static int nios2_timer_set_next_event(unsigned long delta,struct 
clock_event_device *dev)

So you have to reprogram your clock event timer, ie the PIT timer for 
you with the next event fournished by the hrtimer subsystem. The next 
event is given by the delta value
in number of CPU clock periods. Easy after to reprogram the clock event 
timer for the right number of CPU clock periods. In my case, I call 
directly nios2_timer0_start_oneshot(delta) to reprogram my timer in 
delta in the register (minus 1) because my timer runs at the same 
frequency than my CPU processor ;-)

> };
>
>
> unsigned long lpc2xxx_gettimeoffset (void)
> {
> 	//CLOCKS_PER_USEC = LPC2xxx_Fpclk / 1000000;
> 	return (T0TC/(lpc2xxx_fcclk / 1000000));
> }
>
> static irqreturn_t
> lpc2xxx_timer_interrupt(int irq, void *dev_id)
> {
>      if (!(T0IR&  0x01)) return IRQ_NONE;
> /*    do_timer(regs);
>      do_profile(regs);
> */ //timer_tick();
> /* modified 20050608 for new version */
>
> 	pit_clkevt.event_handler(&pit_clkevt);	//handle_event
> //	printk(\"Interrupt\\n\");
> 	
>      T0IR |= 0x01;	/* reset interrupt */
>      return IRQ_HANDLED;
> }
>
> static struct irqaction lpc2xxx_timer_irq = {
>          .name           = \"lpc2xxx-tick\",
> 	.flags		= IRQF_DISABLED | IRQF_TIMER,
>          .handler        = lpc2xxx_timer_interrupt
> };
>
> /*
>   * Set up timer interrupt, and return the current time in seconds.
>   */
> /*
>   Setup PCLK_TIMER0 = Fcclk (01)
>   Setup T0MR0 = 10 (ms)
>   Setup T0PR0 = 0
> */
> void __init  lpc2xxx_time_init (void)
> {
> 	unsigned char clkSel = 0;
> 	unsigned long stat = PLLSTAT;
> 	unsigned long M = stat&  0x7FFFF;
> 	unsigned long N = (stat>>16)&  0xFF;
> 	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
> 	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
> 	lpc2xxx_fcclk = Fcclk;
> 	lpc2xxx_fpclk = Fcclk;
>
> 	/*
>    	 * Here we assume that the clock is the same for all peripherals
>   	 * which of course doesn\'t have to be the case.
> 	 * We should be using the clk.h interface instead.
> 	 */
> 	
> 	clkSel = (unsigned char)(PCLKSEL0&  0xff);
> 	if (clkSel == 0x00)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
> 	else if (clkSel == 0x55)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk;
> 	else if (clkSel == 0xAA)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
> 	else if (clkSel == 0xFF)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;
>
> 	printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
> 		CONFIG_LPC22xx_Fosc,
> 		Fcco,
> 		M,
> 		N);
> 	PCLKSEL0&= ~(3<<2);
> 	PCLKSEL0 |=  (1<<2);
> 	printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
> 		Fcclk, PCLKSEL0, PCLKSEL1);
> 	/*
> 	 * disable and clear timer 0, set to
> 	 */
> 	T0TCR&= ~0x01;
> 	/* initialize the timer period and prescaler */
>
> 	//counts with 72MHz so compare interrupt every 10ms
> 	T0MR0 = 720000;
> 	T0PR = 0;	// prescaler = 0
> 	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/
>
> 	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;
>
> 	/* set up the interrupt vevtor for timer 0 match */
> 	setup_irq(LPC2xxx_INTERRUPT_TIMER0,&lpc2xxx_timer_irq);
> 	
> 	/* enable the timer IRQ */
> 	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);
>
> 	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>
> 	pit_clk.mask = 71999;				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
> 	clocksource_register(&pit_clk);
>
> 	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
> 	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
> 	clockevents_register_device(&pit_clkevt);
>
> 	/* let timer 0 run... */
> 	T0IR = 0x01; /* reset MR0 interrupt*/
> 	T0TCR = 0x02;	/* Reset timer count and prescale counter */
> 	T0TCR = 0x01;	/* enable timer counter and prescale counter */
> }
>
> struct sys_timer lpc22xx_timer = {
> 	.init		= lpc2xxx_time_init,
> };
>
>
>
> The problem is that after a minute or so the kernel freezes and hangs in the cpu_idle() function in arch/arm/kernel/process.c
>
> the board stays in this whileloop in the else condition forever:
>
> while (!need_resched()) {
> #ifdef CONFIG_HOTPLUG_CPU
> 			if (cpu_is_offline(smp_processor_id()))
> 				cpu_die();
> #endif
>
> 			local_irq_disable();
> 			if (hlt_counter) {
> 				local_irq_enable();
> 				cpu_relax();
> 			} else {
> 				stop_critical_timings();
> 				pm_idle();
> 				start_critical_timings();
> 				/*
> 				 * This will eventually be removed - pm_idle
> 				 * functions should always return with IRQs
> 				 * enabled.
> 				 */
> 				WARN_ON(irqs_disabled());
> 				local_irq_enable();
> 			}
> 		}
>
> i dont know what exactly the problem is...
> Do i have to implement a sched_clock routine myself as is saw it in a few implemetations.
> When i do a cat \"/proc/timer_list\" i can see folowing:
>
> cat timer_list
> Timer List Version: v0.5
> HRTIMER_MAX_CLOCK_BASES: 2
> now at 960971480 nsecs
>
> cpu: 0
>   clock 0:
>    .base:       a031c560
>    .index:      0
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get_real
>    .offset:     0 nsecs
> active timers:
>   clock 1:
>    .base:       a031c594
>    .index:      1
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get
>    .offset:     0 nsecs
> active timers:
>   #0: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
>   # expires at 1000000000-1000000000 nsecs [in 39028520 to 39028520 nsecs]
>   #1:<a12fda88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
>   # expires at 1960997774-1961997798 nsecs [in 1000026294 to 1001026318 nsecs]
>    .expires_next   : 2147483646999999999 nsecs
>    .hres_active    : 0
>    .nr_events      : 0
>    .nr_retries     : 0
>    .nr_hangs       : 0
>    .max_hang_time  : 0 nsecs
>    .nohz_mode      : 0
>    .idle_tick      : 0 nsecs
>    .tick_stopped   : 0
>    .idle_jiffies   : 0
>    .idle_calls     : 0
>    .idle_sleeps    : 0
>    .idle_entrytime : 960913921 nsecs
>    .idle_waketime  : 0 nsecs
>    .idle_exittime  : 0 nsecs
>    .idle_sleeptime : 77532270 nsecs
>    .last_jiffies   : 0
>    .next_jiffies   : 0
>    .idle_expires   : 0 nsecs
> jiffies: 4294941108
>
>
> Tick Device: mode:     0
> Per CPU device: 0
> Clock Event Device: pit
>   max_delta_ns:   0
>   min_delta_ns:   0
>   mult:           309237645
>   shift:          32
>   mode:           2
>   next_event:     2147483646999999999 nsecs
>   set_next_event:<(null)>
I think  set_next_event: <(null)> is not normal. In one shot mode, one 
an event is expired, the clock event is then reprogrammed by the new 
one. In my example, it's the nios2_timer_set_next_event() function.
This is my # cat /proc/timer_list

root:/>  cat /proc/timer_list
Timer List Version: v0.5
HRTIMER_MAX_CLOCK_BASES: 2
now at 81543392570 nsecs

cpu: 0
  clock 0:
   .base:       d0510b70
   .index:      0
   .resolution: 1 nsecs
   .get_time:   ktime_get_real
   .offset:     0 nsecs
active timers:
  clock 1:
   .base:       d0510ba4
   .index:      1
   .resolution: 1 nsecs
   .get_time:   ktime_get
   .offset:     0 nsecs
active timers:
  #0:<d05110fc>, tick_sched_timer, S:01
  # expires at 81544000000-81544000000 nsecs [in 607430 to 607430 nsecs]
  #1:<d6c98ad4>, hrtimer_wakeup, S:01
  # expires at 81593595770-81594595746 nsecs [in 50203200 to 51203176 nsecs]
  #2:<d0521054>, sched_rt_period_timer, S:01
  # expires at 82000000000-82000000000 nsecs [in 456607430 to 456607430 nsecs]
   .expires_next   : 81548000000 nsecs
   .hres_active    : 1
   .nr_events      : 19983
   .nr_retries     : 0
   .nr_hangs       : 0
   .max_hang_time  : 0 nsecs
   .nohz_mode      : 0
   .idle_tick      : 0 nsecs
   .tick_stopped   : 0
   .idle_jiffies   : 0
   .idle_calls     : 0
   .idle_sleeps    : 0
   .idle_entrytime : 0 nsecs
   .idle_waketime  : 0 nsecs
   .idle_exittime  : 0 nsecs
   .idle_sleeptime : 0 nsecs
   .last_jiffies   : 0
   .next_jiffies   : 0
   .idle_expires   : 0 nsecs
jiffies: 4294912682


Tick Device: mode:     1
Per CPU device: 0
Clock Event Device: nios2_clockevent
  max_delta_ns:   34359738360
  min_delta_ns:   1000
  mult:           536870912
  shift:          32
  mode:           3
  next_event:     81548000000 nsecs
  set_next_event: nios2_timer_set_next_event
  set_mode:       nios2_timer_set_mode
  event_handler:  hrtimer_interrupt


In your code:
- use T0TC for clock source. I think you've understood.
- use PIT for clock event. You must program it in one shot shot mode 
with the duration given by delta in terms of number of CPU clocks for 
the next event. I don't see such a function in your code. ( 
.set_next_event field).
According to your PIT frequency and functionality, you must transform 
delta value in the right value to program your PIT in order to generate 
an interrupt after a same duration equal to delta * CPU clock period.

Pat.
>   set_mode:       pit_clkevt_mode
>   event_handler:  tick_handle_periodic
>
>
> I enabled some tracing and debuging in the kernel and then the following message was printed when the processor froze:
>
> \"sched: RT throttling activated\"
>
> What does it mean? IS it a problem of my timer implementation or is something else wrong with the system?
>
> I hope somebody can help me on this.
>
> Kind regards
> Johannes Bauer
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Patrice Kadionik. F6KQH / F4CUQ
-----------

+----------------------------------------------------------------------+
+"Tout doit etre aussi simple que possible, pas seulement plus simple" +
+----------------------------------------------------------------------+
+ Patrice Kadionik             http://www.enseirb-matmeca.fr/~kadionik +
+ IMS Laboratory               http://www.ims-bordeaux.fr/             +
+ ENSEIRB-MATMECA              http://www.enseirb-matmeca.fr           +
+ PO BOX 99                    fax   : +33 5.56.37.20.23               +
+ 33402 TALENCE Cedex          voice : +33 5.56.84.23.47               +
+ FRANCE                       mailto:patrice.kadionik@ims-bordeaux.fr +
+----------------------------------------------------------------------+

--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: clocksource and clockevent confusion
  2011-04-07 16:48 Johannes Bauer
  2011-04-07 17:41 ` Patrice Kadionik
@ 2011-04-07 18:37 ` Patrice Kadionik
  1 sibling, 0 replies; 8+ messages in thread
From: Patrice Kadionik @ 2011-04-07 18:37 UTC (permalink / raw)
  To: linux-rt-users

Le 07/04/2011 18:48, Johannes Bauer a écrit :
Hi again,

> Thank you for your help Pat!
>
> I figured out to write a driver, thats the code:
>
> static cycle_t read_pit_clk(struct clocksource *cs)
> {
>
> 	return T0TC;	// returns the actual timer count
> }
>
> static struct clocksource pit_clk = {
> 	.name		= \"pit\",
> 	.rating		= 175,
> 	.read		= read_pit_clk,
> 	.shift		= 28,	//is changed by init code
> 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
>
> void __init  lpc2xxx_time_init (void)
> {
> 	unsigned char clkSel = 0;
> 	unsigned long stat = PLLSTAT;
> 	unsigned long M = stat&  0x7FFFF;
> 	unsigned long N = (stat>>16)&  0xFF;
> 	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
> 	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
> 	lpc2xxx_fcclk = Fcclk;
> 	lpc2xxx_fpclk = Fcclk;
>
> 	/*
>    	 * Here we assume that the clock is the same for all peripherals
>   	 * which of course doesn\'t have to be the case.
> 	 * We should be using the clk.h interface instead.
> 	 */
> 	
> 	clkSel = (unsigned char)(PCLKSEL0&  0xff);
> 	if (clkSel == 0x00)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
> 	else if (clkSel == 0x55)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk;
> 	else if (clkSel == 0xAA)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
> 	else if (clkSel == 0xFF)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;
>
> 	printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
> 		CONFIG_LPC22xx_Fosc,
> 		Fcco,
> 		M,
> 		N);
> 	PCLKSEL0&= ~(3<<2);
> 	PCLKSEL0 |=  (1<<2);
> 	printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
> 		Fcclk, PCLKSEL0, PCLKSEL1);
> 	/*
> 	 * disable and clear timer 0, set to
> 	 */
> 	T0TCR&= ~0x01;
> 	/* initialize the timer period and prescaler */
With hrtimer implementation, you don't ahve to implement the traditional 
titck timer. Once you have a clock event, the hrtimer use it. It tries 
to program the clock event in one shot shot mode (case 
CLOCK_EVT_MODE_ONESHOT) and you have the hrtimer support enabled. If it 
cant, then the subsystem is programmed in periodic mode (case 
CLOCK_EVT_MODE_PERIODIC) like in the traditional mode... no do_timer() 
ar all...

Cheers,

Pat.
> 	//counts with 72MHz so compare interrupt every 10ms
> 	T0MR0 = 720000;
> 	T0PR = 0;	// prescaler = 0
> 	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/
>
> 	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;
>
> 	/* set up the interrupt vevtor for timer 0 match */
> 	setup_irq(LPC2xxx_INTERRUPT_TIMER0,&lpc2xxx_timer_irq);
> 	
> 	/* enable the timer IRQ */
> 	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);
>
> 	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>
> 	pit_clk.mask = 71999;				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
> 	clocksource_register(&pit_clk);
>
> 	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
> 	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
> 	clockevents_register_device(&pit_clkevt);
>
> 	/* let timer 0 run... */
> 	T0IR = 0x01; /* reset MR0 interrupt*/
> 	T0TCR = 0x02;	/* Reset timer count and prescale counter */
> 	T0TCR = 0x01;	/* enable timer counter and prescale counter */
> }
>
> struct sys_timer lpc22xx_timer = {
> 	.init		= lpc2xxx_time_init,
> };
>
>
>
> The problem is that after a minute or so the kernel freezes and hangs in the cpu_idle() function in arch/arm/kernel/process.c
>
> the board stays in this whileloop in the else condition forever:
>
> while (!need_resched()) {
> #ifdef CONFIG_HOTPLUG_CPU
> 			if (cpu_is_offline(smp_processor_id()))
> 				cpu_die();
> #endif
>
> 			local_irq_disable();
> 			if (hlt_counter) {
> 				local_irq_enable();
> 				cpu_relax();
> 			} else {
> 				stop_critical_timings();
> 				pm_idle();
> 				start_critical_timings();
> 				/*
> 				 * This will eventually be removed - pm_idle
> 				 * functions should always return with IRQs
> 				 * enabled.
> 				 */
> 				WARN_ON(irqs_disabled());
> 				local_irq_enable();
> 			}
> 		}
>
> i dont know what exactly the problem is...
> Do i have to implement a sched_clock routine myself as is saw it in a few implemetations.
> When i do a cat \"/proc/timer_list\" i can see folowing:
>
> cat timer_list
> Timer List Version: v0.5
> HRTIMER_MAX_CLOCK_BASES: 2
> now at 960971480 nsecs
>
> cpu: 0
>   clock 0:
>    .base:       a031c560
>    .index:      0
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get_real
>    .offset:     0 nsecs
> active timers:
>   clock 1:
>    .base:       a031c594
>    .index:      1
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get
>    .offset:     0 nsecs
> active timers:
>   #0: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
>   # expires at 1000000000-1000000000 nsecs [in 39028520 to 39028520 nsecs]
>   #1:<a12fda88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
>   # expires at 1960997774-1961997798 nsecs [in 1000026294 to 1001026318 nsecs]
>    .expires_next   : 2147483646999999999 nsecs
>    .hres_active    : 0
>    .nr_events      : 0
>    .nr_retries     : 0
>    .nr_hangs       : 0
>    .max_hang_time  : 0 nsecs
>    .nohz_mode      : 0
>    .idle_tick      : 0 nsecs
>    .tick_stopped   : 0
>    .idle_jiffies   : 0
>    .idle_calls     : 0
>    .idle_sleeps    : 0
>    .idle_entrytime : 960913921 nsecs
>    .idle_waketime  : 0 nsecs
>    .idle_exittime  : 0 nsecs
>    .idle_sleeptime : 77532270 nsecs
>    .last_jiffies   : 0
>    .next_jiffies   : 0
>    .idle_expires   : 0 nsecs
> jiffies: 4294941108
>
>
> Tick Device: mode:     0
> Per CPU device: 0
> Clock Event Device: pit
>   max_delta_ns:   0
>   min_delta_ns:   0
>   mult:           309237645
>   shift:          32
>   mode:           2
>   next_event:     2147483646999999999 nsecs
>   set_next_event:<(null)>
>   set_mode:       pit_clkevt_mode
>   event_handler:  tick_handle_periodic
>
>
> I enabled some tracing and debuging in the kernel and then the following message was printed when the processor froze:
>
> \"sched: RT throttling activated\"
>
> What does it mean? IS it a problem of my timer implementation or is something else wrong with the system?
>
> I hope somebody can help me on this.
>
> Kind regards
> Johannes Bauer
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Patrice Kadionik. F6KQH / F4CUQ
-----------

+----------------------------------------------------------------------+
+"Tout doit etre aussi simple que possible, pas seulement plus simple" +
+----------------------------------------------------------------------+
+ Patrice Kadionik             http://www.enseirb-matmeca.fr/~kadionik +
+ IMS Laboratory               http://www.ims-bordeaux.fr/             +
+ ENSEIRB-MATMECA              http://www.enseirb-matmeca.fr           +
+ PO BOX 99                    fax   : +33 5.56.37.20.23               +
+ 33402 TALENCE Cedex          voice : +33 5.56.84.23.47               +
+ FRANCE                       mailto:patrice.kadionik@ims-bordeaux.fr +
+----------------------------------------------------------------------+

--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: clocksource and clockevent confusion
@ 2011-04-08 13:01 Johannes Bauer
  2011-04-08 14:33 ` Patrice Kadionik
  0 siblings, 1 reply; 8+ messages in thread
From: Johannes Bauer @ 2011-04-08 13:01 UTC (permalink / raw)
  To: linux-rt-users

Hi Pat!
Again thank you for your fast help!

I tried to implement the oneshot functionality.
However the system does not boot properly, and seems to be stuck in the same while loop in process.c. I disabled the dynamic tick configuration and tried with PREEMPT_NONE and PREEMPT_VOLUNTARY and PREEMPT_RT, but it seems not to change a thing. The boot messages seem to tell that first the periodic timer is used and then it is switched to oneshot mode and stops.


<6>Calibrating delay loop... <c>23.24 BogoMIPS (lpj=116224)

Mount-cache hash table entries: 512

<6>NET: Registered protocol family 16

bio: create slab <bio-0> at 0

<5>SCSI subsystem initialized

<6>usbcore: registered new interface driver usbfs

<6>usbcore: registered new interface driver hub

<6>usbcore: registered new device driver usb

<6>Switching to clocksource pit

oneshot

NEXT_EVENT: 510789

NEXT_EVENT: 1061342

<6>NET: Registered protocol family 2

<6>IP route cache hash table entries: 1024 (order: 0, 4096 bytes)

<6>TCP established hash table entries: 1024 (order: 1, 8192 bytes)

<6>TCP bind hash table entries: 1024 (order: 0, 4096 bytes)

<6>TCP: Hash tables configured (established 1024 bind 1024)

<6>TCP reno registered

<6>UDP hash table entries: 256 (order: 0, 4096 bytes)

<6>UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)

<6>NET: Registered protocol family 1

<6>RPC: Registered udp transport module.

<6>RPC: Registered tcp transport module.

<6>RPC: Registered tcp NFSv4.1 backchannel transport module.

<6>Trying to unpack rootfs image as initramfs...

<6>rootfs image is not initramfs (junk in compressed archive); looks like an initrd

<6>Freeing initrd memory: 4000K

<4>NetWinder Floating Point Emulator V0.97 (double precision)

<6>JFFS2 version 2.2. (NAND) (SUMMARY)  © 2001-2006 Red Hat, Inc.

<6>ROMFS MTD (C) 2007 Red Hat, Inc.

<6>Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)

<6>io scheduler noop registered (default)

lpc2478fb: smem_len = 153600

lpc2478fb: line_length = 480



With periodic timer it runs a little bit further and lets me do some input.

Is it possible that thats a problem due to the fact im running uClinux (NOMMU CPU) with uClibc, which seems to have no support for PI mutexes?

Do you have any ideas on getting PREEMPT RT running for NOMMU systems?

The timer code with oneshot looks the following way, for debugging purpose i entered some printks:

static int lpc22xx_next_event(unsigned long delta,
					struct clock_event_device *dev)
{
//	pr_debug(\"%s: next event, delta %x\\n\", __func__, (u32)delta);
	printk(\"NEXT_EVENT: %u\\n\",delta);
	T0MR0 = delta;
	T0PR = 0;
	T0MCR |= 0x03;
	T0TCR |= 0x02;	//reset counter
	return 0;
}

static cycle_t read_pit_clk(struct clocksource *cs)
{

	return (cycle_t) T0TC;	// returns the actual timer count 
}

static struct clocksource pit_clk = {
	.name		= \"pit\",
	.rating		= 175,
	.read		= read_pit_clk,
	.shift		= 28,	//is changed by init code
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

/*
 * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
 */
static void
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		/* update clocksource counter */
		printk(\"periodic\\n\");
		T0MR0 = 720000;
		T0PR = 0;
		T0MCR &= ~0x04;	//be sure timer does not stop on compare match
		T0MCR |= 0x03;
		break;
	case CLOCK_EVT_MODE_ONESHOT:
//		T0MR0 = 720000;
//		T0PR = 0;
		
//		T0MCR |= 0x07;
	
		printk(\"oneshot\\n\");

		break;
		/* FALLTHROUGH */
	case CLOCK_EVT_MODE_SHUTDOWN:
		printk(\"shutdown\\n\");
		T0TCR &= ~0x01;
		break;
	case CLOCK_EVT_MODE_UNUSED:
		printk(\"unused\\n\");
		/* disable irq, leaving the clocksource active */
		T0MCR &= ~0x01;
		break;
	case CLOCK_EVT_MODE_RESUME:
		printk(\"resume\\n\");
		break;
	}
}

static struct clock_event_device pit_clkevt = {
	.name		= \"pit\",
	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
	.shift		= 32,	//is changed by init function
	.rating		= 100,	//dont know yet
	.set_mode	= pit_clkevt_mode,
	.set_next_event = lpc22xx_next_event,
};


unsigned long lpc2xxx_gettimeoffset (void)
{
	//CLOCKS_PER_USEC = LPC2xxx_Fpclk / 1000000;
	return (T0TC/(lpc2xxx_fcclk / 1000000));
}

static irqreturn_t
lpc2xxx_timer_interrupt(int irq, void *dev_id)
{
    if (!(T0IR & 0x01)) return IRQ_NONE;
/*    do_timer(regs);
    do_profile(regs);
*/ //timer_tick(); 
/* modified 20050608 for new version */

	pit_clkevt.event_handler(&pit_clkevt);	//handle_event
	printk(\"Interrupt\\n\");
	
    T0IR |= 0x01;	/* reset interrupt */
    return IRQ_HANDLED;
}

static struct irqaction lpc2xxx_timer_irq = {
        .name           = \"lpc2xxx-tick\",
	.flags		= IRQF_DISABLED | IRQF_TIMER,
        .handler        = lpc2xxx_timer_interrupt
};

/*
 * Set up timer interrupt, and return the current time in seconds.
 */
/*
 Setup PCLK_TIMER0 = Fcclk (01)
 Setup T0MR0 = 10 (ms)
 Setup T0PR0 = 0
*/
void __init  lpc2xxx_time_init (void)
{
	unsigned char clkSel = 0;
	unsigned long stat = PLLSTAT;
	unsigned long M = stat & 0x7FFFF;
	unsigned long N = (stat>>16) & 0xFF;
	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
	lpc2xxx_fcclk = Fcclk;
	lpc2xxx_fpclk = Fcclk;

	/* 
  	 * Here we assume that the clock is the same for all peripherals
 	 * which of course doesn\'t have to be the case.
	 * We should be using the clk.h interface instead.
	 */
	
	clkSel = (unsigned char)(PCLKSEL0 & 0xff);
	if (clkSel == 0x00)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
	else if (clkSel == 0x55)
		lpc2xxx_fpclk = lpc2xxx_fcclk;
	else if (clkSel == 0xAA)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
	else if (clkSel == 0xFF)
		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;

	printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
		CONFIG_LPC22xx_Fosc,
		Fcco,
		M,
		N);
	PCLKSEL0 &= ~(3<<2);
	PCLKSEL0 |=  (1<<2);
	printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
		Fcclk, PCLKSEL0, PCLKSEL1);
	/*
	 * disable and clear timer 0, set to
	 */
	T0TCR &= ~0x01;
	/* initialize the timer period and prescaler */

	//counts with 72MHz so compare interrupt every 10ms
//	T0MR0 = 720000;
//	T0PR = 0;	// prescaler = 0
//	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/

	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;

	/* set up the interrupt vevtor for timer 0 match */
	setup_irq(LPC2xxx_INTERRUPT_TIMER0, &lpc2xxx_timer_irq);
	
	/* enable the timer IRQ */
	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);

	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)

	pit_clk.mask = CLOCKSOURCE_MASK(32);				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
	clocksource_register(&pit_clk);

	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
	pit_clkevt.max_delta_ns =
		clockevent_delta2ns((u32)~0, &pit_clkevt);
	pit_clkevt.min_delta_ns =
		clockevent_delta2ns(1, &pit_clkevt);
	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
	clockevents_register_device(&pit_clkevt);

	/* let timer 0 run... */
	T0IR = 0x01; /* reset MR0 interrupt*/
	T0TCR = 0x02;	/* Reset timer count and prescale counter */
	T0TCR = 0x01;	/* enable timer counter and prescale counter */
}

struct sys_timer lpc22xx_timer = {
	.init		= lpc2xxx_time_init,
};




----- Original von:  Patrice Kadionik

> Le 07/04/2011 18:48, Johannes Bauer a écrit :
Hi again,

> Thank you for your help Pat!
>
> I figured out to write a driver, thats the code:
>
> static cycle_t read_pit_clk(struct clocksource *cs)
> {
>
> 	return T0TC;	// returns the actual timer count
> }
>
> static struct clocksource pit_clk = {
> 	.name		= \\\"pit\\\",
> 	.rating		= 175,
> 	.read		= read_pit_clk,
> 	.shift		= 28,	//is changed by init code
> 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
>
> void __init  lpc2xxx_time_init (void)
> {
> 	unsigned char clkSel = 0;
> 	unsigned long stat = PLLSTAT;
> 	unsigned long M = stat&  0x7FFFF;
> 	unsigned long N = (stat>>16)&  0xFF;
> 	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
> 	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
> 	lpc2xxx_fcclk = Fcclk;
> 	lpc2xxx_fpclk = Fcclk;
>
> 	/*
>    	 * Here we assume that the clock is the same for all peripherals
>   	 * which of course doesn\\\'t have to be the case.
> 	 * We should be using the clk.h interface instead.
> 	 */
> 	
> 	clkSel = (unsigned char)(PCLKSEL0&  0xff);
> 	if (clkSel == 0x00)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
> 	else if (clkSel == 0x55)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk;
> 	else if (clkSel == 0xAA)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
> 	else if (clkSel == 0xFF)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;
>
> 	printk(\\\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\\\n\\\",
> 		CONFIG_LPC22xx_Fosc,
> 		Fcco,
> 		M,
> 		N);
> 	PCLKSEL0&= ~(3<<2);
> 	PCLKSEL0 |=  (1<<2);
> 	printk(\\\"Fcclk=%ld PCLKSEL=%08lx %08lx\\\\n\\\",
> 		Fcclk, PCLKSEL0, PCLKSEL1);
> 	/*
> 	 * disable and clear timer 0, set to
> 	 */
> 	T0TCR&= ~0x01;
> 	/* initialize the timer period and prescaler */
With hrtimer implementation, you don\'t ahve to implement the traditional 
titck timer. Once you have a clock event, the hrtimer use it. It tries 
to program the clock event in one shot shot mode (case 
CLOCK_EVT_MODE_ONESHOT) and you have the hrtimer support enabled. If it 
cant, then the subsystem is programmed in periodic mode (case 
CLOCK_EVT_MODE_PERIODIC) like in the traditional mode... no do_timer() 
ar all...

Cheers,

Pat.
> 	//counts with 72MHz so compare interrupt every 10ms
> 	T0MR0 = 720000;
> 	T0PR = 0;	// prescaler = 0
> 	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/
>
> 	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;
>
> 	/* set up the interrupt vevtor for timer 0 match */
> 	setup_irq(LPC2xxx_INTERRUPT_TIMER0,&lpc2xxx_timer_irq);
> 	
> 	/* enable the timer IRQ */
> 	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);
>
> 	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>
> 	pit_clk.mask = 71999;				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
> 	clocksource_register(&pit_clk);
>
> 	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
> 	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
> 	clockevents_register_device(&pit_clkevt);
>
> 	/* let timer 0 run... */
> 	T0IR = 0x01; /* reset MR0 interrupt*/
> 	T0TCR = 0x02;	/* Reset timer count and prescale counter */
> 	T0TCR = 0x01;	/* enable timer counter and prescale counter */
> }
>
> struct sys_timer lpc22xx_timer = {
> 	.init		= lpc2xxx_time_init,
> };
>
>
>
> The problem is that after a minute or so the kernel freezes and hangs in the cpu_idle() function in arch/arm/kernel/process.c
>
> the board stays in this whileloop in the else condition forever:
>
> while (!need_resched()) {
> #ifdef CONFIG_HOTPLUG_CPU
> 			if (cpu_is_offline(smp_processor_id()))
> 				cpu_die();
> #endif
>
> 			local_irq_disable();
> 			if (hlt_counter) {
> 				local_irq_enable();
> 				cpu_relax();
> 			} else {
> 				stop_critical_timings();
> 				pm_idle();
> 				start_critical_timings();
> 				/*
> 				 * This will eventually be removed - pm_idle
> 				 * functions should always return with IRQs
> 				 * enabled.
> 				 */
> 				WARN_ON(irqs_disabled());
> 				local_irq_enable();
> 			}
> 		}
>
> i dont know what exactly the problem is...
> Do i have to implement a sched_clock routine myself as is saw it in a few implemetations.
> When i do a cat \\\"/proc/timer_list\\\" i can see folowing:
>
> cat timer_list
> Timer List Version: v0.5
> HRTIMER_MAX_CLOCK_BASES: 2
> now at 960971480 nsecs
>
> cpu: 0
>   clock 0:
>    .base:       a031c560
>    .index:      0
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get_real
>    .offset:     0 nsecs
> active timers:
>   clock 1:
>    .base:       a031c594
>    .index:      1
>    .resolution: 10000000 nsecs
>    .get_time:   ktime_get
>    .offset:     0 nsecs
> active timers:
>   #0: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
>   # expires at 1000000000-1000000000 nsecs [in 39028520 to 39028520 nsecs]
>   #1:<a12fda88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
>   # expires at 1960997774-1961997798 nsecs [in 1000026294 to 1001026318 nsecs]
>    .expires_next   : 2147483646999999999 nsecs
>    .hres_active    : 0
>    .nr_events      : 0
>    .nr_retries     : 0
>    .nr_hangs       : 0
>    .max_hang_time  : 0 nsecs
>    .nohz_mode      : 0
>    .idle_tick      : 0 nsecs
>    .tick_stopped   : 0
>    .idle_jiffies   : 0
>    .idle_calls     : 0
>    .idle_sleeps    : 0
>    .idle_entrytime : 960913921 nsecs
>    .idle_waketime  : 0 nsecs
>    .idle_exittime  : 0 nsecs
>    .idle_sleeptime : 77532270 nsecs
>    .last_jiffies   : 0
>    .next_jiffies   : 0
>    .idle_expires   : 0 nsecs
> jiffies: 4294941108
>
>
> Tick Device: mode:     0
> Per CPU device: 0
> Clock Event Device: pit
>   max_delta_ns:   0
>   min_delta_ns:   0
>   mult:           309237645
>   shift:          32
>   mode:           2
>   next_event:     2147483646999999999 nsecs
>   set_next_event:<(null)>
>   set_mode:       pit_clkevt_mode
>   event_handler:  tick_handle_periodic
>
>
> I enabled some tracing and debuging in the kernel and then the following message was printed when the processor froze:
>
> \\\"sched: RT throttling activated\\\"
>
> What does it mean? IS it a problem of my timer implementation or is something else wrong with the system?
>
> I hope somebody can help me on this.
>
> Kind regards
> Johannes Bauer
>
> --
> To unsubscribe from this list: send the line \"unsubscribe linux-rt-users\" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Patrice Kadionik. F6KQH / F4CUQ
-----------

+----------------------------------------------------------------------+
+\"Tout doit etre aussi simple que possible, pas seulement plus simple\" +
+----------------------------------------------------------------------+
+ Patrice Kadionik             http://www.enseirb-matmeca.fr/~kadionik +
+ IMS Laboratory               http://www.ims-bordeaux.fr/             +
+ ENSEIRB-MATMECA              http://www.enseirb-matmeca.fr           +
+ PO BOX 99                    fax   : +33 5.56.37.20.23               +
+ 33402 TALENCE Cedex          voice : +33 5.56.84.23.47               +
+ FRANCE                       mailto:patrice.kadionik@ims-bordeaux.fr +
+----------------------------------------------------------------------+

--
To unsubscribe from this list: send the line \"unsubscribe linux-rt-users\" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: clocksource and clockevent confusion
  2011-04-08 13:01 Johannes Bauer
@ 2011-04-08 14:33 ` Patrice Kadionik
  0 siblings, 0 replies; 8+ messages in thread
From: Patrice Kadionik @ 2011-04-08 14:33 UTC (permalink / raw)
  To: Johannes Bauer; +Cc: linux-rt-users

Le 08/04/2011 15:01, Johannes Bauer a écrit :
> Hi Pat!
Hi Johannes,
> Again thank you for your fast help!
>
> I tried to implement the oneshot functionality.
> However the system does not boot properly, and seems to be stuck in the same while loop in process.c. I disabled the dynamic tick configuration and tried with PREEMPT_NONE and PREEMPT_VOLUNTARY and PREEMPT_RT, but it seems not to change a thing. The boot messages seem to tell that first the periodic timer is used and then it is switched to oneshot mode and stops.
That is the correct behaviour: beginning with the periodic mode and then 
switching (if possible) in the one shot mode if a clock event source is 
found by the hrtimer subsystem..
In the lpc2xxx_time_init(), you must just have general PIT configuration 
if needed and clock source and clock event installation. No periodic 
timer programmation.
Are you sure that the one shot interrupt of your timer is acknowledged?

Try:

lpc2xxx_timer_interrupt(int irq, void *dev_id)
{
  struct clock_event_device *evt =&pit_clkevt;

//	printk(\"Interrupt\\n\");
	
      T0IR |= 0x01;	/* reset interrupt */
      evt->event_handler(evt);
      return IRQ_HANDLED;
}


>
> <6>Calibrating delay loop...<c>23.24 BogoMIPS (lpj=116224)
>
> Mount-cache hash table entries: 512
>
> <6>NET: Registered protocol family 16
>
> bio: create slab<bio-0>  at 0
>
> <5>SCSI subsystem initialized
>
> <6>usbcore: registered new interface driver usbfs
>
> <6>usbcore: registered new interface driver hub
>
> <6>usbcore: registered new device driver usb
>
> <6>Switching to clocksource pit
>
> oneshot
>
> NEXT_EVENT: 510789
>
> NEXT_EVENT: 1061342
>
> <6>NET: Registered protocol family 2
>
> <6>IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
>
> <6>TCP established hash table entries: 1024 (order: 1, 8192 bytes)
>
> <6>TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
>
> <6>TCP: Hash tables configured (established 1024 bind 1024)
>
> <6>TCP reno registered
>
> <6>UDP hash table entries: 256 (order: 0, 4096 bytes)
>
> <6>UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
>
> <6>NET: Registered protocol family 1
>
> <6>RPC: Registered udp transport module.
>
> <6>RPC: Registered tcp transport module.
>
> <6>RPC: Registered tcp NFSv4.1 backchannel transport module.
>
> <6>Trying to unpack rootfs image as initramfs...
>
> <6>rootfs image is not initramfs (junk in compressed archive); looks like an initrd
>
> <6>Freeing initrd memory: 4000K
>
> <4>NetWinder Floating Point Emulator V0.97 (double precision)
>
> <6>JFFS2 version 2.2. (NAND) (SUMMARY)  © 2001-2006 Red Hat, Inc.
>
> <6>ROMFS MTD (C) 2007 Red Hat, Inc.
>
> <6>Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
>
> <6>io scheduler noop registered (default)
>
> lpc2478fb: smem_len = 153600
>
> lpc2478fb: line_length = 480
>
>
>
> With periodic timer it runs a little bit further and lets me do some input.
>
> Is it possible that thats a problem due to the fact im running uClinux (NOMMU CPU) with uClibc, which seems to have no support for PI mutexes?
I don't know.
Are you sure of you oneshot implementation?
> Do you have any ideas on getting PREEMPT RT running for NOMMU systems?
I don't know if it is possible because the PREEMPT-RT patch if for MMU 
processors at first. That's why I've ported it to NIOS 2 with MMU and 
not NIOS without MMU.
> The timer code with oneshot looks the following way, for debugging purpose i entered some printks:
>
> static int lpc22xx_next_event(unsigned long delta,
> 					struct clock_event_device *dev)
> {
> //	pr_debug(\"%s: next event, delta %x\\n\", __func__, (u32)delta);
> 	printk(\"NEXT_EVENT: %u\\n\",delta);
> 	T0MR0 = delta;
Is is really delta that you must program here with your PIT? A number of 
CPU clock? you PIT doesnét run at the same frequency than your CPU?

Pat.
> 	T0PR = 0;
> 	T0MCR |= 0x03;
> 	T0TCR |= 0x02;	//reset counter
> 	return 0;
> }
>
> static cycle_t read_pit_clk(struct clocksource *cs)
> {
>
> 	return (cycle_t) T0TC;	// returns the actual timer count
> }
>
> static struct clocksource pit_clk = {
> 	.name		= \"pit\",
> 	.rating		= 175,
> 	.read		= read_pit_clk,
> 	.shift		= 28,	//is changed by init code
> 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
> /*
>   * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
>   */
> static void
> pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
> {
> 	switch (mode) {
> 	case CLOCK_EVT_MODE_PERIODIC:
> 		/* update clocksource counter */
> 		printk(\"periodic\\n\");
> 		T0MR0 = 720000;
> 		T0PR = 0;
> 		T0MCR&= ~0x04;	//be sure timer does not stop on compare match
> 		T0MCR |= 0x03;
> 		break;
> 	case CLOCK_EVT_MODE_ONESHOT:
> //		T0MR0 = 720000;
> //		T0PR = 0;
> 		
> //		T0MCR |= 0x07;
> 	
> 		printk(\"oneshot\\n\");
>
> 		break;
> 		/* FALLTHROUGH */
> 	case CLOCK_EVT_MODE_SHUTDOWN:
> 		printk(\"shutdown\\n\");
> 		T0TCR&= ~0x01;
> 		break;
> 	case CLOCK_EVT_MODE_UNUSED:
> 		printk(\"unused\\n\");
> 		/* disable irq, leaving the clocksource active */
> 		T0MCR&= ~0x01;
> 		break;
> 	case CLOCK_EVT_MODE_RESUME:
> 		printk(\"resume\\n\");
> 		break;
> 	}
> }
>
> static struct clock_event_device pit_clkevt = {
> 	.name		= \"pit\",
> 	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> 	.shift		= 32,	//is changed by init function
> 	.rating		= 100,	//dont know yet
> 	.set_mode	= pit_clkevt_mode,
> 	.set_next_event = lpc22xx_next_event,
> };
>
>
> unsigned long lpc2xxx_gettimeoffset (void)
> {
> 	//CLOCKS_PER_USEC = LPC2xxx_Fpclk / 1000000;
> 	return (T0TC/(lpc2xxx_fcclk / 1000000));
> }
>
> static irqreturn_t
> lpc2xxx_timer_interrupt(int irq, void *dev_id)
> {
>      if (!(T0IR&  0x01)) return IRQ_NONE;
> /*    do_timer(regs);
>      do_profile(regs);
> */ //timer_tick();
> /* modified 20050608 for new version */
>
> 	pit_clkevt.event_handler(&pit_clkevt);	//handle_event
> 	printk(\"Interrupt\\n\");
> 	
>      T0IR |= 0x01;	/* reset interrupt */
>      return IRQ_HANDLED;
> }
>
> static struct irqaction lpc2xxx_timer_irq = {
>          .name           = \"lpc2xxx-tick\",
> 	.flags		= IRQF_DISABLED | IRQF_TIMER,
>          .handler        = lpc2xxx_timer_interrupt
> };
>
> /*
>   * Set up timer interrupt, and return the current time in seconds.
>   */
> /*
>   Setup PCLK_TIMER0 = Fcclk (01)
>   Setup T0MR0 = 10 (ms)
>   Setup T0PR0 = 0
> */
> void __init  lpc2xxx_time_init (void)
> {
> 	unsigned char clkSel = 0;
> 	unsigned long stat = PLLSTAT;
> 	unsigned long M = stat&  0x7FFFF;
> 	unsigned long N = (stat>>16)&  0xFF;
> 	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
> 	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
> 	lpc2xxx_fcclk = Fcclk;
> 	lpc2xxx_fpclk = Fcclk;
>
> 	/*
>    	 * Here we assume that the clock is the same for all peripherals
>   	 * which of course doesn\'t have to be the case.
> 	 * We should be using the clk.h interface instead.
> 	 */
> 	
> 	clkSel = (unsigned char)(PCLKSEL0&  0xff);
> 	if (clkSel == 0x00)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
> 	else if (clkSel == 0x55)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk;
> 	else if (clkSel == 0xAA)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
> 	else if (clkSel == 0xFF)
> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;
>
> 	printk(\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\n\",
> 		CONFIG_LPC22xx_Fosc,
> 		Fcco,
> 		M,
> 		N);
> 	PCLKSEL0&= ~(3<<2);
> 	PCLKSEL0 |=  (1<<2);
> 	printk(\"Fcclk=%ld PCLKSEL=%08lx %08lx\\n\",
> 		Fcclk, PCLKSEL0, PCLKSEL1);
> 	/*
> 	 * disable and clear timer 0, set to
> 	 */
> 	T0TCR&= ~0x01;
> 	/* initialize the timer period and prescaler */
>
> 	//counts with 72MHz so compare interrupt every 10ms
> //	T0MR0 = 720000;
> //	T0PR = 0;	// prescaler = 0
> //	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/
>
> 	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;
>
> 	/* set up the interrupt vevtor for timer 0 match */
> 	setup_irq(LPC2xxx_INTERRUPT_TIMER0,&lpc2xxx_timer_irq);
> 	
> 	/* enable the timer IRQ */
> 	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);
>
> 	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>
> 	pit_clk.mask = CLOCKSOURCE_MASK(32);				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
> 	clocksource_register(&pit_clk);
>
> 	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
> 	pit_clkevt.max_delta_ns =
> 		clockevent_delta2ns((u32)~0,&pit_clkevt);
> 	pit_clkevt.min_delta_ns =
> 		clockevent_delta2ns(1,&pit_clkevt);
> 	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
> 	clockevents_register_device(&pit_clkevt);
>
> 	/* let timer 0 run... */
> 	T0IR = 0x01; /* reset MR0 interrupt*/
> 	T0TCR = 0x02;	/* Reset timer count and prescale counter */
> 	T0TCR = 0x01;	/* enable timer counter and prescale counter */
> }
>
> struct sys_timer lpc22xx_timer = {
> 	.init		= lpc2xxx_time_init,
> };
>
>
>
>
> ----- Original von:  Patrice Kadionik
>
>> Le 07/04/2011 18:48, Johannes Bauer a écrit :
> Hi again,
>
>> Thank you for your help Pat!
>>
>> I figured out to write a driver, thats the code:
>>
>> static cycle_t read_pit_clk(struct clocksource *cs)
>> {
>>
>> 	return T0TC;	// returns the actual timer count
>> }
>>
>> static struct clocksource pit_clk = {
>> 	.name		= \\\"pit\\\",
>> 	.rating		= 175,
>> 	.read		= read_pit_clk,
>> 	.shift		= 28,	//is changed by init code
>> 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
>> };
>>
>>
>> void __init  lpc2xxx_time_init (void)
>> {
>> 	unsigned char clkSel = 0;
>> 	unsigned long stat = PLLSTAT;
>> 	unsigned long M = stat&   0x7FFFF;
>> 	unsigned long N = (stat>>16)&   0xFF;
>> 	unsigned long Fcco = (2 * (M+1) *CONFIG_LPC22xx_Fosc) / (N+1);
>> 	unsigned long Fcclk = Fcco / ((CCLKCFG&0xFF)+1);
>> 	lpc2xxx_fcclk = Fcclk;
>> 	lpc2xxx_fpclk = Fcclk;
>>
>> 	/*
>>     	 * Here we assume that the clock is the same for all peripherals
>>    	 * which of course doesn\\\'t have to be the case.
>> 	 * We should be using the clk.h interface instead.
>> 	 */
>> 	
>> 	clkSel = (unsigned char)(PCLKSEL0&   0xff);
>> 	if (clkSel == 0x00)
>> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 4;
>> 	else if (clkSel == 0x55)
>> 		lpc2xxx_fpclk = lpc2xxx_fcclk;
>> 	else if (clkSel == 0xAA)
>> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 2;
>> 	else if (clkSel == 0xFF)
>> 		lpc2xxx_fpclk = lpc2xxx_fcclk / 8;
>>
>> 	printk(\\\"LPC2XXX Clocking Fin=%dHz Fcco=%ldHz M=%ld N=%ld\\\\n\\\",
>> 		CONFIG_LPC22xx_Fosc,
>> 		Fcco,
>> 		M,
>> 		N);
>> 	PCLKSEL0&= ~(3<<2);
>> 	PCLKSEL0 |=  (1<<2);
>> 	printk(\\\"Fcclk=%ld PCLKSEL=%08lx %08lx\\\\n\\\",
>> 		Fcclk, PCLKSEL0, PCLKSEL1);
>> 	/*
>> 	 * disable and clear timer 0, set to
>> 	 */
>> 	T0TCR&= ~0x01;
>> 	/* initialize the timer period and prescaler */
> With hrtimer implementation, you don\'t ahve to implement the traditional
> titck timer. Once you have a clock event, the hrtimer use it. It tries
> to program the clock event in one shot shot mode (case
> CLOCK_EVT_MODE_ONESHOT) and you have the hrtimer support enabled. If it
> cant, then the subsystem is programmed in periodic mode (case
> CLOCK_EVT_MODE_PERIODIC) like in the traditional mode... no do_timer()
> ar all...
>
> Cheers,
>
> Pat.
>> 	//counts with 72MHz so compare interrupt every 10ms
>> 	T0MR0 = 720000;
>> 	T0PR = 0;	// prescaler = 0
>> 	T0MCR |= 0x03;			/* generate interrupt when T0MR0 match T0TC and Reset Timer Count*/
>>
>> 	lpc2xxx_timer_irq.handler = lpc2xxx_timer_interrupt;
>>
>> 	/* set up the interrupt vevtor for timer 0 match */
>> 	setup_irq(LPC2xxx_INTERRUPT_TIMER0,&lpc2xxx_timer_irq);
>> 	
>> 	/* enable the timer IRQ */
>> 	lpc22xx_unmask_irq(LPC2xxx_INTERRUPT_TIMER0);
>>
>> 	clocksource_calc_mult_shift(&pit_clk,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>>
>> 	pit_clk.mask = 71999;				// mask is 71999 so the clk subsystem knows where it overruns (is that correct??)
>> 	clocksource_register(&pit_clk);
>>
>> 	clockevents_calc_mult_shift(&pit_clkevt,Fcclk,4);	// minsecvalue =4 no idea why (seen in other codes)
>> 	pit_clkevt.cpumask = cpumask_of(0);		// uniprocessro system
>> 	clockevents_register_device(&pit_clkevt);
>>
>> 	/* let timer 0 run... */
>> 	T0IR = 0x01; /* reset MR0 interrupt*/
>> 	T0TCR = 0x02;	/* Reset timer count and prescale counter */
>> 	T0TCR = 0x01;	/* enable timer counter and prescale counter */
>> }
>>
>> struct sys_timer lpc22xx_timer = {
>> 	.init		= lpc2xxx_time_init,
>> };
>>
>>
>>
>> The problem is that after a minute or so the kernel freezes and hangs in the cpu_idle() function in arch/arm/kernel/process.c
>>
>> the board stays in this whileloop in the else condition forever:
>>
>> while (!need_resched()) {
>> #ifdef CONFIG_HOTPLUG_CPU
>> 			if (cpu_is_offline(smp_processor_id()))
>> 				cpu_die();
>> #endif
>>
>> 			local_irq_disable();
>> 			if (hlt_counter) {
>> 				local_irq_enable();
>> 				cpu_relax();
>> 			} else {
>> 				stop_critical_timings();
>> 				pm_idle();
>> 				start_critical_timings();
>> 				/*
>> 				 * This will eventually be removed - pm_idle
>> 				 * functions should always return with IRQs
>> 				 * enabled.
>> 				 */
>> 				WARN_ON(irqs_disabled());
>> 				local_irq_enable();
>> 			}
>> 		}
>>
>> i dont know what exactly the problem is...
>> Do i have to implement a sched_clock routine myself as is saw it in a few implemetations.
>> When i do a cat \\\"/proc/timer_list\\\" i can see folowing:
>>
>> cat timer_list
>> Timer List Version: v0.5
>> HRTIMER_MAX_CLOCK_BASES: 2
>> now at 960971480 nsecs
>>
>> cpu: 0
>>    clock 0:
>>     .base:       a031c560
>>     .index:      0
>>     .resolution: 10000000 nsecs
>>     .get_time:   ktime_get_real
>>     .offset:     0 nsecs
>> active timers:
>>    clock 1:
>>     .base:       a031c594
>>     .index:      1
>>     .resolution: 10000000 nsecs
>>     .get_time:   ktime_get
>>     .offset:     0 nsecs
>> active timers:
>>    #0: def_rt_bandwidth, sched_rt_period_timer, S:01, __enqueue_rt_entity, sirq-timer/0/4
>>    # expires at 1000000000-1000000000 nsecs [in 39028520 to 39028520 nsecs]
>>    #1:<a12fda88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, inetd/170
>>    # expires at 1960997774-1961997798 nsecs [in 1000026294 to 1001026318 nsecs]
>>     .expires_next   : 2147483646999999999 nsecs
>>     .hres_active    : 0
>>     .nr_events      : 0
>>     .nr_retries     : 0
>>     .nr_hangs       : 0
>>     .max_hang_time  : 0 nsecs
>>     .nohz_mode      : 0
>>     .idle_tick      : 0 nsecs
>>     .tick_stopped   : 0
>>     .idle_jiffies   : 0
>>     .idle_calls     : 0
>>     .idle_sleeps    : 0
>>     .idle_entrytime : 960913921 nsecs
>>     .idle_waketime  : 0 nsecs
>>     .idle_exittime  : 0 nsecs
>>     .idle_sleeptime : 77532270 nsecs
>>     .last_jiffies   : 0
>>     .next_jiffies   : 0
>>     .idle_expires   : 0 nsecs
>> jiffies: 4294941108
>>
>>
>> Tick Device: mode:     0
>> Per CPU device: 0
>> Clock Event Device: pit
>>    max_delta_ns:   0
>>    min_delta_ns:   0
>>    mult:           309237645
>>    shift:          32
>>    mode:           2
>>    next_event:     2147483646999999999 nsecs
>>    set_next_event:<(null)>
>>    set_mode:       pit_clkevt_mode
>>    event_handler:  tick_handle_periodic
>>
>>
>> I enabled some tracing and debuging in the kernel and then the following message was printed when the processor froze:
>>
>> \\\"sched: RT throttling activated\\\"
>>
>> What does it mean? IS it a problem of my timer implementation or is something else wrong with the system?
>>
>> I hope somebody can help me on this.
>>
>> Kind regards
>> Johannes Bauer
>>
>> --
>> To unsubscribe from this list: send the line \"unsubscribe linux-rt-users\" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>


-- 
Patrice Kadionik. F6KQH / F4CUQ
-----------

+----------------------------------------------------------------------+
+"Tout doit etre aussi simple que possible, pas seulement plus simple" +
+----------------------------------------------------------------------+
+ Patrice Kadionik             http://www.enseirb-matmeca.fr/~kadionik +
+ IMS Laboratory               http://www.ims-bordeaux.fr/             +
+ ENSEIRB-MATMECA              http://www.enseirb-matmeca.fr           +
+ PO BOX 99                    fax   : +33 5.56.37.20.23               +
+ 33402 TALENCE Cedex          voice : +33 5.56.84.23.47               +
+ FRANCE                       mailto:patrice.kadionik@ims-bordeaux.fr +
+----------------------------------------------------------------------+

--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2011-04-08 14:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-01 17:25 clocksource and clockevent confusion Johannes Bauer
     [not found] <4458795.11336.1301677125869.JavaMail.root@WARSBL213.highway.telekom.at>
2011-04-04 18:51 ` Johannes Bauer
2011-04-04 19:35   ` Patrice Kadionik
  -- strict thread matches above, loose matches on Subject: below --
2011-04-07 16:48 Johannes Bauer
2011-04-07 17:41 ` Patrice Kadionik
2011-04-07 18:37 ` Patrice Kadionik
2011-04-08 13:01 Johannes Bauer
2011-04-08 14:33 ` Patrice Kadionik

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).