RE: [ANNOUNCE] 3.12.0-rt2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>>> - tried to fix AT91's "already-free IRQ" and highres problem. Michael
>>>   Langfinge reported it initially and Sami Pietikäinen sent a patch for
>>>   the "already-free IRQ" problem. Based on another patch I looked at the
>>>   highres patch and tried to fix it. As I don't have the hardware, some
>>>   feedback would be nice.
>>
>>I did a quick test run with the 3.12.0-rt2 kernel. There are no "Trying to free already free IRQ 1" warnings anymore so that issue seems to be fixed. However, the system still hangs.
>>
>>Now the kernel boots with the CONFIG_HIGH_RES_TIMERS enabled, but hangs when I enable the TCB clock source.
>Okay. So in the working variant with TCB=n, do you have high res timers available?

Today me and my colleague had time to really look into this tcb_clksrc issue.
I am pretty confident that we solved the issue.

In clocksource-tclib-allow-higher-clockrates.patch the clockevent device frequency is
stored to a local variable but never written to the tc_clkevt_device struct (setup_clkevents function).

When the value is later used in tc_mode function the frequency is 0, which is written
to the compare register of the TC and bad things start to happen. This does not
happen with vanilla kernel because it uses hard coded 32k frequency.

Fix: replace local freq variable with clkevt.freq in setup_clkevents function.
I also renamed clk32k_divisor_idx to divisor_idx because the 32k frequency is not
hard coded in RT.

Michael, could you or your colleague test this fix and report if it works for you also.

BR,
Sami Pietikäinen

--- a/drivers/clocksource/tcb_clksrc.c	2013-11-20 22:37:52.000000000 +0200
+++ b/drivers/clocksource/tcb_clksrc.c	2013-11-25 14:54:02.909623861 +0200
@@ -23,8 +23,7 @@
  *     this 32 bit free-running counter. the second channel is not used.
  *
  *   - The third channel may be used to provide a 16-bit clockevent
- *     source, used in either periodic or oneshot mode.  This runs
- *     at 32 KiHZ, and can handle delays of up to two seconds.
+ *     source, used in either periodic or oneshot mode.
  *
  * A boot clocksource and clockevent source are also currently needed,
  * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
@@ -74,6 +73,7 @@ static struct clocksource clksrc = {
 struct tc_clkevt_device {
 	struct clock_event_device	clkevt;
 	struct clk			*clk;
+	u32				freq;
 	void __iomem			*regs;
 };
 
@@ -82,13 +82,6 @@ static struct tc_clkevt_device *to_tc_cl
 	return container_of(clkevt, struct tc_clkevt_device, clkevt);
 }
 
-/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
- * because using one of the divided clocks would usually mean the
- * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
- *
- * A divided clock could be good for high resolution timers, since
- * 30.5 usec resolution can seem "low".
- */
 static u32 timer_clock;
 
 static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
@@ -111,11 +104,12 @@ static void tc_mode(enum clock_event_mod
 	case CLOCK_EVT_MODE_PERIODIC:
 		clk_enable(tcd->clk);
 
-		/* slow clock, count up to RC, then irq and restart */
+		/* count up to RC, then irq and restart */
 		__raw_writel(timer_clock
 				| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
 				regs + ATMEL_TC_REG(2, CMR));
-		__raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
+		__raw_writel((tcd->freq + HZ/2)/HZ,
+			     tcaddr + ATMEL_TC_REG(2, RC));
 
 		/* Enable clock and interrupts on RC compare */
 		__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
@@ -128,7 +122,7 @@ static void tc_mode(enum clock_event_mod
 	case CLOCK_EVT_MODE_ONESHOT:
 		clk_enable(tcd->clk);
 
-		/* slow clock, count up to RC, then irq and stop */
+		/* count up to RC, then irq and stop */
 		__raw_writel(timer_clock | ATMEL_TC_CPCSTOP
 				| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
 				regs + ATMEL_TC_REG(2, CMR));
@@ -157,8 +151,12 @@ static struct tc_clkevt_device clkevt =
 		.name		= "tc_clkevt",
 		.features	= CLOCK_EVT_FEAT_PERIODIC
 					| CLOCK_EVT_FEAT_ONESHOT,
+#ifdef CONFIG_ATMEL_TCB_CLKSRC_USE_SLOW_CLOCK
 		/* Should be lower than at91rm9200's system timer */
 		.rating		= 125,
+#else
+		.rating		= 200,
+#endif
 		.set_next_event	= tc_next_event,
 		.set_mode	= tc_mode,
 	},
@@ -184,8 +182,9 @@ static struct irqaction tc_irqaction = {
 	.handler	= ch2_irq,
 };
 
-static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
+static void __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)
 {
+	unsigned divisor = atmel_tc_divisors[divisor_idx];
 	struct clk *t2_clk = tc->clk[2];
 	int irq = tc->irq[2];
 
@@ -193,11 +192,15 @@ static void __init setup_clkevents(struc
 	clkevt.clk = t2_clk;
 	tc_irqaction.dev_id = &clkevt;
 
-	timer_clock = clk32k_divisor_idx;
+	timer_clock = divisor_idx;
+	if (!divisor)
+		clkevt.freq = 32768;
+	else
+		clkevt.freq = clk_get_rate(t2_clk) / divisor;
 
 	clkevt.clkevt.cpumask = cpumask_of(0);
 
-	clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
+	clockevents_config_and_register(&clkevt.clkevt, clkevt.freq, 1, 0xffff);
 
 	setup_irq(irq, &tc_irqaction);
 }
@@ -322,8 +325,11 @@ static int __init tcb_clksrc_init(void)
 	clocksource_register_hz(&clksrc, divided_rate);
 
 	/* channel 2:  periodic and oneshot timer support */
+#ifdef CONFIG_ATMEL_TCB_CLKSRC_USE_SLOW_CLOCK
 	setup_clkevents(tc, clk32k_divisor_idx);
-
+#else
+	setup_clkevents(tc, best_divisor_idx);
+#endif
 	return 0;
 }
 arch_initcall(tcb_clksrc_init);
��.n��������+%������w��{.n�����{�����ǫ���ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f





[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux