Hi,

here comes version 2 of the I-pipe patch for the S3C24xx ARM. The reported 
problem is solved, the timer works as expected as far as I can see. Linux is 
still there after insmod'ding the native skin. More test results will follow 
next week after I tortured the new patch with the whole testsuite 
arsenal. ;-)

The patch has got two suboptimal characteristics due to the generic ARM I-pipe 
implementation which I did not want to change during the first steps:

1. Regarding the demux of chained IRQs (See [1]). As the S3C24xx has more than 
one chained IRQ there are two consecutive queries for them in 
__ipipe_mach_irq_mux_p() and __ipipe_mach_demux_irq(). This could be 
optimized.

2. If the xenomai timer is stopped the first two jiffies for Linux are one 
timer tick too long. The solution could be a change of this line [2]. The 
patch for the S3C24xx needs a timer reload value of 
__ipipe_mach_ticks_per_jiffy-1 when Xenomai's timer is inactive. For example 
we could introduce a new inline function which is called in line 98 of hal.c. 
The new I-pipe patch would then call 
__ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy-1) and the other ARM 
patches __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy).

Sebastian


[1] 
http://www.rts.uni-hannover.de/xenomai/lxr/source/ksrc/arch/arm/patches/adeos-ipipe-2.6.15-arm-1.5-01.patch?v=SVN-trunk;a=arm#L3761
[2] 
http://www.rts.uni-hannover.de/xenomai/lxr/source/ksrc/arch/arm/hal.c?v=SVN-trunk;a=arm#L98
diff -upr linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/irq.c linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/irq.c
--- linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/irq.c	2006-10-10 16:36:50.000000000 +0200
+++ linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/irq.c	2006-10-26 11:55:45.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <[EMAIL PROTECTED]>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <[EMAIL PROTECTED]>, emlix GmbH
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -48,7 +50,10 @@
  *
  *   25-Jul-2005  Ben Dooks
  *		  Split the S3C2440 IRQ code to seperate file
-*/
+ *
+ *   11-Oct-2006  Sebastian Smolorz
+ *		  Added Adeos/Ipipe support
+ */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -56,6 +61,7 @@
 #include <linux/ioport.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -70,6 +76,14 @@
 #include "pm.h"
 #include "irq.h"
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_CPU_S3C2440
+extern void __ipipe_s3c_irq_demux_wdtac97(unsigned int irq,
+					  struct pt_regs *regs);
+extern void __ipipe_s3c_irq_demux_cam(unsigned int irq, struct pt_regs *regs);
+#endif /* CONFIG_CPU_S3C2440 */
+#endif /* CONFIG_IPIPE */
+
 /* wakeup irq control */
 
 #ifdef CONFIG_PM
@@ -573,6 +587,71 @@ s3c_irq_demux_uart2(unsigned int irq,
 }
 
 
+#ifdef CONFIG_IPIPE
+static void __ipipe_s3c_irq_demux_uart(unsigned int start,
+					unsigned int subsrc,
+					struct pt_regs *regs)
+{
+	unsigned int offset = start - IRQ_S3CUART_RX0;
+
+	subsrc >>= offset;
+	subsrc &= 7;
+
+	if (subsrc != 0) {
+		if (subsrc & 1)
+			__ipipe_handle_irq(start, regs);
+		if (subsrc & 2)
+			__ipipe_handle_irq(start+1, regs);
+		if (subsrc & 4)
+			__ipipe_handle_irq(start+2, regs);
+	}
+}
+
+static void __ipipe_s3c_irq_demux_adc(unsigned int subsrc,
+					struct pt_regs *regs)
+{
+	subsrc >>= 9;
+	subsrc &= 3;
+
+	if (subsrc != 0) {
+		if (subsrc & 1)
+			__ipipe_handle_irq(IRQ_TC, regs);
+		if (subsrc & 2)
+			__ipipe_handle_irq(IRQ_ADC, regs);
+	}
+}
+
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	unsigned int subsrc, submsk;
+	struct irqdesc *desc_unused = irq_desc + irq;
+
+	/* read the current pending interrupts, and the mask
+	 * for what it is available */
+	subsrc = __raw_readl(S3C2410_SUBSRCPND);
+	submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+	subsrc &= ~submsk;
+
+	if (irq == IRQ_UART0)
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX0, subsrc, regs);
+	else if (irq == IRQ_UART1)
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX1, subsrc, regs);
+	else if (irq == IRQ_UART2)
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX2, subsrc, regs);
+	else if (irq == IRQ_ADCPARENT)
+		__ipipe_s3c_irq_demux_adc(subsrc, regs);
+#ifdef CONFIG_CPU_S3C2440
+	else if (irq == IRQ_WDT)
+		__ipipe_s3c_irq_demux_wdtac97(subsrc, regs);
+	else if (irq == IRQ_CAM)
+		__ipipe_s3c_irq_demux_cam(subsrc, regs);
+#endif /* CONFIG_CPU_S3C2440 */
+
+	desc_unused->chip->unmask(irq);
+}
+#endif /* CONFIG_IPIPE */
+
 /* s3c24xx_init_irq
  *
  * Initialise S3C2410 IRQ system
diff -upr linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/s3c2440-irq.c linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/s3c2440-irq.c
--- linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/s3c2440-irq.c	2006-10-10 16:36:50.000000000 +0200
+++ linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/s3c2440-irq.c	2006-10-26 11:55:45.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <[EMAIL PROTECTED]>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <[EMAIL PROTECTED]>, emlix GmbH
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -19,8 +21,10 @@
  *
  * Changelog:
  *	25-Jul-2005 BJD		Split from irq.c
+ *   	11-Oct-2006 Sebastian Smolorz
+ *		    Added Adeos/Ipipe support
  *
-*/
+ */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -28,6 +32,7 @@
 #include <linux/ioport.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -157,6 +162,34 @@ static struct irqchip s3c_irq_cam = {
 	.ack	    = s3c_irq_cam_ack,
 };
 
+#ifdef CONFIG_IPIPE
+void __ipipe_s3c_irq_demux_wdtac97(unsigned int subsrc, struct pt_regs *regs)
+{
+	subsrc >>= 13;
+	subsrc &= 3;
+
+	if (subsrc != 0) {
+		if (subsrc & 1)
+			__ipipe_handle_irq(IRQ_S3C2440_WDT, regs);
+		if (subsrc & 2)
+			__ipipe_handle_irq(IRQ_S3C2440_AC97, regs);
+	}
+}
+
+void __ipipe_s3c_irq_demux_cam(unsigned int subsrc, struct pt_regs *regs)
+{
+	subsrc >>= 11;
+	subsrc &= 3;
+
+	if (subsrc != 0) {
+		if (subsrc & 1)
+			__ipipe_handle_irq(IRQ_S3C2440_CAM_C, regs);
+		if (subsrc & 2)
+			__ipipe_handle_irq(IRQ_S3C2440_CAM_P, regs);
+	}
+}
+#endif /* CONFIG_IPIPE */
+
 static int s3c2440_irq_add(struct sys_device *sysdev)
 {
 	unsigned int irqno;
diff -upr linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/time.c linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/time.c
--- linux-2.6.15-ipipe.orig/arch/arm/mach-s3c2410/time.c	2006-10-10 16:36:50.000000000 +0200
+++ linux-2.6.15-ipipe.work/arch/arm/mach-s3c2410/time.c	2006-10-27 14:47:23.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (C) 2003-2005 Simtec Electronics
  *	Ben Dooks, <[EMAIL PROTECTED]>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <[EMAIL PROTECTED]>, emlix GmbH
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -24,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/leds.h>
@@ -40,7 +43,6 @@
 #include "clock.h"
 #include "cpu.h"
 
-static unsigned long timer_startval;
 static unsigned long timer_usec_ticks;
 
 #define TIMER_USEC_SHIFT 16
@@ -55,6 +57,24 @@ static unsigned long timer_usec_ticks;
  * Original patch by Dimitry Andric, updated by Ben Dooks
 */
 
+static unsigned long timer_reload = 0;
+static unsigned long tcon_stop = 0;
+static unsigned long timer_lxlost = 0;
+
+#ifdef CONFIG_IPIPE
+int __ipipe_mach_timerint = IRQ_TIMER4;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+static unsigned long long __ipipe_mach_tsc = 0;
+static int timer_wrapped = 0;
+static DEFINE_SPINLOCK(timer_lock);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+#endif /* CONFIG_IPIPE */
 
 /* timer_mask_usec_ticks
  *
@@ -85,12 +105,6 @@ static inline unsigned long timer_ticks_
 	return res >> TIMER_USEC_SHIFT;
 }
 
-/***
- * Returns microsecond  since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
- * IRQs are disabled before entering here from do_gettimeofday()
- */
-
 #define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
 
 static unsigned long s3c2410_gettimeoffset (void)
@@ -102,7 +116,7 @@ static unsigned long s3c2410_gettimeoffs
 	/* work out how many ticks have gone since last timer interrupt */
 
         tval =  __raw_readl(S3C2410_TCNTO(4));
-	tdone = timer_startval - tval;
+	tdone = timer_reload - tval;
 
 	/* check to see if there is an interrupt pending */
 
@@ -114,15 +128,38 @@ static unsigned long s3c2410_gettimeoffs
 		 */
 
 		tval =  __raw_readl(S3C2410_TCNTO(4));
-		tdone = timer_startval - tval;
+		tdone = timer_reload - tval;
 
 		if (tval != 0)
-			tdone += timer_startval;
+			tdone += timer_reload + 1;
 	}
 
-	return timer_ticks_to_usec(tdone);
+	return timer_ticks_to_usec(timer_lxlost + tdone);
+}
+
+static inline void timer_restart(unsigned long reload)
+{
+	/* Auto reload */
+	unsigned long tcon = tcon_stop | S3C2410_TCON_T4RELOAD;
+
+	/* Stop timer */
+	__raw_writel(tcon_stop, S3C2410_TCON);
+
+	__raw_writel(reload, S3C2410_TCNTB(4));
+	__raw_writel(reload, S3C2410_TCMPB(4));
+	
+	/* Manual update */
+	__raw_writel(tcon | S3C2410_TCON_T4MANUALUPD, S3C2410_TCON);
+
+	/* Start timer */
+	__raw_writel(tcon | S3C2410_TCON_T4START, S3C2410_TCON);
 }
 
+static inline void set_dec(unsigned long reload)
+{
+	timer_restart(reload);
+	timer_reload = reload;
+}
 
 /*
  * IRQ handler for the timer
@@ -131,6 +168,24 @@ static irqreturn_t
 s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	write_seqlock(&xtime_lock);
+
+#ifdef CONFIG_IPIPE
+	timer_lxlost = 0;
+
+	if (!__ipipe_mach_timerstolen) {
+		__ipipe_mach_tsc += __ipipe_mach_ticks_per_jiffy;
+		/* If this is the first interrupt after having stopped
+		   the Xenomai timer the auto reload value must be decreased
+		   by one tick. So max. 2 jiffies are one tick too long after
+		   the Xenomai timer has stopped. */
+		if (unlikely(timer_reload == __ipipe_mach_ticks_per_jiffy)) {
+			timer_reload--;
+			__raw_writel(timer_reload, S3C2410_TCNTB(4));
+			__raw_writel(timer_reload, S3C2410_TCMPB(4));
+		}
+	}
+#endif /* CONFIG_IPIPE */
+
 	timer_tick(regs);
 	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
@@ -209,6 +264,10 @@ static void s3c2410_timer_setup (void)
 		tcnt = (pclk / 6) / HZ;
 	}
 
+#ifdef CONFIG_IPIPE
+	__ipipe_mach_ticks_per_jiffy = tcnt;
+#endif /* CONFIG_IPIPE */
+
 	/* timers reload after counting zero, so reduce the count by 1 */
 
 	tcnt--;
@@ -225,23 +284,10 @@ static void s3c2410_timer_setup (void)
 	__raw_writel(tcfg1, S3C2410_TCFG1);
 	__raw_writel(tcfg0, S3C2410_TCFG0);
 
-	timer_startval = tcnt;
-	__raw_writel(tcnt, S3C2410_TCNTB(4));
-
-	/* ensure timer is stopped... */
-
 	tcon &= ~(7<<20);
-	tcon |= S3C2410_TCON_T4RELOAD;
-	tcon |= S3C2410_TCON_T4MANUALUPD;
+	tcon_stop = tcon;
 
-	__raw_writel(tcon, S3C2410_TCON);
-	__raw_writel(tcnt, S3C2410_TCNTB(4));
-	__raw_writel(tcnt, S3C2410_TCMPB(4));
-
-	/* start the timer running */
-	tcon |= S3C2410_TCON_T4START;
-	tcon &= ~S3C2410_TCON_T4MANUALUPD;
-	__raw_writel(tcon, S3C2410_TCON);
+	set_dec(tcnt);
 }
 
 static void __init s3c2410_timer_init (void)
@@ -255,3 +301,64 @@ struct sys_timer s3c24xx_timer = {
 	.offset		= s3c2410_gettimeoffset,
 	.resume		= s3c2410_timer_setup
 };
+
+#ifdef CONFIG_IPIPE
+static inline unsigned long s3c2410_getticksoffset(void)
+{
+	unsigned long tdone;
+	unsigned long tval;
+
+	/* work out how many ticks have gone since last timer interrupt */
+
+        tval =  __raw_readl(S3C2410_TCNTO(4));
+	tdone = timer_reload - tval;
+
+	if (timer_wrapped && tval != 0)
+		tdone += timer_reload + 1;
+
+	return tdone;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	unsigned long bitval = 1UL << (IRQ_TIMER4 - IRQ_EINT0);
+
+	if (__ipipe_mach_timerstolen)
+		timer_wrapped = 1;
+
+	__raw_writel(bitval, S3C2410_SRCPND);
+	__raw_writel(bitval, S3C2410_INTPND);
+}
+
+unsigned long long __ipipe_mach_get_tsc(void)
+{
+	unsigned long long result;
+	unsigned long flags;
+
+	spin_lock_irqsave_hw(&timer_lock, flags);
+	result = __ipipe_mach_tsc + s3c2410_getticksoffset();
+	spin_unlock_irqrestore_hw(&timer_lock, flags);
+	return result;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+void __ipipe_mach_set_dec(unsigned long reload)
+{
+	unsigned long ticks;
+	unsigned long flags;
+
+	spin_lock_irqsave_hw(&timer_lock, flags);
+	ticks = s3c2410_getticksoffset();
+	__ipipe_mach_tsc += ticks;
+	timer_lxlost += ticks;
+	set_dec(reload);
+	timer_wrapped = 0;
+	spin_unlock_irqrestore_hw(&timer_lock, flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return __raw_readl(S3C2410_TCNTO(4));
+}
+#endif /* CONFIG_IPIPE */
diff -upr linux-2.6.15-ipipe.orig/include/asm-arm/arch-s3c2410/irqs.h linux-2.6.15-ipipe.work/include/asm-arm/arch-s3c2410/irqs.h
--- linux-2.6.15-ipipe.orig/include/asm-arm/arch-s3c2410/irqs.h	2006-10-10 16:37:15.000000000 +0200
+++ linux-2.6.15-ipipe.work/include/asm-arm/arch-s3c2410/irqs.h	2006-10-26 11:55:45.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003-2005 Simtec Electronics
  *   Ben Dooks <[EMAIL PROTECTED]>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <[EMAIL PROTECTED]>, emlix GmbH
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -13,6 +15,7 @@
  *  12-Mar-2004 BJD  Fixed bug in header protection
  *  10-Feb-2005 BJD  Added camera IRQ from [EMAIL PROTECTED]
  *  28-Feb-2005 BJD  Updated s3c2440 IRQs
+ *  11-Oct-2006      Added Adeos/Ipipe support
  */
 
 
@@ -122,5 +125,20 @@
 
 #define NR_IRQS (IRQ_S3C2440_AC97+1)
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_CPU_S3C2440
+#define __ipipe_mach_irq_mux_p(irq)	((irq) == IRQ_UART0 	||	\
+					 (irq) == IRQ_UART1 	||	\
+					 (irq) == IRQ_UART2 	||	\
+					 (irq) == IRQ_ADCPARENT	||	\
+					 (irq) == IRQ_WDT	||	\
+					 (irq) == IRQ_CAM)
+#else /* !CONFIG_CPU_S3C2440 */
+#define __ipipe_mach_irq_mux_p(irq)	((irq) == IRQ_UART0 	||	\
+					 (irq) == IRQ_UART1 	||	\
+					 (irq) == IRQ_UART2 	||	\
+					 (irq) == IRQ_ADCPARENT)
+#endif /* CONFIG_CPU_S3C2440 */
+#endif /* CONFIG_IPIPE */
 
 #endif /* __ASM_ARCH_IRQ_H */
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to