All of lore.kernel.org
 help / color / mirror / Atom feed
* [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
@ 2007-04-10 16:47 Gregory CLEMENT
  2007-04-10 17:15 ` Gilles Chanteperdrix
                   ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-10 16:47 UTC (permalink / raw)
  To: adeos-main, BOUIN Alexandre

[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]

Hello,

We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.

This patch must be applied on vanilla 2.6.19 with at91 patch (
http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
supporting AT91SAM9261.
So first get vanilla kernel, then apply at91 patch then apply our
patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.

For now it works with Xenomai on AT91SAM9261-EK, if someone is
intersting we can send the benchmark result.
As AT91SAM926x are pretty similar of AT91RM9200, there is a some
duplicate code and some common code.
In the future it could be also work on all AT91SAM926x, we can test
it. But before going ahead we would like some comment on this patch.

The better would be working on 2.6.20 which already have support for
AT91SAM926x, but we didn't see any arm patch on this kernel nor any
file modified on git.

Hope this patch will be usefull.

PS: Would we post it on xenomai list also?

-- 
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40

[-- Attachment #2: adeos-ipipe-2.6.19-arm-1.6-05-at91sam9261.patch --]
[-- Type: text/x-patch, Size: 263758 bytes --]

diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/boot/compressed/head.S linux-2.6.19.patched/arch/arm/boot/compressed/head.S
--- linux-2.6.19.at91/arch/arm/boot/compressed/head.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/boot/compressed/head.S	2007-04-04 11:52:05.000000000 +0200
@@ -833,6 +833,16 @@ memdump:	mov	r12, r0
 		mov	pc, r10
 #endif
 
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+                .text
+                .align 0
+                .type mcount %function
+                .global mcount
+mcount:
+		mov pc, lr	@ just return
+#endif
+
+
 reloc_end:
 
 		.align
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/Kconfig linux-2.6.19.patched/arch/arm/Kconfig
--- linux-2.6.19.at91/arch/arm/Kconfig	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/Kconfig	2007-04-04 11:52:05.000000000 +0200
@@ -487,6 +487,8 @@ config LOCAL_TIMERS
 	  accounting to be spread across the timer interval, preventing a
 	  "thundering herd" at every timer tick.
 
+source "kernel/ipipe/Kconfig"
+
 config PREEMPT
 	bool "Preemptible Kernel (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-armv.S linux-2.6.19.patched/arch/arm/kernel/entry-armv.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-armv.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-armv.S	2007-04-04 11:52:05.000000000 +0200
@@ -4,6 +4,7 @@
  *  Copyright (C) 1996,1997,1998 Russell King.
  *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
  *  nommu support by Hyok S. Choi (hyok.choi@samsung.com)
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -27,13 +28,21 @@
  * Interrupt handling.  Preserves r7, r8, r9
  */
 	.macro	irq_handler
-1:	get_irqnr_and_base r0, r6, r5, lr
+#ifdef CONFIG_IPIPE
+	mov r0, #2
+#endif
+1:	get_irqnr_and_base r1, r6, r5, lr
+	movne   r0, r1
 	movne	r1, sp
 	@
 	@ routine called with r0 = irq number, r1 = struct pt_regs *
 	@
 	adrne	lr, 1b
+#ifdef CONFIG_IPIPE
+	bne	__ipipe_grab_irq
+#else
 	bne	asm_do_IRQ
+#endif
 
 #ifdef CONFIG_SMP
 	/*
@@ -42,18 +51,22 @@
 	 * this macro assumes that irqstat (r6) and base (r5) are
 	 * preserved from get_irqnr_and_base above
 	 */
-	test_for_ipi r0, r6, r5, lr
+	test_for_ipi r1, r6, r5, lr
 	movne	r0, sp
 	adrne	lr, 1b
 	bne	do_IPI
 
 #ifdef CONFIG_LOCAL_TIMERS
-	test_for_ltirq r0, r6, r5, lr
+	test_for_ltirq r1, r6, r5, lr
 	movne	r0, sp
 	adrne	lr, 1b
 	bne	do_local_timer
 #endif
 #endif
+#ifdef CONFIG_IPIPE
+	cmp	r0, #2
+	bleq	__ipipe_check_root_interruptible
+#endif	
 
 	.endm
 
@@ -196,14 +209,25 @@ __irq_svc:
 #endif
 #ifdef CONFIG_PREEMPT
 	get_thread_info tsk
+#ifndef CONFIG_IPIPE
 	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
 	add	r7, r8, #1			@ increment it
 	str	r7, [tsk, #TI_PREEMPT]
 #endif
+#endif
 
 	irq_handler
+#ifdef CONFIG_IPIPE
+	cmp	r0, #0
+	beq	__ipipe_fast_svc_irq_exit
+#endif
+
 #ifdef CONFIG_PREEMPT
 	ldr	r0, [tsk, #TI_FLAGS]		@ get flags
+#ifdef CONFIG_IPIPE
+	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
+	mov     r7, r8
+#endif	
 	tst	r0, #_TIF_NEED_RESCHED
 	blne	svc_preempt
 preempt_return:
@@ -212,6 +236,9 @@ preempt_return:
 	teq	r0, r7
 	strne	r0, [r0, -r0]			@ bug()
 #endif
+#ifdef CONFIG_IPIPE
+__ipipe_fast_svc_irq_exit:
+#endif
 	ldr	r0, [sp, #S_PSR]		@ irqs are already disabled
 	msr	spsr_cxsf, r0
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -231,19 +258,33 @@ svc_preempt:
 	ldr	r1, [r6, #8]			@ local_bh_count
 	adds	r0, r0, r1
 	movne	pc, lr
+#ifdef CONFIG_IPIPE
+	bl	__ipipe_fast_stall_root
+	enable_irq
+#endif
 	mov	r7, #0				@ preempt_schedule_irq
 	str	r7, [tsk, #TI_PREEMPT]		@ expects preempt_count == 0
 1:	bl	preempt_schedule_irq		@ irq en/disable is done inside
 	ldr	r0, [tsk, #TI_FLAGS]		@ get new tasks TI_FLAGS
 	tst	r0, #_TIF_NEED_RESCHED
-	beq	preempt_return			@ go again
-	b	1b
+	bne	1b
+#ifdef CONFIG_IPIPE
+	disable_irq
+	bl	__ipipe_fast_unstall_root
+#endif
+	b	preempt_return			@ go again
 #endif
 
 	.align	5
 __und_svc:
 	svc_entry
 
+#ifdef CONFIG_IPIPE
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	bne	1f
+#endif /* CONFIG_IPIPE */
 	@
 	@ call emulation code, which returns using r9 if it has emulated
 	@ the instruction, or the more conventional lr if we are to treat
@@ -410,18 +451,28 @@ __irq_usr:
 #endif
 	get_thread_info tsk
 #ifdef CONFIG_PREEMPT
+#ifndef CONFIG_IPIPE
 	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
 	add	r7, r8, #1			@ increment it
 	str	r7, [tsk, #TI_PREEMPT]
 #endif
+#endif
 
 	irq_handler
+#ifdef CONFIG_IPIPE
+	cmp	r0, #0
+	bne	__ipipe_usr_irq_continue
+	slow_restore_user_regs			@ Fast exit path over non-root domains
+__ipipe_usr_irq_continue:
+#endif
 #ifdef CONFIG_PREEMPT
+#ifndef CONFIG_IPIPE
 	ldr	r0, [tsk, #TI_PREEMPT]
 	str	r8, [tsk, #TI_PREEMPT]
 	teq	r0, r7
 	strne	r0, [r0, -r0]
 #endif
+#endif
 #ifdef CONFIG_TRACE_IRQFLAGS
 	bl	trace_hardirqs_on
 #endif
@@ -517,8 +568,8 @@ call_fpe:
 	mov	pc, lr				@ CP#8
 	mov	pc, lr				@ CP#9
 #ifdef CONFIG_VFP
-	b	do_vfp				@ CP#10 (VFP)
-	b	do_vfp				@ CP#11 (VFP)
+	b	_do_vfp				@ CP#10 (VFP)
+	b	_do_vfp				@ CP#11 (VFP)
 #else
 	mov	pc, lr				@ CP#10 (VFP)
 	mov	pc, lr				@ CP#11 (VFP)
@@ -529,11 +580,35 @@ call_fpe:
 	mov	pc, lr				@ CP#15 (Control)
 
 do_fpe:
+#ifdef CONFIG_IPIPE
+	mov	r4, r0
+	mov	r0, #5				@ == IPIPE_TRAP_FPU
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	ldrne	pc, [r9]
+	mov	r0, r4
+#endif
 	enable_irq
 	ldr	r4, .LCfp
 	add	r10, r10, #TI_FPSTATE		@ r10 = workspace
 	ldr	pc, [r4]			@ Call FP module USR entry point
 
+#ifdef CONFIG_VFP
+_do_vfp:
+#ifdef CONFIG_IPIPE
+	mov	r4, r0
+	mov	r0, #6				@ == IPIPE_TRAP_VFP
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	ldrne	pc, [r9]
+	mov	r0, r4
+#endif
+	b	do_vfp
+#endif
+
+
 /*
  * The FP module is called with these registers set:
  *  r0  = instruction
@@ -566,6 +641,13 @@ __pabt_usr:
  * This is the return code to user mode for abort handlers
  */
 ENTRY(ret_from_exception)
+#ifdef CONFIG_IPIPE
+	bl     __ipipe_check_root
+	cmp     r0, #0
+	bne     1f
+	slow_restore_user_regs          @ Fast exit path over non-root domains
+1:
+#endif /* CONFIG_IPIPE */
 	get_thread_info tsk
 	mov	why, #0
 	b	ret_to_user
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-common.S linux-2.6.19.patched/arch/arm/kernel/entry-common.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-common.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-common.S	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/kernel/entry-common.S
  *
  *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -19,13 +20,18 @@
  * possible here, and this includes saving r0 back into the SVC
  * stack.
  */
+#ifdef CONFIG_IPIPE
+__ipipe_ret_fast_syscall:
+	ldr	r0, [sp, #S_R0+S_OFF]		@ returned r0
+	/* fall through */
+#endif
 ret_fast_syscall:
 	disable_irq				@ disable interrupts
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	bne	fast_work_pending
 
-	@ fast_restore_user_regs
+fast_restore_user_regs:
 	ldr	r1, [sp, #S_OFF + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #S_OFF + S_PC]!	@ get pc
 	msr	spsr_cxsf, r1			@ save in spsr_svc
@@ -34,6 +40,13 @@ ret_fast_syscall:
 	add	sp, sp, #S_FRAME_SIZE - S_PC
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 
+#ifdef CONFIG_IPIPE
+__ipipe_fast_exit_syscall:
+	ldr	r0, [sp, #S_R0+S_OFF]		@ returned r0
+	disable_irq				@ disable interrupts
+	b	fast_restore_user_regs
+#endif /* CONFIG_IPIPE */
+
 /*
  * Ok, we need to do extra processing, enter the slow path.
  */
@@ -61,19 +74,15 @@ ret_slow_syscall:
 	tst	r1, #_TIF_WORK_MASK
 	bne	work_pending
 no_work_pending:
-	@ slow_restore_user_regs
-	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
-	ldr	lr, [sp, #S_PC]!		@ get pc
-	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
-	mov	r0, r0
-	add	sp, sp, #S_FRAME_SIZE - S_PC
-	movs	pc, lr				@ return & move spsr_svc into cpsr
+	slow_restore_user_regs
 
 /*
  * This is how we return from a fork.
  */
 ENTRY(ret_from_fork)
+#ifdef CONFIG_IPIPE
+	enable_irq
+#endif /* CONFIG_IPIPE */
 	bl	schedule_tail
 	get_thread_info tsk
 	ldr	r1, [tsk, #TI_FLAGS]		@ check for syscall tracing
@@ -198,6 +207,17 @@ ENTRY(vector_swi)
 #endif
 
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
+#ifdef CONFIG_IPIPE
+	stmfd	sp!, {r0-r3, ip}
+	add	r1, sp, #S_OFF
+	add	r1, r1, #20
+	mov	r0, scno
+	bl	__ipipe_syscall_root
+	cmp	r0, #0
+	ldmfd	sp!, {r0-r3, ip}
+	blt	__ipipe_ret_fast_syscall
+	bgt	__ipipe_fast_exit_syscall
+#endif /* CONFIG_IPIPE */
 	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
 
@@ -244,6 +264,9 @@ __sys_trace_return:
 __cr_alignment:
 	.word	cr_alignment
 #endif
+#ifdef CONFIG_IPIPE
+	.word	__ipipe_syscall_root
+#endif
 	.ltorg
 
 /*
@@ -390,3 +413,28 @@ ENTRY(sys_oabi_call_table)
 
 #endif
 
+
+#ifdef CONFIG_FRAME_POINTER
+
+	.text
+	.align 0
+	.type arm_return_addr %function
+	.global arm_return_addr
+
+arm_return_addr:
+	mov	ip, r0
+	mov	r0, fp
+3:
+	cmp	r0, #0
+	beq	1f		@ frame list hit end, bail
+	cmp	ip, #0
+	beq	2f		@ reached desired frame
+	ldr	r0, [r0, #-12]  @ else continue, get next fp
+	sub	ip, ip, #1
+	b	3b
+2:
+	ldr	r0, [r0, #-4]   @ get target return address
+1:
+	mov	pc, lr
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-header.S linux-2.6.19.patched/arch/arm/kernel/entry-header.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-header.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-header.S	2007-04-04 11:52:05.000000000 +0200
@@ -49,6 +49,15 @@
 #endif
 	.endm
 
+	.macro slow_restore_user_regs
+	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
+	ldr	lr, [sp, #S_PC]!		@ get pc
+	msr	spsr_cxsf, r1			@ save in spsr_svc
+	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
+	mov	r0, r0
+	add	sp, sp, #S_FRAME_SIZE - S_PC
+	movs	pc, lr				@ return & move spsr_svc into cpsr
+	.endm
 
 /*
  * These are the registers used in the syscall handler, and allow us to
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ipipe.c linux-2.6.19.patched/arch/arm/kernel/ipipe.c
--- linux-2.6.19.at91/arch/arm/kernel/ipipe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ipipe.c	2007-04-04 11:52:05.000000000 +0200
@@ -0,0 +1,532 @@
+/* -*- linux-c -*-
+ * linux/arch/arm/kernel/ipipe.c
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ * Copyright (C) 2004 Wolfgang Grandegger (Adeos/arm port over 2.4).
+ * Copyright (C) 2005 Heikki Lindholm (PowerPC 970 fixes).
+ * Copyright (C) 2005 Stelian Pop.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-dependent I-PIPE support for ARM.
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/unistd.h>
+#include <asm/mach/irq.h>
+#include <asm/mmu_context.h>
+
+/* Current reload value for the decrementer. */
+unsigned long __ipipe_decr_ticks;
+
+/* Next tick date (timebase value). */
+unsigned long long __ipipe_decr_next[IPIPE_NR_CPUS];
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+extern struct irqdesc irq_desc[];
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static ipipe_spinlock_t __ipipe_cpu_barrier = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+/* Always called with hw interrupts off. */
+
+void __ipipe_do_critical_sync(unsigned irq)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	cpu_set(cpuid, __ipipe_cpu_sync_map);
+
+	/*
+	 * Now we are in sync with the lock requestor running on another
+	 * CPU. Enter a spinning wait until he releases the global
+	 * lock.
+	 */
+	spin_lock_hw(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock_hw(&__ipipe_cpu_barrier);
+
+	cpu_clear(cpuid, __ipipe_cpu_sync_map);
+}
+
+#endif	/* CONFIG_SMP */
+
+/*
+ * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+ * just like if it has been actually received from a hw source. Also
+ * works for virtual interrupts.
+ */
+int ipipe_trigger_irq(unsigned irq)
+{
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	local_irq_save_hw(flags);
+
+	__ipipe_handle_irq(irq, NULL);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+void __ipipe_init_platform(void)
+{
+	__ipipe_decr_ticks = __ipipe_mach_ticks_per_jiffy;
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = __ipipe_mach_timerint;
+	info->archdep.tmfreq = info->cpufreq;
+
+	return 0;
+}
+
+static void __ipipe_set_decr(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	__ipipe_decr_next[cpuid] = __ipipe_read_timebase() + __ipipe_decr_ticks;
+	__ipipe_mach_set_dec(__ipipe_decr_ticks);
+}
+
+int ipipe_tune_timer(unsigned long ns, int flags)
+{
+	unsigned long x, ticks;
+
+	if (flags & IPIPE_RESET_TIMER)
+		ticks = __ipipe_mach_ticks_per_jiffy;
+	else {
+		ticks = (ns / 1000) * (__ipipe_mach_ticks_per_jiffy) / (1000000 / HZ);
+
+		if (ticks > __ipipe_mach_ticks_per_jiffy)
+			return -EINVAL;
+	}
+
+	x = ipipe_critical_enter(&__ipipe_set_decr);	/* Sync with all CPUs */
+	__ipipe_decr_ticks = ticks;
+	__ipipe_set_decr();
+	ipipe_critical_exit(x);
+
+	return 0;
+}
+
+static int __ipipe_ack_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_ack(irq, desc);
+	return 1;
+}
+
+static int __ipipe_ack_timerirq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_ack(irq, desc);
+	__ipipe_mach_acktimer();
+#ifdef irq_finish
+ 	/* AT91 specific workaround */
+	irq_finish(irq);
+#endif /* irq_finish */
+	desc->ipipe_end(irq, desc);
+	return 1;
+}
+
+void __ipipe_enable_irqdesc(unsigned irq)
+{
+	irq_desc[irq].status &= ~IRQ_DISABLED;
+}
+
+static void __ipipe_enable_sync(void)
+{
+	__ipipe_decr_next[ipipe_processor_id()] =
+		__ipipe_read_timebase() + __ipipe_mach_get_dec();
+}
+
+/*
+ * __ipipe_enable_pipeline() -- We are running on the boot CPU, hw
+ * interrupts are off, and secondary CPUs are still lost in space.
+ */
+void __ipipe_enable_pipeline(void)
+{
+	unsigned long flags;
+	unsigned irq;
+
+	flags = ipipe_critical_enter(&__ipipe_enable_sync);
+
+	/* First, virtualize all interrupts from the root domain. */
+
+	for (irq = 0; irq < NR_IRQS; irq++)
+		ipipe_virtualize_irq(ipipe_root_domain,
+				     irq,
+				     (ipipe_irq_handler_t)&asm_do_IRQ, NULL,
+				     ((irq == __ipipe_mach_timerint)
+				      ? &__ipipe_ack_timerirq
+				      : &__ipipe_ack_irq),
+				     IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	__ipipe_decr_next[ipipe_processor_id()] =
+		__ipipe_read_timebase() + __ipipe_mach_get_dec();
+
+	ipipe_critical_exit(flags);
+}
+
+/*
+ * ipipe_critical_enter() -- Grab the superlock excluding all CPUs
+ * but the current one from a critical section. This lock is used when
+ * we must enforce a global critical section for a single CPU in a
+ * possibly SMP system whichever context the CPUs are running.
+ */
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+		cpumask_t lock_map;
+
+		ipipe_load_cpuid();
+
+		if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) {
+			while (cpu_test_and_set(BITS_PER_LONG - 1,
+						__ipipe_cpu_lock_map)) {
+				int n = 0;
+				do {
+					cpu_relax();
+				} while (++n < cpuid);
+			}
+
+			spin_lock_hw(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			send_IPI_allbutself(IPIPE_CRITICAL_VECTOR);
+
+			cpus_andnot(lock_map, cpu_online_map,
+				    __ipipe_cpu_lock_map);
+
+			while (!cpus_equal(__ipipe_cpu_sync_map, lock_map))
+				cpu_relax();
+		}
+
+		atomic_inc(&__ipipe_critical_count);
+	}
+#endif	/* CONFIG_SMP */
+
+	return flags;
+}
+
+/* ipipe_critical_exit() -- Release the superlock. */
+
+void ipipe_critical_exit(unsigned long flags)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+
+		ipipe_load_cpuid();
+
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock_hw(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(cpuid, __ipipe_cpu_lock_map);
+			cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map);
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	local_irq_restore_hw(flags);
+}
+
+asmlinkage int __ipipe_check_root(void)
+{
+	return per_cpu(ipipe_percpu_domain, ipipe_processor_id()) == ipipe_root_domain;
+}
+
+asmlinkage int __ipipe_check_root_interruptible(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	return (per_cpu(ipipe_percpu_domain, cpuid) == ipipe_root_domain &&	
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+/* Called from entry-armv.S with hw interrupts off */
+asmlinkage void __ipipe_fast_stall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);	
+}
+
+/* Called from entry-armv.S with hw interrupts off */
+asmlinkage void __ipipe_fast_unstall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+}
+
+asmlinkage int __ipipe_syscall_root(unsigned long scno, struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags, origr7;
+
+	/* We use r7 to pass the syscall number to the other domains */
+	origr7 = regs->ARM_r7;
+	regs->ARM_r7 = __NR_SYSCALL_BASE + scno;
+	/*
+	 * This routine either returns:
+	 * 0 -- if the syscall is to be passed to Linux;
+	 * >0 -- if the syscall should not be passed to Linux, and no
+	 * tail work should be performed;
+	 * <0 -- if the syscall should not be passed to Linux but the
+	 * tail work has to be performed (for handling signals etc).
+	 */
+
+	if (__ipipe_syscall_watched_p(current, regs->ARM_r7) &&
+	    __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
+	    __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) {
+		if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) {
+			/*
+			 * Sync pending VIRQs before _TIF_NEED_RESCHED
+			 * is tested.
+			 */
+			ipipe_lock_cpu(flags);
+			if ((ipipe_root_domain->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+			ipipe_unlock_cpu(flags);
+			regs->ARM_r7 = origr7;
+			return -1;
+		}
+		regs->ARM_r7 = origr7;
+		return 1;
+	}
+
+	regs->ARM_r7 = origr7;
+	return 0;
+}
+
+/*
+ * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+ * interrupt protection log is maintained here for each domain. Hw
+ * interrupts are off on entry.
+ */
+void __ipipe_handle_irq(int irq, struct pt_regs *regs)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *head, *pos;
+	ipipe_declare_cpuid;
+	int m_ack;
+
+	m_ack = (regs == NULL);
+
+	if (irq >= IPIPE_NR_IRQS) {
+		printk(KERN_ERR "I-pipe: spurious interrupt %d\n", irq);
+		return;
+	}
+
+	ipipe_load_cpuid();
+
+	this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
+		head = &this_domain->p_link;
+	else {
+		head = __ipipe_pipeline.next;
+		next_domain = list_entry(head, struct ipipe_domain, p_link);
+		if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) {
+			if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+				next_domain->irqs[irq].acknowledge(irq);
+			if (likely(__ipipe_dispatch_wired(next_domain, irq)))
+				goto finalize;
+			return;
+		}
+	}
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		next_domain = list_entry(pos, struct ipipe_domain, p_link);
+
+		/*
+		 * For each domain handling the incoming IRQ, mark it as
+		 * pending in its log.
+		 */
+		if (test_bit(IPIPE_HANDLE_FLAG,
+			     &next_domain->irqs[irq].control)) {
+			/*
+			 * Domains that handle this IRQ are polled for
+			 * acknowledging it by decreasing priority order. The
+			 * interrupt must be made pending _first_ in the
+			 * domain's status flags before the PIC is unlocked.
+			 */
+
+			next_domain->cpudata[cpuid].irq_counters[irq].total_hits++;
+			next_domain->cpudata[cpuid].irq_counters[irq].pending_hits++;
+			__ipipe_set_irq_bit(next_domain, cpuid, irq);
+
+			/*
+			 * Always get the first master acknowledge available.
+			 * Once we've got it, allow slave acknowledge
+			 * handlers to run (until one of them stops us).
+			 */
+			if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+				m_ack = next_domain->irqs[irq].acknowledge(irq);
+		}
+
+		/*
+		 * If the domain does not want the IRQ to be passed down the
+		 * interrupt pipe, exit the loop now.
+		 */
+
+		if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+finalize:
+	/*
+	 * Now walk the pipeline, yielding control to the highest
+	 * priority domain that has pending interrupt(s) or
+	 * immediately to the current domain if the interrupt has been
+	 * marked as 'sticky'. This search does not go beyond the
+	 * current domain in the pipeline.
+	 */
+
+	__ipipe_walk_pipeline(head, cpuid);
+}
+
+asmlinkage int __ipipe_grab_irq(int irq, struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+
+	if (irq == __ipipe_mach_timerint) {
+
+		__ipipe_tick_regs[cpuid].ARM_cpsr = regs->ARM_cpsr;
+		__ipipe_tick_regs[cpuid].ARM_pc = regs->ARM_pc;
+
+		if (__ipipe_decr_ticks != __ipipe_mach_ticks_per_jiffy) {
+			unsigned long long next_date, now;
+
+			next_date = __ipipe_decr_next[cpuid];
+
+			while ((now = __ipipe_read_timebase()) >= next_date)
+				next_date += __ipipe_decr_ticks;
+
+			__ipipe_mach_set_dec(next_date - now);
+
+			__ipipe_decr_next[cpuid] = next_date;
+		}
+	}
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	ipipe_trace_begin(regs->ARM_ORIG_r0);
+#endif
+
+	if (__ipipe_mach_irq_mux_p(irq))
+		__ipipe_mach_demux_irq(irq, regs);
+	else
+		__ipipe_handle_irq(irq, regs);
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	ipipe_trace_end(regs->ARM_ORIG_r0);
+#endif
+
+#ifdef irq_finish
+ 	/* AT91 specific workaround */
+	if (irq != __ipipe_mach_timerint)
+		irq_finish(irq);
+#endif /* irq_finish */
+	ipipe_load_cpuid();
+
+	return (per_cpu(ipipe_percpu_domain, cpuid) == ipipe_root_domain &&	
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+EXPORT_SYMBOL(__ipipe_decr_ticks);
+EXPORT_SYMBOL(__ipipe_decr_next);
+EXPORT_SYMBOL(ipipe_critical_enter);
+EXPORT_SYMBOL(ipipe_critical_exit);
+EXPORT_SYMBOL(ipipe_trigger_irq);
+EXPORT_SYMBOL(ipipe_get_sysinfo);
+EXPORT_SYMBOL(ipipe_tune_timer);
+
+EXPORT_SYMBOL_GPL(show_stack);
+#ifndef MULTI_CPU
+EXPORT_SYMBOL_GPL(cpu_do_switch_mm);
+#endif
+
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+void notrace mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif /* CONFIG_IPIPE_TRACE_MCOUNT */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ipipe-mcount.S linux-2.6.19.patched/arch/arm/kernel/ipipe-mcount.S
--- linux-2.6.19.at91/arch/arm/kernel/ipipe-mcount.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ipipe-mcount.S	2007-04-04 11:52:05.000000000 +0200
@@ -0,0 +1,38 @@
+/*
+ *  linux/arch/arm/kernel/ipipe-mcount.S
+ *
+ *  Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, emlix GmbH
+ */
+
+#ifdef CONFIG_FRAME_POINTER
+
+	.text
+	.align 0
+	.type mcount %function
+	.global mcount
+
+mcount:
+
+	ldr	ip, =ipipe_trace_enable	@ leave early, if disabled
+	ldr	ip, [ip]
+	cmp	ip, #0
+	moveq	pc,lr
+
+	mov	ip,  sp
+	stmdb   sp!, {r0 - r3, fp, ip, lr, pc}	@ create stack frame
+
+	mov	r3, #0			@ no additional value (v)
+	ldr	r2, [fp, #-4]		@ get lr (the return address
+					@ of the caller of the
+					@ instrumented function)
+	mov	r1, lr			@ get lr - (the return address
+					@ of the instrumented function)
+	mov	r0, #0			@ IPIPE_TRACE_FN
+
+	sub	fp, ip, #4		@ point fp at this frame
+
+	bl	__ipipe_trace
+
+	ldmdb   fp, {r0 - r3, fp, sp, pc}	@ pop entry frame and return
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/irq.c linux-2.6.19.patched/arch/arm/kernel/irq.c
--- linux-2.6.19.at91/arch/arm/kernel/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/irq.c	2007-04-04 11:52:05.000000000 +0200
@@ -125,8 +125,10 @@ asmlinkage void asm_do_IRQ(unsigned int 
 
 	desc_handle_irq(irq, desc);
 
+#ifndef CONFIG_IPIPE
 	/* AT91 specific workaround */
 	irq_finish(irq);
+#endif /* !CONFIG_IPIPE */
 
 	irq_exit();
 	set_irq_regs(old_regs);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/Makefile linux-2.6.19.patched/arch/arm/kernel/Makefile
--- linux-2.6.19.at91/arch/arm/kernel/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/Makefile	2007-04-04 11:52:05.000000000 +0200
@@ -20,6 +20,8 @@ obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
+obj-$(CONFIG_IPIPE)		+= ipipe.o
+obj-$(CONFIG_IPIPE_TRACE_MCOUNT)	+= ipipe-mcount.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/process.c linux-2.6.19.patched/arch/arm/kernel/process.c
--- linux-2.6.19.at91/arch/arm/kernel/process.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/process.c	2007-04-04 11:52:05.000000000 +0200
@@ -125,6 +125,12 @@ static void default_idle(void)
 		local_irq_disable();
 		if (!need_resched()) {
 			timer_dyn_reprogram();
+#ifdef CONFIG_IPIPE
+			__ipipe_unstall_root();
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+			ipipe_trace_end(0x8000000E);
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+#endif /* CONFIG_IPIPE */
 			arch_idle();
 		}
 		local_irq_enable();
@@ -153,6 +159,7 @@ void cpu_idle(void)
 
 		if (!idle)
 			idle = default_idle;
+ 		ipipe_suspend_domain();
 		leds_event(led_idle_start);
 		while (!need_resched())
 			idle();
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ptrace.c linux-2.6.19.patched/arch/arm/kernel/ptrace.c
--- linux-2.6.19.at91/arch/arm/kernel/ptrace.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ptrace.c	2007-04-04 11:52:05.000000000 +0200
@@ -485,6 +485,10 @@ void ptrace_break(struct task_struct *ts
 
 static int break_trap(struct pt_regs *regs, unsigned int instr)
 {
+
+	if (ipipe_trap_notify(IPIPE_TRAP_BREAK,regs))
+		return 0;
+
 	ptrace_break(current, regs);
 	return 0;
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/traps.c linux-2.6.19.patched/arch/arm/kernel/traps.c
--- linux-2.6.19.at91/arch/arm/kernel/traps.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/traps.c	2007-04-04 11:52:05.000000000 +0200
@@ -306,6 +306,9 @@ asmlinkage void do_undefinstr(struct pt_
 	}
 	spin_unlock_irq(&undef_lock);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_UNDEFINSTR,regs))
+		return;
+
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_UNDEFINED) {
 		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c	2007-04-04 11:52:05.000000000 +0200
@@ -33,6 +33,13 @@ static struct map_desc at91rm9200_io_des
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+#ifdef CONFIG_IPIPE
+		.virtual	= AT91_VA_BASE_TCB0,
+		.pfn		= __phys_to_pfn(AT91RM9200_BASE_TCB0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+        }, {
+#endif /* CONFIG_IPIPE */
 		.virtual	= AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE,
 		.pfn		= __phys_to_pfn(AT91RM9200_SRAM_BASE),
 		.length		= AT91RM9200_SRAM_SIZE,
@@ -247,6 +254,7 @@ void __init at91rm9200_initialize(unsign
  * The default interrupt priority levels (0 = lowest, 7 = highest).
  */
 static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
 	7,	/* Advanced Interrupt Controller (FIQ) */
 	7,	/* System Peripherals */
 	0,	/* Parallel IO Controller A */
@@ -279,6 +287,42 @@ static unsigned int at91rm9200_default_i
 	0,	/* Advanced Interrupt Controller (IRQ4) */
 	0,	/* Advanced Interrupt Controller (IRQ5) */
 	0	/* Advanced Interrupt Controller (IRQ6) */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+   I-pipe. */
+	7,	/* Advanced Interrupt Controller */
+	6,	/* System Peripheral */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C */
+	0,	/* Parallel IO Controller D */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
+	5,	/* USART 3 */
+	0,	/* Multimedia Card Interface */
+	3,	/* USB Device Port */
+	0,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface */
+	4,	/* Serial Synchronous Controller */
+	4,	/* Serial Synchronous Controller */
+	4,	/* Serial Synchronous Controller */
+	7,	/* Timer Counter 0 */
+	7,	/* Timer Counter 1 */
+	7,	/* Timer Counter 2 */
+	0,	/* Timer Counter 3 */
+	0,	/* Timer Counter 4 */
+	0,	/* Timer Counter 5 */
+	2,	/* USB Host port */
+	2,	/* Ethernet MAC */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0	/* Advanced Interrupt Controller */
+#endif /*CONFIG_IPIPE */
 };
 
 void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200_time.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200_time.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200_time.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200_time.c	2007-04-04 11:52:05.000000000 +0200
@@ -34,6 +34,62 @@
 
 static unsigned long last_crtr;
 
+#ifdef CONFIG_IPIPE
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <asm/arch/at91rm9200_tc.h>
+#include "clock.h"
+
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+
+#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
+#define AT91_TC_REG_MASK (0xffff)
+
+#if (CONFIG_IPIPE_AT91_TC==0)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC0
+#elif (CONFIG_IPIPE_AT91_TC==1)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC1
+#elif (CONFIG_IPIPE_AT91_TC==2)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC2
+#else
+#error IPIPE_AT91_TC must be 0, 1 or 2.
+#endif
+
+static inline unsigned int at91_tc_read(unsigned int reg_offset)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	return readl((void __iomem *)(addr + reg_offset));
+}
+
+static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	writel(value, (void __iomem *)(addr + reg_offset));
+}
+
+#define read_CV() at91_tc_read(AT91_TC_CV)
+#define read_RC() at91_tc_read(AT91_TC_RC)
+#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
+
+int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int at91_timer_initialized;
+#endif /* CONFIG_IPIPE */
+
 /*
  * The ST_CRTR is updated asynchronously to the master clock.  It is therefore
  *  necessary to read it twice (with the same value) to ensure accuracy.
@@ -41,14 +97,16 @@ static unsigned long last_crtr;
 static inline unsigned long read_CRTR(void) {
 	unsigned long x1, x2;
 
+	x2 = at91_sys_read(AT91_ST_CRTR);
 	do {
-		x1 = at91_sys_read(AT91_ST_CRTR);
+		x1 = x2;
 		x2 = at91_sys_read(AT91_ST_CRTR);
 	} while (x1 != x2);
 
 	return x1;
 }
 
+#ifndef CONFIG_IPIPE
 /*
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
@@ -144,3 +202,209 @@ struct sys_timer at91rm9200_timer = {
 	.resume		= at91rm9200_timer_reset,
 };
 
+#else /* CONFIG_IPIPE */
+
+/*
+ * Returns number of microseconds since last timer interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeofday()
+ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+ *  'tick' is usecs per jiffy (linux/timex.h).
+ */
+static unsigned long at91rm9200_gettimeoffset(void)
+{
+	unsigned long elapsed;
+
+	elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
+
+	return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	at91_tc_read(AT91_TC_SR);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
+{
+	/*
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+
+	write_seqlock(&xtime_lock);
+
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+	} else {
+		while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
+			timer_tick();
+			last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+		}
+		write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
+	}
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91rm9200_bad_freq(int irq, void *dev_id)
+{
+	static int ticks = 0;
+
+	if (++ticks != HZ * 120) {
+		if (!console_drivers || try_acquire_console_sem())
+			return at91rm9200_timer_interrupt(irq, dev_id);
+	
+		release_console_sem();
+	}
+
+	panic("AT91 clock rate incorrectly set.\n"
+	      "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
+	      clk_get_rate(clk_get(NULL, "mck")));
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(at91_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned short mid;
+				unsigned short low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned short low;
+				unsigned short mid;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long long result;
+		unsigned short stamp;
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = read_CV();
+		if (unlikely(stamp < local_tsc->low)) {
+			if (unlikely(!++local_tsc->mid))
+				/* 32 bit counter wrapped, increment high word. */
+				local_tsc->high++;
+		}
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	if (delay > 2) {
+		local_irq_save_hw(flags);
+		write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
+}
+
+static struct irqaction at91rm9200_timer_irq = {
+	.name		= "at91_tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= &at91rm9200_timer_interrupt
+};
+
+static char clk_name [] = "tc%";
+
+static struct clk tc = {
+	.name		= (const char *) clk_name,
+	.users          = 0,
+	.type		= CLK_TYPE_PERIPHERAL,
+	.pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
+};
+
+void __init at91rm9200_timer_init(void)
+{
+	unsigned long v;
+	
+	if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
+		at91rm9200_timer_irq.handler = &at91rm9200_bad_freq;
+
+	snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
+	clk_register(&tc);
+	clk_enable(&tc);
+	
+	/* No Sync. */
+	at91_tc_write(AT91_TC_BCR, 0);
+
+	/* program NO signal on XCN */
+	v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+	v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
+	v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
+	writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+
+	/* Disable the channel */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
+
+	/* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
+	at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
+
+	/* Disable all interrupts. */
+	at91_tc_write(AT91_TC_IDR, ~0ul);
+
+	/* Load the TC register C. */
+	last_crtr = 0;
+	write_RC(LATCH);
+
+	/* Enable CPCS interrupt. */
+	at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
+
+	/* Set up the interrupt. */
+	setup_irq(KERNEL_TIMER_IRQ_NUM, &at91rm9200_timer_irq);
+
+	/* Enable the channel. */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
+
+	at91_timer_initialized = 1;
+}
+
+struct sys_timer at91rm9200_timer = {
+	.init		= at91rm9200_timer_init,
+	.offset		= at91rm9200_gettimeoffset,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-10 07:58:16.000000000 +0200
@@ -27,6 +27,13 @@ static struct map_desc at91sam9261_io_de
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+#ifdef CONFIG_IPIPE
+		.virtual	= AT91_VA_BASE_TCB0,
+		.pfn		= __phys_to_pfn(AT91SAM9261_BASE_TCB0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+        }, {
+#endif /* CONFIG_IPIPE */
 		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
 		.pfn		= __phys_to_pfn(AT91SAM9261_SRAM_BASE),
 		.length		= AT91SAM9261_SRAM_SIZE,
@@ -242,6 +249,7 @@ void __init at91sam9261_initialize(unsig
  * The default interrupt priority levels (0 = lowest, 7 = highest).
  */
 static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
 	7,	/* Advanced Interrupt Controller */
 	7,	/* System Peripherals */
 	0,	/* Parallel IO Controller A */
@@ -274,6 +282,42 @@ static unsigned int at91sam9261_default_
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+   I-pipe. */
+	7,	/* Advanced Interrupt Controller */
+	7,	/* System Peripherals */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C */
+	0,
+	6,	/* USART 0 */
+	6,	/* USART 1 */
+	6,	/* USART 2 */
+	0,	/* Multimedia Card Interface */
+	4,	/* USB Device Port */
+	0,	/* Two-Wire Interface */
+	6,	/* Serial Peripheral Interface 0 */
+	6,	/* Serial Peripheral Interface 1 */
+	5,	/* Serial Synchronous Controller 0 */
+	5,	/* Serial Synchronous Controller 1 */
+	5,	/* Serial Synchronous Controller 2 */
+	7,	/* Timer Counter 0 */
+	7,	/* Timer Counter 1 */
+	7,	/* Timer Counter 2 */
+	3,	/* USB Host port */
+	3,	/* LCD Controller */
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+#endif /*CONFIG_IPIPE */
 };
 
 void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-04 11:52:05.000000000 +0200
@@ -22,10 +22,69 @@
 
 #include <asm/arch/at91_pit.h>
 
+static unsigned long last_crtr;
+
+#ifdef CONFIG_IPIPE
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/at91_tc.h>
+#include "clock.h"
+
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+
+#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
+#define AT91_TC_REG_MASK (0xffff)
+
+#if (CONFIG_IPIPE_AT91_TC==0)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC0
+#elif (CONFIG_IPIPE_AT91_TC==1)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC1
+#elif (CONFIG_IPIPE_AT91_TC==2)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC2
+#else
+#error IPIPE_AT91_TC must be 0, 1 or 2.
+#endif
+
+static inline unsigned int at91_tc_read(unsigned int reg_offset)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	return readl((void __iomem *)(addr + reg_offset));
+}
+
+static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	writel(value, (void __iomem *)(addr + reg_offset));
+}
+
+#define read_CV() at91_tc_read(AT91_TC_CV)
+#define read_RC() at91_tc_read(AT91_TC_RC)
+#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
+
+int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int at91_timer_initialized;
+#endif /* CONFIG_IPIPE */
 
 #define PIT_CPIV(x)	((x) & AT91_PIT_CPIV)
 #define PIT_PICNT(x)	(((x) & AT91_PIT_PICNT) >> 20)
 
+#ifndef CONFIG_IPIPE
 /*
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
@@ -112,3 +171,209 @@ struct sys_timer at91sam926x_timer = {
 	.resume		= at91sam926x_timer_reset,
 };
 
+#else /* CONFIG_IPIPE */
+
+/*
+ * Returns number of microseconds since last timer interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeofday()
+ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+*  'tick' is usecs per jiffy (linux/timex.h).
+ */
+static unsigned long at91sam926x_gettimeoffset(void)
+{
+	unsigned long elapsed;
+
+	elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
+
+	return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	at91_tc_read(AT91_TC_SR);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
+{
+	/*
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+
+	write_seqlock(&xtime_lock);
+
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+	} else {
+		while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
+			timer_tick();
+			last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+		}
+		write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
+	}
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91sam926x_bad_freq(int irq, void *dev_id)
+{
+	static int ticks = 0;
+
+	if (++ticks != HZ * 120) {
+		if (!console_drivers || try_acquire_console_sem())
+			return at91sam926x_timer_interrupt(irq, dev_id);
+	
+		release_console_sem();
+	}
+
+	panic("AT91 clock rate incorrectly set.\n"
+	      "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
+	      clk_get_rate(clk_get(NULL, "mck")));
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(at91_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned short mid;
+				unsigned short low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned short low;
+				unsigned short mid;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long long result;
+		unsigned short stamp;
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = read_CV();
+		if (unlikely(stamp < local_tsc->low)) {
+			if (unlikely(!++local_tsc->mid))
+				/* 32 bit counter wrapped, increment high word. */
+				local_tsc->high++;
+		}
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	if (delay > 2) {
+		local_irq_save_hw(flags);
+		write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
+}
+
+static struct irqaction at91sam926x_timer_irq = {
+	.name		= "at91_tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= &at91sam926x_timer_interrupt
+};
+
+static char clk_name [] = "tc%";
+
+static struct clk tc = {
+	.name		= (const char *) clk_name,
+	.users          = 0,
+	.type		= CLK_TYPE_PERIPHERAL,
+	.pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
+};
+
+void __init at91sam926x_timer_init(void)
+{
+	unsigned long v;
+	
+	if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
+		at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
+
+	snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
+	clk_register(&tc);
+	clk_enable(&tc);
+	
+	/* No Sync. */
+	at91_tc_write(AT91_TC_BCR, 0);
+
+	/* program NO signal on XCN */
+	v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+	v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
+	v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
+	writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+
+	/* Disable the channel */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
+
+	/* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
+	at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
+
+	/* Disable all interrupts. */
+	at91_tc_write(AT91_TC_IDR, ~0ul);
+
+	/* Load the TC register C. */
+	last_crtr = 0;
+	write_RC(LATCH);
+
+	/* Enable CPCS interrupt. */
+	at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
+
+	/* Set up the interrupt. */
+	setup_irq(KERNEL_TIMER_IRQ_NUM, &at91sam926x_timer_irq);
+
+	/* Enable the channel. */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
+
+	at91_timer_initialized = 1;
+}
+
+struct sys_timer at91sam926x_timer = {
+	.init		= at91sam926x_timer_init,
+	.offset		= at91sam926x_gettimeoffset,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c	2007-04-04 11:52:05.000000000 +0200
@@ -22,6 +22,11 @@
 #include <asm/arch/at91_pio.h>
 #include <asm/arch/at91_pmc.h>
 #include <asm/arch/gpio.h>
+#ifdef CONFIG_IPIPE
+#include <asm/irq.h>
+
+unsigned __ipipe_at91_gpio_banks = 0;
+#endif /* CONFIG_IPIPE */
 
 #include "generic.h"
 
@@ -328,6 +333,9 @@ static int gpio_irq_type(unsigned pin, u
 
 static struct irq_chip gpio_irqchip = {
 	.name		= "GPIO",
+#ifdef CONFIG_IPIPE
+	.ack            = gpio_irq_mask,
+#endif
 	.mask		= gpio_irq_mask,
 	.unmask		= gpio_irq_unmask,
 	.set_type	= gpio_irq_type,
@@ -376,6 +384,50 @@ static void gpio_irq_handler(unsigned ir
 	/* now it may re-trigger */
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc = irq_desc + irq;
+	unsigned	pin;
+	struct irqdesc	*gpio;
+	void __iomem	*pio;
+	u32		isr;
+
+	pio = get_irq_chip_data(irq);
+
+	/* temporarily mask (level sensitive) parent IRQ */
+	desc->chip->ack(irq);
+	for (;;) {
+		isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
+		if (!isr)
+			break;
+
+		pin = (unsigned) get_irq_data(irq);
+		gpio = &irq_desc[pin];
+
+		while (isr) {
+			if (isr & 1) {
+				if (unlikely(gpio->depth)) {
+					/*
+					 * The core ARM interrupt handler lazily disables IRQs so
+					 * another IRQ must be generated before it actually gets
+					 * here to be disabled on the GPIO controller.
+					 */
+					gpio_irq_mask(pin);
+				}
+				else
+					__ipipe_handle_irq(pin, regs);
+			}
+			pin++;
+			gpio++;
+			isr >>= 1;
+		}
+	}
+	desc->chip->unmask(irq);
+	/* now it may re-trigger */
+}
+#endif /* CONFIG_IPIPE */
+
 /*--------------------------------------------------------------------------*/
 
 /*
@@ -424,4 +476,7 @@ void __init at91_gpio_init(struct at91_g
 
 	gpio = data;
 	gpio_banks = nr_banks;
+#ifdef CONFIG_IPIPE
+	__ipipe_at91_gpio_banks = nr_banks;
+#endif /* CONFIG_IPIPE */
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig	2007-04-10 15:20:34.000000000 +0200
@@ -118,6 +118,34 @@ endif
 
 # ----------------------------------------------------------
 
+if ARCH_AT91SAM9261 || ARCH_AT91RM9200
+
+comment "Ipipe dependent"
+
+config IPIPE_AT91_TC
+	depends on IPIPE
+	int "AT91 TC used as time base"
+	default 0
+	help
+	When Adeos interrupt pipeline is enabled, TC0 is used by default
+	as time base, but you can use TC1 or TC2 by setting this variable to 1
+	or 2. This should only be needed to avoid conflicts with other drivers.
+
+config IPIPE_AT91_MCK
+	depends on IPIPE
+	int "AT91 Master clock Frequency"
+	default 59904000 if MACH_AT91RM9200EK
+	default 99328000 if MACH_AT91SAM9261EK
+	default 53000000
+	help
+	When Adeos interrupt pipeline is enabled, AT91 timer is based on
+	the AT91 master clock, whose frequency need hence to be known at
+	compilation time.
+
+endif
+
+# ----------------------------------------------------------
+
 comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-integrator/core.c linux-2.6.19.patched/arch/arm/mach-integrator/core.c
--- linux-2.6.19.at91/arch/arm/mach-integrator/core.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-integrator/core.c	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mach-integrator/core.c
  *
  *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -195,53 +196,57 @@ EXPORT_SYMBOL(cm_control);
 /*
  * How long is the timer interval?
  */
-#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
-#else
 #define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
-#endif
 
 static unsigned long timer_reload;
+static unsigned long timer_interval;
+static unsigned long timer_lxlost;
+static int tscok;
+
+#ifdef CONFIG_IPIPE
+int __ipipe_mach_timerint = IRQ_TIMERINT1;
+static unsigned long long __ipipe_mach_tsc;
+static IPIPE_DEFINE_SPINLOCK(timer_lock);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+#endif
 
 /*
- * Returns number of ms since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
+ * Called with IRQ disabled from do_gettimeofday().
  */
-unsigned long integrator_gettimeoffset(void)
+static inline unsigned long integrator_getticksoffset(void)
 {
-	unsigned long ticks1, ticks2, status;
+	unsigned long ticks;
 
-	/*
-	 * Get the current number of ticks.  Note that there is a race
-	 * condition between us reading the timer and checking for
-	 * an interrupt.  We get around this by ensuring that the
-	 * counter has not reloaded between our two reads.
-	 */
-	ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
-	do {
-		ticks1 = ticks2;
-		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
-		ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
-	} while (ticks2 > ticks1);
+	if (!tscok)
+		return 0;
 
-	/*
-	 * Number of ticks since last interrupt.
-	 */
-	ticks1 = timer_reload - ticks2;
+	ticks = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
 
-	/*
-	 * Interrupt pending?  If so, we've reloaded once already.
-	 */
-	if (status & (1 << IRQ_TIMERINT1))
-		ticks1 += timer_reload;
+	if (ticks > timer_reload)
+		ticks = 0xffff + timer_reload - ticks;
+	else
+		ticks = timer_reload - ticks;
+
+	if (timer_interval < 0x10000)
+		return ticks;
+	else if (timer_interval < 0x100000)
+		return ticks * 16;
+	else
+		return ticks * 256;
+}
 
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+unsigned long integrator_gettimeoffset(void)
+{
 	/*
 	 * Convert the ticks to usecs
 	 */
-	return TICKS2USECS(ticks1);
+	return TICKS2USECS(timer_lxlost + integrator_getticksoffset());
 }
 
 /*
@@ -252,10 +257,22 @@ integrator_timer_interrupt(int irq, void
 {
 	write_seqlock(&xtime_lock);
 
+	timer_lxlost = 0;
+
+#ifdef CONFIG_IPIPE
 	/*
-	 * clear the interrupt
+	 * If Linux is the only domain, ack the timer and reprogram it
 	 */
+	if (!__ipipe_mach_timerstolen) {
+		__ipipe_mach_tsc += integrator_getticksoffset();
+#else
 	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
+#endif
+
+		writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+#ifdef CONFIG_IPIPE
+	}
+#endif
 
 	/*
 	 * the clock tick routines are only processed on the
@@ -286,24 +303,30 @@ static struct irqaction integrator_timer
 	.handler	= integrator_timer_interrupt,
 };
 
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
+static inline void set_dec(unsigned long reload)
 {
-	unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+	unsigned int ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_IE;
 
 	timer_reload = reload;
-	timer_ctrl |= ctrl;
+	timer_interval = reload;
 
-	if (timer_reload > 0x100000) {
+	if (timer_reload >= 0x100000) {
 		timer_reload >>= 8;
-		timer_ctrl |= TIMER_CTRL_DIV256;
-	} else if (timer_reload > 0x010000) {
+		ctrl |= TIMER_CTRL_DIV256;
+	} else if (timer_reload >= 0x010000) {
 		timer_reload >>= 4;
-		timer_ctrl |= TIMER_CTRL_DIV16;
+		ctrl |= TIMER_CTRL_DIV16;
 	}
 
+	writel(ctrl, TIMER1_VA_BASE + TIMER_CTRL);
+	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
+{
 	/*
 	 * Initialise to a known state (all timers off)
 	 */
@@ -311,12 +334,57 @@ void __init integrator_time_init(unsigne
 	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
 	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 
-	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
-	writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
-	writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
+	set_dec(reload);
 
 	/*
 	 * Make irqs happen for the system timer
 	 */
 	setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
+
+	tscok = 1;
 }
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	unsigned long long result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	result = __ipipe_mach_tsc + integrator_getticksoffset();
+	spin_unlock_irqrestore(&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(&timer_lock, flags);
+	ticks = integrator_getticksoffset();
+	__ipipe_mach_tsc += ticks;
+	timer_lxlost += ticks;
+
+	set_dec(reload);
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return readl(TIMER1_VA_BASE + TIMER_VALUE);
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-integrator/integrator_cp.c linux-2.6.19.patched/arch/arm/mach-integrator/integrator_cp.c
--- linux-2.6.19.at91/arch/arm/mach-integrator/integrator_cp.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-integrator/integrator_cp.c	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mach-integrator/integrator_cp.c
  *
  *  Copyright (C) 2003 Deep Blue Solutions Ltd
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -19,6 +20,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
 #include <linux/amba/clcd.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -222,6 +224,31 @@ sic_handle_irq(unsigned int irq, struct 
 	} while (status);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+
+	if (status == 0) {
+		do_bad_IRQ(irq, desc_unused);
+		return;
+	}
+
+	do {
+		irq = ffs(status) - 1;
+		status &= ~(1 << irq);
+
+		irq += IRQ_SIC_START;
+
+		__ipipe_handle_irq(irq, regs);
+	} while (status);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 static void __init intcp_init_irq(void)
 {
 	unsigned int i;
@@ -568,9 +595,14 @@ static void __init intcp_init(void)
 
 #define TIMER_CTRL_IE	(1 << 5)			/* Interrupt Enable */
 
+#ifdef CONFIG_IPIPE
+unsigned int __ipipe_mach_ticks_per_jiffy = 1000000 * TICKS_PER_uSEC / HZ;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+#endif
+
 static void __init intcp_timer_init(void)
 {
-	integrator_time_init(1000000 / HZ, TIMER_CTRL_IE);
+	integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, TIMER_CTRL_IE);
 }
 
 static struct sys_timer cp_timer = {
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-pxa/irq.c linux-2.6.19.patched/arch/arm/mach-pxa/irq.c
--- linux-2.6.19.at91/arch/arm/mach-pxa/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-pxa/irq.c	2007-04-04 11:52:05.000000000 +0200
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -216,6 +217,42 @@ static void pxa_gpio_demux_handler(unsig
 	} while (loop);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+	unsigned int i, mask[4];
+	int loop;
+
+	do {
+		loop = 0;
+
+		mask[0] = GEDR0 & ~3;
+		mask[1] = GEDR1;
+		mask[2] = GEDR2;
+#if PXA_LAST_GPIO < 96
+		i = 3;
+#else /* PXA_LAST_GPIO >= 96 */
+		mask[3] = GEDR3;
+		i = 4;
+#endif /* PXA_LAST_GPIO >= 96 */
+		for (; i; i--) {
+			loop |= mask[i - 1];
+			while (mask[i - 1]) {
+				irq = fls(mask[i - 1]) - 1;
+				mask[i - 1] &= ~(1 << irq);
+				irq = IRQ_GPIO((i - 1) * 32 + irq);
+
+				__ipipe_handle_irq(irq, regs);
+			}
+		}
+	} while (loop);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 static void pxa_ack_muxed_gpio(unsigned int irq)
 {
 	int gpio = irq - IRQ_GPIO(2) + 2;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-pxa/time.c linux-2.6.19.patched/arch/arm/mach-pxa/time.c
--- linux-2.6.19.at91/arch/arm/mach-pxa/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-pxa/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -18,6 +18,7 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -29,6 +30,23 @@
 #include <asm/arch/pxa-regs.h>
 
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+int __ipipe_mach_timerint = IRQ_OST0;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int pxa_timer_initialized;
+static unsigned long last_jiffy_time;
+#endif /* CONFIG_IPIPE */
+
 static inline unsigned long pxa_get_rtc_time(void)
 {
 	return RCNR;
@@ -53,6 +71,9 @@ static unsigned long pxa_gettimeoffset (
 {
 	long ticks_to_match, elapsed, usec;
 
+#ifdef CONFIG_IPIPE
+	if (!__ipipe_mach_timerstolen) {
+#endif
 	/* Get ticks before next timer match */
 	ticks_to_match = OSMR0 - OSCR;
 
@@ -62,6 +83,10 @@ static unsigned long pxa_gettimeoffset (
 	/* don't get fooled by the workaround in pxa_timer_interrupt() */
 	if (elapsed <= 0)
 		return 0;
+#ifdef CONFIG_IPIPE
+	} else
+		elapsed = OSCR - last_jiffy_time;
+#endif
 
 	/* Now convert them to usec */
 	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
@@ -104,9 +129,27 @@ pxa_timer_interrupt(int irq, void *dev_i
 	 * affect things only when the timer IRQ has been delayed by nearly
 	 * exactly one tick period which should be a pretty rare event.
 	 */
+#ifdef CONFIG_IPIPE
+	/*
+	 * - if Linux is running natively (no ipipe), ack and reprogram the timer
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_jiffy_time += LATCH;
+	} else
+#endif /* CONFIG_IPIPE */
 	do {
 		timer_tick();
+#ifdef CONFIG_IPIPE
+		last_jiffy_time += LATCH;
+#else /* !CONFIG_IPIPE */
 		OSSR = OSSR_M0;  /* Clear match on timer 0 */
+#endif /* !CONFIG_IPIPE */
 		next_match = (OSMR0 += LATCH);
 	} while( (signed long)(next_match - OSCR) <= 8 );
 
@@ -138,6 +181,10 @@ static void __init pxa_timer_init(void)
 	setup_irq(IRQ_OST0, &pxa_timer_irq);
 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
 	OSCR = 0;		/* initialize free-running timer */
+
+#ifdef CONFIG_IPIPE
+	pxa_timer_initialized = 1;
+#endif /* CONFIG_IPIPE */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -215,3 +262,75 @@ struct sys_timer pxa_timer = {
 	.dyn_tick	= &pxa_dyn_tick,
 #endif
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	OSSR = OSSR_M0;  /* Clear match on timer 0 */
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(pxa_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned long low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned long low;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long stamp, flags;
+		unsigned long long result;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = OSCR;
+		if (unlikely(stamp < local_tsc->low))
+			/* 32 bit counter wrapped, increment high word. */
+			local_tsc->high++;
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	if (delay > 8) {
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		OSMR0 = delay + OSCR;
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(IRQ_OST0);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return OSMR0 - OSCR;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/irq.c linux-2.6.19.patched/arch/arm/mach-s3c2410/irq.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
-*/
+ *
+ *   30-Oct-2006  Sebastian Smolorz
+ *		  Added Adeos/I-pipe 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
@@ -668,6 +682,79 @@ int s3c24xx_irq_resume(struct sys_device
 #define s3c24xx_irq_resume  NULL
 #endif
 
+#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;
+
+	switch (irq) {
+	case IRQ_UART0:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX0, subsrc, regs);
+		break;
+	case IRQ_UART1:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX1, subsrc, regs);
+		break;
+	case IRQ_UART2:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX2, subsrc, regs);
+		break;
+	case IRQ_ADCPARENT:
+		__ipipe_s3c_irq_demux_adc(subsrc, regs);
+		break;
+#ifdef CONFIG_CPU_S3C2440
+	case IRQ_WDT:
+		__ipipe_s3c_irq_demux_wdtac97(subsrc, regs);
+		break;
+	case IRQ_CAM:
+		__ipipe_s3c_irq_demux_cam(subsrc, regs);
+		break;
+#endif /* CONFIG_CPU_S3C2440 */
+	}
+
+	desc_unused->chip->unmask(irq);
+}
+#endif /* CONFIG_IPIPE */
+
 /* s3c24xx_init_irq
  *
  * Initialise S3C2410 IRQ system
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/s3c2440-irq.c linux-2.6.19.patched/arch/arm/mach-s3c2410/s3c2440-irq.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/s3c2440-irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/s3c2440-irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
@@ -25,6 +27,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>
@@ -96,6 +99,34 @@ static struct irqchip s3c_irq_wdtac97 = 
 	.ack	    = s3c_irq_wdtac97_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 -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/time.c linux-2.6.19.patched/arch/arm/mach-s3c2410/time.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (C) 2003-2005 Simtec Electronics
  *	Ben Dooks, <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
@@ -25,6 +27,7 @@
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clk.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 last_free_running_tcnt = 0;
+static unsigned long free_running_tcon = 0;
+static unsigned long timer_lxlost = 0;
+
+#ifdef CONFIG_IPIPE
+unsigned int __ipipe_mach_ticks_per_jiffy;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+int __ipipe_mach_timerint = IRQ_TIMER4;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+static unsigned long long __ipipe_mach_tsc = 0;
+static unsigned long timer_ackval = 1UL << (IRQ_TIMER4 - IRQ_EINT0);
+static IPIPE_DEFINE_SPINLOCK(timer_lock);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+#endif /* CONFIG_IPIPE */
 
 /* timer_mask_usec_ticks
  *
@@ -85,44 +105,46 @@ 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)
+static inline unsigned long timer_freerunning_getvalue(void)
 {
-	unsigned long tdone;
-	unsigned long irqpend;
-	unsigned long tval;
-
-	/* work out how many ticks have gone since last timer interrupt */
+	return __raw_readl(S3C2410_TCNTO(3));
+}
 
-        tval =  __raw_readl(S3C2410_TCNTO(4));
-	tdone = timer_startval - tval;
+static inline unsigned long timer_freerunning_getticksoffset(unsigned long tval)
+{
+	long tdone;
 
-	/* check to see if there is an interrupt pending */
+	tdone =  last_free_running_tcnt - tval;
+	if (tdone < 0)
+		tdone += 0x10000;
 
-	irqpend = __raw_readl(S3C2410_SRCPND);
-	if (irqpend & SRCPND_TIMER4) {
-		/* re-read the timer, and try and fix up for the missed
-		 * interrupt. Note, the interrupt may go off before the
-		 * timer has re-loaded from wrapping.
-		 */
+	return tdone;
+}
 
-		tval =  __raw_readl(S3C2410_TCNTO(4));
-		tdone = timer_startval - tval;
+static inline unsigned long getticksoffset(void)
+{
+	return timer_freerunning_getticksoffset(timer_freerunning_getvalue());
+}
 
-		if (tval != 0)
-			tdone += timer_startval;
-	}
+#ifdef CONFIG_IPIPE
+static inline unsigned long getticksoffset_tscupdate(void)
+{
+	unsigned long tval;
+	unsigned long ticks;
 
-	return timer_ticks_to_usec(tdone);
+	tval = timer_freerunning_getvalue();
+	ticks = timer_freerunning_getticksoffset(tval);
+	last_free_running_tcnt = tval;
+	__ipipe_mach_tsc += ticks;
+	return ticks;
 }
+#endif /* CONFIG_IPIPE */
 
+static unsigned long s3c2410_gettimeoffset (void)
+{
+	return timer_ticks_to_usec(timer_lxlost + getticksoffset());
+}
 
 /*
  * IRQ handler for the timer
@@ -131,6 +153,14 @@ static irqreturn_t
 s3c2410_timer_interrupt(int irq, void *dev_id)
 {
 	write_seqlock(&xtime_lock);
+
+#ifdef CONFIG_IPIPE
+	timer_lxlost = 0;
+
+	if (!__ipipe_mach_timerstolen)
+		getticksoffset_tscupdate();
+#endif /* CONFIG_IPIPE */
+
 	timer_tick();
 	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
@@ -149,10 +179,10 @@ static struct irqaction s3c2410_timer_ir
 	machine_is_osiris() )
 
 /*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up timer interrupt.
  *
- * Currently we only use timer4, as it is the only timer which has no
- * other function that can be exploited externally
+ * Currently we use timer4 as event timer and timer3 as tick counter which
+ * permanently counts ticks without interrupt generation.
  */
 static void s3c2410_timer_setup (void)
 {
@@ -160,6 +190,7 @@ static void s3c2410_timer_setup (void)
 	unsigned long tcnt;
 	unsigned long tcfg1;
 	unsigned long tcfg0;
+	unsigned long intmask;
 
 	tcnt = 0xffff;  /* default value for tcnt */
 
@@ -176,8 +207,8 @@ static void s3c2410_timer_setup (void)
 		timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
 		tcnt = 12000000 / HZ;
 
-		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-		tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
+		tcfg1 &= ~(S3C2410_TCFG1_MUX4_MASK | S3C2410_TCFG1_MUX3_MASK);
+		tcfg1 |= (S3C2410_TCFG1_MUX4_TCLK1 | S3C2410_TCFG1_MUX3_TCLK1);
 	} else {
 		unsigned long pclk;
 		struct clk *clk;
@@ -205,8 +236,8 @@ static void s3c2410_timer_setup (void)
 
 		timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
 
-		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-		tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+		tcfg1 &= ~(S3C2410_TCFG1_MUX4_MASK | S3C2410_TCFG1_MUX3_MASK);
+		tcfg1 |= (S3C2410_TCFG1_MUX4_DIV2 | S3C2410_TCFG1_MUX3_DIV2);
 
 		tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
 		tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
@@ -214,6 +245,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--;
@@ -230,23 +265,37 @@ 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... */
+	/* ensure timers are stopped... */
+	tcon &= ~(0x3f<<17);
+	__raw_writel(tcon, S3C2410_TCON);
 
-	tcon &= ~(7<<20);
-	tcon |= S3C2410_TCON_T4RELOAD;
-	tcon |= S3C2410_TCON_T4MANUALUPD;
+	/* Mask timer3 interrupt. */
+	intmask = __raw_readl(S3C2410_INTMSK);
+	intmask |= 1UL << (IRQ_TIMER3 - IRQ_EINT0);
+	__raw_writel(intmask, S3C2410_INTMSK);
 
-	__raw_writel(tcon, S3C2410_TCON);
+	/* Set timer values */
 	__raw_writel(tcnt, S3C2410_TCNTB(4));
 	__raw_writel(tcnt, S3C2410_TCMPB(4));
+	__raw_writel(0xffff, S3C2410_TCNTB(3));
+	__raw_writel(0xffff, S3C2410_TCMPB(3));
 
-	/* start the timer running */
-	tcon |= S3C2410_TCON_T4START;
-	tcon &= ~S3C2410_TCON_T4MANUALUPD;
+	/* Set base tcon value for later programming of timer 4 by Xenomai. */
+	free_running_tcon = tcon |  S3C2410_TCON_T3RELOAD | S3C2410_TCON_T3START;
+
+	/* Set auto reloads for both timers. */
+	tcon |= S3C2410_TCON_T3RELOAD | S3C2410_TCON_T4RELOAD;
+
+	/* Manual update */
+	__raw_writel(tcon | S3C2410_TCON_T3MANUALUPD
+			  | S3C2410_TCON_T4MANUALUPD, S3C2410_TCON);
+
+	tcon |= S3C2410_TCON_T3START | S3C2410_TCON_T4START;
+	/* Start timers.*/
 	__raw_writel(tcon, S3C2410_TCON);
+
+	/* Save start value of timer 3 as begining of first period. */
+	last_free_running_tcnt = 0xffff;
 }
 
 static void __init s3c2410_timer_init (void)
@@ -260,3 +309,56 @@ struct sys_timer s3c24xx_timer = {
 	.offset		= s3c2410_gettimeoffset,
 	.resume		= s3c2410_timer_setup
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	__raw_writel(timer_ackval, S3C2410_SRCPND);
+	__raw_writel(timer_ackval, S3C2410_INTPND);
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	unsigned long long result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	result = __ipipe_mach_tsc + getticksoffset();
+	spin_unlock_irqrestore(&timer_lock, flags);
+	return result;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+static inline void set_dec(unsigned long reload)
+{
+	__raw_writel(reload, S3C2410_TCNTB(4));
+	/* Manual update */
+	__raw_writel(free_running_tcon | S3C2410_TCON_T4MANUALUPD, S3C2410_TCON);
+	/* Start timer */
+	__raw_writel(free_running_tcon | S3C2410_TCON_T4START, S3C2410_TCON);
+}
+
+void __ipipe_mach_set_dec(unsigned long reload)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	timer_lxlost += getticksoffset_tscupdate();
+	set_dec(reload);
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+	free_running_tcon |= S3C2410_TCON_T4RELOAD;
+	__ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy - 1);
+	free_running_tcon &= ~S3C2410_TCON_T4RELOAD;
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return __raw_readl(S3C2410_TCNTO(4));
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-sa1100/irq.c linux-2.6.19.patched/arch/arm/mach-sa1100/irq.c
--- linux-2.6.19.at91/arch/arm/mach-sa1100/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-sa1100/irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -16,6 +16,7 @@
 #include <linux/ioport.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/mach/irq.h>
@@ -137,6 +138,37 @@ sa1100_high_gpio_handler(unsigned int ir
 	} while (mask);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+	unsigned int mask;
+
+	mask = GEDR & 0xfffff800;
+	do {
+		/*
+		 * clear down all currently active IRQ sources.
+		 * We will be processing them all.
+		 */
+		GEDR = mask;
+
+		irq = IRQ_GPIO11;
+		mask >>= 11;
+		do {
+			if (mask & 1)
+				__ipipe_handle_irq(irq, regs);
+			mask >>= 1;
+			irq++;
+		} while (mask);
+
+		mask = GEDR & 0xfffff800;
+	} while (mask);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 /*
  * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
  * In addition, the IRQs are all collected up into one bit in the
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-sa1100/time.c linux-2.6.19.patched/arch/arm/mach-sa1100/time.c
--- linux-2.6.19.at91/arch/arm/mach-sa1100/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-sa1100/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/signal.h>
+#include <linux/module.h>
 
 #include <asm/mach/time.h>
 #include <asm/hardware.h>
@@ -21,6 +22,23 @@
 #define RTC_DEF_DIVIDER		(32768 - 1)
 #define RTC_DEF_TRIM            0
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+int __ipipe_mach_timerint = IRQ_OST0;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int sa1100_timer_initialized;
+static unsigned long last_jiffy_time;
+#endif /* CONFIG_IPIPE */
+
 static unsigned long __init sa1100_get_rtc_time(void)
 {
 	/*
@@ -59,11 +77,18 @@ static unsigned long sa1100_gettimeoffse
 {
 	unsigned long ticks_to_match, elapsed, usec;
 
+#ifdef CONFIG_IPIPE
+	if (!__ipipe_mach_timerstolen) {
+#endif
 	/* Get ticks before next timer match */
 	ticks_to_match = OSMR0 - OSCR;
 
 	/* We need elapsed ticks since last match */
 	elapsed = LATCH - ticks_to_match;
+#ifdef CONFIG_IPIPE
+	} else
+		elapsed = OSCR - last_jiffy_time;
+#endif
 
 	/* Now convert them to usec */
 	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
@@ -98,9 +123,27 @@ sa1100_timer_interrupt(int irq, void *de
 	 * ensured, hence we can use do_gettimeofday() from interrupt
 	 * handlers.
 	 */
+#ifdef CONFIG_IPIPE
+	/*
+	 * - if Linux is running natively (no ipipe), ack and reprogram the timer
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_jiffy_time += LATCH;
+	} else
+#endif /* CONFIG_IPIPE */
 	do {
 		timer_tick();
+#ifdef CONFIG_IPIPE
+		last_jiffy_time += LATCH;
+#else /* !CONFIG_IPIPE */
 		OSSR = OSSR_M0;  /* Clear match on timer 0 */
+#endif /* !CONFIG_IPIPE */
 		next_match = (OSMR0 += LATCH);
 	} while ((signed long)(next_match - OSCR) <= 0);
 
@@ -132,6 +175,10 @@ static void __init sa1100_timer_init(voi
 	setup_irq(IRQ_OST0, &sa1100_timer_irq);
 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
 	OSCR = 0;		/* initialize free-running timer */
+
+#ifdef CONFIG_IPIPE
+	sa1100_timer_initialized = 1;
+#endif /* CONFIG_IPIPE */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -210,3 +257,72 @@ struct sys_timer sa1100_timer = {
 	.dyn_tick	= &sa1100_dyn_tick,
 #endif
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	OSSR = OSSR_M0;  /* Clear match on timer 0 */
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(sa1100_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned long low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned long low;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long stamp, flags;
+		unsigned long long result;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = OSCR;
+		if (unlikely(stamp < local_tsc->low))
+			/* 32 bit counter wrapped, increment high word. */
+			local_tsc->high++;
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+        OSMR0 = delay + OSCR;
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return OSMR0 - OSCR;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/copypage-v4mc.c linux-2.6.19.patched/arch/arm/mm/copypage-v4mc.c
--- linux-2.6.19.at91/arch/arm/mm/copypage-v4mc.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/copypage-v4mc.c	2007-04-04 11:52:06.000000000 +0200
@@ -43,7 +43,7 @@ static DEFINE_SPINLOCK(minicache_lock);
  * instruction.  If your processor does not supply this, you have to write your
  * own copy_user_page that does the right thing.
  */
-static void __attribute__((naked))
+static void notrace __attribute__((naked))
 mc_copy_user_page(void *from, void *to)
 {
 	asm volatile(
@@ -82,7 +82,7 @@ void v4_mc_copy_user_page(void *kto, con
 /*
  * ARMv4 optimised clear_user_page
  */
-void __attribute__((naked))
+void notrace __attribute__((naked))
 v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
 {
 	asm volatile(
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/copypage-xscale.c linux-2.6.19.patched/arch/arm/mm/copypage-xscale.c
--- linux-2.6.19.at91/arch/arm/mm/copypage-xscale.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/copypage-xscale.c	2007-04-04 11:52:06.000000000 +0200
@@ -41,7 +41,7 @@ static DEFINE_SPINLOCK(minicache_lock);
  * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
  * and merged as appropriate.
  */
-static void __attribute__((naked))
+static void notrace __attribute__((naked))
 mc_copy_user_page(void *from, void *to)
 {
 	/*
@@ -104,7 +104,7 @@ void xscale_mc_copy_user_page(void *kto,
 /*
  * XScale optimised clear_user_page
  */
-void __attribute__((naked))
+void notrace __attribute__((naked))
 xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr)
 {
 	asm volatile(
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/fault.c linux-2.6.19.patched/arch/arm/mm/fault.c
--- linux-2.6.19.at91/arch/arm/mm/fault.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/fault.c	2007-04-04 11:52:06.000000000 +0200
@@ -223,6 +223,9 @@ do_page_fault(unsigned long addr, unsign
 	struct mm_struct *mm;
 	int fault, sig, code;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+		return 0;
+
 	tsk = current;
 	mm  = tsk->mm;
 
@@ -327,6 +330,9 @@ do_translation_fault(unsigned long addr,
 	if (addr < TASK_SIZE)
 		return do_page_fault(addr, fsr, regs);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+		return 0;
+
 	index = pgd_index(addr);
 
 	/*
@@ -362,6 +368,10 @@ bad_area:
 static int
 do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+
+	if (ipipe_trap_notify(IPIPE_TRAP_SECTION,regs))
+		return 0;
+
 	do_bad_area(addr, fsr, regs);
 	return 0;
 }
@@ -372,6 +382,9 @@ do_sect_fault(unsigned long addr, unsign
 static int
 do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_DABT,regs))
+		return 0;
+
 	return 1;
 }
 
@@ -447,6 +460,9 @@ do_DataAbort(unsigned long addr, unsigne
 	if (!inf->fn(addr, fsr, regs))
 		return;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_UNKNOWN,regs))
+		return;
+
 	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
 
@@ -463,3 +479,35 @@ do_PrefetchAbort(unsigned long addr, str
 	do_translation_fault(addr, 0, regs);
 }
 
+#ifdef CONFIG_IPIPE
+static void vmalloc_sync_one(pgd_t *pgd, unsigned long addr)
+{
+	unsigned int index = pgd_index(addr);
+	pgd_t *pgd_k;
+	pmd_t *pmd, *pmd_k;
+
+	pgd += index;
+	pgd_k = init_mm.pgd + index;
+
+	if (!pgd_present(*pgd))
+		set_pgd(pgd, *pgd_k);
+
+	pmd_k = pmd_offset(pgd_k, addr);
+	pmd   = pmd_offset(pgd, addr);
+
+	copy_pmd(pmd, pmd_k);
+}
+
+int __ipipe_pin_range_mapping(struct mm_struct *mm,
+			      unsigned long start, unsigned long end)
+{
+	unsigned long next, addr = start;
+
+	do {
+		next = pgd_addr_end(addr, end);
+		vmalloc_sync_one(mm->pgd, addr);
+	} while (addr = next, addr != end);
+
+	return 0;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/drivers/pci/htirq.c linux-2.6.19.patched/drivers/pci/htirq.c
--- linux-2.6.19.at91/drivers/pci/htirq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/drivers/pci/htirq.c	2007-04-04 11:52:06.000000000 +0200
@@ -21,7 +21,7 @@
  * With multiple simultaneous hypertransport irq devices it might pay
  * to make this more fine grained.  But start with simple, stupid, and correct.
  */
-static DEFINE_SPINLOCK(ht_irq_lock);
+static IPIPE_DEFINE_SPINLOCK(ht_irq_lock);
 
 struct ht_irq_cfg {
 	struct pci_dev *dev;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-04 11:52:06.000000000 +0200
@@ -42,7 +42,28 @@
  * Virtual to Physical Address mapping for IO devices.
  */
 #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
-#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
+#ifdef CONFIG_IPIPE
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
+#else
+#error "Unsupported AT91 processor"
+#endif
+#endif /* CONFIG_IPIPE */
 
  /* Internal SRAM is mapped below the IO devices */
 #define AT91_SRAM_MAX		SZ_1M
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -41,4 +41,23 @@
  */
 #define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
 
+#if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
+extern unsigned __ipipe_at91_gpio_banks;
+
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
+
+#endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
+
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h	2007-04-04 11:52:06.000000000 +0200
@@ -25,7 +25,11 @@
 
 #if defined(CONFIG_ARCH_AT91RM9200)
 
+#ifndef CONFIG_IPIPE
 #define CLOCK_TICK_RATE		(AT91_SLOW_CLOCK)
+#else /* !CONFIG_IPIPE */
+#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
+#endif /* !CONFIG_IPIPE */
 
 #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
 
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S	2007-04-04 11:52:06.000000000 +0200
@@ -22,7 +22,11 @@
 		teq	\irqstat, #0
 		ldreq	\irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
 		moveq	\irqnr, #IRQ_CIC_START
-
+#ifdef CONFIG_IPIPE
+		tst	\irqstat, #0x00000040			@ check IRQ_TIMERINT1 first
+		movne	\irqnr, #6
+		bne	1003f
+#endif /* CONFIG_IPIPE */
 1001:		tst	\irqstat, #15
 		bne	1002f
 		add	\irqnr, \irqnr, #4
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/irqs.h linux-2.6.19.patched/include/asm-arm/arch-integrator/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -80,3 +80,6 @@
 
 #define NR_IRQS                         47
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_CP_CPPLDINT)
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/platform.h linux-2.6.19.patched/include/asm-arm/arch-integrator/platform.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/platform.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/platform.h	2007-04-04 11:52:06.000000000 +0200
@@ -26,7 +26,7 @@
  * 	NOTE: This is a multi-hosted header file for use with uHAL and
  * 	      supported debuggers.
  *
- * 	$Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $
+ * 	$Id: platform.h,v 1.2 2006/02/20 13:54:22 rpm Exp $
  *
  * ***********************************************************************/
 
@@ -436,7 +436,7 @@
  *  Timer definitions
  *
  *  Only use timer 1 & 2
- *  (both run at 24MHz and will need the clock divider set to 16).
+ *  (both run at 1MHZ on /CP and at 24MHz on /AP)
  *
  *  Timer 0 runs at bus frequency and therefore could vary and currently
  *  uHAL can't handle that.
@@ -449,7 +449,12 @@
 
 #define MAX_TIMER                       2
 #define MAX_PERIOD                      699050
+
+#ifdef CONFIG_ARCH_INTEGRATOR_CP
+#define TICKS_PER_uSEC                  1
+#else
 #define TICKS_PER_uSEC                  24
+#endif
 
 /*
  *  These are useconds NOT ticks.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/timex.h linux-2.6.19.patched/include/asm-arm/arch-integrator/timex.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/timex.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/timex.h	2007-04-04 11:52:06.000000000 +0200
@@ -21,6 +21,6 @@
  */
 
 /*
- * ??
+ * Timer rate
  */
-#define CLOCK_TICK_RATE		(50000000 / 16)
+#define CLOCK_TICK_RATE		(1000000)
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-pxa/irqs.h linux-2.6.19.patched/include/asm-arm/arch-pxa/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-pxa/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-pxa/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -72,6 +72,10 @@
 			((i) - IRQ_GPIO(2) + 2)
 #define IRQ_TO_GPIO(i)	(((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_GPIO_2_x)
+#endif /* CONFIG_IPIPE */
+
 #if defined(CONFIG_PXA25x)
 #define PXA_LAST_GPIO	84
 #elif defined(CONFIG_PXA27x)
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-s3c2410/irqs.h linux-2.6.19.patched/include/asm-arm/arch-s3c2410/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-s3c2410/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-s3c2410/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003-2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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.
@@ -116,4 +118,26 @@
 #define NR_IRQS (IRQ_S3C2440_AC97+1)
 
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_irqbit(irq)	(1 << ((irq) - S3C2410_CPUIRQ_OFFSET))
+
+#ifdef CONFIG_CPU_S3C2440
+#define __ipipe_muxed_irqmask	(__ipipe_irqbit(IRQ_UART0)	|	\
+				 __ipipe_irqbit(IRQ_UART1)	|	\
+				 __ipipe_irqbit(IRQ_UART2)	|	\
+				 __ipipe_irqbit(IRQ_ADCPARENT)	|	\
+				 __ipipe_irqbit(IRQ_WDT)	|	\
+				 __ipipe_irqbit(IRQ_CAM))
+#else /* !CONFIG_CPU_S3C2440 */
+#define __ipipe_muxed_irqmask	(__ipipe_irqbit(IRQ_UART0)	|	\
+				 __ipipe_irqbit(IRQ_UART1)	|	\
+				 __ipipe_irqbit(IRQ_UART2)	|	\
+				 __ipipe_irqbit(IRQ_ADCPARENT))
+#endif /* CONFIG_CPU_S3C2440 */
+
+#define __ipipe_mach_irq_mux_p(irq)	((irq) <= IRQ_ADCPARENT  &&	\
+					 (__ipipe_irqbit(irq) &		\
+					  __ipipe_muxed_irqmask))
+#endif /* CONFIG_IPIPE */
+
 #endif /* __ASM_ARCH_IRQ_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-sa1100/irqs.h linux-2.6.19.patched/include/asm-arm/arch-sa1100/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-sa1100/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-sa1100/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -144,6 +144,10 @@
 #define IRQ_LOCOMO_SPI_OVRN	(IRQ_BOARD_END + 20)
 #define IRQ_LOCOMO_SPI_TEND	(IRQ_BOARD_END + 21)
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_GPIO11_27)
+#endif /* CONFIG_IPIPE */
+
 /*
  * Figure out the MAX IRQ number.
  *
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/atomic.h linux-2.6.19.patched/include/asm-arm/atomic.h
--- linux-2.6.19.at91/include/asm-arm/atomic.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/atomic.h	2007-04-04 11:52:06.000000000 +0200
@@ -103,9 +103,9 @@ static inline void atomic_clear_mask(uns
 	unsigned long tmp, tmp2;
 
 	__asm__ __volatile__("@ atomic_clear_mask\n"
-"1:	ldrex	%0, %2\n"
+"1:	ldrex	%0, [%2]\n"
 "	bic	%0, %0, %3\n"
-"	strex	%1, %0, %2\n"
+"	strex	%1, %0, [%2]\n"
 "	teq	%1, #0\n"
 "	bne	1b"
 	: "=&r" (tmp), "=&r" (tmp2)
@@ -128,10 +128,10 @@ static inline int atomic_add_return(int 
 	unsigned long flags;
 	int val;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	val = v->counter;
 	v->counter = val += i;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return val;
 }
@@ -141,10 +141,10 @@ static inline int atomic_sub_return(int 
 	unsigned long flags;
 	int val;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	val = v->counter;
 	v->counter = val -= i;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return val;
 }
@@ -154,11 +154,11 @@ static inline int atomic_cmpxchg(atomic_
 	int ret;
 	unsigned long flags;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	ret = v->counter;
 	if (likely(ret == old))
 		v->counter = new;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return ret;
 }
@@ -167,9 +167,9 @@ static inline void atomic_clear_mask(uns
 {
 	unsigned long flags;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*addr &= ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 #endif /* __LINUX_ARM_ARCH__ */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/bitops.h linux-2.6.19.patched/include/asm-arm/bitops.h
--- linux-2.6.19.at91/include/asm-arm/bitops.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/bitops.h	2007-04-04 11:52:06.000000000 +0200
@@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(un
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p |= mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
@@ -49,9 +49,9 @@ static inline void ____atomic_clear_bit(
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p &= ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
@@ -61,9 +61,9 @@ static inline void ____atomic_change_bit
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p ^= mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline int
@@ -75,10 +75,10 @@ ____atomic_test_and_set_bit(unsigned int
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res | mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
@@ -92,10 +92,10 @@ ____atomic_test_and_clear_bit(unsigned i
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res & ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
@@ -109,10 +109,10 @@ ____atomic_test_and_change_bit(unsigned 
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res ^ mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/ipipe.h linux-2.6.19.patched/include/asm-arm/ipipe.h
--- linux-2.6.19.at91/include/asm-arm/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/ipipe.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,207 @@
+/* -*- linux-c -*-
+ * include/asm-arm/ipipe.h
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ * Copyright (C) 2005 Stelian Pop.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ARM_IPIPE_H
+#define __ARM_IPIPE_H
+
+#ifdef CONFIG_IPIPE
+
+#include <asm/irq.h>
+#include <asm/percpu.h>
+
+#define IPIPE_ARCH_STRING	"1.6-05"
+#define IPIPE_MAJOR_NUMBER	1
+#define IPIPE_MINOR_NUMBER	6
+#define IPIPE_PATCH_NUMBER	5
+
+#define IPIPE_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	5	/* 25 for 32bits arch. */
+
+#ifdef CONFIG_SMP
+#error "I-pipe/arm: SMP not yet implemented"
+#define ipipe_processor_id()	(current_thread_info()->cpu)
+#else /* !CONFIG_SMP */
+#define ipipe_processor_id()	0
+#endif	/* CONFIG_SMP */
+
+/* Note that we disable the interrupts around context_switch,
+ * or we'll get into severe problems when scheduling Xenomai's
+ * user space real time threads.
+ * This can however cause high latencies, see for example:
+ * 	http://www.ussg.iu.edu/hypermail/linux/kernel/0405.2/1388.html
+ * This may need further optimization...
+ */
+#define prepare_arch_switch(next)				\
+do {								\
+	ipipe_schedule_notify(current, next);			\
+	local_irq_disable_hw();					\
+} while(0)
+
+#define task_hijacked(p)						\
+	({								\
+		int __x__ = ipipe_current_domain != ipipe_root_domain;	\
+		/* We would need to clear the SYNC flag for the root domain */ \
+		/* over the current processor in SMP mode. */		\
+		local_irq_enable_hw(); __x__;				\
+	})
+
+/* ARM traps */
+#define IPIPE_TRAP_ACCESS	 0	/* Data or instruction access exception */
+#define IPIPE_TRAP_SECTION	 1	/* Section fault */
+#define IPIPE_TRAP_DABT		 2	/* Generic data abort */
+#define IPIPE_TRAP_UNKNOWN	 3	/* Unknown exception */
+#define IPIPE_TRAP_BREAK	 4	/* Instruction breakpoint */
+#define IPIPE_TRAP_FPU		 5	/* Floating point exception */
+#define IPIPE_TRAP_VFP		 6	/* VFP floating point exception */
+#define IPIPE_TRAP_UNDEFINSTR	 7	/* Undefined instruction */
+#define IPIPE_NR_FAULTS		 8
+
+/* Pseudo-vectors used for kernel events */
+#define IPIPE_FIRST_EVENT	IPIPE_NR_FAULTS
+#define IPIPE_EVENT_SYSCALL	(IPIPE_FIRST_EVENT)
+#define IPIPE_EVENT_SCHEDULE	(IPIPE_FIRST_EVENT + 1)
+#define IPIPE_EVENT_SIGWAKE	(IPIPE_FIRST_EVENT + 2)
+#define IPIPE_EVENT_SETSCHED	(IPIPE_FIRST_EVENT + 3)
+#define IPIPE_EVENT_INIT	(IPIPE_FIRST_EVENT + 4)
+#define IPIPE_EVENT_EXIT	(IPIPE_FIRST_EVENT + 5)
+#define IPIPE_EVENT_CLEANUP	(IPIPE_FIRST_EVENT + 6)
+#define IPIPE_LAST_EVENT	IPIPE_EVENT_CLEANUP
+#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 1)
+
+extern unsigned long arm_return_addr(int level);
+
+#define BROKEN_BUILTIN_RETURN_ADDRESS
+#define __BUILTIN_RETURN_ADDRESS0 arm_return_addr(0)
+#define __BUILTIN_RETURN_ADDRESS1 arm_return_addr(1)
+
+
+struct ipipe_domain;
+
+struct ipipe_sysinfo {
+
+	int ncpus;		/* Number of CPUs on board */
+	u64 cpufreq;		/* CPU frequency (in Hz) */
+
+	/* Arch-dependent block */
+
+	struct {
+		unsigned tmirq;	/* Timer tick IRQ */
+		u64 tmfreq;	/* Timer frequency */
+	} archdep;
+};
+
+/* arch specific stuff */
+extern int __ipipe_mach_timerint;
+extern int __ipipe_mach_timerstolen;
+extern unsigned int __ipipe_mach_ticks_per_jiffy;
+extern void __ipipe_mach_acktimer(void);
+extern unsigned long long __ipipe_mach_get_tsc(void);
+extern void __ipipe_mach_set_dec(unsigned long);
+extern void __ipipe_mach_release_timer(void);
+extern unsigned long __ipipe_mach_get_dec(void);
+extern void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs);
+
+#define ipipe_read_tsc(t)		do { t = __ipipe_mach_get_tsc(); } while (0)
+#define __ipipe_read_timebase()		__ipipe_mach_get_tsc()
+
+#define ipipe_cpu_freq()	(HZ * __ipipe_mach_ticks_per_jiffy)
+#define ipipe_tsc2ns(t) \
+({ \
+	unsigned long long delta = (t)*1000; \
+	do_div(delta, ipipe_cpu_freq() / 1000000 + 1); \
+	(unsigned long)delta; \
+})
+#define ipipe_tsc2us(t) \
+({ \
+	unsigned long long delta = (t); \
+	do_div(delta, ipipe_cpu_freq() / 1000000 + 1); \
+	(unsigned long)delta; \
+})
+
+/* Private interface -- Internal use only */
+
+#define __ipipe_check_platform()	do { } while(0)
+
+void __ipipe_init_platform(void);
+
+#define __ipipe_enable_irq(irq)	irq_desc[irq].chip->enable(irq)
+
+#define __ipipe_disable_irq(irq)	irq_desc[irq].chip->disable(irq)
+
+#define __ipipe_hook_critical_ipi(ipd) do { } while(0)
+
+void __ipipe_enable_irqdesc(unsigned irq);
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_do_IRQ(int irq,
+		    struct pt_regs *regs);
+
+void __ipipe_do_timer(int irq,
+		      struct pt_regs *regs);
+
+void __ipipe_do_critical_sync(unsigned irq,
+			      void *cookie);
+
+extern unsigned long __ipipe_decr_ticks;
+
+extern unsigned long long __ipipe_decr_next[];
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+void __ipipe_handle_irq(int irq,
+			struct pt_regs *regs);
+
+#define __ipipe_tick_irq	ipipe_timerint
+
+static inline unsigned long __ipipe_ffnz(unsigned long ul)
+{
+	return ffs(ul) - 1;
+}
+
+/* When running handlers, enable hw interrupts for all domains but the
+ * one heading the pipeline, so that IRQs can never be significantly
+ * deferred for the latter. */
+#define __ipipe_run_isr(ipd, irq, cpuid) 	\
+do {					 	\
+	local_irq_enable_nohead(ipd);		\
+	if (ipd == ipipe_root_domain) {		\
+		((void (*)(unsigned, struct pt_regs *))			\
+		 ipd->irqs[irq].handler) (irq, __ipipe_tick_regs + cpuid); \
+	} else {							\
+		__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
+		ipd->irqs[irq].handler(irq,ipd->irqs[irq].cookie);	\
+		__set_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
+	}								\
+	local_irq_disable_nohead(ipd);					\
+} while(0)
+
+#define __ipipe_syscall_watched_p(p, sc)	\
+	(((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= __ARM_NR_BASE + 64)
+
+#else /* !CONFIG_IPIPE */
+
+#define task_hijacked(p)	0
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__ARM_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/irqflags.h linux-2.6.19.patched/include/asm-arm/irqflags.h
--- linux-2.6.19.at91/include/asm-arm/irqflags.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/irqflags.h	2007-04-04 11:52:06.000000000 +0200
@@ -10,30 +10,30 @@
  */
 #if __LINUX_ARM_ARCH__ >= 6
 
-#define raw_local_irq_save(x)					\
+#define local_irq_save_hw_notrace(x)					\
 	({							\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
+	"mrs	%0, cpsr		@ local_irq_save_hw\n"	\
 	"cpsid	i"						\
 	: "=r" (x) : : "memory", "cc");				\
 	})
 
-#define raw_local_irq_enable()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
-#define raw_local_irq_disable() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
-#define local_fiq_enable()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
-#define local_fiq_disable() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
+#define local_irq_enable_hw_notrace()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
+#define local_irq_disable_hw_notrace() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
+#define local_fiq_enable_hw_notrace()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
+#define local_fiq_disable_hw_notrace() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
 
 #else
 
 /*
  * Save the current interrupt enable state & disable IRQs
  */
-#define raw_local_irq_save(x)					\
+#define local_irq_save_hw_notrace(x)					\
 	({							\
 		unsigned long temp;				\
 		(void) (&temp == &x);				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
+	"mrs	%0, cpsr		@ local_irq_save_hw\n"	\
 "	orr	%1, %0, #128\n"					\
 "	msr	cpsr_c, %1"					\
 	: "=r" (x), "=r" (temp)					\
@@ -44,11 +44,11 @@
 /*
  * Enable IRQs
  */
-#define raw_local_irq_enable()					\
+#define local_irq_enable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_enable\n"	\
+	"mrs	%0, cpsr		@ local_irq_enable_hw\n"	\
 "	bic	%0, %0, #128\n"					\
 "	msr	cpsr_c, %0"					\
 	: "=r" (temp)						\
@@ -59,11 +59,11 @@
 /*
  * Disable IRQs
  */
-#define raw_local_irq_disable()					\
+#define local_irq_disable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_disable\n"	\
+	"mrs	%0, cpsr		@ local_irq_disable_hw\n"	\
 "	orr	%0, %0, #128\n"					\
 "	msr	cpsr_c, %0"					\
 	: "=r" (temp)						\
@@ -74,7 +74,7 @@
 /*
  * Enable FIQs
  */
-#define local_fiq_enable()					\
+#define local_fiq_enable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
@@ -89,7 +89,7 @@
 /*
  * Disable FIQs
  */
-#define local_fiq_disable()					\
+#define local_fiq_disable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
@@ -106,19 +106,19 @@
 /*
  * Save the current interrupt enable state.
  */
-#define raw_local_save_flags(x)					\
+#define local_save_flags_hw(x)					\
 	({							\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_save_flags"	\
+	"mrs	%0, cpsr		@ local_save_flags_hw"	\
 	: "=r" (x) : : "memory", "cc");				\
 	})
 
 /*
  * restore saved IRQ & FIQ state
  */
-#define raw_local_irq_restore(x)				\
+#define local_irq_restore_hw_notrace(x)				\
 	__asm__ __volatile__(					\
-	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
+	"msr	cpsr_c, %0		@ local_irq_restore_hw\n"	\
 	:							\
 	: "r" (x)						\
 	: "memory", "cc")
@@ -128,5 +128,93 @@
 	(int)((flags) & PSR_I_BIT);	\
 })
 
+#define irqs_disabled_hw()			\
+({						\
+	unsigned long flags;			\
+	local_save_flags_hw(flags);		\
+	raw_irqs_disabled_flags(flags);		\
+})
+			
+
+#ifdef CONFIG_IPIPE
+
+void __ipipe_stall_root(void);
+void __ipipe_unstall_root(void);
+unsigned long __ipipe_test_root(void);
+unsigned long __ipipe_test_and_stall_root(void);
+void __ipipe_restore_root(unsigned long flags);
+
+/* PSR_I_BIT is bit no. 7 and is set if interrupts are _disabled_ */
+#define raw_local_irq_save(flags)		((flags) = __ipipe_test_and_stall_root() << 7)
+#define raw_local_irq_enable()		__ipipe_unstall_root()
+#define raw_local_irq_disable()		__ipipe_stall_root()
+#define local_fiq_enable()		__ipipe_unstall_root()
+#define local_fiq_disable()		__ipipe_stall_root()
+#define raw_local_save_flags(flags)	((flags) = __ipipe_test_root() << 7)
+#define raw_local_irq_restore(flags)	__ipipe_restore_root(flags & (1 << 7))
+
+#define raw_irqs_disabled()		__ipipe_test_root()
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+#include <linux/ipipe_trace.h>
+
+#define local_irq_disable_hw() do { \
+	if (!irqs_disabled_hw()) { \
+		local_irq_disable_hw_notrace(); \
+		ipipe_trace_begin(0x80000000); \
+	} \
+} while (0)
+#define local_irq_enable_hw() do { \
+	if (irqs_disabled_hw()) { \
+		ipipe_trace_end(0x80000000); \
+		local_irq_enable_hw_notrace(); \
+	} \
+} while (0)
+#define local_irq_save_hw(x) do { \
+	local_save_flags_hw(x); \
+	if (raw_irqs_disabled_flags(x)) { \
+		local_irq_disable_hw_notrace(); \
+		ipipe_trace_begin(0x80000001); \
+	} \
+} while (0)
+#define local_irq_restore_hw(x) do { \
+	if (raw_irqs_disabled_flags(x)) \
+		ipipe_trace_end(0x80000001); \
+	local_irq_restore_hw_notrace(x); \
+} while (0)
+
+#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#define local_irq_save_hw(flags)	local_irq_save_hw_notrace(flags)
+#define local_irq_enable_hw()		local_irq_enable_hw_notrace()
+#define local_irq_disable_hw()		local_irq_disable_hw_notrace()
+#define local_fiq_enable_hw()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable_hw()		local_fiq_disable_hw_notrace()
+#define local_irq_restore_hw(flags)	local_irq_restore_hw_notrace(flags)
+
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#else /* !CONFIG_IPIPE */
+
+#define raw_local_irq_save(flags)	local_irq_save_hw_notrace(flags)
+#define raw_local_irq_enable()		local_irq_enable_hw_notrace()
+#define raw_local_irq_disable()		local_irq_disable_hw_notrace()
+#define local_fiq_enable()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable()		local_fiq_disable_hw_notrace()
+#define raw_local_save_flags(flags)	local_save_flags_hw(flags)
+#define raw_local_irq_restore(flags)	local_irq_restore_hw_notrace(flags)
+
+#define local_irq_save_hw(flags)	local_irq_save_hw_notrace(flags)
+#define local_irq_enable_hw()		local_irq_enable_hw_notrace()
+#define local_irq_disable_hw()		local_irq_disable_hw_notrace()
+#define local_fiq_enable_hw()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable_hw()		local_fiq_disable_hw_notrace()
+#define local_irq_restore_hw(flags)	local_irq_restore_hw_notrace(flags)
+
+#define irqs_disabled()		irqs_disabled_hw()
+
+#endif /* CONFIG_IPIPE */
+
 #endif
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/mmu_context.h linux-2.6.19.patched/include/asm-arm/mmu_context.h
--- linux-2.6.19.at91/include/asm-arm/mmu_context.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/mmu_context.h	2007-04-04 11:52:06.000000000 +0200
@@ -93,14 +93,17 @@ switch_mm(struct mm_struct *prev, struct
 	  struct task_struct *tsk)
 {
 #ifdef CONFIG_MMU
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu = smp_processor_id_hw();
 
 	if (prev != next) {
+		unsigned long flags;
+		local_irq_save_hw_cond(flags);
 		cpu_set(cpu, next->cpu_vm_mask);
 		check_context(next);
 		cpu_switch_mm(next->pgd, next);
 		if (cache_is_vivt())
 			cpu_clear(cpu, prev->cpu_vm_mask);
+		local_irq_restore_hw_cond(flags);
 	}
 #endif
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/system.h linux-2.6.19.patched/include/asm-arm/system.h
--- linux-2.6.19.at91/include/asm-arm/system.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/system.h	2007-04-04 11:52:06.000000000 +0200
@@ -286,17 +286,17 @@ static inline unsigned long __xchg(unsig
 #error SMP is not supported on this platform
 #endif
 	case 1:
-		raw_local_irq_save(flags);
+		local_irq_save_hw(flags);
 		ret = *(volatile unsigned char *)ptr;
 		*(volatile unsigned char *)ptr = x;
-		raw_local_irq_restore(flags);
+		local_irq_restore_hw(flags);
 		break;
 
 	case 4:
-		raw_local_irq_save(flags);
+		local_irq_save_hw(flags);
 		ret = *(volatile unsigned long *)ptr;
 		*(volatile unsigned long *)ptr = x;
-		raw_local_irq_restore(flags);
+		local_irq_restore_hw(flags);
 		break;
 #else
 	case 1:
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/hardirq.h linux-2.6.19.patched/include/linux/hardirq.h
--- linux-2.6.19.at91/include/linux/hardirq.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/hardirq.h	2007-04-04 11:52:06.000000000 +0200
@@ -128,7 +128,7 @@ static inline void account_system_vtime(
  */
 extern void irq_exit(void);
 
-#define nmi_enter()		do { lockdep_off(); irq_enter(); } while (0)
-#define nmi_exit()		do { __irq_exit(); lockdep_on(); } while (0)
+#define nmi_enter()		do { if (ipipe_root_domain_p) { lockdep_off(); irq_enter(); } } while (0)
+#define nmi_exit()		do { if (ipipe_root_domain_p) { __irq_exit(); lockdep_on(); } } while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/ipipe.h linux-2.6.19.patched/include/linux/ipipe.h
--- linux-2.6.19.at91/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/linux/ipipe.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,716 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe.h
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_IPIPE_H
+#define __LINUX_IPIPE_H
+
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/percpu.h>
+#include <linux/mutex.h>
+#include <linux/linkage.h>
+#include <asm/ipipe.h>
+
+#ifdef CONFIG_IPIPE
+
+#define IPIPE_VERSION_STRING	IPIPE_ARCH_STRING
+#define IPIPE_RELEASE_NUMBER	((IPIPE_MAJOR_NUMBER << 16) | \
+				 (IPIPE_MINOR_NUMBER <<  8) | \
+				 (IPIPE_PATCH_NUMBER))
+
+#ifndef BROKEN_BUILTIN_RETURN_ADDRESS
+#define __BUILTIN_RETURN_ADDRESS0 ((unsigned long)__builtin_return_address(0))
+#define __BUILTIN_RETURN_ADDRESS1 ((unsigned long)__builtin_return_address(1))
+#endif /* !BUILTIN_RETURN_ADDRESS */
+
+#define IPIPE_ROOT_PRIO		100
+#define IPIPE_ROOT_ID		0
+#define IPIPE_ROOT_NPTDKEYS	4	/* Must be <= BITS_PER_LONG */
+
+#define IPIPE_RESET_TIMER	0x1
+#define IPIPE_GRAB_TIMER	0x2
+
+/* Global domain flags */
+#define IPIPE_SPRINTK_FLAG	0	/* Synchronous printk() allowed */
+#define IPIPE_AHEAD_FLAG	1	/* Domain always heads the pipeline */
+
+/* Per-cpu pipeline status */
+#define IPIPE_STALL_FLAG	0	/* Stalls a pipeline stage -- guaranteed at bit #0 */
+#define IPIPE_SYNC_FLAG		1	/* The interrupt syncer is running for the domain */
+#define IPIPE_NOSTACK_FLAG	2	/* Domain currently runs on a foreign stack */
+
+#define IPIPE_SYNC_MASK		(1 << IPIPE_SYNC_FLAG)
+
+/* Interrupt control bits */
+#define IPIPE_HANDLE_FLAG	0
+#define IPIPE_PASS_FLAG		1
+#define IPIPE_ENABLE_FLAG	2
+#define IPIPE_DYNAMIC_FLAG	IPIPE_HANDLE_FLAG
+#define IPIPE_STICKY_FLAG	3
+#define IPIPE_SYSTEM_FLAG	4
+#define IPIPE_LOCK_FLAG		5
+#define IPIPE_WIRED_FLAG	6
+#define IPIPE_EXCLUSIVE_FLAG	7
+
+#define IPIPE_HANDLE_MASK	(1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK		(1 << IPIPE_PASS_FLAG)
+#define IPIPE_ENABLE_MASK	(1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK	IPIPE_HANDLE_MASK
+#define IPIPE_STICKY_MASK	(1 << IPIPE_STICKY_FLAG)
+#define IPIPE_SYSTEM_MASK	(1 << IPIPE_SYSTEM_FLAG)
+#define IPIPE_LOCK_MASK		(1 << IPIPE_LOCK_FLAG)
+#define IPIPE_WIRED_MASK	(1 << IPIPE_WIRED_FLAG)
+#define IPIPE_EXCLUSIVE_MASK	(1 << IPIPE_EXCLUSIVE_FLAG)
+
+#define IPIPE_DEFAULT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+#define IPIPE_STDROOT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_SYSTEM_MASK)
+
+#define IPIPE_EVENT_SELF        0x80000000
+
+/* Number of virtual IRQs */
+#define IPIPE_NR_VIRQS		BITS_PER_LONG
+/* First virtual IRQ # */
+#define IPIPE_VIRQ_BASE		(((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG)
+/* Total number of IRQ slots */
+#define IPIPE_NR_IRQS		(IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS)
+/* Number of indirect words needed to map the whole IRQ space. */
+#define IPIPE_IRQ_IWORDS	((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define IPIPE_IRQ_IMASK		(BITS_PER_LONG - 1)
+#define IPIPE_IRQMASK_ANY	(~0L)
+#define IPIPE_IRQMASK_VIRT	(IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+#ifdef CONFIG_SMP
+
+#define IPIPE_NR_CPUS		NR_CPUS
+#define ipipe_declare_cpuid	int cpuid
+#define ipipe_load_cpuid()	do { \
+					cpuid = ipipe_processor_id();	\
+				} while(0)
+#define ipipe_lock_cpu(flags)	do { \
+					local_irq_save_hw(flags); \
+					cpuid = ipipe_processor_id(); \
+				} while(0)
+#define ipipe_unlock_cpu(flags)	local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)	ipipe_lock_cpu(flags)
+#define ipipe_put_cpu(flags)	ipipe_unlock_cpu(flags)
+#define ipipe_current_domain	per_cpu(ipipe_percpu_domain, ipipe_processor_id())
+
+#else /* !CONFIG_SMP */
+
+#define IPIPE_NR_CPUS		1
+#define ipipe_declare_cpuid	const int cpuid = 0
+#define ipipe_load_cpuid()	do { } while(0)
+#define ipipe_lock_cpu(flags)	local_irq_save_hw(flags)
+#define ipipe_unlock_cpu(flags)	local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)	do { (void)(flags); } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#define ipipe_current_domain	per_cpu(ipipe_percpu_domain, 0)
+
+#endif /* CONFIG_SMP */
+
+#define ipipe_virtual_irq_p(irq)	((irq) >= IPIPE_VIRQ_BASE && \
+					 (irq) < IPIPE_NR_IRQS)
+
+typedef void (*ipipe_irq_handler_t)(unsigned irq,
+				    void *cookie);
+
+#define IPIPE_SAME_HANDLER	((ipipe_irq_handler_t)(-1))
+
+typedef int (*ipipe_irq_ackfn_t)(unsigned irq);
+
+typedef int (*ipipe_event_handler_t)(unsigned event,
+				     struct ipipe_domain *from,
+				     void *data);
+struct ipipe_domain {
+
+	struct list_head p_link;	/* Link in pipeline */
+
+	struct ipcpudata {
+		unsigned long status;
+		unsigned long irq_pending_hi;
+		unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+		struct ipirqcnt {
+			unsigned long pending_hits;
+			unsigned long total_hits;
+		} irq_counters[IPIPE_NR_IRQS];
+		unsigned long long evsync;
+	} ____cacheline_aligned_in_smp cpudata[IPIPE_NR_CPUS];
+
+	struct {
+		unsigned long control;
+		ipipe_irq_ackfn_t acknowledge;
+		ipipe_irq_handler_t handler;
+		void *cookie;
+	} ____cacheline_aligned irqs[IPIPE_NR_IRQS];
+
+	ipipe_event_handler_t evhand[IPIPE_NR_EVENTS]; /* Event handlers. */
+	unsigned long long evself;	/* Self-monitored event bits. */
+	unsigned long flags;
+	unsigned domid;
+	const char *name;
+	int priority;
+	void *pdd;
+	struct mutex mutex;
+};
+
+#define IPIPE_HEAD_PRIORITY	(-1) /* For domains always heading the pipeline */
+
+struct ipipe_domain_attr {
+
+	unsigned domid;		/* Domain identifier -- Magic value set by caller */
+	const char *name;	/* Domain name -- Warning: won't be dup'ed! */
+	int priority;		/* Priority in interrupt pipeline */
+	void (*entry) (void);	/* Domain entry point */
+	void *pdd;		/* Per-domain (opaque) data pointer */
+};
+
+/* The following macros must be used hw interrupts off. */
+
+#define __ipipe_irq_cookie(ipd,irq)	(ipd)->irqs[irq].cookie
+#define __ipipe_irq_handler(ipd,irq)	(ipd)->irqs[irq].handler
+
+#define __ipipe_cpudata_irq_hits(ipd,cpuid,irq)	((ipd)->cpudata[cpuid].irq_counters[irq].total_hits)
+
+#define __ipipe_set_irq_bit(ipd,cpuid,irq) \
+do { \
+	if (!test_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) { \
+		__set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+		__set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+	} \
+} while(0)
+
+#define __ipipe_clear_pend(ipd,cpuid,irq) \
+do { \
+	__clear_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+	if ((ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \
+		__clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+} while(0)
+
+#define __ipipe_lock_irq(ipd,cpuid,irq) \
+do { \
+	if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+		__ipipe_clear_pend(ipd,cpuid,irq); \
+} while(0)
+
+#define __ipipe_unlock_irq(ipd,irq) \
+do { \
+	int __cpuid, __nr_cpus = num_online_cpus(); \
+	if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+		for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \
+			if ((ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits > 0) { /* We need atomic ops next. */ \
+				set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+				set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[__cpuid].irq_pending_hi); \
+			} \
+} while(0)
+
+#define __ipipe_clear_irq(ipd,irq) \
+do { \
+	int __cpuid, __nr_cpus = num_online_cpus(); \
+	clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control); \
+	for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) { \
+		(ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits = 0; \
+		__ipipe_clear_pend(ipd,__cpuid,irq); \
+	} \
+} while(0)
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+#define write_lock_hw(x)		__raw_write_lock(&(x)->raw_lock)
+#define write_trylock_hw(x)		__raw_write_trylock(&(x)->raw_lock)
+#define write_unlock_hw(x)		__raw_write_unlock(&(x)->raw_lock)
+#define read_lock_hw(x)		__raw_read_lock(&(x)->raw_lock)
+#define read_trylock_hw(x)		__raw_read_trylock(&(x)->raw_lock)
+#define read_unlock_hw(x)		__raw_read_unlock(&(x)->raw_lock)
+#else /* UP non-debug */
+#define write_lock_hw(lock)		do { (void)(lock); } while (0)
+#define write_trylock_hw(lock)	({ (void)(lock); 1; })
+#define write_unlock_hw(lock)		do { (void)(lock); } while (0)
+#define read_lock_hw(lock)		do { (void)(lock); } while (0)
+#define read_trylock_hw(lock)		({ (void)(lock); 1; })
+#define read_unlock_hw(lock)		do { (void)(lock); } while (0)
+#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */
+
+typedef rwlock_t			ipipe_rwlock_t;
+#define IPIPE_RW_LOCK_UNLOCKED		RW_LOCK_UNLOCKED
+
+#define read_lock_irqsave_hw(lock, flags)	\
+do {						\
+	local_irq_save_hw(flags);		\
+	read_lock_hw(lock);			\
+} while (0)
+
+#define read_unlock_irqrestore_hw(lock, flags)	\
+do {						\
+	read_unlock_hw(lock);			\
+	local_irq_restore_hw(flags);		\
+} while (0)
+
+#define write_lock_irqsave_hw(lock, flags)	\
+do {						\
+	local_irq_save_hw(flags);		\
+	write_lock_hw(lock);			\
+} while (0)
+
+#define write_unlock_irqrestore_hw(lock, flags)	\
+do {						\
+	write_unlock_hw(lock);			\
+	local_irq_restore_hw(flags);		\
+} while (0)
+
+DECLARE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain);
+
+extern struct ipipe_domain ipipe_root;
+
+#define ipipe_root_domain (&ipipe_root)
+
+extern unsigned __ipipe_printk_virq;
+
+extern unsigned long __ipipe_virtual_irq_map;
+
+extern struct list_head __ipipe_pipeline;
+
+extern int __ipipe_event_monitors[];
+
+/* Private interface */
+
+void ipipe_init(void);
+
+#ifdef CONFIG_PROC_FS
+void ipipe_init_proc(void);
+
+#ifdef CONFIG_IPIPE_TRACE
+void __ipipe_init_tracer(void);
+#else /* !CONFIG_IPIPE_TRACE */
+#define __ipipe_init_tracer()       do { } while(0)
+#endif /* CONFIG_IPIPE_TRACE */
+
+#else	/* !CONFIG_PROC_FS */
+#define ipipe_init_proc()	do { } while(0)
+#endif	/* CONFIG_PROC_FS */
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_flush_printk(unsigned irq, void *cookie);
+
+void __ipipe_stall_root(void);
+
+void __ipipe_unstall_root(void);
+
+unsigned long __ipipe_test_root(void);
+
+unsigned long __ipipe_test_and_stall_root(void);
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid);
+
+void fastcall __ipipe_restore_root(unsigned long x);
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head);
+
+int fastcall __ipipe_dispatch_event(unsigned event, void *data);
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq);
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask);
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end);
+
+struct mm_struct;
+
+int __ipipe_pin_range_mapping(struct mm_struct *mm,
+			      unsigned long start, unsigned long end);
+
+#ifndef __ipipe_sync_pipeline
+#define __ipipe_sync_pipeline(syncmask) __ipipe_sync_stage(syncmask)
+#endif
+
+#ifndef __ipipe_run_irqtail
+#define __ipipe_run_irqtail() do { } while(0)
+#endif
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+/*
+ * Keep the following as a macro, so that client code could check for
+ * the support of the invariant pipeline head optimization.
+ */
+#define __ipipe_pipeline_head() list_entry(__ipipe_pipeline.next,struct ipipe_domain,p_link)
+
+#define __ipipe_event_monitored_p(ev) \
+	(__ipipe_event_monitors[ev] > 0 || (ipipe_current_domain->evself & (1LL << ev)))
+
+#ifdef CONFIG_SMP
+
+cpumask_t __ipipe_set_irq_affinity(unsigned irq,
+				   cpumask_t cpumask);
+
+int fastcall __ipipe_send_ipi(unsigned ipi,
+			      cpumask_t cpumask);
+
+#endif /* CONFIG_SMP */
+
+/* Called with hw interrupts off. */
+static inline void __ipipe_switch_to(struct ipipe_domain *out,
+				     struct ipipe_domain *in, int cpuid)
+{
+	void ipipe_suspend_domain(void);
+
+	/*
+	 * "in" is guaranteed to be closer than "out" from the head of the
+	 * pipeline (and obviously different).
+	 */
+
+	out->cpudata[cpuid].evsync = 0;
+	per_cpu(ipipe_percpu_domain, cpuid) = in;
+
+	ipipe_suspend_domain();	/* Sync stage and propagate interrupts. */
+	ipipe_load_cpuid();	/* Processor might have changed. */
+
+	if (per_cpu(ipipe_percpu_domain, cpuid) == in)
+		/*
+		 * Otherwise, something has changed the current domain under
+		 * our feet recycling the register set; do not override.
+		 */
+		per_cpu(ipipe_percpu_domain, cpuid) = out;
+}
+
+#define ipipe_sigwake_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SIGWAKE)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SIGWAKE,p);		\
+} while(0)
+
+#define ipipe_exit_notify(p)	\
+do {				\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_EXIT)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_EXIT,p);		\
+} while(0)
+
+#define ipipe_setsched_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SETSCHED)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SETSCHED,p);		\
+} while(0)
+
+#define ipipe_schedule_notify(prev, next)				\
+do {									\
+	if ((((prev)->flags|(next)->flags) & PF_EVNOTIFY) &&		\
+	    __ipipe_event_monitored_p(IPIPE_EVENT_SCHEDULE))		\
+		__ipipe_dispatch_event(IPIPE_EVENT_SCHEDULE,next);	\
+} while(0)
+
+#define ipipe_trap_notify(ex, regs)		\
+({						\
+	ipipe_declare_cpuid;			\
+	int ret = 0;				\
+	ipipe_load_cpuid();			\
+	if ((test_bit(IPIPE_NOSTACK_FLAG, &ipipe_current_domain->cpudata[cpuid].status) || \
+	     ((current)->flags & PF_EVNOTIFY)) &&			\
+	    __ipipe_event_monitored_p(ex))				\
+		ret = __ipipe_dispatch_event(ex, regs);			\
+	ret;								\
+})
+
+static inline void ipipe_init_notify(struct task_struct *p)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_INIT))
+		__ipipe_dispatch_event(IPIPE_EVENT_INIT,p);
+}
+
+static inline void ipipe_cleanup_notify(struct mm_struct *mm)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_CLEANUP))
+		__ipipe_dispatch_event(IPIPE_EVENT_CLEANUP,mm);
+}
+
+/* Public interface */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr);
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd);
+
+void ipipe_suspend_domain(void);
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask);
+
+int ipipe_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+unsigned ipipe_alloc_virq(void);
+
+int ipipe_free_virq(unsigned virq);
+
+int fastcall ipipe_trigger_irq(unsigned irq);
+
+static inline int ipipe_propagate_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, ipipe_current_domain->p_link.next);
+}
+
+static inline int ipipe_schedule_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, &ipipe_current_domain->p_link);
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x);
+
+static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+static inline void ipipe_restore_pipeline_nosync(struct ipipe_domain *ipd,
+						 unsigned long x, int cpuid)
+{
+	/*
+	 * If cpuid is current, then it must be held on entry
+	 * (ipipe_get_cpu/local_irq_save_hw/local_irq_disable_hw).
+	 */
+
+	if (x)
+		__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	else
+		__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+static inline void ipipe_stall_pipeline_head(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	__set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status);
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline_head(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	return __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status);
+}
+
+void ipipe_unstall_pipeline_head(void);
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head,
+					    unsigned long x);
+
+static inline void ipipe_restore_pipeline_head(unsigned long x)
+{
+	struct ipipe_domain *head = __ipipe_pipeline_head();
+	/* On some archs, __test_and_set_bit() might return different
+	 * truth value than test_bit(), so we test the exclusive OR of
+	 * both statuses, assuming that the lowest bit is always set in
+	 * the truth value (if this is wrong, the failed optimization will
+	 * be caught in __ipipe_restore_pipeline_head() if
+	 * CONFIG_DEBUG_KERNEL is set). */
+	if ((x ^ test_bit(IPIPE_STALL_FLAG, &head->cpudata[ipipe_processor_id()].status)) & 1)
+		__ipipe_restore_pipeline_head(head,x);
+}
+
+#define ipipe_unstall_pipeline() \
+	ipipe_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_unstall_pipeline() \
+	ipipe_test_and_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_pipeline() \
+	ipipe_test_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_stall_pipeline() \
+	ipipe_test_and_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_stall_pipeline() \
+	ipipe_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_restore_pipeline(x) \
+	ipipe_restore_pipeline_from(ipipe_current_domain, (x))
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr);
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *sysinfo);
+
+int ipipe_tune_timer(unsigned long ns,
+		     int flags);
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void));
+
+void ipipe_critical_exit(unsigned long flags);
+
+static inline void ipipe_set_printk_sync(struct ipipe_domain *ipd)
+{
+	set_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_printk_async(struct ipipe_domain *ipd)
+{
+	clear_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	ipipe_declare_cpuid;
+	ipipe_load_cpuid();
+	__set_bit(IPIPE_NOSTACK_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+static inline void ipipe_clear_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	ipipe_declare_cpuid;
+	ipipe_load_cpuid();
+	__clear_bit(IPIPE_NOSTACK_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+#define ipipe_safe_current()					\
+({								\
+	ipipe_declare_cpuid;					\
+	struct task_struct *p;					\
+	ipipe_load_cpuid();					\
+	p = test_bit(IPIPE_NOSTACK_FLAG,			\
+		     &per_cpu(ipipe_percpu_domain, cpuid)->cpudata[cpuid].status) ? &init_task : current; \
+	p; \
+})
+
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler);
+
+cpumask_t ipipe_set_irq_affinity(unsigned irq,
+				 cpumask_t cpumask);
+
+int fastcall ipipe_send_ipi(unsigned ipi,
+			    cpumask_t cpumask);
+
+int ipipe_setscheduler_root(struct task_struct *p,
+			    int policy,
+			    int prio);
+
+int ipipe_reenter_root(struct task_struct *prev,
+		       int policy,
+		       int prio);
+
+int ipipe_alloc_ptdkey(void);
+
+int ipipe_free_ptdkey(int key);
+
+int fastcall ipipe_set_ptd(int key,
+			   void *value);
+
+void fastcall *ipipe_get_ptd(int key);
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk);
+
+#define local_irq_enable_hw_cond()		local_irq_enable_hw()
+#define local_irq_disable_hw_cond()		local_irq_disable_hw()
+#define local_irq_save_hw_cond(flags)	local_irq_save_hw(flags)
+#define local_irq_restore_hw_cond(flags)	local_irq_restore_hw(flags)
+#define local_irq_disable_head()		ipipe_stall_pipeline_head()
+
+#define local_irq_enable_nohead(ipd)			\
+	do {						\
+		if (!__ipipe_pipeline_head_p(ipd))	\
+			local_irq_enable_hw();		\
+	} while(0)
+
+#define local_irq_disable_nohead(ipd)		\
+	do {						\
+		if (!__ipipe_pipeline_head_p(ipd))	\
+			local_irq_disable_hw();		\
+	} while(0)
+
+#define smp_processor_id_hw()				ipipe_processor_id()
+
+#define ipipe_irq_lock(irq)						\
+	do {								\
+		ipipe_declare_cpuid;					\
+		ipipe_load_cpuid();					\
+		__ipipe_lock_irq(per_cpu(ipipe_percpu_domain, cpuid), cpuid, irq);\
+	} while(0)
+
+#define ipipe_irq_unlock(irq)						\
+	do {								\
+		ipipe_declare_cpuid;					\
+		ipipe_load_cpuid();					\
+		__ipipe_unlock_irq(per_cpu(ipipe_percpu_domain, cpuid), irq);	\
+	} while(0)
+
+#define ipipe_root_domain_p		(ipipe_current_domain == ipipe_root_domain)
+
+#else	/* !CONFIG_IPIPE */
+
+#define ipipe_init()			do { } while(0)
+#define ipipe_suspend_domain()	do { } while(0)
+#define ipipe_sigwake_notify(p)	do { } while(0)
+#define ipipe_setsched_notify(p)	do { } while(0)
+#define ipipe_init_notify(p)		do { } while(0)
+#define ipipe_exit_notify(p)		do { } while(0)
+#define ipipe_cleanup_notify(mm)	do { } while(0)
+#define ipipe_trap_notify(t,r)	0
+#define ipipe_init_proc()		do { } while(0)
+#define __ipipe_pin_range_globally(start, end) do { } while(0)
+
+#define local_irq_enable_hw_cond()		do { } while(0)
+#define local_irq_disable_hw_cond()		do { } while(0)
+#define local_irq_save_hw_cond(flags)	do { (void)(flags); } while(0)
+#define local_irq_restore_hw_cond(flags)	do { } while(0)
+#define smp_processor_id_hw()			smp_processor_id()
+
+#define ipipe_irq_lock(irq)		do { } while(0)
+#define ipipe_irq_unlock(irq)		do { } while(0)
+
+#define ipipe_root_domain_p		1
+#define ipipe_safe_current		current
+
+#define local_irq_disable_head()	local_irq_disable()
+
+#endif	/* CONFIG_IPIPE */
+
+#endif	/* !__LINUX_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/ipipe_trace.h linux-2.6.19.patched/include/linux/ipipe_trace.h
--- linux-2.6.19.at91/include/linux/ipipe_trace.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/linux/ipipe_trace.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,44 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe_trace.h
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005, 2006 Jan Kiszka.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LINUX_IPIPE_TRACE_H
+#define _LINUX_IPIPE_TRACE_H
+
+#ifdef CONFIG_IPIPE_TRACE
+
+#include <linux/types.h>
+
+void ipipe_trace_begin(unsigned long v);
+void ipipe_trace_end(unsigned long v);
+void ipipe_trace_freeze(unsigned long v);
+void ipipe_trace_special(unsigned char special_id, unsigned long v);
+void ipipe_trace_pid(pid_t pid, short prio);
+
+int ipipe_trace_max_reset(void);
+int ipipe_trace_frozen_reset(void);
+
+void ipipe_trace_panic_freeze(void);
+void ipipe_trace_panic_dump(void);
+
+#endif /* CONFIG_IPIPE_TRACE */
+
+#endif	/* !__LINUX_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/irq.h linux-2.6.19.patched/include/linux/irq.h
--- linux-2.6.19.at91/include/linux/irq.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/irq.h	2007-04-04 11:52:06.000000000 +0200
@@ -146,6 +146,12 @@ struct irq_chip {
  * Pad this out to 32 bytes for cache and indexing reasons.
  */
 struct irq_desc {
+#ifdef CONFIG_IPIPE
+	void			fastcall (*ipipe_ack)(unsigned int irq,
+						      struct irq_desc *desc);
+	void			fastcall (*ipipe_end)(unsigned int irq,
+						      struct irq_desc *desc);
+#endif /* CONFIG_IPIPE */
 	irq_flow_handler_t	handle_irq;
 	struct irq_chip		*chip;
 	void			*handler_data;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/linkage.h linux-2.6.19.patched/include/linux/linkage.h
--- linux-2.6.19.at91/include/linux/linkage.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/linkage.h	2007-04-04 11:52:06.000000000 +0200
@@ -64,4 +64,8 @@
 #define fastcall
 #endif
 
+#ifndef notrace
+#define notrace		__attribute__((no_instrument_function))
+#endif
+
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/mm.h linux-2.6.19.patched/include/linux/mm.h
--- linux-2.6.19.at91/include/linux/mm.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/mm.h	2007-04-04 11:52:06.000000000 +0200
@@ -166,6 +166,7 @@ extern unsigned int kobjsize(const void 
 #define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
 #define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
 #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
+#define VM_PINNED	0x10000000	/* Disable faults for the vma */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/preempt.h linux-2.6.19.patched/include/linux/preempt.h
--- linux-2.6.19.at91/include/linux/preempt.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/preempt.h	2007-04-04 11:52:06.000000000 +0200
@@ -26,22 +26,37 @@
 
 asmlinkage void preempt_schedule(void);
 
+#ifdef CONFIG_IPIPE
+#include <asm/ipipe.h>
+DECLARE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain);
+extern struct ipipe_domain ipipe_root;
+#define ipipe_preempt_guard() (per_cpu(ipipe_percpu_domain, ipipe_processor_id()) == &ipipe_root)
+#else  /* !CONFIG_IPIPE */
+#define ipipe_preempt_guard()	1
+#endif /* CONFIG_IPIPE */
+
 #define preempt_disable() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	inc_preempt_count(); \
 	barrier(); \
+	}								\
 } while (0)
 
 #define preempt_enable_no_resched() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	barrier(); \
 	dec_preempt_count(); \
+	}								\
 } while (0)
 
 #define preempt_check_resched() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
 		preempt_schedule(); \
+	}								\
 } while (0)
 
 #define preempt_enable() \
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/sched.h linux-2.6.19.patched/include/linux/sched.h
--- linux-2.6.19.at91/include/linux/sched.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/sched.h	2007-04-04 11:52:06.000000000 +0200
@@ -54,6 +54,7 @@ struct sched_param {
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/nodemask.h>
+#include <linux/ipipe.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -150,6 +151,13 @@ extern unsigned long weighted_cpuload(co
 /* in tsk->state again */
 #define TASK_NONINTERACTIVE	64
 #define TASK_DEAD		128
+#ifdef CONFIG_IPIPE
+#define TASK_ATOMICSWITCH	512
+#define TASK_NOWAKEUP          1024
+#else  /* !CONFIG_IPIPE */
+#define TASK_ATOMICSWITCH	0
+#define TASK_NOWAKEUP          0
+#endif /* CONFIG_IPIPE */
 
 #define __set_task_state(tsk, state_value)		\
 	do { (tsk)->state = (state_value); } while (0)
@@ -1015,6 +1023,9 @@ struct task_struct {
 
 	atomic_t fs_excl;	/* holding fs exclusive resources */
 	struct rcu_head rcu;
+#ifdef CONFIG_IPIPE
+	void *ptd[IPIPE_ROOT_NPTDKEYS];
+#endif
 
 	/*
 	 * cache last used pipe for splice
@@ -1115,6 +1126,11 @@ static inline void put_task_struct(struc
 #define PF_SPREAD_SLAB	0x02000000	/* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER	0x20000000	/* Thread belongs to the rt mutex tester */
+#ifdef CONFIG_IPIPE
+#define PF_EVNOTIFY    0x40000000	/* Notify other domains about internal events */
+#else
+#define PF_EVNOTIFY    0
+#endif /* CONFIG_IPIPE */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/spinlock.h linux-2.6.19.patched/include/linux/spinlock.h
--- linux-2.6.19.at91/include/linux/spinlock.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/spinlock.h	2007-04-04 11:52:06.000000000 +0200
@@ -171,7 +171,97 @@ do {								\
 #define read_trylock(lock)		__cond_lock(lock, _read_trylock(lock))
 #define write_trylock(lock)		__cond_lock(lock, _write_trylock(lock))
 
-#define spin_lock(lock)			_spin_lock(lock)
+#undef TYPE_EQUAL
+#define TYPE_EQUAL(lock, type) \
+	__builtin_types_compatible_p(typeof(lock), type *)
+
+#define PICK_SPINOP(op, lock)						\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		_spin##op((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINOP_RAW(op, lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		__raw_spin##op(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_disable_hw();					\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_enable_hw();					\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ_RAW(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_disable_hw();					\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		local_irq_disable();					\
+		__raw_spin_lock(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ_RAW(lock)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_enable_hw();				\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		__raw_spin_unlock(&((spinlock_t *)(lock))->raw_lock);	\
+		local_irq_enable();					\
+} while (0)
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+extern int __bad_spinlock_type(void);
+
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_save_hw(flags);				\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		flags = _spin_lock_irqsave((spinlock_t *)(lock));	\
+	else __bad_spinlock_type();					\
+} while (0)
+#else
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_save_hw(flags);				\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irqsave((spinlock_t *)(lock), flags);	\
+} while (0)
+#endif
+
+#define PICK_SPINUNLOCK_IRQRESTORE(lock, flags)			\
+	do {								\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_restore_hw(flags);				\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irqrestore((spinlock_t *)(lock), flags);	\
+} while (0)
+
+#define spin_lock(lock)	PICK_SPINOP(_lock, lock)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define spin_lock_nested(lock, subclass) _spin_lock_nested(lock, subclass)
@@ -184,7 +274,7 @@ do {								\
 
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
 
-#define spin_lock_irqsave(lock, flags)	flags = _spin_lock_irqsave(lock)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	flags = _read_lock_irqsave(lock)
 #define write_lock_irqsave(lock, flags)	flags = _write_lock_irqsave(lock)
 
@@ -198,7 +288,7 @@ do {								\
 
 #else
 
-#define spin_lock_irqsave(lock, flags)	_spin_lock_irqsave(lock, flags)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	_read_lock_irqsave(lock, flags)
 #define write_lock_irqsave(lock, flags)	_write_lock_irqsave(lock, flags)
 #define spin_lock_irqsave_nested(lock, flags, subclass)	\
@@ -206,7 +296,7 @@ do {								\
 
 #endif
 
-#define spin_lock_irq(lock)		_spin_lock_irq(lock)
+#define spin_lock_irq(lock)		PICK_SPINLOCK_IRQ(lock)
 #define spin_lock_bh(lock)		_spin_lock_bh(lock)
 
 #define read_lock_irq(lock)		_read_lock_irq(lock)
@@ -220,18 +310,17 @@ do {								\
  */
 #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
 	!defined(CONFIG_SMP)
-# define spin_unlock(lock)		_spin_unlock(lock)
+#define spin_unlock(lock)		PICK_SPINOP(_unlock, lock)
 # define read_unlock(lock)		_read_unlock(lock)
 # define write_unlock(lock)		_write_unlock(lock)
-# define spin_unlock_irq(lock)		_spin_unlock_irq(lock)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ(lock)
 # define read_unlock_irq(lock)		_read_unlock_irq(lock)
 # define write_unlock_irq(lock)		_write_unlock_irq(lock)
 #else
-# define spin_unlock(lock)		__raw_spin_unlock(&(lock)->raw_lock)
+# define spin_unlock(lock)		PICK_SPINOP_RAW(_unlock, lock)
 # define read_unlock(lock)		__raw_read_unlock(&(lock)->raw_lock)
 # define write_unlock(lock)		__raw_write_unlock(&(lock)->raw_lock)
-# define spin_unlock_irq(lock) \
-    do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ_RAW(lock)
 # define read_unlock_irq(lock) \
     do { __raw_read_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
 # define write_unlock_irq(lock) \
@@ -239,7 +328,7 @@ do {								\
 #endif
 
 #define spin_unlock_irqrestore(lock, flags) \
-					_spin_unlock_irqrestore(lock, flags)
+					PICK_SPINUNLOCK_IRQRESTORE(lock, flags)
 #define spin_unlock_bh(lock)		_spin_unlock_bh(lock)
 
 #define read_unlock_irqrestore(lock, flags) \
@@ -286,4 +375,16 @@ extern int _atomic_dec_and_lock(atomic_t
  */
 #define spin_can_lock(lock)	(!spin_is_locked(lock))
 
+#ifdef CONFIG_IPIPE
+#define spin_lock_irqsave_cond(lock, flags) \
+	spin_lock_irqsave(lock,flags)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock_irqrestore(lock,flags)
+#else
+#define spin_lock_irqsave_cond(lock, flags) \
+	do { (void)(flags); spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock(lock)
+#endif
+
 #endif /* __LINUX_SPINLOCK_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/spinlock_types.h linux-2.6.19.patched/include/linux/spinlock_types.h
--- linux-2.6.19.at91/include/linux/spinlock_types.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/spinlock_types.h	2007-04-04 11:52:06.000000000 +0200
@@ -31,6 +31,10 @@ typedef struct {
 #endif
 } spinlock_t;
 
+typedef struct {
+	raw_spinlock_t __raw_lock;
+} __ipipe_spinlock_t;
+
 #define SPINLOCK_MAGIC		0xdead4ead
 
 typedef struct {
@@ -86,9 +90,19 @@ typedef struct {
 #endif
 
 #define SPIN_LOCK_UNLOCKED	__SPIN_LOCK_UNLOCKED(old_style_spin_init)
+#define IPIPE_SPIN_LOCK_UNLOCKED					\
+	(__ipipe_spinlock_t) {	.__raw_lock = __RAW_SPIN_LOCK_UNLOCKED }
 #define RW_LOCK_UNLOCKED	__RW_LOCK_UNLOCKED(old_style_rw_init)
 
 #define DEFINE_SPINLOCK(x)	spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
 #define DEFINE_RWLOCK(x)	rwlock_t x = __RW_LOCK_UNLOCKED(x)
 
+#ifdef CONFIG_IPIPE
+# define ipipe_spinlock_t	__ipipe_spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) ipipe_spinlock_t x = IPIPE_SPIN_LOCK_UNLOCKED
+#else
+# define ipipe_spinlock_t	spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) DEFINE_SPINLOCK(x)
+#endif
+
 #endif /* __LINUX_SPINLOCK_TYPES_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/init/Kconfig linux-2.6.19.patched/init/Kconfig
--- linux-2.6.19.at91/init/Kconfig	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/init/Kconfig	2007-04-04 11:52:06.000000000 +0200
@@ -67,6 +67,7 @@ menu "General setup"
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-ipipe"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/init/main.c linux-2.6.19.patched/init/main.c
--- linux-2.6.19.at91/init/main.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/init/main.c	2007-04-04 11:52:06.000000000 +0200
@@ -489,7 +489,7 @@ asmlinkage void __init start_kernel(void
 	unwind_init();
 	lockdep_init();
 
-	local_irq_disable();
+	local_irq_disable_hw();
 	early_boot_irqs_off();
 	early_init_irq_lock_class();
 
@@ -535,6 +535,11 @@ asmlinkage void __init start_kernel(void
 	softirq_init();
 	timekeeping_init();
 	time_init();
+	/*
+	 * We need to wait for the interrupt and time subsystems to be
+	 * initialized before enabling the pipeline.
+	 */
+ 	ipipe_init();
 	profile_init();
 	if (!irqs_disabled())
 		printk("start_kernel(): bug: interrupts were enabled early\n");
@@ -683,6 +688,7 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
+	ipipe_init_proc();
 
 	do_initcalls();
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/exit.c linux-2.6.19.patched/kernel/exit.c
--- linux-2.6.19.at91/kernel/exit.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/exit.c	2007-04-04 11:52:06.000000000 +0200
@@ -918,6 +918,7 @@ fastcall NORET_TYPE void do_exit(long co
 
 	if (group_dead)
 		acct_process();
+ 	ipipe_exit_notify(tsk);
 	exit_sem(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/fork.c linux-2.6.19.patched/kernel/fork.c
--- linux-2.6.19.at91/kernel/fork.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/fork.c	2007-04-04 11:52:06.000000000 +0200
@@ -384,6 +384,7 @@ void mmput(struct mm_struct *mm)
 	might_sleep();
 
 	if (atomic_dec_and_test(&mm->mm_users)) {
+		ipipe_cleanup_notify(mm);
 		exit_aio(mm);
 		exit_mmap(mm);
 		if (!list_empty(&mm->mmlist)) {
@@ -914,7 +915,7 @@ static inline void copy_flags(unsigned l
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE | PF_EVNOTIFY);
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
@@ -1258,6 +1259,14 @@ static struct task_struct *copy_process(
 	spin_unlock(&current->sighand->siglock);
 	write_unlock_irq(&tasklist_lock);
 	proc_fork_connector(p);
+#ifdef CONFIG_IPIPE
+	{
+	int k;
+
+	for (k = 0; k < IPIPE_ROOT_NPTDKEYS; k++)
+		p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_IPIPE */
 	return p;
 
 bad_fork_cleanup_namespaces:
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/core.c linux-2.6.19.patched/kernel/ipipe/core.c
--- linux-2.6.19.at91/kernel/ipipe/core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/core.c	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,1419 @@
+/* -*- linux-c -*-
+ * linux/kernel/ipipe/core.c
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-independent I-PIPE core support.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif	/* CONFIG_PROC_FS */
+#include <linux/irq.h>
+
+MODULE_DESCRIPTION("I-pipe");
+MODULE_LICENSE("GPL");
+
+static int __ipipe_ptd_key_count;
+
+static unsigned long __ipipe_ptd_key_map;
+
+struct ipipe_domain ipipe_root =
+	{ .cpudata = {[0 ... IPIPE_NR_CPUS-1] =
+		{ .status = (1<<IPIPE_STALL_FLAG) } } };
+
+DEFINE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain) =
+	{ &ipipe_root };
+
+static IPIPE_DEFINE_SPINLOCK(__ipipe_pipelock);
+
+LIST_HEAD(__ipipe_pipeline);
+
+unsigned long __ipipe_virtual_irq_map;
+
+#ifdef CONFIG_PRINTK
+unsigned __ipipe_printk_virq;
+#endif /* CONFIG_PRINTK */
+
+int __ipipe_event_monitors[IPIPE_NR_EVENTS];
+
+/*
+ * ipipe_init() -- Initialization routine of the IPIPE layer. Called
+ * by the host kernel early during the boot procedure.
+ */
+void ipipe_init(void)
+{
+	struct ipipe_domain *ipd = &ipipe_root;
+
+	__ipipe_check_platform();	/* Do platform dependent checks first. */
+
+	/*
+	 * A lightweight registration code for the root domain. We are
+	 * running on the boot CPU, hw interrupts are off, and
+	 * secondary CPUs are still lost in space.
+	 */
+
+	ipd->name = "Linux";
+	ipd->domid = IPIPE_ROOT_ID;
+	ipd->priority = IPIPE_ROOT_PRIO;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+	list_add_tail(&ipd->p_link, &__ipipe_pipeline);
+
+	__ipipe_init_platform();
+
+#ifdef CONFIG_PRINTK
+	__ipipe_printk_virq = ipipe_alloc_virq();	/* Cannot fail here. */
+	ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk;
+	ipd->irqs[__ipipe_printk_virq].cookie = NULL;
+	ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+	ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+#endif /* CONFIG_PRINTK */
+
+	__ipipe_enable_pipeline();
+
+	printk(KERN_INFO "I-pipe %s: pipeline enabled.\n",
+	       IPIPE_VERSION_STRING);
+}
+
+void __ipipe_init_stage(struct ipipe_domain *ipd)
+{
+	int cpuid, n;
+
+	for (cpuid = 0; cpuid < IPIPE_NR_CPUS; cpuid++) {
+		ipd->cpudata[cpuid].irq_pending_hi = 0;
+
+		for (n = 0; n < IPIPE_IRQ_IWORDS; n++)
+			ipd->cpudata[cpuid].irq_pending_lo[n] = 0;
+
+		for (n = 0; n < IPIPE_NR_IRQS; n++) {
+			ipd->cpudata[cpuid].irq_counters[n].total_hits = 0;
+			ipd->cpudata[cpuid].irq_counters[n].pending_hits = 0;
+		}
+
+		ipd->cpudata[cpuid].evsync = 0;
+	}
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++) {
+		ipd->irqs[n].acknowledge = NULL;
+		ipd->irqs[n].handler = NULL;
+		ipd->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+	for (n = 0; n < IPIPE_NR_EVENTS; n++)
+		ipd->evhand[n] = NULL;
+
+	ipd->evself = 0LL;
+	mutex_init(&ipd->mutex);
+
+	__ipipe_hook_critical_ipi(ipd);
+}
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd)
+{
+	ipipe_unstall_pipeline_from(ipd);
+
+#ifdef CONFIG_SMP
+	{
+		int cpu;
+
+		for_each_online_cpu(cpu) {
+			while (ipd->cpudata[cpu].irq_pending_hi != 0)
+				cpu_relax();
+		}
+	}
+#endif	/* CONFIG_SMP */
+}
+
+void __ipipe_stall_root(void)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+}
+
+void __ipipe_unstall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+
+	ipipe_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+
+	if (unlikely(ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0))
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+	local_irq_enable_hw();
+}
+
+unsigned long __ipipe_test_root(void)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	x = test_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	x = test_and_set_bit(IPIPE_STALL_FLAG,
+			     &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+void fastcall __ipipe_restore_root(unsigned long x)
+{
+	if (x)
+		__ipipe_stall_root();
+	else
+		__ipipe_unstall_root();
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	ipipe_declare_cpuid;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+}
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	ipipe_declare_cpuid;
+	unsigned long s;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	s = __test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	s = test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+
+	return s;
+}
+
+/*
+ * ipipe_unstall_pipeline_from() -- Unstall the pipeline and
+ * synchronize pending interrupts for a given domain. See
+ * __ipipe_walk_pipeline() for more information.
+ */
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	struct list_head *pos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (ipd == per_cpu(ipipe_percpu_domain, cpuid))
+		pos = &ipd->p_link;
+	else
+		pos = __ipipe_pipeline.next;
+
+	__ipipe_walk_pipeline(pos, cpuid);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_enable_hw();
+	else
+		ipipe_unlock_cpu(flags);
+}
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_unstall_pipeline_from(ipd);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x)
+{
+	if (x)
+		ipipe_stall_pipeline_from(ipd);
+	else
+		ipipe_unstall_pipeline_from(ipd);
+}
+
+void ipipe_unstall_pipeline_head(void)
+{
+	struct ipipe_domain *head;
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	head = __ipipe_pipeline_head();
+	__clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+
+	if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) {
+		if (likely(head == per_cpu(ipipe_percpu_domain, cpuid)))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+		else
+			__ipipe_walk_pipeline(&head->p_link, cpuid);
+        }
+
+	local_irq_enable_hw();
+}
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head, unsigned long x)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+
+	if (x) {
+#ifdef CONFIG_DEBUG_KERNEL
+		static int warned;
+		if (!warned && test_and_set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status)) {
+			/*
+			 * Already stalled albeit ipipe_restore_pipeline_head()
+			 * should have detected it? Send a warning once.\n");
+			 */
+			warned = 1;
+			printk(KERN_WARNING
+				   "I-pipe: ipipe_restore_pipeline_head() optimization failed.\n");
+			dump_stack();
+		}
+#else /* !CONFIG_DEBUG_KERNEL */
+		set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+#endif /* CONFIG_DEBUG_KERNEL */
+	}
+	else {
+		__clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+		if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) {
+			if (likely(head == per_cpu(ipipe_percpu_domain, cpuid)))
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else
+				__ipipe_walk_pipeline(&head->p_link, cpuid);
+		}
+		local_irq_enable_hw();
+	}
+}
+
+/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must
+   be called with local hw interrupts disabled. */
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid)
+{
+	struct ipipe_domain *this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status))
+			break;	/* Stalled stage -- do not go further. */
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi != 0) {
+
+			if (next_domain == this_domain)
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else {
+				__ipipe_switch_to(this_domain, next_domain,
+						  cpuid);
+
+				ipipe_load_cpuid();	/* Processor might have changed. */
+
+				if (this_domain->cpudata[cpuid].
+				    irq_pending_hi != 0
+				    && !test_bit(IPIPE_STALL_FLAG,
+						 &this_domain->cpudata[cpuid].status))
+					__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+}
+
+/*
+ * ipipe_suspend_domain() -- Suspend the current domain, switching to
+ * the next one which has pending work down the pipeline.
+ */
+void ipipe_suspend_domain(void)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	this_domain = next_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	__clear_bit(IPIPE_STALL_FLAG, &this_domain->cpudata[cpuid].status);
+
+	if (this_domain->cpudata[cpuid].irq_pending_hi != 0)
+		goto sync_stage;
+
+	for (;;) {
+		ln = next_domain->p_link.next;
+
+		if (ln == &__ipipe_pipeline)
+			break;
+
+		next_domain = list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG,
+			     &next_domain->cpudata[cpuid].status))
+			break;
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi == 0)
+			continue;
+
+		per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+
+sync_stage:
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+			/*
+			 * Something has changed the current domain under our
+			 * feet, recycling the register set; take note.
+			 */
+			this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+	}
+
+	per_cpu(ipipe_percpu_domain, cpuid) = this_domain;
+
+	ipipe_unlock_cpu(flags);
+}
+
+/* ipipe_alloc_virq() -- Allocate a pipelined virtual/soft interrupt.
+ * Virtual interrupts are handled in exactly the same way than their
+ * hw-generated counterparts wrt pipelining.
+ */
+unsigned ipipe_alloc_virq(void)
+{
+	unsigned long flags, irq = 0;
+	int ipos;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	if (__ipipe_virtual_irq_map != ~0) {
+		ipos = ffz(__ipipe_virtual_irq_map);
+		set_bit(ipos, &__ipipe_virtual_irq_map);
+		irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return irq;
+}
+
+/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw
+   acknowledge routine) to an interrupt for a given domain. */
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask)
+{
+	unsigned long flags;
+	int err;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (!test_bit(IPIPE_AHEAD_FLAG, &ipd->flags))
+		/* Silently unwire interrupts for non-heading domains. */
+		modemask &= ~IPIPE_WIRED_MASK;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	if (handler != NULL) {
+
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = ipd->irqs[irq].handler;
+			cookie = ipd->irqs[irq].cookie;
+
+			if (handler == NULL) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+		} else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+			   ipd->irqs[irq].handler != NULL) {
+			err = -EBUSY;
+			goto unlock_and_exit;
+		}
+
+		/* Wired interrupts can only be delivered to domains
+		 * always heading the pipeline, and using dynamic
+		 * propagation. */
+
+		if ((modemask & IPIPE_WIRED_MASK) != 0) {
+			if ((modemask & (IPIPE_PASS_MASK | IPIPE_STICKY_MASK)) != 0) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+			modemask |= (IPIPE_HANDLE_MASK);
+		}
+
+		if ((modemask & IPIPE_STICKY_MASK) != 0)
+			modemask |= IPIPE_HANDLE_MASK;
+	} else
+		modemask &=
+		    ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK |
+		      IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK);
+
+	if (acknowledge == NULL && !ipipe_virtual_irq_p(irq))
+		/* Acknowledge handler unspecified for a hw interrupt:
+		   use the Linux-defined handler instead. */
+		acknowledge = ipipe_root_domain->irqs[irq].acknowledge;
+
+	ipd->irqs[irq].handler = handler;
+	ipd->irqs[irq].cookie = cookie;
+	ipd->irqs[irq].acknowledge = acknowledge;
+	ipd->irqs[irq].control = modemask;
+
+	if (irq < NR_IRQS && handler != NULL && !ipipe_virtual_irq_p(irq)) {
+		__ipipe_enable_irqdesc(irq);
+
+		if ((modemask & IPIPE_ENABLE_MASK) != 0) {
+			if (ipd != ipipe_current_domain) {
+				/* IRQ enable/disable state is domain-sensitive, so we may
+				   not change it for another domain. What is allowed
+				   however is forcing some domain to handle an interrupt
+				   source, by passing the proper 'ipd' descriptor which
+				   thus may be different from ipipe_current_domain. */
+				err = -EPERM;
+				goto unlock_and_exit;
+			}
+
+			__ipipe_enable_irq(irq);
+		}
+	}
+
+	err = 0;
+
+      unlock_and_exit:
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return err;
+}
+
+/* ipipe_control_irq() -- Change modes of a pipelined interrupt for
+ * the current domain. */
+
+int ipipe_control_irq(unsigned irq, unsigned clrmask, unsigned setmask)
+{
+	struct ipipe_domain *ipd;
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	ipd = ipipe_current_domain;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (ipd->irqs[irq].handler == NULL)
+		setmask &= ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	if ((setmask & IPIPE_STICKY_MASK) != 0)
+		setmask |= IPIPE_HANDLE_MASK;
+
+	if ((clrmask & (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK)) != 0)	/* If one goes, both go. */
+		clrmask |= (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	ipd->irqs[irq].control &= ~clrmask;
+	ipd->irqs[irq].control |= setmask;
+
+	if ((setmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_enable_irq(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_disable_irq(irq);
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+/* __ipipe_dispatch_event() -- Low-level event dispatcher. */
+
+int fastcall __ipipe_dispatch_event (unsigned event, void *data)
+{
+	struct ipipe_domain *start_domain, *this_domain, *next_domain;
+	ipipe_event_handler_t evhand;
+	struct list_head *pos, *npos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+	int propagate = 1;
+
+	ipipe_lock_cpu(flags);
+
+	start_domain = this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	list_for_each_safe(pos,npos,&__ipipe_pipeline) {
+
+		/*
+		 * Note: Domain migration may occur while running
+		 * event or interrupt handlers, in which case the
+		 * current register set is going to be recycled for a
+		 * different domain than the initiating one. We do
+		 * care for that, always tracking the current domain
+		 * descriptor upon return from those handlers.
+		 */
+		next_domain = list_entry(pos,struct ipipe_domain,p_link);
+
+		/*
+		 * Keep a cached copy of the handler's address since
+		 * ipipe_catch_event() may clear it under our feet.
+		 */
+
+		evhand = next_domain->evhand[event];
+
+		if (evhand != NULL) {
+			per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+			next_domain->cpudata[cpuid].evsync |= (1LL << event);
+			ipipe_unlock_cpu(flags);
+			propagate = !evhand(event,start_domain,data);
+			ipipe_lock_cpu(flags);
+			next_domain->cpudata[cpuid].evsync &= ~(1LL << event);
+			if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+				this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+		}
+
+		if (next_domain != ipipe_root_domain &&	/* NEVER sync the root stage here. */
+		    next_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) {
+			per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			ipipe_load_cpuid();
+			if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+				this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+		}
+
+		per_cpu(ipipe_percpu_domain, cpuid) = this_domain;
+
+		if (next_domain == this_domain || !propagate)
+			break;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return !propagate;
+}
+
+/*
+ * __ipipe_dispatch_wired -- Wired interrupt dispatcher. Wired
+ * interrupts are immediately and unconditionally delivered to the
+ * domain heading the pipeline upon receipt, and such domain must have
+ * been registered as an invariant head for the system (priority ==
+ * IPIPE_HEAD_PRIORITY). The motivation for using wired interrupts is
+ * to get an extra-fast dispatching path for those IRQs, by relying on
+ * a straightforward logic based on assumptions that must always be
+ * true for invariant head domains.  The following assumptions are
+ * made when dealing with such interrupts:
+ *
+ * 1- Wired interrupts are purely dynamic, i.e. the decision to
+ * propagate them down the pipeline must be done from the head domain
+ * ISR.
+ * 2- Wired interrupts cannot be shared or sticky.
+ * 3- The root domain cannot be an invariant pipeline head, in
+ * consequence of what the root domain cannot handle wired
+ * interrupts.
+ * 4- Wired interrupts must have a valid acknowledge handler for the
+ * head domain (if needed), and in any case, must not rely on handlers
+ * provided by lower priority domains during the acknowledge cycle
+ * (see __ipipe_handle_irq).
+ *
+ * Called with hw interrupts off.
+ */
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq)
+{
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *old;
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+	cpudata = &head->cpudata[cpuid];
+	cpudata->irq_counters[irq].total_hits++;
+
+	if (test_bit(IPIPE_LOCK_FLAG, &head->irqs[irq].control)) {
+		/* If we can't process this IRQ right now, we must
+		 * mark it as pending, so that it will get played
+		 * during normal log sync when the corresponding
+		 * interrupt source is eventually unlocked. */
+		cpudata->irq_counters[irq].pending_hits++;
+		return 0;
+	}
+
+	if (test_bit(IPIPE_STALL_FLAG, &cpudata->status)) {
+		cpudata->irq_counters[irq].pending_hits++;
+		__ipipe_set_irq_bit(head, cpuid, irq);
+		return 0;
+	}
+
+	old = per_cpu(ipipe_percpu_domain, cpuid);
+	per_cpu(ipipe_percpu_domain, cpuid) = head; /* Switch to the head domain. */
+
+	__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+	head->irqs[irq].handler(irq,head->irqs[irq].cookie); /* Call the ISR. */
+	__ipipe_run_irqtail();
+	__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+	/* We expect the caller to start a complete pipeline walk upon
+	 * return, so that propagated interrupts will get played. */
+
+	if (per_cpu(ipipe_percpu_domain, cpuid) == head)
+		per_cpu(ipipe_percpu_domain, cpuid) = old; /* Back to the preempted domain. */
+
+	return 1;
+}
+
+/*
+ * __ipipe_sync_stage() -- Flush the pending IRQs for the current
+ * domain (and processor). This routine flushes the interrupt log
+ * (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+ * more on the deferred interrupt scheme). Every interrupt that
+ * occurred while the pipeline was stalled gets played. WARNING:
+ * callers on SMP boxen should always check for CPU migration on
+ * return of this routine. One can control the kind of interrupts
+ * which are going to be sync'ed using the syncmask
+ * parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+ * plays virtual interrupts only.
+ *
+ * This routine must be called with hw interrupts off.
+ */
+void fastcall __ipipe_sync_stage(unsigned long syncmask)
+{
+	unsigned long mask, submask;
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *ipd;
+	ipipe_declare_cpuid;
+	int level, rank;
+	unsigned irq;
+
+	ipipe_load_cpuid();
+	ipd = per_cpu(ipipe_percpu_domain, cpuid);
+	cpudata = &ipd->cpudata[cpuid];
+
+	if (__test_and_set_bit(IPIPE_SYNC_FLAG, &cpudata->status))
+		return;
+
+	/*
+	 * The policy here is to keep the dispatching code interrupt-free
+	 * by stalling the current stage. If the upper domain handler
+	 * (which we call) wants to re-enable interrupts while in a safe
+	 * portion of the code (e.g. SA_INTERRUPT flag unset for Linux's
+	 * sigaction()), it will have to unstall (then stall again before
+	 * returning to us!) the stage when it sees fit.
+	 */
+	while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0) {
+		level = __ipipe_ffnz(mask);
+
+		while ((submask = cpudata->irq_pending_lo[level]) != 0) {
+			rank = __ipipe_ffnz(submask);
+			irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+			if (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control)) {
+				__clear_bit(rank, &cpudata->irq_pending_lo[level]);
+				continue;
+			}
+
+			if (--cpudata->irq_counters[irq].pending_hits == 0) {
+				__clear_bit(rank, &cpudata->irq_pending_lo[level]);
+				if (cpudata->irq_pending_lo[level] == 0)
+					__clear_bit(level, &cpudata->irq_pending_hi);
+			}
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			if (ipd == ipipe_root_domain)
+				trace_hardirqs_off();
+
+			__ipipe_run_isr(ipd, irq, cpuid);
+#ifdef CONFIG_SMP
+			{
+				int _cpuid = ipipe_processor_id();
+
+				if (_cpuid != cpuid) {	/* Handle CPU migration. */
+					/*
+					 * We expect any domain to clear the SYNC bit each
+					 * time it switches in a new task, so that preemptions
+					 * and/or CPU migrations (in the SMP case) over the
+					 * ISR do not lock out the log syncer for some
+					 * indefinite amount of time. In the Linux case,
+					 * schedule() handles this (see kernel/sched.c). For
+					 * this reason, we don't bother clearing it here for
+					 * the source CPU in the migration handling case,
+					 * since it must have scheduled another task in by
+					 * now.
+					 */
+					cpuid = _cpuid;
+					cpudata = &ipd->cpudata[cpuid];
+					__set_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+				}
+			}
+#endif	/* CONFIG_SMP */
+			if (ipd == ipipe_root_domain &&
+			    test_bit(IPIPE_STALL_FLAG, &cpudata->status))
+				trace_hardirqs_on();
+
+			__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* ipipe_register_domain() -- Link a new domain to the pipeline. */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr)
+{
+	struct list_head *pos;
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may register a new domain.\n");
+		return -EPERM;
+	}
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY &&
+	    test_bit(IPIPE_AHEAD_FLAG,&__ipipe_pipeline_head()->flags))
+		return -EAGAIN;	/* Cannot override current head. */
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+		if (_ipd->domid == attr->domid)
+			break;
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (pos != &__ipipe_pipeline)
+		/* A domain with the given id already exists -- fail. */
+		return -EBUSY;
+
+	ipd->name = attr->name;
+	ipd->domid = attr->domid;
+	ipd->pdd = attr->pdd;
+	ipd->flags = 0;
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY) {
+		ipd->priority = INT_MAX;
+		__set_bit(IPIPE_AHEAD_FLAG,&ipd->flags);
+	}
+	else
+		ipd->priority = attr->priority;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_add_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+		if (ipd->priority > _ipd->priority)
+			break;
+	}
+
+	list_add_tail(&ipd->p_link, pos);
+
+	ipipe_critical_exit(flags);
+
+	printk(KERN_WARNING "I-pipe: Domain %s registered.\n", ipd->name);
+
+	/*
+	 * Finally, allow the new domain to perform its initialization
+	 * chores.
+	 */
+
+	if (attr->entry != NULL) {
+		ipipe_declare_cpuid;
+
+		ipipe_lock_cpu(flags);
+
+		per_cpu(ipipe_percpu_domain, cpuid) = ipd;
+		attr->entry();
+		per_cpu(ipipe_percpu_domain, cpuid) = ipipe_root_domain;
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,
+			      &ipipe_root_domain->cpudata[cpuid].status))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		ipipe_unlock_cpu(flags);
+	}
+
+	return 0;
+}
+
+/* ipipe_unregister_domain() -- Remove a domain from the pipeline. */
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd)
+{
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may unregister a domain.\n");
+		return -EPERM;
+	}
+
+	if (ipd == ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Cannot unregister the root domain.\n");
+		return -EPERM;
+	}
+#ifdef CONFIG_SMP
+	{
+		int nr_cpus = num_online_cpus(), _cpuid;
+		unsigned irq;
+
+		/*
+		 * In the SMP case, wait for the logged events to drain on
+		 * other processors before eventually removing the domain
+		 * from the pipeline.
+		 */
+
+		ipipe_unstall_pipeline_from(ipd);
+
+		flags = ipipe_critical_enter(NULL);
+
+		for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+			clear_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control);
+			clear_bit(IPIPE_STICKY_FLAG, &ipd->irqs[irq].control);
+			set_bit(IPIPE_PASS_FLAG, &ipd->irqs[irq].control);
+		}
+
+		ipipe_critical_exit(flags);
+
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+				while (ipd->cpudata[_cpuid].irq_counters[irq].pending_hits > 0)
+					cpu_relax();
+	}
+#endif	/* CONFIG_SMP */
+
+	mutex_lock(&ipd->mutex);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_remove_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	/*
+	 * Simply remove the domain from the pipeline and we are almost done.
+	 */
+
+	flags = ipipe_critical_enter(NULL);
+	list_del_init(&ipd->p_link);
+	ipipe_critical_exit(flags);
+
+	__ipipe_cleanup_domain(ipd);
+
+	mutex_unlock(&ipd->mutex);
+
+	printk(KERN_WARNING "I-pipe: Domain %s unregistered.\n", ipd->name);
+
+	return 0;
+}
+
+/*
+ * ipipe_propagate_irq() -- Force a given IRQ propagation on behalf of
+ * a running interrupt handler to the next domain down the pipeline.
+ * ipipe_schedule_irq() -- Does almost the same as above, but attempts
+ * to pend the interrupt for the current domain first.
+ */
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head)
+{
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	ipipe_lock_cpu(flags);
+
+	ln = head;
+
+	while (ln != &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+			list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control)) {
+			ipd->cpudata[cpuid].irq_counters[irq].total_hits++;
+			ipd->cpudata[cpuid].irq_counters[irq].pending_hits++;
+			__ipipe_set_irq_bit(ipd, cpuid, irq);
+			ipipe_unlock_cpu(flags);
+			return 1;
+		}
+
+		ln = ipd->p_link.next;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return 0;
+}
+
+/* ipipe_free_virq() -- Release a virtual/soft interrupt. */
+
+int ipipe_free_virq(unsigned virq)
+{
+	if (!ipipe_virtual_irq_p(virq))
+		return -EINVAL;
+
+	clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map);
+
+	return 0;
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr)
+{
+	attr->name = "anon";
+	attr->domid = 1;
+	attr->entry = NULL;
+	attr->priority = IPIPE_ROOT_PRIO;
+	attr->pdd = NULL;
+}
+
+/*
+ * ipipe_catch_event() -- Interpose or remove an event handler for a
+ * given domain.
+ */
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler)
+{
+	ipipe_event_handler_t old_handler;
+	unsigned long flags;
+	int self = 0, cpuid;
+
+	if (event & IPIPE_EVENT_SELF) {
+		event &= ~IPIPE_EVENT_SELF;
+		self = 1;
+	}
+
+	if (event >= IPIPE_NR_EVENTS)
+		return NULL;
+
+	flags = ipipe_critical_enter(NULL);
+
+	if (!(old_handler = xchg(&ipd->evhand[event],handler)))	{
+		if (handler) {
+			if (self)
+				ipd->evself |= (1LL << event);
+			else
+				__ipipe_event_monitors[event]++;
+		}
+	}
+	else if (!handler) {
+		if (ipd->evself & (1LL << event))
+			ipd->evself &= ~(1LL << event);
+		else
+			__ipipe_event_monitors[event]--;
+	} else if ((ipd->evself & (1LL << event)) && !self) {
+			__ipipe_event_monitors[event]++;
+			ipd->evself &= ~(1LL << event);
+	} else if (!(ipd->evself & (1LL << event)) && self) {
+			__ipipe_event_monitors[event]--;
+			ipd->evself |= (1LL << event);
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (!handler && ipipe_root_domain_p) {
+		/*
+		 * If we cleared a handler on behalf of the root
+		 * domain, we have to wait for any current invocation
+		 * to drain, since our caller might subsequently unmap
+		 * the target domain. To this aim, this code
+		 * synchronizes with __ipipe_dispatch_event(),
+		 * guaranteeing that either the dispatcher sees a null
+		 * handler in which case it discards the invocation
+		 * (which also prevents from entering a livelock), or
+		 * finds a valid handler and calls it. Symmetrically,
+		 * ipipe_catch_event() ensures that the called code
+		 * won't be unmapped under our feet until the event
+		 * synchronization flag is cleared for the given event
+		 * on all CPUs.
+		 */
+
+		for_each_online_cpu(cpuid) {
+			while (ipd->cpudata[cpuid].evsync & (1LL << event))
+				schedule_timeout_interruptible(HZ / 50);
+		}
+	}
+
+	return old_handler;
+}
+
+cpumask_t ipipe_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+{
+#ifdef CONFIG_SMP
+	if (irq >= IPIPE_NR_XIRQS)
+		/* Allow changing affinity of external IRQs only. */
+		return CPU_MASK_NONE;
+
+	if (num_online_cpus() > 1)
+		return __ipipe_set_irq_affinity(irq,cpumask);
+#endif /* CONFIG_SMP */
+
+	return CPU_MASK_NONE;
+}
+
+int fastcall ipipe_send_ipi (unsigned ipi, cpumask_t cpumask)
+
+{
+#ifdef CONFIG_SMP
+	return __ipipe_send_ipi(ipi,cpumask);
+#else /* !CONFIG_SMP */
+	return -EINVAL;
+#endif /* CONFIG_SMP */
+}
+
+int ipipe_alloc_ptdkey (void)
+{
+	unsigned long flags;
+	int key = -1;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (__ipipe_ptd_key_count < IPIPE_ROOT_NPTDKEYS) {
+		key = ffz(__ipipe_ptd_key_map);
+		set_bit(key,&__ipipe_ptd_key_map);
+		__ipipe_ptd_key_count++;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return key;
+}
+
+int ipipe_free_ptdkey (int key)
+{
+	unsigned long flags;
+
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (test_and_clear_bit(key,&__ipipe_ptd_key_map))
+		__ipipe_ptd_key_count--;
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return 0;
+}
+
+int fastcall ipipe_set_ptd (int key, void *value)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	current->ptd[key] = value;
+
+	return 0;
+}
+
+void fastcall *ipipe_get_ptd (int key)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return NULL;
+
+	return current->ptd[key];
+}
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *ipipe_proc_root;
+
+static int __ipipe_version_info_proc(char *page,
+				     char **start,
+				     off_t off, int count, int *eof, void *data)
+{
+	int len = sprintf(page, "%s\n", IPIPE_VERSION_STRING);
+
+	len -= off;
+
+	if (len <= off + count)
+		*eof = 1;
+
+	*start = page + off;
+
+	if(len > count)
+		len = count;
+
+	if(len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_common_info_show(struct seq_file *p, void *data)
+{
+	struct ipipe_domain *ipd = (struct ipipe_domain *)p->private;
+	char handling, stickiness, lockbit, exclusive, virtuality;
+
+	unsigned long ctlbits;
+	unsigned irq;
+
+	seq_printf(p, "       +----- Handling ([A]ccepted, [G]rabbed, [W]ired, [D]iscarded)\n");
+	seq_printf(p, "       |+---- Sticky\n");
+	seq_printf(p, "       ||+--- Locked\n");
+	seq_printf(p, "       |||+-- Exclusive\n");
+	seq_printf(p, "       ||||+- Virtual\n");
+	seq_printf(p, "[IRQ]  |||||\n");
+
+	mutex_lock(&ipd->mutex);
+
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+		/* Remember to protect against
+		 * ipipe_virtual_irq/ipipe_control_irq if more fields
+		 * get involved. */
+		ctlbits = ipd->irqs[irq].control;
+
+		if (irq >= IPIPE_NR_XIRQS && !ipipe_virtual_irq_p(irq))
+			/*
+			 * There might be a hole between the last external
+			 * IRQ and the first virtual one; skip it.
+			 */
+			continue;
+
+		if (ipipe_virtual_irq_p(irq)
+		    && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))
+			/* Non-allocated virtual IRQ; skip it. */
+			continue;
+
+		/*
+		 * Statuses are as follows:
+		 * o "accepted" means handled _and_ passed down the pipeline.
+		 * o "grabbed" means handled, but the interrupt might be
+		 * terminated _or_ passed down the pipeline depending on
+		 * what the domain handler asks for to the I-pipe.
+		 * o "wired" is basically the same as "grabbed", except that
+		 * the interrupt is unconditionally delivered to an invariant
+		 * pipeline head domain.
+		 * o "passed" means unhandled by the domain but passed
+		 * down the pipeline.
+		 * o "discarded" means unhandled and _not_ passed down the
+		 * pipeline. The interrupt merely disappears from the
+		 * current domain down to the end of the pipeline.
+		 */
+		if (ctlbits & IPIPE_HANDLE_MASK) {
+			if (ctlbits & IPIPE_PASS_MASK)
+				handling = 'A';
+			else if (ctlbits & IPIPE_WIRED_MASK)
+				handling = 'W';
+			else
+				handling = 'G';
+		} else if (ctlbits & IPIPE_PASS_MASK)
+			/* Do not output if no major action is taken. */
+			continue;
+		else
+			handling = 'D';
+
+		if (ctlbits & IPIPE_STICKY_MASK)
+			stickiness = 'S';
+		else
+			stickiness = '.';
+
+		if (ctlbits & IPIPE_LOCK_MASK)
+			lockbit = 'L';
+		else
+			lockbit = '.';
+
+		if (ctlbits & IPIPE_EXCLUSIVE_MASK)
+			exclusive = 'X';
+		else
+			exclusive = '.';
+
+		if (ipipe_virtual_irq_p(irq))
+			virtuality = 'V';
+		else
+			virtuality = '.';
+
+		seq_printf(p, " %3u:  %c%c%c%c%c\n",
+			     irq, handling, stickiness, lockbit, exclusive, virtuality);
+	}
+
+	seq_printf(p, "[Domain info]\n");
+
+	seq_printf(p, "id=0x%.8x\n", ipd->domid);
+
+	if (test_bit(IPIPE_AHEAD_FLAG,&ipd->flags))
+		seq_printf(p, "priority=topmost\n");
+	else
+		seq_printf(p, "priority=%d\n", ipd->priority);
+
+	mutex_unlock(&ipd->mutex);
+
+	return 0;
+}
+
+static int __ipipe_common_info_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, __ipipe_common_info_show, PROC_I(inode)->pde->data);
+}
+
+static struct file_operations __ipipe_info_proc_ops = {
+	.owner		= THIS_MODULE,
+	.open		= __ipipe_common_info_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd)
+{
+	struct proc_dir_entry *e = create_proc_entry(ipd->name, 0444, ipipe_proc_root);
+	if (e) {
+		e->proc_fops = &__ipipe_info_proc_ops;
+		e->data = (void*) ipd;
+	}
+}
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd)
+{
+	remove_proc_entry(ipd->name,ipipe_proc_root);
+}
+
+void __init ipipe_init_proc(void)
+{
+	ipipe_proc_root = create_proc_entry("ipipe",S_IFDIR, 0);
+	create_proc_read_entry("version",0444,ipipe_proc_root,&__ipipe_version_info_proc,NULL);
+	__ipipe_add_domain_proc(ipipe_root_domain);
+
+	__ipipe_init_tracer();
+}
+
+#endif	/* CONFIG_PROC_FS */
+
+EXPORT_SYMBOL(ipipe_virtualize_irq);
+EXPORT_SYMBOL(ipipe_control_irq);
+EXPORT_SYMBOL(ipipe_suspend_domain);
+EXPORT_SYMBOL(ipipe_alloc_virq);
+EXPORT_PER_CPU_SYMBOL(ipipe_percpu_domain);
+EXPORT_SYMBOL(ipipe_root);
+EXPORT_SYMBOL(ipipe_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_restore_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_head);
+EXPORT_SYMBOL(__ipipe_restore_pipeline_head);
+EXPORT_SYMBOL(__ipipe_unstall_root);
+EXPORT_SYMBOL(__ipipe_stall_root);
+EXPORT_SYMBOL(__ipipe_restore_root);
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+EXPORT_SYMBOL(__ipipe_test_root);
+EXPORT_SYMBOL(__ipipe_dispatch_event);
+EXPORT_SYMBOL(__ipipe_pipeline);
+EXPORT_SYMBOL(ipipe_register_domain);
+EXPORT_SYMBOL(ipipe_unregister_domain);
+EXPORT_SYMBOL(ipipe_free_virq);
+EXPORT_SYMBOL(ipipe_init_attr);
+EXPORT_SYMBOL(ipipe_catch_event);
+EXPORT_SYMBOL(ipipe_alloc_ptdkey);
+EXPORT_SYMBOL(ipipe_free_ptdkey);
+EXPORT_SYMBOL(ipipe_set_ptd);
+EXPORT_SYMBOL(ipipe_get_ptd);
+EXPORT_SYMBOL(ipipe_set_irq_affinity);
+EXPORT_SYMBOL(ipipe_send_ipi);
+EXPORT_SYMBOL(__ipipe_schedule_irq);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Kconfig linux-2.6.19.patched/kernel/ipipe/Kconfig
--- linux-2.6.19.at91/kernel/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Kconfig	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,6 @@
+config IPIPE
+	bool "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Kconfig.debug linux-2.6.19.patched/kernel/ipipe/Kconfig.debug
--- linux-2.6.19.at91/kernel/ipipe/Kconfig.debug	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Kconfig.debug	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,69 @@
+config IPIPE_DEBUG
+	bool "I-pipe debugging"
+	depends on IPIPE
+
+config IPIPE_TRACE
+	bool "Latency tracing"
+	depends on IPIPE_DEBUG
+	select FRAME_POINTER
+	select KALLSYMS
+	select PROC_FS
+	---help---
+	  Activate this option if you want to use per-function tracing of
+	  the kernel. The tracer will collect data via instrumentation
+	  features like the one below or with the help of explicite calls
+	  of ipipe_trace_xxx(). See include/linux/ipipe_trace.h for the
+	  in-kernel tracing API. The collected data and runtime control
+	  is available via /proc/ipipe/trace/*.
+
+config IPIPE_TRACE_ENABLE
+	bool "Enable tracing on boot"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  Disable this option if you want to arm the tracer after booting
+	  manually ("echo 1 > /proc/ipipe/tracer/enable"). This can reduce
+	  boot time on slow embedded devices due to the tracer overhead.
+
+config IPIPE_TRACE_MCOUNT
+	bool "Instrument function entries"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  When enabled, records every kernel function entry in the tracer
+	  log. While this slows down the system noticeably, it provides
+	  the highest level of information about the flow of events.
+	  However, it can be switch off in order to record only explicit
+	  I-pipe trace points.
+
+config IPIPE_TRACE_IRQSOFF
+	bool "Trace IRQs-off times"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  Activate this option if I-pipe shall trace the longest path
+	  with hard-IRQs switched off.
+
+config IPIPE_TRACE_SHIFT
+	int "Depth of trace log (14 => 16Kpoints, 15 => 32Kpoints)"
+	range 10 18
+	default 14
+	depends on IPIPE_TRACE
+	---help---
+	  The number of trace points to hold tracing data for each
+	  trace path, as a power of 2.
+
+config IPIPE_TRACE_VMALLOC
+	bool "Use vmalloc'ed trace buffer"
+	depends on IPIPE_TRACE
+	---help---
+	  Instead of reserving static kernel data, the required buffer
+	  is allocated via vmalloc during boot-up when this option is
+	  enabled. This can help to start systems that are low on memory,
+	  but it slightly degrades overall performance. Try this option
+	  when a traced kernel hangs unexpectedly at boot time.
+
+config IPIPE_TRACE_ENABLE_VALUE
+	int
+	default 0 if !IPIPE_TRACE_ENABLE
+	default 1 if IPIPE_TRACE_ENABLE
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Makefile linux-2.6.19.patched/kernel/ipipe/Makefile
--- linux-2.6.19.at91/kernel/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_IPIPE)	+= core.o
+obj-$(CONFIG_IPIPE_TRACE) += tracer.o
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/tracer.c linux-2.6.19.patched/kernel/ipipe/tracer.c
--- linux-2.6.19.at91/kernel/ipipe/tracer.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/tracer.c	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,1275 @@
+/* -*- linux-c -*-
+ * kernel/ipipe/tracer.c
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005, 2006 Jan Kiszka.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/vmalloc.h>
+#include <linux/utsrelease.h>
+#include <linux/ipipe_trace.h>
+#include <asm/uaccess.h>
+
+#define IPIPE_TRACE_PATHS           4 /* <!> Do not lower below 3 */
+#define IPIPE_DEFAULT_ACTIVE        0
+#define IPIPE_DEFAULT_MAX           1
+#define IPIPE_DEFAULT_FROZEN        2
+
+#define IPIPE_TRACE_POINTS          (1 << CONFIG_IPIPE_TRACE_SHIFT)
+#define WRAP_POINT_NO(point)        ((point) & (IPIPE_TRACE_POINTS-1))
+
+#define IPIPE_DEFAULT_PRE_TRACE     10
+#define IPIPE_DEFAULT_POST_TRACE    10
+#define IPIPE_DEFAULT_BACK_TRACE    30
+
+#define IPIPE_DELAY_NOTE            1000  /* in nanoseconds */
+#define IPIPE_DELAY_WARN            10000 /* in nanoseconds */
+
+#define IPIPE_TFLG_NMI_LOCK         0x0001
+#define IPIPE_TFLG_NMI_HIT          0x0002
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
+#define IPIPE_TFLG_CURRDOM_SHIFT    10   /* bits 10..11: current domain */
+#define IPIPE_TFLG_CURRDOM_MASK     0x0C00
+#define IPIPE_TFLG_DOMSTATE_SHIFT   12   /* bits 12..15: domain stalled? */
+#define IPIPE_TFLG_DOMSTATE_BITS    3
+
+#define IPIPE_TFLG_DOMAIN_STALLED(point, n) \
+	(point->flags & (1 << (n + IPIPE_TFLG_DOMSTATE_SHIFT)))
+#define IPIPE_TFLG_CURRENT_DOMAIN(point) \
+	((point->flags & IPIPE_TFLG_CURRDOM_MASK) >> IPIPE_TFLG_CURRDOM_SHIFT)
+
+
+struct ipipe_trace_point{
+	short type;
+	short flags;
+	unsigned long eip;
+	unsigned long parent_eip;
+	unsigned long v;
+	unsigned long long timestamp;
+};
+
+struct ipipe_trace_path{
+	volatile int flags;
+	int dump_lock; /* separated from flags due to cross-cpu access */
+	int trace_pos; /* next point to fill */
+	int begin, end; /* finalised path begin and end */
+	int post_trace; /* non-zero when in post-trace phase */
+	unsigned long long length; /* max path length in cycles */
+	unsigned long nmi_saved_eip; /* for deferred requests from NMIs */
+	unsigned long nmi_saved_parent_eip;
+	unsigned long nmi_saved_v;
+	struct ipipe_trace_point point[IPIPE_TRACE_POINTS];
+} ____cacheline_aligned_in_smp;
+
+enum ipipe_trace_type
+{
+	IPIPE_TRACE_FUNC = 0,
+	IPIPE_TRACE_BEGIN,
+	IPIPE_TRACE_END,
+	IPIPE_TRACE_FREEZE,
+	IPIPE_TRACE_SPECIAL,
+	IPIPE_TRACE_PID,
+};
+
+#define IPIPE_TYPE_MASK             0x0007
+#define IPIPE_TYPE_BITS             3
+
+
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+
+static struct ipipe_trace_path *trace_paths[NR_CPUS];
+
+#else /* !CONFIG_IPIPE_TRACE_VMALLOC */
+
+static struct ipipe_trace_path trace_paths[NR_CPUS][IPIPE_TRACE_PATHS] =
+	{ [0 ... NR_CPUS-1] =
+		{ [0 ... IPIPE_TRACE_PATHS-1] =
+			{ .begin = -1, .end = -1 }
+		}
+	};
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+
+int ipipe_trace_enable = 0;
+
+static int active_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_ACTIVE };
+static int max_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_MAX };
+static int frozen_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_FROZEN };
+static IPIPE_DEFINE_SPINLOCK(global_path_lock);
+static int pre_trace = IPIPE_DEFAULT_PRE_TRACE;
+static int post_trace = IPIPE_DEFAULT_POST_TRACE;
+static int back_trace = IPIPE_DEFAULT_BACK_TRACE;
+static int verbose_trace;
+static unsigned long trace_overhead;
+
+static DEFINE_MUTEX(out_mutex);
+static struct ipipe_trace_path *print_path;
+static struct ipipe_trace_path *panic_path;
+static int print_pre_trace;
+static int print_post_trace;
+
+
+static long __ipipe_signed_tsc2us(long long tsc);
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point);
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip);
+
+
+static notrace void
+__ipipe_store_domain_states(struct ipipe_trace_point *point, int cpu_id)
+{
+	struct list_head *pos;
+	int i = 0;
+
+	list_for_each_prev(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpu_id].status))
+			point->flags |= 1 << (i + IPIPE_TFLG_DOMSTATE_SHIFT);
+
+		if (ipd == per_cpu(ipipe_percpu_domain, cpu_id))
+			point->flags |= i << IPIPE_TFLG_CURRDOM_SHIFT;
+
+		if (++i > IPIPE_TFLG_DOMSTATE_BITS)
+			break;
+	}
+}
+
+static notrace int __ipipe_get_free_trace_path(int old, int cpu_id)
+{
+	int new_active = old;
+	struct ipipe_trace_path *tp;
+
+	do {
+		if (++new_active == IPIPE_TRACE_PATHS)
+			new_active = 0;
+		tp = &trace_paths[cpu_id][new_active];
+	} while ((new_active == max_path[cpu_id]) ||
+	         (new_active == frozen_path[cpu_id]) ||
+	         tp->dump_lock);
+
+	return new_active;
+}
+
+static notrace void
+__ipipe_migrate_pre_trace(struct ipipe_trace_path *new_tp,
+                          struct ipipe_trace_path *old_tp, int old_pos)
+{
+	int i;
+
+	new_tp->trace_pos = pre_trace+1;
+
+	for (i = new_tp->trace_pos; i > 0; i--)
+		memcpy(&new_tp->point[WRAP_POINT_NO(new_tp->trace_pos-i)],
+		       &old_tp->point[WRAP_POINT_NO(old_pos-i)],
+		       sizeof(struct ipipe_trace_point));
+
+	/* mark the end (i.e. the point before point[0]) invalid */
+	new_tp->point[IPIPE_TRACE_POINTS-1].eip = 0;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_end(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	unsigned long long length;
+
+	/* do we have a new worst case? */
+	length = tp->point[tp->end].timestamp -
+	         tp->point[tp->begin].timestamp;
+	if (length > (trace_paths[cpu_id][max_path[cpu_id]]).length) {
+		/* we need protection here against other cpus trying
+		   to start a proc dump */
+		spin_lock(&global_path_lock);
+
+		/* active path holds new worst case */
+		tp->length = length;
+		max_path[cpu_id] = active;
+
+		/* find next unused trace path */
+		active = __ipipe_get_free_trace_path(active, cpu_id);
+
+		spin_unlock(&global_path_lock);
+
+		tp = &trace_paths[cpu_id][active];
+
+		/* migrate last entries for pre-tracing */
+		__ipipe_migrate_pre_trace(tp, old_tp, pos);
+	}
+
+	return tp;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_freeze(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	int i;
+
+	/* frozen paths have no core (begin=end) */
+	tp->begin = tp->end;
+
+	/* we need protection here against other cpus trying
+	 * to set their frozen path or to start a proc dump */
+	spin_lock(&global_path_lock);
+
+	frozen_path[cpu_id] = active;
+
+	/* find next unused trace path */
+	active = __ipipe_get_free_trace_path(active, cpu_id);
+
+	/* check if this is the first frozen path */
+	for_each_online_cpu(i) {
+		if ((i != cpu_id) &&
+		    (trace_paths[i][frozen_path[i]].end >= 0))
+			tp->end = -1;
+	}
+
+	spin_unlock(&global_path_lock);
+
+	tp = &trace_paths[cpu_id][active];
+
+	/* migrate last entries for pre-tracing */
+	__ipipe_migrate_pre_trace(tp, old_tp, pos);
+
+	return tp;
+}
+
+void notrace
+__ipipe_trace(enum ipipe_trace_type type, unsigned long eip,
+              unsigned long parent_eip, unsigned long v)
+{
+	struct ipipe_trace_path *tp, *old_tp;
+	int pos, next_pos, begin;
+	struct ipipe_trace_point *point;
+	unsigned long flags;
+	int cpu_id;
+
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+ restart:
+	tp = old_tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here starts a race window with NMIs - catched below */
+
+	/* check for NMI recursion */
+	if (unlikely(tp->flags & IPIPE_TFLG_NMI_LOCK)) {
+		tp->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* first freeze request from NMI context? */
+		if ((type == IPIPE_TRACE_FREEZE) &&
+		    !(tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)) {
+			/* save arguments and mark deferred freezing */
+			tp->flags |= IPIPE_TFLG_NMI_FREEZE_REQ;
+			tp->nmi_saved_eip = eip;
+			tp->nmi_saved_parent_eip = parent_eip;
+			tp->nmi_saved_v = v;
+		}
+		return; /* no need for restoring flags inside IRQ */
+	}
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (unlikely(tp != &trace_paths[cpu_id][active_path[cpu_id]])) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	/* get the point buffer */
+	pos = tp->trace_pos;
+	point = &tp->point[pos];
+
+	/* store all trace point data */
+	point->type = type;
+	point->flags = raw_irqs_disabled_flags(flags) ? IPIPE_TFLG_HWIRQ_OFF : 0;
+	point->eip = eip;
+	point->parent_eip = parent_eip;
+	point->v = v;
+	ipipe_read_tsc(point->timestamp);
+
+	__ipipe_store_domain_states(point, cpu_id);
+
+	/* forward to next point buffer */
+	next_pos = WRAP_POINT_NO(pos+1);
+	tp->trace_pos = next_pos;
+
+	/* only mark beginning if we haven't started yet */
+	begin = tp->begin;
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
+		tp->begin = pos;
+
+	/* end of critical path, start post-trace if not already started */
+	if (unlikely(type == IPIPE_TRACE_END) &&
+	    (begin >= 0) && !tp->post_trace)
+		tp->post_trace = post_trace + 1;
+
+	/* freeze only if the slot is free and we are not already freezing */
+	if (unlikely(type == IPIPE_TRACE_FREEZE) &&
+	    (trace_paths[cpu_id][frozen_path[cpu_id]].begin < 0) &&
+	    !(tp->flags & IPIPE_TFLG_FREEZING)) {
+		tp->post_trace = post_trace + 1;
+		tp->flags |= IPIPE_TFLG_FREEZING;
+	}
+
+	/* enforce end of trace in case of overflow */
+	if (unlikely(WRAP_POINT_NO(next_pos + 1) == begin)) {
+		tp->end = pos;
+		goto enforce_end;
+	}
+
+	/* stop tracing this path if we are in post-trace and
+	 *  a) that phase is over now or
+	 *  b) a new TRACE_BEGIN came in but we are not freezing this path */
+	if (unlikely((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
+	             ((type == IPIPE_TRACE_BEGIN) &&
+	              !(tp->flags & IPIPE_TFLG_FREEZING))))) {
+		/* store the path's end (i.e. excluding post-trace) */
+		tp->end = WRAP_POINT_NO(pos - post_trace + tp->post_trace);
+
+ enforce_end:
+		if (tp->flags & IPIPE_TFLG_FREEZING)
+			tp = __ipipe_trace_freeze(cpu_id, tp, pos);
+		else
+			tp = __ipipe_trace_end(cpu_id, tp, pos);
+
+		/* reset the active path, maybe already start a new one */
+		tp->begin = (type == IPIPE_TRACE_BEGIN) ?
+			WRAP_POINT_NO(tp->trace_pos - 1) : -1;
+		tp->end = -1;
+		tp->post_trace = 0;
+		tp->flags = 0;
+
+		/* update active_path not earlier to avoid races with NMIs */
+		active_path[cpu_id] = tp - trace_paths[cpu_id];
+	}
+
+	/* we still have old_tp and point,
+	 * let's reset NMI lock and check for catches */
+	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+	if (unlikely(old_tp->flags & IPIPE_TFLG_NMI_HIT)) {
+		/* well, this late tagging may not immediately be visible for
+		 * other cpus already dumping this path - a minor issue */
+		point->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* handle deferred freezing from NMI context */
+		if (old_tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+			__ipipe_trace(IPIPE_TRACE_FREEZE, old_tp->nmi_saved_eip,
+			              old_tp->nmi_saved_parent_eip,
+			              old_tp->nmi_saved_v);
+	}
+
+	local_irq_restore_hw_notrace(flags);
+}
+
+static unsigned long __ipipe_global_path_lock(void)
+{
+	unsigned long flags;
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	spin_lock_irqsave(&global_path_lock, flags);
+
+	cpu_id = ipipe_processor_id();
+ restart:
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here is small race window with NMIs - catched below */
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (tp != &trace_paths[cpu_id][active_path[cpu_id]]) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	return flags;
+}
+
+static void __ipipe_global_path_unlock(unsigned long flags)
+{
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	/* release spinlock first - it's not involved in the NMI issue */
+	spin_unlock(&global_path_lock);
+
+	cpu_id = ipipe_processor_id();
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+	/* handle deferred freezing from NMI context */
+	if (tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+		__ipipe_trace(IPIPE_TRACE_FREEZE, tp->nmi_saved_eip,
+		              tp->nmi_saved_parent_eip, tp->nmi_saved_v);
+
+	local_irq_restore_hw(flags);
+}
+
+void notrace ipipe_trace_begin(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_BEGIN, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_begin);
+
+void notrace ipipe_trace_end(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_END, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_end);
+
+void notrace ipipe_trace_freeze(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_FREEZE, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_freeze);
+
+void notrace ipipe_trace_special(unsigned char id, unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_SPECIAL | (id << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_special);
+
+void notrace ipipe_trace_pid(pid_t pid, short prio)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_PID | (prio << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, pid);
+}
+EXPORT_SYMBOL(ipipe_trace_pid);
+
+int ipipe_trace_max_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_online_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][max_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+int ipipe_trace_frozen_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_online_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
+void ipipe_trace_panic_freeze(void)
+{
+	unsigned long flags;
+	int cpu_id;
+
+	ipipe_trace_enable = 0;
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+
+	panic_path = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(ipipe_trace_panic_freeze);
+
+static void
+__ipipe_get_task_info(char *task_info, struct ipipe_trace_point *point,
+                      int trylock)
+{
+	struct task_struct *task = NULL;
+	char buf[8];
+	int i;
+	int locked = 1;
+
+	if (trylock && !read_trylock(&tasklist_lock))
+		locked = 0;
+	else
+		read_lock(&tasklist_lock);
+
+	if (locked)
+		task = find_task_by_pid((pid_t)point->v);
+
+	if (task)
+		strncpy(task_info, task->comm, 11);
+	else
+		strcpy(task_info, "-<?>-");
+
+	if (locked)
+		read_unlock(&tasklist_lock);
+
+	for (i = strlen(task_info); i < 11; i++)
+		task_info[i] = ' ';
+
+	sprintf(buf, " %d ", point->type >> IPIPE_TYPE_BITS);
+	strcpy(task_info + (11 - strlen(buf)), buf);
+}
+
+void ipipe_trace_panic_dump(void)
+{
+	int cnt = back_trace;
+	int start, pos;
+	char task_info[12];
+
+	printk("I-pipe tracer log (%d points):\n", cnt);
+
+	start = pos = WRAP_POINT_NO(panic_path->trace_pos-1);
+
+	while (cnt-- > 0) {
+		struct ipipe_trace_point *point = &panic_path->point[pos];
+		long time;
+		char buf[16];
+	       int i;
+
+	       printk(" %c", (point->flags & IPIPE_TFLG_HWIRQ_OFF) ?
+			      '|' : ' ');
+
+	       for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		       printk("%c",
+			      (IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			      (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				       '#' : '+') :
+			       (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				       '*' : ' '));
+
+		if (!point->eip)
+			printk("-<invalid>-\n");
+		else {
+			__ipipe_trace_point_type(buf, point);
+			printk(buf);
+
+			switch (point->type & IPIPE_TYPE_MASK) {
+				case IPIPE_TRACE_FUNC:
+					printk("           ");
+					break;
+
+				case IPIPE_TRACE_PID:
+					__ipipe_get_task_info(task_info,
+							      point, 1);
+					printk(task_info);
+					break;
+
+				default:
+					printk("0x%08lx ", point->v);
+			}
+
+			time = __ipipe_signed_tsc2us(point->timestamp -
+				panic_path->point[start].timestamp);
+			printk(" %5ld ", time);
+
+			__ipipe_print_symname(NULL, point->eip);
+			printk(" (");
+			__ipipe_print_symname(NULL, point->parent_eip);
+			printk(")\n");
+		}
+		pos = WRAP_POINT_NO(pos - 1);
+	}
+}
+EXPORT_SYMBOL(ipipe_trace_panic_dump);
+
+
+/* --- /proc output --- */
+
+static notrace int __ipipe_in_critical_trpath(long point_no)
+{
+	return ((WRAP_POINT_NO(point_no-print_path->begin) <
+	         WRAP_POINT_NO(print_path->end-print_path->begin)) ||
+	        ((print_path->end == print_path->begin) &&
+	         (WRAP_POINT_NO(point_no-print_path->end) >
+	          print_post_trace)));
+}
+
+static long __ipipe_signed_tsc2us(long long tsc)
+{
+        unsigned long long abs_tsc;
+        long us;
+
+	/* ipipe_tsc2us works on unsigned => handle sign separately */
+        abs_tsc = (tsc >= 0) ? tsc : -tsc;
+        us = ipipe_tsc2us(abs_tsc);
+        if (tsc < 0)
+                return -us;
+        else
+                return us;
+}
+
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point)
+{
+	switch (point->type & IPIPE_TYPE_MASK) {
+		case IPIPE_TRACE_FUNC:
+			strcpy(buf, "func    ");
+			break;
+
+		case IPIPE_TRACE_BEGIN:
+			strcpy(buf, "begin   ");
+			break;
+
+		case IPIPE_TRACE_END:
+			strcpy(buf, "end     ");
+			break;
+
+		case IPIPE_TRACE_FREEZE:
+			strcpy(buf, "freeze  ");
+			break;
+
+		case IPIPE_TRACE_SPECIAL:
+			sprintf(buf, "(0x%02x)  ",
+				point->type >> IPIPE_TYPE_BITS);
+			break;
+
+		case IPIPE_TRACE_PID:
+			sprintf(buf, "[%5d] ", (pid_t)point->v);
+			break;
+	}
+}
+
+static void
+__ipipe_print_pathmark(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	char mark = ' ';
+	int point_no = point - print_path->point;
+	int i;
+
+	if (print_path->end == point_no)
+		mark = '<';
+	else if (print_path->begin == point_no)
+		mark = '>';
+	else if (__ipipe_in_critical_trpath(point_no))
+		mark = ':';
+	seq_printf(m, "%c%c", mark,
+	           (point->flags & IPIPE_TFLG_HWIRQ_OFF) ? '|' : ' ');
+
+	if (!verbose_trace)
+		return;
+
+	for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		seq_printf(m, "%c",
+			(IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			    (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				'#' : '+') :
+			(IPIPE_TFLG_DOMAIN_STALLED(point, i) ? '*' : ' '));
+}
+
+static void
+__ipipe_print_delay(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	unsigned long delay = 0;
+	int next;
+	char *mark = "  ";
+
+	next = WRAP_POINT_NO(point+1 - print_path->point);
+
+	if (next != print_path->trace_pos)
+		delay = ipipe_tsc2ns(print_path->point[next].timestamp -
+		                     point->timestamp);
+
+	if (__ipipe_in_critical_trpath(point - print_path->point)) {
+		if (delay > IPIPE_DELAY_WARN)
+			mark = "! ";
+		else if (delay > IPIPE_DELAY_NOTE)
+			mark = "+ ";
+	}
+	seq_puts(m, mark);
+
+	if (verbose_trace)
+		seq_printf(m, "%3lu.%03lu%c ", delay/1000, delay%1000,
+		           (point->flags & IPIPE_TFLG_NMI_HIT) ? 'N' : ' ');
+	else
+		seq_puts(m, " ");
+}
+
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip)
+{
+	char namebuf[KSYM_NAME_LEN+1];
+	unsigned long size, offset;
+	const char *sym_name;
+	char *modname;
+
+	sym_name = kallsyms_lookup(eip, &size, &offset, &modname, namebuf);
+
+	/* printing to /proc? */
+	if (m) {
+		if (sym_name) {
+			if (verbose_trace) {
+				seq_printf(m, "%s+0x%lx", sym_name, offset);
+				if (modname)
+					seq_printf(m, " [%s]", modname);
+			} else
+				seq_puts(m, sym_name);
+		} else
+			seq_printf(m, "<%08lx>", eip);
+	} else {
+		/* panic dump */
+		if (sym_name) {
+			printk("%s+0x%lx", sym_name, offset);
+			if (modname)
+				printk(" [%s]", modname);
+		}
+	}
+}
+
+#if defined(CONFIG_XENO_OPT_DEBUG) || defined(CONFIG_DEBUG_PREEMPT)
+static void __ipipe_print_dbgwarning(struct seq_file *m)
+{
+	seq_puts(m, "\n******** WARNING ********\n"
+		"The following debugging options will increase the observed "
+		"latencies:\n"
+#ifdef CONFIG_XENO_OPT_DEBUG
+		" o CONFIG_XENO_OPT_DEBUG\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_XENO_OPT_DEBUG_QUEUES
+		" o CONFIG_XENO_OPT_DEBUG_QUEUES (very costly)\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_DEBUG_PREEMPT
+		" o CONFIG_DEBUG_PREEMPT\n"
+#endif /* CONFIG_DEBUG_PREEMPT */
+		"\n");
+}
+#else /* !WARN_ON_DEBUGGING_LATENCIES */
+# define __ipipe_print_dbgwarning(m)
+#endif /* WARN_ON_DEBUGGING_LATENCIES */
+
+static void __ipipe_print_headline(struct seq_file *m)
+{
+	seq_printf(m, "Calibrated minimum trace-point overhead: %lu.%03lu "
+		   "us\n\n", trace_overhead/1000, trace_overhead%1000);
+
+	if (verbose_trace) {
+		const char *name[4] = { [0 ... 3] = "<unused>" };
+		struct list_head *pos;
+		int i = 0;
+
+		list_for_each_prev(pos, &__ipipe_pipeline) {
+			struct ipipe_domain *ipd =
+				list_entry(pos, struct ipipe_domain, p_link);
+
+			name[i] = ipd->name;
+			if (++i > 3)
+				break;
+		}
+
+		seq_printf(m,
+		           " +----- Hard IRQs ('|': locked)\n"
+		           " |+---- %s\n"
+		           " ||+--- %s\n"
+		           " |||+-- %s\n"
+		           " ||||+- %s%s\n"
+		           " |||||                        +---------- "
+		               "Delay flag ('+': > %d us, '!': > %d us)\n"
+		           " |||||                        |        +- "
+		               "NMI noise ('N')\n"
+		           " |||||                        |        |\n"
+		           "      Type    User Val.   Time    Delay  Function "
+		               "(Parent)\n",
+		           name[3], name[2], name[1], name[0],
+		           name[0] ? " ('*': domain stalled, '+': current, "
+		               "'#': current+stalled)" : "",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+	} else
+		seq_printf(m,
+		           " +--------------- Hard IRQs ('|': locked)\n"
+		           " |             +- Delay flag "
+		               "('+': > %d us, '!': > %d us)\n"
+		           " |             |\n"
+		           "  Type     Time   Function (Parent)\n",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+}
+
+static void *__ipipe_max_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		unsigned long length_usecs;
+		int points, i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the longest of all per-cpu paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][max_path[i]];
+			if ((print_path == NULL) ||
+			    (path->length > print_path->length))
+				print_path = path;
+		}
+		print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		/* does this path actually contain data? */
+		if (print_path->end == print_path->begin)
+			return NULL;
+
+		/* number of points inside the critical path */
+		points = WRAP_POINT_NO(print_path->end-print_path->begin+1);
+
+		/* pre- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, pre-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = pre_trace;
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (points+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 1 - points -
+				print_post_trace;
+
+		length_usecs = ipipe_tsc2us(print_path->length);
+		seq_printf(m, "I-pipe worst-case tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Begin: %lld cycles, Trace Points: %d (-%d/+%d), "
+			"Length: %lu us\n",
+			print_path->point[print_path->begin].timestamp,
+			points, print_pre_trace, print_post_trace, length_usecs);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + n)];
+}
+
+static void *__ipipe_prtrace_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	loff_t n = ++*pos;
+
+	/* check if we are inside the trace range with the next entry */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + *pos)];
+}
+
+static void __ipipe_prtrace_stop(struct seq_file *m, void *p)
+{
+	if (print_path)
+		print_path->dump_lock = 0;
+	mutex_unlock(&out_mutex);
+}
+
+static int __ipipe_prtrace_show(struct seq_file *m, void *p)
+{
+	long time;
+	struct ipipe_trace_point *point = p;
+	char buf[16];
+
+	if (!point->eip) {
+		seq_puts(m, "-<invalid>-\n");
+		return 0;
+	}
+
+	__ipipe_print_pathmark(m, point);
+	__ipipe_trace_point_type(buf, point);
+	seq_puts(m, buf);
+	if (verbose_trace)
+		switch (point->type & IPIPE_TYPE_MASK) {
+			case IPIPE_TRACE_FUNC:
+				seq_puts(m, "           ");
+				break;
+
+			case IPIPE_TRACE_PID:
+				__ipipe_get_task_info(buf, point, 0);
+				seq_puts(m, buf);
+				break;
+
+			default:
+				seq_printf(m, "0x%08lx ", point->v);
+		}
+
+	time = __ipipe_signed_tsc2us(point->timestamp -
+		print_path->point[print_path->begin].timestamp);
+	seq_printf(m, "%5ld", time);
+
+	__ipipe_print_delay(m, point);
+	__ipipe_print_symname(m, point->eip);
+	seq_puts(m, " (");
+	__ipipe_print_symname(m, point->parent_eip);
+	seq_puts(m, ")\n");
+
+	return 0;
+}
+
+static struct seq_operations __ipipe_max_ptrace_ops = {
+	.start = __ipipe_max_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_max_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_max_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_max_reset(struct file *file, const char __user *pbuffer,
+                  size_t count, loff_t *data)
+{
+	mutex_lock(&out_mutex);
+	ipipe_trace_max_reset();
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_max_prtrace_fops = {
+	.open       = __ipipe_max_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_max_reset,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static void *__ipipe_frozen_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		int i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the first of all per-cpu frozen paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][frozen_path[i]];
+			if (path->end >= 0)
+				print_path = path;
+		}
+		if (print_path)
+			print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		if (!print_path)
+			return NULL;
+
+		/* back- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, back-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = back_trace-1; /* substract freeze point */
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (1+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 2 -
+				print_post_trace;
+
+		seq_printf(m, "I-pipe frozen back-tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------"
+			"------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Freeze: %lld cycles, Trace Points: %d (+%d)\n",
+			print_path->point[print_path->begin].timestamp,
+			print_pre_trace+1, print_post_trace);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= print_pre_trace + 1 + print_post_trace)
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin-
+	                                        print_pre_trace+n)];
+}
+
+static struct seq_operations __ipipe_frozen_ptrace_ops = {
+	.start = __ipipe_frozen_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_frozen_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_frozen_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_frozen_ctrl(struct file *file, const char __user *pbuffer,
+                    size_t count, loff_t *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, pbuffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	ipipe_trace_frozen_reset();
+	if (val > 0)
+		ipipe_trace_freeze(-1);
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_frozen_prtrace_fops = {
+	.open       = __ipipe_frozen_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_frozen_ctrl,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static int __ipipe_rd_proc_val(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%u\n", *(int *)data);
+	len -= off;
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_wr_proc_val(struct file *file, const char __user *buffer,
+                               unsigned long count, void *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, buffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	*(int *)data = val;
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+extern struct proc_dir_entry *ipipe_proc_root;
+
+static void __init
+__ipipe_create_trace_proc_val(struct proc_dir_entry *trace_dir,
+                              const char *name, int *value_ptr)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_entry(name, 0644, trace_dir);
+	if (entry) {
+		entry->data = value_ptr;
+		entry->read_proc = __ipipe_rd_proc_val;
+		entry->write_proc = __ipipe_wr_proc_val;
+		entry->owner = THIS_MODULE;
+	}
+}
+
+void __init __ipipe_init_tracer(void)
+{
+	struct proc_dir_entry *trace_dir;
+	struct proc_dir_entry *entry;
+	unsigned long long start, end, min = ULLONG_MAX;
+	int i;
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+	int cpu, path;
+
+	for_each_possible_cpu(cpu) {
+		trace_paths[cpu] = vmalloc(
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		if (!trace_paths) {
+			printk(KERN_ERR "I-pipe: "
+			       "insufficient memory for trace buffer.\n");
+			return;
+		}
+		memset(trace_paths[cpu], 0,
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		for (path = 0; path < IPIPE_TRACE_PATHS; path++) {
+			trace_paths[cpu][path].begin = -1;
+			trace_paths[cpu][path].end   = -1;
+		}
+	}
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+	ipipe_trace_enable = CONFIG_IPIPE_TRACE_ENABLE_VALUE;
+
+	/* Calculate minimum overhead of __ipipe_trace() */
+	local_irq_disable_hw();
+	for (i = 0; i < 100; i++) {
+		ipipe_read_tsc(start);
+		__ipipe_trace(IPIPE_TRACE_FUNC, __BUILTIN_RETURN_ADDRESS0,
+			      __BUILTIN_RETURN_ADDRESS1, 0);
+		ipipe_read_tsc(end);
+
+		end -= start;
+		if (end < min)
+			min = end;
+	}
+	local_irq_enable_hw();
+	trace_overhead = ipipe_tsc2ns(min);
+
+	trace_dir = create_proc_entry("trace", S_IFDIR, ipipe_proc_root);
+
+	entry = create_proc_entry("max", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_max_prtrace_fops;
+
+	entry = create_proc_entry("frozen", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_frozen_prtrace_fops;
+
+	__ipipe_create_trace_proc_val(trace_dir, "pre_trace_points",
+	                              &pre_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "post_trace_points",
+	                              &post_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "back_trace_points",
+	                              &back_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "verbose",
+	                              &verbose_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "enable",
+	                              &ipipe_trace_enable);
+}
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/irq/chip.c linux-2.6.19.patched/kernel/irq/chip.c
--- linux-2.6.19.at91/kernel/irq/chip.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/irq/chip.c	2007-04-04 11:52:06.000000000 +0200
@@ -308,7 +308,9 @@ handle_level_irq(unsigned int irq, struc
 	irqreturn_t action_ret;
 
 	spin_lock(&desc->lock);
+#ifndef CONFIG_IPIPE
 	mask_ack_irq(desc, irq);
+#endif /* CONFIG_IPIPE */
 
 	if (unlikely(desc->status & IRQ_INPROGRESS))
 		goto out_unlock;
@@ -431,8 +433,10 @@ handle_edge_irq(unsigned int irq, struct
 
 	kstat_cpu(cpu).irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	/* Start handling the irq */
 	desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	/* Mark the IRQ currently in progress.*/
 	desc->status |= IRQ_INPROGRESS;
@@ -472,6 +476,64 @@ out_unlock:
 	spin_unlock(&desc->lock);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_end_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	mask_ack_irq(desc, irq);
+}
+
+void fastcall __ipipe_end_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->unmask)
+		desc->chip->unmask(irq);
+}
+
+void fastcall __ipipe_ack_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_end_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->eoi(irq);
+}
+
+void fastcall __ipipe_ack_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_bad_irq(unsigned irq, struct irq_desc *desc)
+{
+	static int done;
+
+	handle_bad_irq(irq, desc);
+
+	if (!done) {
+		printk(KERN_WARNING "%s: unknown flow handler for IRQ %d\n",
+		       __FUNCTION__, irq);
+		done = 1;
+	}
+}
+
+void fastcall __ipipe_end_bad_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+#endif /* CONFIG_IPIPE */
+
 #ifdef CONFIG_SMP
 /**
  *	handle_percpu_IRQ - Per CPU local irq handler
@@ -487,8 +549,10 @@ handle_percpu_irq(unsigned int irq, stru
 
 	kstat_this_cpu.irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	if (desc->chip->ack)
 		desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
@@ -498,6 +562,22 @@ handle_percpu_irq(unsigned int irq, stru
 		desc->chip->eoi(irq);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->ack)
+		desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->eoi)
+		desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_IPIPE */
+
 #endif /* CONFIG_SMP */
 
 void
@@ -517,6 +597,34 @@ __set_irq_handler(unsigned int irq, irq_
 
 	if (!handle)
 		handle = handle_bad_irq;
+#ifdef CONFIG_IPIPE
+	else if (handle == &handle_simple_irq) {
+		desc->ipipe_ack = &__ipipe_ack_simple_irq;
+		desc->ipipe_end = &__ipipe_end_simple_irq;
+	}
+	else if (handle == &handle_level_irq) {
+		desc->ipipe_ack = &__ipipe_ack_level_irq;
+		desc->ipipe_end = &__ipipe_end_level_irq;
+	}
+	else if (handle == &handle_edge_irq) {
+		desc->ipipe_ack = &__ipipe_ack_edge_irq;
+		desc->ipipe_end = &__ipipe_end_edge_irq;
+	}
+	else if (handle == &handle_fasteoi_irq) {
+		desc->ipipe_ack = &__ipipe_ack_fasteoi_irq;
+		desc->ipipe_end = &__ipipe_end_fasteoi_irq;
+	}
+#ifdef CONFIG_SMP
+	else if (handle == &handle_percpu_irq) {
+		desc->ipipe_ack = &__ipipe_ack_percpu_irq;
+		desc->ipipe_end = &__ipipe_end_percpu_irq;
+	}
+#endif /* CONFIG_SMP */
+	else {
+		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+		desc->ipipe_end = &__ipipe_end_bad_irq;
+	}
+#endif /* CONFIG_IPIPE */
 
 	if (desc->chip == &no_irq_chip) {
 		printk(KERN_WARNING "Trying to install %sinterrupt handler "
@@ -541,6 +649,10 @@ __set_irq_handler(unsigned int irq, irq_
 		}
 		desc->status |= IRQ_DISABLED;
 		desc->depth = 1;
+#ifdef CONFIG_IPIPE
+		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+		desc->ipipe_end = &__ipipe_end_bad_irq;
+#endif /* CONFIG_IPIPE */
 	}
 	desc->handle_irq = handle;
 	desc->name = name;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/Makefile linux-2.6.19.patched/kernel/Makefile
--- linux-2.6.19.at91/kernel/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -48,6 +48,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_RELAY) += relay.o
+obj-$(CONFIG_IPIPE) += ipipe/
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/printk.c linux-2.6.19.patched/kernel/printk.c
--- linux-2.6.19.at91/kernel/printk.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/printk.c	2007-04-04 11:52:06.000000000 +0200
@@ -489,6 +489,78 @@ static int have_callable_console(void)
  * printf(3)
  */
 
+#ifdef CONFIG_IPIPE
+
+static ipipe_spinlock_t __ipipe_printk_lock = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static int __ipipe_printk_fill;
+
+static char __ipipe_printk_buf[__LOG_BUF_LEN];
+
+void __ipipe_flush_printk (unsigned virq, void *cookie)
+{
+	char *p = __ipipe_printk_buf;
+	int len, lmax, out = 0;
+	unsigned long flags;
+
+	goto start;
+
+	do {
+		spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+ start:
+		lmax = __ipipe_printk_fill;
+		while (out < lmax) {
+			len = strlen(p) + 1;
+			printk("%s",p);
+			p += len;
+			out += len;
+		}
+		spin_lock_irqsave(&__ipipe_printk_lock, flags);
+	}
+	while (__ipipe_printk_fill != lmax);
+
+	__ipipe_printk_fill = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+}
+
+asmlinkage int printk(const char *fmt, ...)
+{
+	int r, fbytes, oldcount;
+    	unsigned long flags;
+	va_list args;
+
+	va_start(args, fmt);
+
+	if (ipipe_current_domain == ipipe_root_domain ||
+	    test_bit(IPIPE_SPRINTK_FLAG,&ipipe_current_domain->flags) ||
+	    oops_in_progress) {
+		r = vprintk(fmt, args);
+		goto out;
+	}
+
+	spin_lock_irqsave(&__ipipe_printk_lock, flags);
+
+	oldcount = __ipipe_printk_fill;
+	fbytes = __LOG_BUF_LEN - oldcount;
+
+	if (fbytes > 1)	{
+		r = vscnprintf(__ipipe_printk_buf + __ipipe_printk_fill,
+			       fbytes, fmt, args) + 1; /* account for the null byte */
+		__ipipe_printk_fill += r;
+	} else
+		r = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+
+	if (oldcount == 0)
+		ipipe_trigger_irq(__ipipe_printk_virq);
+out:
+	va_end(args);
+
+	return r;
+}
+#else /* !CONFIG_IPIPE */
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
@@ -500,6 +572,7 @@ asmlinkage int printk(const char *fmt, .
 
 	return r;
 }
+#endif /* CONFIG_IPIPE */
 
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int printk_cpu = UINT_MAX;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/sched.c linux-2.6.19.patched/kernel/sched.c
--- linux-2.6.19.at91/kernel/sched.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/sched.c	2007-04-04 11:52:06.000000000 +0200
@@ -1391,7 +1391,7 @@ static int try_to_wake_up(struct task_st
 
 	rq = task_rq_lock(p, &flags);
 	old_state = p->state;
-	if (!(old_state & state))
+	if (!(old_state & state) || (old_state & TASK_NOWAKEUP))
 		goto out;
 
 	if (p->array)
@@ -1809,6 +1809,8 @@ asmlinkage void schedule_tail(struct tas
 #endif
 	if (current->set_child_tid)
 		put_user(current->pid, current->set_child_tid);
+
+	ipipe_init_notify(current);
 }
 
 /*
@@ -3324,12 +3326,17 @@ asmlinkage void __sched schedule(void)
 	long *switch_count;
 	struct rq *rq;
 
+#ifdef CONFIG_IPIPE
+	if (unlikely(!ipipe_root_domain_p))
+		return;
+#endif /* CONFIG_IPIPE */
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
 	 * schedule() atomically, we ignore that path for now.
 	 * Otherwise, whine if we are scheduling when we should not be.
 	 */
-	if (unlikely(in_atomic() && !current->exit_state)) {
+	if (unlikely(!(current->state & TASK_ATOMICSWITCH) && in_atomic() &&
+			!current->exit_state)) {
 		printk(KERN_ERR "BUG: scheduling while atomic: "
 			"%s/0x%08x/%d\n",
 			current->comm, preempt_count(), current->pid);
@@ -3337,8 +3344,13 @@ asmlinkage void __sched schedule(void)
 	}
 	profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
+	if (unlikely(current->state & TASK_ATOMICSWITCH)) {
+		current->state &= ~TASK_ATOMICSWITCH;
+		goto need_resched_nodisable;
+	}
 need_resched:
 	preempt_disable();
+need_resched_nodisable:
 	prev = current;
 	release_kernel_lock(prev);
 need_resched_nonpreemptible:
@@ -3456,6 +3468,8 @@ switch_tasks:
 		prepare_task_switch(rq, next);
 		prev = context_switch(rq, prev, next);
 		barrier();
+ 		if (task_hijacked(prev))
+ 		    return;
 		/*
 		 * this_rq must be evaluated again because prev may have moved
 		 * CPUs since it called schedule(), thus the 'rq' on its stack
@@ -3469,7 +3483,7 @@ switch_tasks:
 	if (unlikely(reacquire_kernel_lock(prev) < 0))
 		goto need_resched_nonpreemptible;
 	preempt_enable_no_resched();
-	if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
+	if (unlikely(test_thread_flag(TIF_NEED_RESCHED) && ipipe_root_domain_p))
 		goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
@@ -3487,6 +3501,11 @@ asmlinkage void __sched preempt_schedule
 	struct task_struct *task = current;
 	int saved_lock_depth;
 #endif
+#ifdef CONFIG_IPIPE
+	/* Do not reschedule over non-Linux domains. */
+	if (unlikely(!ipipe_root_domain_p))
+		return;
+#endif /* CONFIG_IPIPE */
 	/*
 	 * If there is a non-zero preempt_count or interrupts are disabled,
 	 * we do not want to preempt the current task.  Just return..
@@ -4185,6 +4204,7 @@ recheck:
 		deactivate_task(p, rq);
 	oldprio = p->prio;
 	__setscheduler(p, policy, param->sched_priority);
+	ipipe_setsched_notify(p);
 	if (array) {
 		__activate_task(p, rq);
 		/*
@@ -6950,3 +6970,50 @@ void set_curr_task(int cpu, struct task_
 }
 
 #endif
+
+#ifdef CONFIG_IPIPE
+
+int ipipe_setscheduler_root (struct task_struct *p, int policy, int prio)
+{
+	struct prio_array *array;
+	unsigned long flags;
+	struct rq *rq;
+	int oldprio;
+
+	rq = task_rq_lock(p, &flags);
+	array = p->array;
+	if (array)
+		deactivate_task(p, rq);
+	oldprio = p->prio;
+	__setscheduler(p, policy, prio);
+	if (array) {
+		__activate_task(p, rq);
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	task_rq_unlock(rq, &flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_setscheduler_root);
+
+int ipipe_reenter_root (struct task_struct *prev, int policy, int prio)
+{
+	finish_task_switch(this_rq(), prev);
+	if (reacquire_kernel_lock(current) < 0)
+		;
+	preempt_enable_no_resched();
+
+	if (current->policy != policy || current->rt_priority != prio)
+		return ipipe_setscheduler_root(current,policy,prio);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_reenter_root);
+
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/signal.c linux-2.6.19.patched/kernel/signal.c
--- linux-2.6.19.at91/kernel/signal.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/signal.c	2007-04-04 11:52:06.000000000 +0200
@@ -504,6 +504,7 @@ void signal_wake_up(struct task_struct *
 	unsigned int mask;
 
 	set_tsk_thread_flag(t, TIF_SIGPENDING);
+	ipipe_sigwake_notify(t); /* TIF_SIGPENDING must be set first. */
 
 	/*
 	 * For SIGKILL, we want to wake it up in the stopped/traced case.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/spinlock.c linux-2.6.19.patched/kernel/spinlock.c
--- linux-2.6.19.at91/kernel/spinlock.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/spinlock.c	2007-04-04 11:52:06.000000000 +0200
@@ -88,7 +88,7 @@ unsigned long __lockfunc _spin_lock_irqs
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_LOCKING
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
@@ -305,7 +305,7 @@ unsigned long __lockfunc _spin_lock_irqs
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_SPIN_LOCKING
+#if defined(CONFIG_PROVE_SPIN_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/ioremap.c linux-2.6.19.patched/lib/ioremap.c
--- linux-2.6.19.at91/lib/ioremap.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/ioremap.c	2007-04-04 11:52:06.000000000 +0200
@@ -11,6 +11,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
 		unsigned long end, unsigned long phys_addr, pgprot_t prot)
@@ -85,7 +86,7 @@ int ioremap_page_range(unsigned long add
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
-
+	__ipipe_pin_range_globally(start, end);
 	flush_cache_vmap(start, end);
 
 	return err;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/Kconfig.debug linux-2.6.19.patched/lib/Kconfig.debug
--- linux-2.6.19.at91/lib/Kconfig.debug	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/Kconfig.debug	2007-04-04 11:52:06.000000000 +0200
@@ -46,6 +46,8 @@ config UNUSED_SYMBOLS
 	  you really need it, and what the merge plan to the mainline kernel for
 	  your module is.
 
+source "kernel/ipipe/Kconfig.debug"
+
 config DEBUG_KERNEL
 	bool "Kernel debugging"
 	help
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/smp_processor_id.c linux-2.6.19.patched/lib/smp_processor_id.c
--- linux-2.6.19.at91/lib/smp_processor_id.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/smp_processor_id.c	2007-04-04 11:52:06.000000000 +0200
@@ -13,6 +13,11 @@ unsigned int debug_smp_processor_id(void
 	int this_cpu = raw_smp_processor_id();
 	cpumask_t this_mask;
 
+#ifdef CONFIG_IPIPE
+ 	if (ipipe_current_domain != ipipe_root_domain)
+	    return this_cpu;
+#endif /* CONFIG_IPIPE */
+
 	if (likely(preempt_count))
 		goto out;
 
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/spinlock_debug.c linux-2.6.19.patched/lib/spinlock_debug.c
--- linux-2.6.19.at91/lib/spinlock_debug.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/spinlock_debug.c	2007-04-04 11:52:06.000000000 +0200
@@ -129,6 +129,8 @@ void _raw_spin_lock(spinlock_t *lock)
 	debug_spin_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_lock);
+
 int _raw_spin_trylock(spinlock_t *lock)
 {
 	int ret = __raw_spin_trylock(&lock->raw_lock);
@@ -144,12 +146,16 @@ int _raw_spin_trylock(spinlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_spin_trylock);
+
 void _raw_spin_unlock(spinlock_t *lock)
 {
 	debug_spin_unlock(lock);
 	__raw_spin_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_unlock);
+
 static void rwlock_bug(rwlock_t *lock, const char *msg)
 {
 	if (!debug_locks_off())
@@ -195,6 +201,8 @@ void _raw_read_lock(rwlock_t *lock)
 	__raw_read_lock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_lock);
+
 int _raw_read_trylock(rwlock_t *lock)
 {
 	int ret = __raw_read_trylock(&lock->raw_lock);
@@ -208,12 +216,16 @@ int _raw_read_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_read_trylock);
+
 void _raw_read_unlock(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
 	__raw_read_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_unlock);
+
 static inline void debug_write_lock_before(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
@@ -271,6 +283,8 @@ void _raw_write_lock(rwlock_t *lock)
 	debug_write_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_write_lock);
+
 int _raw_write_trylock(rwlock_t *lock)
 {
 	int ret = __raw_write_trylock(&lock->raw_lock);
@@ -286,8 +300,12 @@ int _raw_write_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_write_trylock);
+
 void _raw_write_unlock(rwlock_t *lock)
 {
 	debug_write_unlock(lock);
 	__raw_write_unlock(&lock->raw_lock);
 }
+
+EXPORT_SYMBOL(_raw_write_unlock);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/Makefile linux-2.6.19.patched/Makefile
--- linux-2.6.19.at91/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -491,6 +491,10 @@ endif
 
 include $(srctree)/arch/$(ARCH)/Makefile
 
+ifdef CONFIG_IPIPE_TRACE_MCOUNT
+CFLAGS          += -pg
+endif
+
 ifdef CONFIG_FRAME_POINTER
 CFLAGS		+= -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
 else
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/memory.c linux-2.6.19.patched/mm/memory.c
--- linux-2.6.19.at91/mm/memory.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/memory.c	2007-04-04 11:52:06.000000000 +0200
@@ -50,6 +50,7 @@
 #include <linux/delayacct.h>
 #include <linux/init.h>
 #include <linux/writeback.h>
+#include <linux/vmalloc.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -418,13 +419,41 @@ struct page *vm_normal_page(struct vm_ar
 	return pfn_to_page(pfn);
 }
 
+static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
+{
+	/*
+	 * If the source page was a PFN mapping, we don't have
+	 * a "struct page" for it. We do a best-effort copy by
+	 * just copying from the original user address. If that
+	 * fails, we just zero-fill it. Live with it.
+	 */
+	if (unlikely(!src)) {
+		void *kaddr = kmap_atomic(dst, KM_USER0);
+		void __user *uaddr = (void __user *)(va & PAGE_MASK);
+
+		/*
+		 * This really shouldn't fail, because the page is there
+		 * in the page tables. But it might just be unreadable,
+		 * in which case we just give up and fill the result with
+		 * zeroes.
+		 */
+		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
+			memset(kaddr, 0, PAGE_SIZE);
+		kunmap_atomic(kaddr, KM_USER0);
+		flush_dcache_page(dst);
+		return;
+		
+	}
+	copy_user_highpage(dst, src, va);
+}
+
 /*
  * copy one vm_area from one task to the other. Assumes the page tables
  * already present in the new task to be cleared in the whole range
  * covered by this vma.
  */
 
-static inline void
+static inline int
 copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
 		unsigned long addr, int *rss)
@@ -466,6 +495,25 @@ copy_one_pte(struct mm_struct *dst_mm, s
 	 * in the parent and the child
 	 */
 	if (is_cow_mapping(vm_flags)) {
+#ifdef CONFIG_IPIPE
+		if (((vm_flags|src_mm->def_flags) & (VM_LOCKED|VM_PINNED)) == (VM_LOCKED|VM_PINNED)) {
+			struct page *old_page = vm_normal_page(vma, addr, pte);
+			page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+			if (!page)
+				return -ENOMEM;
+
+			cow_user_page(page, old_page, addr);
+			pte = mk_pte(page, vma->vm_page_prot);
+			
+			if (vm_flags & VM_SHARED)
+				pte = pte_mkclean(pte);
+			pte = pte_mkold(pte);
+
+			page_dup_rmap(page);
+			rss[!!PageAnon(page)]++;
+			goto out_set_pte;
+		}
+#endif /* CONFIG_IPIPE */
 		ptep_set_wrprotect(src_mm, addr, src_pte);
 		pte = pte_wrprotect(pte);
 	}
@@ -487,6 +535,7 @@ copy_one_pte(struct mm_struct *dst_mm, s
 
 out_set_pte:
 	set_pte_at(dst_mm, addr, dst_pte, pte);
+	return 0;
 }
 
 static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
@@ -524,7 +573,9 @@ again:
 			progress++;
 			continue;
 		}
-		copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vma, addr, rss);
+		if (copy_one_pte(dst_mm, src_mm, dst_pte,
+				 src_pte, vma, addr, rss))
+			return -ENOMEM;
 		progress += 8;
 	} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 
@@ -1431,34 +1482,6 @@ static inline pte_t maybe_mkwrite(pte_t 
 	return pte;
 }
 
-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
-{
-	/*
-	 * If the source page was a PFN mapping, we don't have
-	 * a "struct page" for it. We do a best-effort copy by
-	 * just copying from the original user address. If that
-	 * fails, we just zero-fill it. Live with it.
-	 */
-	if (unlikely(!src)) {
-		void *kaddr = kmap_atomic(dst, KM_USER0);
-		void __user *uaddr = (void __user *)(va & PAGE_MASK);
-
-		/*
-		 * This really shouldn't fail, because the page is there
-		 * in the page tables. But it might just be unreadable,
-		 * in which case we just give up and fill the result with
-		 * zeroes.
-		 */
-		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
-			memset(kaddr, 0, PAGE_SIZE);
-		kunmap_atomic(kaddr, KM_USER0);
-		flush_dcache_page(dst);
-		return;
-		
-	}
-	copy_user_highpage(dst, src, va);
-}
-
 /*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
@@ -2676,3 +2699,117 @@ int access_process_vm(struct task_struct
 
 	return buf - old_buf;
 }
+
+#ifdef CONFIG_IPIPE
+
+static inline int ipipe_pin_pte_range(struct mm_struct *mm, pmd_t *pmd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	spinlock_t *ptl;
+	pte_t *pte;
+	
+	do {
+		pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+		if (!pte)
+			continue;
+
+		if (!pte_present(*pte)) {
+			pte_unmap_unlock(pte, ptl);
+			continue;
+		}
+
+		if (do_wp_page(mm, vma, addr, pte, pmd, ptl, *pte) == VM_FAULT_OOM)
+			return -ENOMEM;
+	} while (addr += PAGE_SIZE, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pmd_range(struct mm_struct *mm, pud_t *pud,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if (ipipe_pin_pte_range(mm, pmd, vma, addr, end))
+			return -ENOMEM;
+	} while (pmd++, addr = next, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pud_range(struct mm_struct *mm, pgd_t *pgd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pud_t *pud;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (ipipe_pin_pmd_range(mm, pud, vma, addr, end))
+			return -ENOMEM;
+	} while (pud++, addr = next, addr != end);
+	return 0;
+}
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk)
+{
+	unsigned long addr, next, end;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	int result = 0;
+	pgd_t *pgd;
+
+	mm = get_task_mm(tsk);
+	if (!mm)
+		return -EPERM;
+
+	down_write(&mm->mmap_sem);
+	if (mm->def_flags & VM_PINNED)
+		goto done_mm;
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!is_cow_mapping(vma->vm_flags))
+			continue;
+
+		addr = vma->vm_start;
+		end = vma->vm_end;
+		
+		pgd = pgd_offset(mm, addr);
+		do {
+			next = pgd_addr_end(addr, end);
+			if (ipipe_pin_pud_range(mm, pgd, vma, addr, next)) {
+				result = -ENOMEM;
+				goto done_mm;
+			}
+		} while (pgd++, addr = next, addr != end);
+	}
+	mm->def_flags |= VM_PINNED;
+
+  done_mm:
+	up_write(&mm->mmap_sem);
+	mmput(mm);
+	return result;
+}
+
+EXPORT_SYMBOL(ipipe_disable_ondemand_mappings);
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end)
+{
+	struct task_struct *p;
+
+	read_lock(&tasklist_lock);
+
+	for_each_process(p)
+		if (p->mm)
+			__ipipe_pin_range_mapping(p->mm, start, end);
+
+	read_unlock(&tasklist_lock);
+}
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/mlock.c linux-2.6.19.patched/mm/mlock.c
--- linux-2.6.19.at91/mm/mlock.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/mlock.c	2007-04-04 11:52:06.000000000 +0200
@@ -162,10 +162,10 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
-	unsigned int def_flags = 0;
+	unsigned int def_flags = current->mm->def_flags & VM_PINNED;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
+		def_flags |= VM_LOCKED;
 	current->mm->def_flags = def_flags;
 	if (flags == MCL_FUTURE)
 		goto out;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/vmalloc.c linux-2.6.19.patched/mm/vmalloc.c
--- linux-2.6.19.at91/mm/vmalloc.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/vmalloc.c	2007-04-04 11:52:06.000000000 +0200
@@ -19,6 +19,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -156,6 +157,7 @@ int map_vm_area(struct vm_struct *area, 
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
+	__ipipe_pin_range_globally((unsigned long) area->addr, end);
 	flush_cache_vmap((unsigned long) area->addr, end);
 	return err;
 }

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-10 16:47 [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel Gregory CLEMENT
@ 2007-04-10 17:15 ` Gilles Chanteperdrix
  2007-04-11  9:01   ` Gregory CLEMENT
  2007-04-10 17:20 ` [Xenomai-core] " Gregory CLEMENT
  2007-04-12 17:24 ` [Adeos-main] " Jose Pascual
  2 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-10 17:15 UTC (permalink / raw)
  To: Gregory CLEMENT; +Cc: BOUIN Alexandre, adeos-main

Gregory CLEMENT wrote:
> Hello,
> 
> We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
> 
> This patch must be applied on vanilla 2.6.19 with at91 patch (
> http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
> supporting AT91SAM9261.
> So first get vanilla kernel, then apply at91 patch then apply our
> patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
> 
> For now it works with Xenomai on AT91SAM9261-EK, if someone is
> intersting we can send the benchmark result.
> As AT91SAM926x are pretty similar of AT91RM9200, there is a some
> duplicate code and some common code.
> In the future it could be also work on all AT91SAM926x, we can test
> it. But before going ahead we would like some comment on this patch.
> 
> The better would be working on 2.6.20 which already have support for
> AT91SAM926x, but we didn't see any arm patch on this kernel nor any
> file modified on git.
> 
> Hope this patch will be usefull.

It looks good. I will try and port the I-pipe patch for ARM to Linux
2.6.20. In the meantime, could you separate the AT91SAM9261 specific
code and the changes (if any) made to the rest of the I-pipe from the
rest of the I-pipe ? This would ease distribution and maintenance.

> PS: Would we post it on xenomai list also?

Yes, maybe some people there would like to know about this patch.

-- 
                                                 Gilles Chanteperdrix


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

* [Xenomai-core] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-10 16:47 [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel Gregory CLEMENT
  2007-04-10 17:15 ` Gilles Chanteperdrix
@ 2007-04-10 17:20 ` Gregory CLEMENT
  2007-04-12 17:24 ` [Adeos-main] " Jose Pascual
  2 siblings, 0 replies; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-10 17:20 UTC (permalink / raw)
  To: xenomai, BOUIN Alexandre

[-- Attachment #1: Type: text/plain, Size: 1071 bytes --]

This mail was already sent on adeos mailing list and may interest you:

Hello,

We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.

This patch must be applied on vanilla 2.6.19 with at91 patch (
http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
supporting AT91SAM9261.
So first get vanilla kernel, then apply at91 patch then apply our
patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.

For now it works with Xenomai on AT91SAM9261-EK, if someone is
intersting we can send the benchmark result.
As AT91SAM926x are pretty similar of AT91RM9200, there is a some
duplicate code and some common code.
In the future it could be also work on all AT91SAM926x, we can test
it. But before going ahead we would like some comment on this patch.

The better would be working on 2.6.20 which already have support for
AT91SAM926x, but we didn't see any arm patch on this kernel nor any
file modified on git.

Hope this patch will be usefull.

--
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40

[-- Attachment #2: adeos-ipipe-2.6.19-arm-1.6-05-at91sam9261.patch --]
[-- Type: text/x-patch, Size: 263758 bytes --]

diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/boot/compressed/head.S linux-2.6.19.patched/arch/arm/boot/compressed/head.S
--- linux-2.6.19.at91/arch/arm/boot/compressed/head.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/boot/compressed/head.S	2007-04-04 11:52:05.000000000 +0200
@@ -833,6 +833,16 @@ memdump:	mov	r12, r0
 		mov	pc, r10
 #endif
 
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+                .text
+                .align 0
+                .type mcount %function
+                .global mcount
+mcount:
+		mov pc, lr	@ just return
+#endif
+
+
 reloc_end:
 
 		.align
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/Kconfig linux-2.6.19.patched/arch/arm/Kconfig
--- linux-2.6.19.at91/arch/arm/Kconfig	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/Kconfig	2007-04-04 11:52:05.000000000 +0200
@@ -487,6 +487,8 @@ config LOCAL_TIMERS
 	  accounting to be spread across the timer interval, preventing a
 	  "thundering herd" at every timer tick.
 
+source "kernel/ipipe/Kconfig"
+
 config PREEMPT
 	bool "Preemptible Kernel (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-armv.S linux-2.6.19.patched/arch/arm/kernel/entry-armv.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-armv.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-armv.S	2007-04-04 11:52:05.000000000 +0200
@@ -4,6 +4,7 @@
  *  Copyright (C) 1996,1997,1998 Russell King.
  *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
  *  nommu support by Hyok S. Choi (hyok.choi@samsung.com)
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -27,13 +28,21 @@
  * Interrupt handling.  Preserves r7, r8, r9
  */
 	.macro	irq_handler
-1:	get_irqnr_and_base r0, r6, r5, lr
+#ifdef CONFIG_IPIPE
+	mov r0, #2
+#endif
+1:	get_irqnr_and_base r1, r6, r5, lr
+	movne   r0, r1
 	movne	r1, sp
 	@
 	@ routine called with r0 = irq number, r1 = struct pt_regs *
 	@
 	adrne	lr, 1b
+#ifdef CONFIG_IPIPE
+	bne	__ipipe_grab_irq
+#else
 	bne	asm_do_IRQ
+#endif
 
 #ifdef CONFIG_SMP
 	/*
@@ -42,18 +51,22 @@
 	 * this macro assumes that irqstat (r6) and base (r5) are
 	 * preserved from get_irqnr_and_base above
 	 */
-	test_for_ipi r0, r6, r5, lr
+	test_for_ipi r1, r6, r5, lr
 	movne	r0, sp
 	adrne	lr, 1b
 	bne	do_IPI
 
 #ifdef CONFIG_LOCAL_TIMERS
-	test_for_ltirq r0, r6, r5, lr
+	test_for_ltirq r1, r6, r5, lr
 	movne	r0, sp
 	adrne	lr, 1b
 	bne	do_local_timer
 #endif
 #endif
+#ifdef CONFIG_IPIPE
+	cmp	r0, #2
+	bleq	__ipipe_check_root_interruptible
+#endif	
 
 	.endm
 
@@ -196,14 +209,25 @@ __irq_svc:
 #endif
 #ifdef CONFIG_PREEMPT
 	get_thread_info tsk
+#ifndef CONFIG_IPIPE
 	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
 	add	r7, r8, #1			@ increment it
 	str	r7, [tsk, #TI_PREEMPT]
 #endif
+#endif
 
 	irq_handler
+#ifdef CONFIG_IPIPE
+	cmp	r0, #0
+	beq	__ipipe_fast_svc_irq_exit
+#endif
+
 #ifdef CONFIG_PREEMPT
 	ldr	r0, [tsk, #TI_FLAGS]		@ get flags
+#ifdef CONFIG_IPIPE
+	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
+	mov     r7, r8
+#endif	
 	tst	r0, #_TIF_NEED_RESCHED
 	blne	svc_preempt
 preempt_return:
@@ -212,6 +236,9 @@ preempt_return:
 	teq	r0, r7
 	strne	r0, [r0, -r0]			@ bug()
 #endif
+#ifdef CONFIG_IPIPE
+__ipipe_fast_svc_irq_exit:
+#endif
 	ldr	r0, [sp, #S_PSR]		@ irqs are already disabled
 	msr	spsr_cxsf, r0
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -231,19 +258,33 @@ svc_preempt:
 	ldr	r1, [r6, #8]			@ local_bh_count
 	adds	r0, r0, r1
 	movne	pc, lr
+#ifdef CONFIG_IPIPE
+	bl	__ipipe_fast_stall_root
+	enable_irq
+#endif
 	mov	r7, #0				@ preempt_schedule_irq
 	str	r7, [tsk, #TI_PREEMPT]		@ expects preempt_count == 0
 1:	bl	preempt_schedule_irq		@ irq en/disable is done inside
 	ldr	r0, [tsk, #TI_FLAGS]		@ get new tasks TI_FLAGS
 	tst	r0, #_TIF_NEED_RESCHED
-	beq	preempt_return			@ go again
-	b	1b
+	bne	1b
+#ifdef CONFIG_IPIPE
+	disable_irq
+	bl	__ipipe_fast_unstall_root
+#endif
+	b	preempt_return			@ go again
 #endif
 
 	.align	5
 __und_svc:
 	svc_entry
 
+#ifdef CONFIG_IPIPE
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	bne	1f
+#endif /* CONFIG_IPIPE */
 	@
 	@ call emulation code, which returns using r9 if it has emulated
 	@ the instruction, or the more conventional lr if we are to treat
@@ -410,18 +451,28 @@ __irq_usr:
 #endif
 	get_thread_info tsk
 #ifdef CONFIG_PREEMPT
+#ifndef CONFIG_IPIPE
 	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
 	add	r7, r8, #1			@ increment it
 	str	r7, [tsk, #TI_PREEMPT]
 #endif
+#endif
 
 	irq_handler
+#ifdef CONFIG_IPIPE
+	cmp	r0, #0
+	bne	__ipipe_usr_irq_continue
+	slow_restore_user_regs			@ Fast exit path over non-root domains
+__ipipe_usr_irq_continue:
+#endif
 #ifdef CONFIG_PREEMPT
+#ifndef CONFIG_IPIPE
 	ldr	r0, [tsk, #TI_PREEMPT]
 	str	r8, [tsk, #TI_PREEMPT]
 	teq	r0, r7
 	strne	r0, [r0, -r0]
 #endif
+#endif
 #ifdef CONFIG_TRACE_IRQFLAGS
 	bl	trace_hardirqs_on
 #endif
@@ -517,8 +568,8 @@ call_fpe:
 	mov	pc, lr				@ CP#8
 	mov	pc, lr				@ CP#9
 #ifdef CONFIG_VFP
-	b	do_vfp				@ CP#10 (VFP)
-	b	do_vfp				@ CP#11 (VFP)
+	b	_do_vfp				@ CP#10 (VFP)
+	b	_do_vfp				@ CP#11 (VFP)
 #else
 	mov	pc, lr				@ CP#10 (VFP)
 	mov	pc, lr				@ CP#11 (VFP)
@@ -529,11 +580,35 @@ call_fpe:
 	mov	pc, lr				@ CP#15 (Control)
 
 do_fpe:
+#ifdef CONFIG_IPIPE
+	mov	r4, r0
+	mov	r0, #5				@ == IPIPE_TRAP_FPU
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	ldrne	pc, [r9]
+	mov	r0, r4
+#endif
 	enable_irq
 	ldr	r4, .LCfp
 	add	r10, r10, #TI_FPSTATE		@ r10 = workspace
 	ldr	pc, [r4]			@ Call FP module USR entry point
 
+#ifdef CONFIG_VFP
+_do_vfp:
+#ifdef CONFIG_IPIPE
+	mov	r4, r0
+	mov	r0, #6				@ == IPIPE_TRAP_VFP
+	mov	r1, sp				@ r0 = trapno, r1 = &regs
+	bl	__ipipe_dispatch_event		@ branch to trap handler
+	cmp	r0, #0
+	ldrne	pc, [r9]
+	mov	r0, r4
+#endif
+	b	do_vfp
+#endif
+
+
 /*
  * The FP module is called with these registers set:
  *  r0  = instruction
@@ -566,6 +641,13 @@ __pabt_usr:
  * This is the return code to user mode for abort handlers
  */
 ENTRY(ret_from_exception)
+#ifdef CONFIG_IPIPE
+	bl     __ipipe_check_root
+	cmp     r0, #0
+	bne     1f
+	slow_restore_user_regs          @ Fast exit path over non-root domains
+1:
+#endif /* CONFIG_IPIPE */
 	get_thread_info tsk
 	mov	why, #0
 	b	ret_to_user
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-common.S linux-2.6.19.patched/arch/arm/kernel/entry-common.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-common.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-common.S	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/kernel/entry-common.S
  *
  *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -19,13 +20,18 @@
  * possible here, and this includes saving r0 back into the SVC
  * stack.
  */
+#ifdef CONFIG_IPIPE
+__ipipe_ret_fast_syscall:
+	ldr	r0, [sp, #S_R0+S_OFF]		@ returned r0
+	/* fall through */
+#endif
 ret_fast_syscall:
 	disable_irq				@ disable interrupts
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	bne	fast_work_pending
 
-	@ fast_restore_user_regs
+fast_restore_user_regs:
 	ldr	r1, [sp, #S_OFF + S_PSR]	@ get calling cpsr
 	ldr	lr, [sp, #S_OFF + S_PC]!	@ get pc
 	msr	spsr_cxsf, r1			@ save in spsr_svc
@@ -34,6 +40,13 @@ ret_fast_syscall:
 	add	sp, sp, #S_FRAME_SIZE - S_PC
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 
+#ifdef CONFIG_IPIPE
+__ipipe_fast_exit_syscall:
+	ldr	r0, [sp, #S_R0+S_OFF]		@ returned r0
+	disable_irq				@ disable interrupts
+	b	fast_restore_user_regs
+#endif /* CONFIG_IPIPE */
+
 /*
  * Ok, we need to do extra processing, enter the slow path.
  */
@@ -61,19 +74,15 @@ ret_slow_syscall:
 	tst	r1, #_TIF_WORK_MASK
 	bne	work_pending
 no_work_pending:
-	@ slow_restore_user_regs
-	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
-	ldr	lr, [sp, #S_PC]!		@ get pc
-	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
-	mov	r0, r0
-	add	sp, sp, #S_FRAME_SIZE - S_PC
-	movs	pc, lr				@ return & move spsr_svc into cpsr
+	slow_restore_user_regs
 
 /*
  * This is how we return from a fork.
  */
 ENTRY(ret_from_fork)
+#ifdef CONFIG_IPIPE
+	enable_irq
+#endif /* CONFIG_IPIPE */
 	bl	schedule_tail
 	get_thread_info tsk
 	ldr	r1, [tsk, #TI_FLAGS]		@ check for syscall tracing
@@ -198,6 +207,17 @@ ENTRY(vector_swi)
 #endif
 
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
+#ifdef CONFIG_IPIPE
+	stmfd	sp!, {r0-r3, ip}
+	add	r1, sp, #S_OFF
+	add	r1, r1, #20
+	mov	r0, scno
+	bl	__ipipe_syscall_root
+	cmp	r0, #0
+	ldmfd	sp!, {r0-r3, ip}
+	blt	__ipipe_ret_fast_syscall
+	bgt	__ipipe_fast_exit_syscall
+#endif /* CONFIG_IPIPE */
 	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
 
@@ -244,6 +264,9 @@ __sys_trace_return:
 __cr_alignment:
 	.word	cr_alignment
 #endif
+#ifdef CONFIG_IPIPE
+	.word	__ipipe_syscall_root
+#endif
 	.ltorg
 
 /*
@@ -390,3 +413,28 @@ ENTRY(sys_oabi_call_table)
 
 #endif
 
+
+#ifdef CONFIG_FRAME_POINTER
+
+	.text
+	.align 0
+	.type arm_return_addr %function
+	.global arm_return_addr
+
+arm_return_addr:
+	mov	ip, r0
+	mov	r0, fp
+3:
+	cmp	r0, #0
+	beq	1f		@ frame list hit end, bail
+	cmp	ip, #0
+	beq	2f		@ reached desired frame
+	ldr	r0, [r0, #-12]  @ else continue, get next fp
+	sub	ip, ip, #1
+	b	3b
+2:
+	ldr	r0, [r0, #-4]   @ get target return address
+1:
+	mov	pc, lr
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/entry-header.S linux-2.6.19.patched/arch/arm/kernel/entry-header.S
--- linux-2.6.19.at91/arch/arm/kernel/entry-header.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/entry-header.S	2007-04-04 11:52:05.000000000 +0200
@@ -49,6 +49,15 @@
 #endif
 	.endm
 
+	.macro slow_restore_user_regs
+	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
+	ldr	lr, [sp, #S_PC]!		@ get pc
+	msr	spsr_cxsf, r1			@ save in spsr_svc
+	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
+	mov	r0, r0
+	add	sp, sp, #S_FRAME_SIZE - S_PC
+	movs	pc, lr				@ return & move spsr_svc into cpsr
+	.endm
 
 /*
  * These are the registers used in the syscall handler, and allow us to
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ipipe.c linux-2.6.19.patched/arch/arm/kernel/ipipe.c
--- linux-2.6.19.at91/arch/arm/kernel/ipipe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ipipe.c	2007-04-04 11:52:05.000000000 +0200
@@ -0,0 +1,532 @@
+/* -*- linux-c -*-
+ * linux/arch/arm/kernel/ipipe.c
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ * Copyright (C) 2004 Wolfgang Grandegger (Adeos/arm port over 2.4).
+ * Copyright (C) 2005 Heikki Lindholm (PowerPC 970 fixes).
+ * Copyright (C) 2005 Stelian Pop.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-dependent I-PIPE support for ARM.
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/unistd.h>
+#include <asm/mach/irq.h>
+#include <asm/mmu_context.h>
+
+/* Current reload value for the decrementer. */
+unsigned long __ipipe_decr_ticks;
+
+/* Next tick date (timebase value). */
+unsigned long long __ipipe_decr_next[IPIPE_NR_CPUS];
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+extern struct irqdesc irq_desc[];
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static ipipe_spinlock_t __ipipe_cpu_barrier = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+/* Always called with hw interrupts off. */
+
+void __ipipe_do_critical_sync(unsigned irq)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	cpu_set(cpuid, __ipipe_cpu_sync_map);
+
+	/*
+	 * Now we are in sync with the lock requestor running on another
+	 * CPU. Enter a spinning wait until he releases the global
+	 * lock.
+	 */
+	spin_lock_hw(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock_hw(&__ipipe_cpu_barrier);
+
+	cpu_clear(cpuid, __ipipe_cpu_sync_map);
+}
+
+#endif	/* CONFIG_SMP */
+
+/*
+ * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+ * just like if it has been actually received from a hw source. Also
+ * works for virtual interrupts.
+ */
+int ipipe_trigger_irq(unsigned irq)
+{
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	local_irq_save_hw(flags);
+
+	__ipipe_handle_irq(irq, NULL);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+void __ipipe_init_platform(void)
+{
+	__ipipe_decr_ticks = __ipipe_mach_ticks_per_jiffy;
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = __ipipe_mach_timerint;
+	info->archdep.tmfreq = info->cpufreq;
+
+	return 0;
+}
+
+static void __ipipe_set_decr(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	__ipipe_decr_next[cpuid] = __ipipe_read_timebase() + __ipipe_decr_ticks;
+	__ipipe_mach_set_dec(__ipipe_decr_ticks);
+}
+
+int ipipe_tune_timer(unsigned long ns, int flags)
+{
+	unsigned long x, ticks;
+
+	if (flags & IPIPE_RESET_TIMER)
+		ticks = __ipipe_mach_ticks_per_jiffy;
+	else {
+		ticks = (ns / 1000) * (__ipipe_mach_ticks_per_jiffy) / (1000000 / HZ);
+
+		if (ticks > __ipipe_mach_ticks_per_jiffy)
+			return -EINVAL;
+	}
+
+	x = ipipe_critical_enter(&__ipipe_set_decr);	/* Sync with all CPUs */
+	__ipipe_decr_ticks = ticks;
+	__ipipe_set_decr();
+	ipipe_critical_exit(x);
+
+	return 0;
+}
+
+static int __ipipe_ack_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_ack(irq, desc);
+	return 1;
+}
+
+static int __ipipe_ack_timerirq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_ack(irq, desc);
+	__ipipe_mach_acktimer();
+#ifdef irq_finish
+ 	/* AT91 specific workaround */
+	irq_finish(irq);
+#endif /* irq_finish */
+	desc->ipipe_end(irq, desc);
+	return 1;
+}
+
+void __ipipe_enable_irqdesc(unsigned irq)
+{
+	irq_desc[irq].status &= ~IRQ_DISABLED;
+}
+
+static void __ipipe_enable_sync(void)
+{
+	__ipipe_decr_next[ipipe_processor_id()] =
+		__ipipe_read_timebase() + __ipipe_mach_get_dec();
+}
+
+/*
+ * __ipipe_enable_pipeline() -- We are running on the boot CPU, hw
+ * interrupts are off, and secondary CPUs are still lost in space.
+ */
+void __ipipe_enable_pipeline(void)
+{
+	unsigned long flags;
+	unsigned irq;
+
+	flags = ipipe_critical_enter(&__ipipe_enable_sync);
+
+	/* First, virtualize all interrupts from the root domain. */
+
+	for (irq = 0; irq < NR_IRQS; irq++)
+		ipipe_virtualize_irq(ipipe_root_domain,
+				     irq,
+				     (ipipe_irq_handler_t)&asm_do_IRQ, NULL,
+				     ((irq == __ipipe_mach_timerint)
+				      ? &__ipipe_ack_timerirq
+				      : &__ipipe_ack_irq),
+				     IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	__ipipe_decr_next[ipipe_processor_id()] =
+		__ipipe_read_timebase() + __ipipe_mach_get_dec();
+
+	ipipe_critical_exit(flags);
+}
+
+/*
+ * ipipe_critical_enter() -- Grab the superlock excluding all CPUs
+ * but the current one from a critical section. This lock is used when
+ * we must enforce a global critical section for a single CPU in a
+ * possibly SMP system whichever context the CPUs are running.
+ */
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+		cpumask_t lock_map;
+
+		ipipe_load_cpuid();
+
+		if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) {
+			while (cpu_test_and_set(BITS_PER_LONG - 1,
+						__ipipe_cpu_lock_map)) {
+				int n = 0;
+				do {
+					cpu_relax();
+				} while (++n < cpuid);
+			}
+
+			spin_lock_hw(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			send_IPI_allbutself(IPIPE_CRITICAL_VECTOR);
+
+			cpus_andnot(lock_map, cpu_online_map,
+				    __ipipe_cpu_lock_map);
+
+			while (!cpus_equal(__ipipe_cpu_sync_map, lock_map))
+				cpu_relax();
+		}
+
+		atomic_inc(&__ipipe_critical_count);
+	}
+#endif	/* CONFIG_SMP */
+
+	return flags;
+}
+
+/* ipipe_critical_exit() -- Release the superlock. */
+
+void ipipe_critical_exit(unsigned long flags)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+
+		ipipe_load_cpuid();
+
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock_hw(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(cpuid, __ipipe_cpu_lock_map);
+			cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map);
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	local_irq_restore_hw(flags);
+}
+
+asmlinkage int __ipipe_check_root(void)
+{
+	return per_cpu(ipipe_percpu_domain, ipipe_processor_id()) == ipipe_root_domain;
+}
+
+asmlinkage int __ipipe_check_root_interruptible(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	return (per_cpu(ipipe_percpu_domain, cpuid) == ipipe_root_domain &&	
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+/* Called from entry-armv.S with hw interrupts off */
+asmlinkage void __ipipe_fast_stall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);	
+}
+
+/* Called from entry-armv.S with hw interrupts off */
+asmlinkage void __ipipe_fast_unstall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+}
+
+asmlinkage int __ipipe_syscall_root(unsigned long scno, struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags, origr7;
+
+	/* We use r7 to pass the syscall number to the other domains */
+	origr7 = regs->ARM_r7;
+	regs->ARM_r7 = __NR_SYSCALL_BASE + scno;
+	/*
+	 * This routine either returns:
+	 * 0 -- if the syscall is to be passed to Linux;
+	 * >0 -- if the syscall should not be passed to Linux, and no
+	 * tail work should be performed;
+	 * <0 -- if the syscall should not be passed to Linux but the
+	 * tail work has to be performed (for handling signals etc).
+	 */
+
+	if (__ipipe_syscall_watched_p(current, regs->ARM_r7) &&
+	    __ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
+	    __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) {
+		if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) {
+			/*
+			 * Sync pending VIRQs before _TIF_NEED_RESCHED
+			 * is tested.
+			 */
+			ipipe_lock_cpu(flags);
+			if ((ipipe_root_domain->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+			ipipe_unlock_cpu(flags);
+			regs->ARM_r7 = origr7;
+			return -1;
+		}
+		regs->ARM_r7 = origr7;
+		return 1;
+	}
+
+	regs->ARM_r7 = origr7;
+	return 0;
+}
+
+/*
+ * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+ * interrupt protection log is maintained here for each domain. Hw
+ * interrupts are off on entry.
+ */
+void __ipipe_handle_irq(int irq, struct pt_regs *regs)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *head, *pos;
+	ipipe_declare_cpuid;
+	int m_ack;
+
+	m_ack = (regs == NULL);
+
+	if (irq >= IPIPE_NR_IRQS) {
+		printk(KERN_ERR "I-pipe: spurious interrupt %d\n", irq);
+		return;
+	}
+
+	ipipe_load_cpuid();
+
+	this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
+		head = &this_domain->p_link;
+	else {
+		head = __ipipe_pipeline.next;
+		next_domain = list_entry(head, struct ipipe_domain, p_link);
+		if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) {
+			if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+				next_domain->irqs[irq].acknowledge(irq);
+			if (likely(__ipipe_dispatch_wired(next_domain, irq)))
+				goto finalize;
+			return;
+		}
+	}
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		next_domain = list_entry(pos, struct ipipe_domain, p_link);
+
+		/*
+		 * For each domain handling the incoming IRQ, mark it as
+		 * pending in its log.
+		 */
+		if (test_bit(IPIPE_HANDLE_FLAG,
+			     &next_domain->irqs[irq].control)) {
+			/*
+			 * Domains that handle this IRQ are polled for
+			 * acknowledging it by decreasing priority order. The
+			 * interrupt must be made pending _first_ in the
+			 * domain's status flags before the PIC is unlocked.
+			 */
+
+			next_domain->cpudata[cpuid].irq_counters[irq].total_hits++;
+			next_domain->cpudata[cpuid].irq_counters[irq].pending_hits++;
+			__ipipe_set_irq_bit(next_domain, cpuid, irq);
+
+			/*
+			 * Always get the first master acknowledge available.
+			 * Once we've got it, allow slave acknowledge
+			 * handlers to run (until one of them stops us).
+			 */
+			if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+				m_ack = next_domain->irqs[irq].acknowledge(irq);
+		}
+
+		/*
+		 * If the domain does not want the IRQ to be passed down the
+		 * interrupt pipe, exit the loop now.
+		 */
+
+		if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+finalize:
+	/*
+	 * Now walk the pipeline, yielding control to the highest
+	 * priority domain that has pending interrupt(s) or
+	 * immediately to the current domain if the interrupt has been
+	 * marked as 'sticky'. This search does not go beyond the
+	 * current domain in the pipeline.
+	 */
+
+	__ipipe_walk_pipeline(head, cpuid);
+}
+
+asmlinkage int __ipipe_grab_irq(int irq, struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+
+	if (irq == __ipipe_mach_timerint) {
+
+		__ipipe_tick_regs[cpuid].ARM_cpsr = regs->ARM_cpsr;
+		__ipipe_tick_regs[cpuid].ARM_pc = regs->ARM_pc;
+
+		if (__ipipe_decr_ticks != __ipipe_mach_ticks_per_jiffy) {
+			unsigned long long next_date, now;
+
+			next_date = __ipipe_decr_next[cpuid];
+
+			while ((now = __ipipe_read_timebase()) >= next_date)
+				next_date += __ipipe_decr_ticks;
+
+			__ipipe_mach_set_dec(next_date - now);
+
+			__ipipe_decr_next[cpuid] = next_date;
+		}
+	}
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	ipipe_trace_begin(regs->ARM_ORIG_r0);
+#endif
+
+	if (__ipipe_mach_irq_mux_p(irq))
+		__ipipe_mach_demux_irq(irq, regs);
+	else
+		__ipipe_handle_irq(irq, regs);
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	ipipe_trace_end(regs->ARM_ORIG_r0);
+#endif
+
+#ifdef irq_finish
+ 	/* AT91 specific workaround */
+	if (irq != __ipipe_mach_timerint)
+		irq_finish(irq);
+#endif /* irq_finish */
+	ipipe_load_cpuid();
+
+	return (per_cpu(ipipe_percpu_domain, cpuid) == ipipe_root_domain &&	
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+EXPORT_SYMBOL(__ipipe_decr_ticks);
+EXPORT_SYMBOL(__ipipe_decr_next);
+EXPORT_SYMBOL(ipipe_critical_enter);
+EXPORT_SYMBOL(ipipe_critical_exit);
+EXPORT_SYMBOL(ipipe_trigger_irq);
+EXPORT_SYMBOL(ipipe_get_sysinfo);
+EXPORT_SYMBOL(ipipe_tune_timer);
+
+EXPORT_SYMBOL_GPL(show_stack);
+#ifndef MULTI_CPU
+EXPORT_SYMBOL_GPL(cpu_do_switch_mm);
+#endif
+
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+void notrace mcount(void);
+EXPORT_SYMBOL(mcount);
+#endif /* CONFIG_IPIPE_TRACE_MCOUNT */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ipipe-mcount.S linux-2.6.19.patched/arch/arm/kernel/ipipe-mcount.S
--- linux-2.6.19.at91/arch/arm/kernel/ipipe-mcount.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ipipe-mcount.S	2007-04-04 11:52:05.000000000 +0200
@@ -0,0 +1,38 @@
+/*
+ *  linux/arch/arm/kernel/ipipe-mcount.S
+ *
+ *  Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, emlix GmbH
+ */
+
+#ifdef CONFIG_FRAME_POINTER
+
+	.text
+	.align 0
+	.type mcount %function
+	.global mcount
+
+mcount:
+
+	ldr	ip, =ipipe_trace_enable	@ leave early, if disabled
+	ldr	ip, [ip]
+	cmp	ip, #0
+	moveq	pc,lr
+
+	mov	ip,  sp
+	stmdb   sp!, {r0 - r3, fp, ip, lr, pc}	@ create stack frame
+
+	mov	r3, #0			@ no additional value (v)
+	ldr	r2, [fp, #-4]		@ get lr (the return address
+					@ of the caller of the
+					@ instrumented function)
+	mov	r1, lr			@ get lr - (the return address
+					@ of the instrumented function)
+	mov	r0, #0			@ IPIPE_TRACE_FN
+
+	sub	fp, ip, #4		@ point fp at this frame
+
+	bl	__ipipe_trace
+
+	ldmdb   fp, {r0 - r3, fp, sp, pc}	@ pop entry frame and return
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/irq.c linux-2.6.19.patched/arch/arm/kernel/irq.c
--- linux-2.6.19.at91/arch/arm/kernel/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/irq.c	2007-04-04 11:52:05.000000000 +0200
@@ -125,8 +125,10 @@ asmlinkage void asm_do_IRQ(unsigned int 
 
 	desc_handle_irq(irq, desc);
 
+#ifndef CONFIG_IPIPE
 	/* AT91 specific workaround */
 	irq_finish(irq);
+#endif /* !CONFIG_IPIPE */
 
 	irq_exit();
 	set_irq_regs(old_regs);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/Makefile linux-2.6.19.patched/arch/arm/kernel/Makefile
--- linux-2.6.19.at91/arch/arm/kernel/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/Makefile	2007-04-04 11:52:05.000000000 +0200
@@ -20,6 +20,8 @@ obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
+obj-$(CONFIG_IPIPE)		+= ipipe.o
+obj-$(CONFIG_IPIPE_TRACE_MCOUNT)	+= ipipe-mcount.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/process.c linux-2.6.19.patched/arch/arm/kernel/process.c
--- linux-2.6.19.at91/arch/arm/kernel/process.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/process.c	2007-04-04 11:52:05.000000000 +0200
@@ -125,6 +125,12 @@ static void default_idle(void)
 		local_irq_disable();
 		if (!need_resched()) {
 			timer_dyn_reprogram();
+#ifdef CONFIG_IPIPE
+			__ipipe_unstall_root();
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+			ipipe_trace_end(0x8000000E);
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+#endif /* CONFIG_IPIPE */
 			arch_idle();
 		}
 		local_irq_enable();
@@ -153,6 +159,7 @@ void cpu_idle(void)
 
 		if (!idle)
 			idle = default_idle;
+ 		ipipe_suspend_domain();
 		leds_event(led_idle_start);
 		while (!need_resched())
 			idle();
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/ptrace.c linux-2.6.19.patched/arch/arm/kernel/ptrace.c
--- linux-2.6.19.at91/arch/arm/kernel/ptrace.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/ptrace.c	2007-04-04 11:52:05.000000000 +0200
@@ -485,6 +485,10 @@ void ptrace_break(struct task_struct *ts
 
 static int break_trap(struct pt_regs *regs, unsigned int instr)
 {
+
+	if (ipipe_trap_notify(IPIPE_TRAP_BREAK,regs))
+		return 0;
+
 	ptrace_break(current, regs);
 	return 0;
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/kernel/traps.c linux-2.6.19.patched/arch/arm/kernel/traps.c
--- linux-2.6.19.at91/arch/arm/kernel/traps.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/kernel/traps.c	2007-04-04 11:52:05.000000000 +0200
@@ -306,6 +306,9 @@ asmlinkage void do_undefinstr(struct pt_
 	}
 	spin_unlock_irq(&undef_lock);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_UNDEFINSTR,regs))
+		return;
+
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_UNDEFINED) {
 		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c	2007-04-04 11:52:05.000000000 +0200
@@ -33,6 +33,13 @@ static struct map_desc at91rm9200_io_des
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+#ifdef CONFIG_IPIPE
+		.virtual	= AT91_VA_BASE_TCB0,
+		.pfn		= __phys_to_pfn(AT91RM9200_BASE_TCB0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+        }, {
+#endif /* CONFIG_IPIPE */
 		.virtual	= AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE,
 		.pfn		= __phys_to_pfn(AT91RM9200_SRAM_BASE),
 		.length		= AT91RM9200_SRAM_SIZE,
@@ -247,6 +254,7 @@ void __init at91rm9200_initialize(unsign
  * The default interrupt priority levels (0 = lowest, 7 = highest).
  */
 static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
 	7,	/* Advanced Interrupt Controller (FIQ) */
 	7,	/* System Peripherals */
 	0,	/* Parallel IO Controller A */
@@ -279,6 +287,42 @@ static unsigned int at91rm9200_default_i
 	0,	/* Advanced Interrupt Controller (IRQ4) */
 	0,	/* Advanced Interrupt Controller (IRQ5) */
 	0	/* Advanced Interrupt Controller (IRQ6) */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+   I-pipe. */
+	7,	/* Advanced Interrupt Controller */
+	6,	/* System Peripheral */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C */
+	0,	/* Parallel IO Controller D */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
+	5,	/* USART 3 */
+	0,	/* Multimedia Card Interface */
+	3,	/* USB Device Port */
+	0,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface */
+	4,	/* Serial Synchronous Controller */
+	4,	/* Serial Synchronous Controller */
+	4,	/* Serial Synchronous Controller */
+	7,	/* Timer Counter 0 */
+	7,	/* Timer Counter 1 */
+	7,	/* Timer Counter 2 */
+	0,	/* Timer Counter 3 */
+	0,	/* Timer Counter 4 */
+	0,	/* Timer Counter 5 */
+	2,	/* USB Host port */
+	2,	/* Ethernet MAC */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0	/* Advanced Interrupt Controller */
+#endif /*CONFIG_IPIPE */
 };
 
 void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200_time.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200_time.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200_time.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200_time.c	2007-04-04 11:52:05.000000000 +0200
@@ -34,6 +34,62 @@
 
 static unsigned long last_crtr;
 
+#ifdef CONFIG_IPIPE
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <asm/arch/at91rm9200_tc.h>
+#include "clock.h"
+
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+
+#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
+#define AT91_TC_REG_MASK (0xffff)
+
+#if (CONFIG_IPIPE_AT91_TC==0)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC0
+#elif (CONFIG_IPIPE_AT91_TC==1)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC1
+#elif (CONFIG_IPIPE_AT91_TC==2)
+#   define KERNEL_TIMER_IRQ_NUM AT91RM9200_ID_TC2
+#else
+#error IPIPE_AT91_TC must be 0, 1 or 2.
+#endif
+
+static inline unsigned int at91_tc_read(unsigned int reg_offset)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	return readl((void __iomem *)(addr + reg_offset));
+}
+
+static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	writel(value, (void __iomem *)(addr + reg_offset));
+}
+
+#define read_CV() at91_tc_read(AT91_TC_CV)
+#define read_RC() at91_tc_read(AT91_TC_RC)
+#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
+
+int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int at91_timer_initialized;
+#endif /* CONFIG_IPIPE */
+
 /*
  * The ST_CRTR is updated asynchronously to the master clock.  It is therefore
  *  necessary to read it twice (with the same value) to ensure accuracy.
@@ -41,14 +97,16 @@ static unsigned long last_crtr;
 static inline unsigned long read_CRTR(void) {
 	unsigned long x1, x2;
 
+	x2 = at91_sys_read(AT91_ST_CRTR);
 	do {
-		x1 = at91_sys_read(AT91_ST_CRTR);
+		x1 = x2;
 		x2 = at91_sys_read(AT91_ST_CRTR);
 	} while (x1 != x2);
 
 	return x1;
 }
 
+#ifndef CONFIG_IPIPE
 /*
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
@@ -144,3 +202,209 @@ struct sys_timer at91rm9200_timer = {
 	.resume		= at91rm9200_timer_reset,
 };
 
+#else /* CONFIG_IPIPE */
+
+/*
+ * Returns number of microseconds since last timer interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeofday()
+ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+ *  'tick' is usecs per jiffy (linux/timex.h).
+ */
+static unsigned long at91rm9200_gettimeoffset(void)
+{
+	unsigned long elapsed;
+
+	elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
+
+	return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	at91_tc_read(AT91_TC_SR);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
+{
+	/*
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+
+	write_seqlock(&xtime_lock);
+
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+	} else {
+		while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
+			timer_tick();
+			last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+		}
+		write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
+	}
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91rm9200_bad_freq(int irq, void *dev_id)
+{
+	static int ticks = 0;
+
+	if (++ticks != HZ * 120) {
+		if (!console_drivers || try_acquire_console_sem())
+			return at91rm9200_timer_interrupt(irq, dev_id);
+	
+		release_console_sem();
+	}
+
+	panic("AT91 clock rate incorrectly set.\n"
+	      "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
+	      clk_get_rate(clk_get(NULL, "mck")));
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(at91_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned short mid;
+				unsigned short low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned short low;
+				unsigned short mid;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long long result;
+		unsigned short stamp;
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = read_CV();
+		if (unlikely(stamp < local_tsc->low)) {
+			if (unlikely(!++local_tsc->mid))
+				/* 32 bit counter wrapped, increment high word. */
+				local_tsc->high++;
+		}
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	if (delay > 2) {
+		local_irq_save_hw(flags);
+		write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
+}
+
+static struct irqaction at91rm9200_timer_irq = {
+	.name		= "at91_tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= &at91rm9200_timer_interrupt
+};
+
+static char clk_name [] = "tc%";
+
+static struct clk tc = {
+	.name		= (const char *) clk_name,
+	.users          = 0,
+	.type		= CLK_TYPE_PERIPHERAL,
+	.pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
+};
+
+void __init at91rm9200_timer_init(void)
+{
+	unsigned long v;
+	
+	if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
+		at91rm9200_timer_irq.handler = &at91rm9200_bad_freq;
+
+	snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
+	clk_register(&tc);
+	clk_enable(&tc);
+	
+	/* No Sync. */
+	at91_tc_write(AT91_TC_BCR, 0);
+
+	/* program NO signal on XCN */
+	v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+	v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
+	v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
+	writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+
+	/* Disable the channel */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
+
+	/* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
+	at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
+
+	/* Disable all interrupts. */
+	at91_tc_write(AT91_TC_IDR, ~0ul);
+
+	/* Load the TC register C. */
+	last_crtr = 0;
+	write_RC(LATCH);
+
+	/* Enable CPCS interrupt. */
+	at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
+
+	/* Set up the interrupt. */
+	setup_irq(KERNEL_TIMER_IRQ_NUM, &at91rm9200_timer_irq);
+
+	/* Enable the channel. */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
+
+	at91_timer_initialized = 1;
+}
+
+struct sys_timer at91rm9200_timer = {
+	.init		= at91rm9200_timer_init,
+	.offset		= at91rm9200_gettimeoffset,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-10 07:58:16.000000000 +0200
@@ -27,6 +27,13 @@ static struct map_desc at91sam9261_io_de
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+#ifdef CONFIG_IPIPE
+		.virtual	= AT91_VA_BASE_TCB0,
+		.pfn		= __phys_to_pfn(AT91SAM9261_BASE_TCB0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+        }, {
+#endif /* CONFIG_IPIPE */
 		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
 		.pfn		= __phys_to_pfn(AT91SAM9261_SRAM_BASE),
 		.length		= AT91SAM9261_SRAM_SIZE,
@@ -242,6 +249,7 @@ void __init at91sam9261_initialize(unsig
  * The default interrupt priority levels (0 = lowest, 7 = highest).
  */
 static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
 	7,	/* Advanced Interrupt Controller */
 	7,	/* System Peripherals */
 	0,	/* Parallel IO Controller A */
@@ -274,6 +282,42 @@ static unsigned int at91sam9261_default_
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+   I-pipe. */
+	7,	/* Advanced Interrupt Controller */
+	7,	/* System Peripherals */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C */
+	0,
+	6,	/* USART 0 */
+	6,	/* USART 1 */
+	6,	/* USART 2 */
+	0,	/* Multimedia Card Interface */
+	4,	/* USB Device Port */
+	0,	/* Two-Wire Interface */
+	6,	/* Serial Peripheral Interface 0 */
+	6,	/* Serial Peripheral Interface 1 */
+	5,	/* Serial Synchronous Controller 0 */
+	5,	/* Serial Synchronous Controller 1 */
+	5,	/* Serial Synchronous Controller 2 */
+	7,	/* Timer Counter 0 */
+	7,	/* Timer Counter 1 */
+	7,	/* Timer Counter 2 */
+	3,	/* USB Host port */
+	3,	/* LCD Controller */
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+#endif /*CONFIG_IPIPE */
 };
 
 void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-04 11:52:05.000000000 +0200
@@ -22,10 +22,69 @@
 
 #include <asm/arch/at91_pit.h>
 
+static unsigned long last_crtr;
+
+#ifdef CONFIG_IPIPE
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/at91_tc.h>
+#include "clock.h"
+
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+
+#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
+#define AT91_TC_REG_MASK (0xffff)
+
+#if (CONFIG_IPIPE_AT91_TC==0)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC0
+#elif (CONFIG_IPIPE_AT91_TC==1)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC1
+#elif (CONFIG_IPIPE_AT91_TC==2)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC2
+#else
+#error IPIPE_AT91_TC must be 0, 1 or 2.
+#endif
+
+static inline unsigned int at91_tc_read(unsigned int reg_offset)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	return readl((void __iomem *)(addr + reg_offset));
+}
+
+static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	writel(value, (void __iomem *)(addr + reg_offset));
+}
+
+#define read_CV() at91_tc_read(AT91_TC_CV)
+#define read_RC() at91_tc_read(AT91_TC_RC)
+#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
+
+int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int at91_timer_initialized;
+#endif /* CONFIG_IPIPE */
 
 #define PIT_CPIV(x)	((x) & AT91_PIT_CPIV)
 #define PIT_PICNT(x)	(((x) & AT91_PIT_PICNT) >> 20)
 
+#ifndef CONFIG_IPIPE
 /*
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
@@ -112,3 +171,209 @@ struct sys_timer at91sam926x_timer = {
 	.resume		= at91sam926x_timer_reset,
 };
 
+#else /* CONFIG_IPIPE */
+
+/*
+ * Returns number of microseconds since last timer interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeofday()
+ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+*  'tick' is usecs per jiffy (linux/timex.h).
+ */
+static unsigned long at91sam926x_gettimeoffset(void)
+{
+	unsigned long elapsed;
+
+	elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
+
+	return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	at91_tc_read(AT91_TC_SR);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
+{
+	/*
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+
+	write_seqlock(&xtime_lock);
+
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+	} else {
+		while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
+			timer_tick();
+			last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+		}
+		write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
+	}
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91sam926x_bad_freq(int irq, void *dev_id)
+{
+	static int ticks = 0;
+
+	if (++ticks != HZ * 120) {
+		if (!console_drivers || try_acquire_console_sem())
+			return at91sam926x_timer_interrupt(irq, dev_id);
+	
+		release_console_sem();
+	}
+
+	panic("AT91 clock rate incorrectly set.\n"
+	      "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
+	      clk_get_rate(clk_get(NULL, "mck")));
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(at91_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned short mid;
+				unsigned short low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned short low;
+				unsigned short mid;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long long result;
+		unsigned short stamp;
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = read_CV();
+		if (unlikely(stamp < local_tsc->low)) {
+			if (unlikely(!++local_tsc->mid))
+				/* 32 bit counter wrapped, increment high word. */
+				local_tsc->high++;
+		}
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	if (delay > 2) {
+		local_irq_save_hw(flags);
+		write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
+}
+
+static struct irqaction at91sam926x_timer_irq = {
+	.name		= "at91_tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= &at91sam926x_timer_interrupt
+};
+
+static char clk_name [] = "tc%";
+
+static struct clk tc = {
+	.name		= (const char *) clk_name,
+	.users          = 0,
+	.type		= CLK_TYPE_PERIPHERAL,
+	.pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
+};
+
+void __init at91sam926x_timer_init(void)
+{
+	unsigned long v;
+	
+	if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
+		at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
+
+	snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
+	clk_register(&tc);
+	clk_enable(&tc);
+	
+	/* No Sync. */
+	at91_tc_write(AT91_TC_BCR, 0);
+
+	/* program NO signal on XCN */
+	v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+	v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
+	v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
+	writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+
+	/* Disable the channel */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
+
+	/* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
+	at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
+
+	/* Disable all interrupts. */
+	at91_tc_write(AT91_TC_IDR, ~0ul);
+
+	/* Load the TC register C. */
+	last_crtr = 0;
+	write_RC(LATCH);
+
+	/* Enable CPCS interrupt. */
+	at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
+
+	/* Set up the interrupt. */
+	setup_irq(KERNEL_TIMER_IRQ_NUM, &at91sam926x_timer_irq);
+
+	/* Enable the channel. */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
+
+	at91_timer_initialized = 1;
+}
+
+struct sys_timer at91sam926x_timer = {
+	.init		= at91sam926x_timer_init,
+	.offset		= at91sam926x_gettimeoffset,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c	2007-04-04 11:52:05.000000000 +0200
@@ -22,6 +22,11 @@
 #include <asm/arch/at91_pio.h>
 #include <asm/arch/at91_pmc.h>
 #include <asm/arch/gpio.h>
+#ifdef CONFIG_IPIPE
+#include <asm/irq.h>
+
+unsigned __ipipe_at91_gpio_banks = 0;
+#endif /* CONFIG_IPIPE */
 
 #include "generic.h"
 
@@ -328,6 +333,9 @@ static int gpio_irq_type(unsigned pin, u
 
 static struct irq_chip gpio_irqchip = {
 	.name		= "GPIO",
+#ifdef CONFIG_IPIPE
+	.ack            = gpio_irq_mask,
+#endif
 	.mask		= gpio_irq_mask,
 	.unmask		= gpio_irq_unmask,
 	.set_type	= gpio_irq_type,
@@ -376,6 +384,50 @@ static void gpio_irq_handler(unsigned ir
 	/* now it may re-trigger */
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc = irq_desc + irq;
+	unsigned	pin;
+	struct irqdesc	*gpio;
+	void __iomem	*pio;
+	u32		isr;
+
+	pio = get_irq_chip_data(irq);
+
+	/* temporarily mask (level sensitive) parent IRQ */
+	desc->chip->ack(irq);
+	for (;;) {
+		isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
+		if (!isr)
+			break;
+
+		pin = (unsigned) get_irq_data(irq);
+		gpio = &irq_desc[pin];
+
+		while (isr) {
+			if (isr & 1) {
+				if (unlikely(gpio->depth)) {
+					/*
+					 * The core ARM interrupt handler lazily disables IRQs so
+					 * another IRQ must be generated before it actually gets
+					 * here to be disabled on the GPIO controller.
+					 */
+					gpio_irq_mask(pin);
+				}
+				else
+					__ipipe_handle_irq(pin, regs);
+			}
+			pin++;
+			gpio++;
+			isr >>= 1;
+		}
+	}
+	desc->chip->unmask(irq);
+	/* now it may re-trigger */
+}
+#endif /* CONFIG_IPIPE */
+
 /*--------------------------------------------------------------------------*/
 
 /*
@@ -424,4 +476,7 @@ void __init at91_gpio_init(struct at91_g
 
 	gpio = data;
 	gpio_banks = nr_banks;
+#ifdef CONFIG_IPIPE
+	__ipipe_at91_gpio_banks = nr_banks;
+#endif /* CONFIG_IPIPE */
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig
--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig	2007-04-10 15:20:34.000000000 +0200
@@ -118,6 +118,34 @@ endif
 
 # ----------------------------------------------------------
 
+if ARCH_AT91SAM9261 || ARCH_AT91RM9200
+
+comment "Ipipe dependent"
+
+config IPIPE_AT91_TC
+	depends on IPIPE
+	int "AT91 TC used as time base"
+	default 0
+	help
+	When Adeos interrupt pipeline is enabled, TC0 is used by default
+	as time base, but you can use TC1 or TC2 by setting this variable to 1
+	or 2. This should only be needed to avoid conflicts with other drivers.
+
+config IPIPE_AT91_MCK
+	depends on IPIPE
+	int "AT91 Master clock Frequency"
+	default 59904000 if MACH_AT91RM9200EK
+	default 99328000 if MACH_AT91SAM9261EK
+	default 53000000
+	help
+	When Adeos interrupt pipeline is enabled, AT91 timer is based on
+	the AT91 master clock, whose frequency need hence to be known at
+	compilation time.
+
+endif
+
+# ----------------------------------------------------------
+
 comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-integrator/core.c linux-2.6.19.patched/arch/arm/mach-integrator/core.c
--- linux-2.6.19.at91/arch/arm/mach-integrator/core.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-integrator/core.c	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mach-integrator/core.c
  *
  *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -195,53 +196,57 @@ EXPORT_SYMBOL(cm_control);
 /*
  * How long is the timer interval?
  */
-#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
-#else
 #define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
-#endif
 
 static unsigned long timer_reload;
+static unsigned long timer_interval;
+static unsigned long timer_lxlost;
+static int tscok;
+
+#ifdef CONFIG_IPIPE
+int __ipipe_mach_timerint = IRQ_TIMERINT1;
+static unsigned long long __ipipe_mach_tsc;
+static IPIPE_DEFINE_SPINLOCK(timer_lock);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+#endif
 
 /*
- * Returns number of ms since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
+ * Called with IRQ disabled from do_gettimeofday().
  */
-unsigned long integrator_gettimeoffset(void)
+static inline unsigned long integrator_getticksoffset(void)
 {
-	unsigned long ticks1, ticks2, status;
+	unsigned long ticks;
 
-	/*
-	 * Get the current number of ticks.  Note that there is a race
-	 * condition between us reading the timer and checking for
-	 * an interrupt.  We get around this by ensuring that the
-	 * counter has not reloaded between our two reads.
-	 */
-	ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
-	do {
-		ticks1 = ticks2;
-		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
-		ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
-	} while (ticks2 > ticks1);
+	if (!tscok)
+		return 0;
 
-	/*
-	 * Number of ticks since last interrupt.
-	 */
-	ticks1 = timer_reload - ticks2;
+	ticks = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
 
-	/*
-	 * Interrupt pending?  If so, we've reloaded once already.
-	 */
-	if (status & (1 << IRQ_TIMERINT1))
-		ticks1 += timer_reload;
+	if (ticks > timer_reload)
+		ticks = 0xffff + timer_reload - ticks;
+	else
+		ticks = timer_reload - ticks;
+
+	if (timer_interval < 0x10000)
+		return ticks;
+	else if (timer_interval < 0x100000)
+		return ticks * 16;
+	else
+		return ticks * 256;
+}
 
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+unsigned long integrator_gettimeoffset(void)
+{
 	/*
 	 * Convert the ticks to usecs
 	 */
-	return TICKS2USECS(ticks1);
+	return TICKS2USECS(timer_lxlost + integrator_getticksoffset());
 }
 
 /*
@@ -252,10 +257,22 @@ integrator_timer_interrupt(int irq, void
 {
 	write_seqlock(&xtime_lock);
 
+	timer_lxlost = 0;
+
+#ifdef CONFIG_IPIPE
 	/*
-	 * clear the interrupt
+	 * If Linux is the only domain, ack the timer and reprogram it
 	 */
+	if (!__ipipe_mach_timerstolen) {
+		__ipipe_mach_tsc += integrator_getticksoffset();
+#else
 	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
+#endif
+
+		writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+#ifdef CONFIG_IPIPE
+	}
+#endif
 
 	/*
 	 * the clock tick routines are only processed on the
@@ -286,24 +303,30 @@ static struct irqaction integrator_timer
 	.handler	= integrator_timer_interrupt,
 };
 
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
+static inline void set_dec(unsigned long reload)
 {
-	unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+	unsigned int ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_IE;
 
 	timer_reload = reload;
-	timer_ctrl |= ctrl;
+	timer_interval = reload;
 
-	if (timer_reload > 0x100000) {
+	if (timer_reload >= 0x100000) {
 		timer_reload >>= 8;
-		timer_ctrl |= TIMER_CTRL_DIV256;
-	} else if (timer_reload > 0x010000) {
+		ctrl |= TIMER_CTRL_DIV256;
+	} else if (timer_reload >= 0x010000) {
 		timer_reload >>= 4;
-		timer_ctrl |= TIMER_CTRL_DIV16;
+		ctrl |= TIMER_CTRL_DIV16;
 	}
 
+	writel(ctrl, TIMER1_VA_BASE + TIMER_CTRL);
+	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
+{
 	/*
 	 * Initialise to a known state (all timers off)
 	 */
@@ -311,12 +334,57 @@ void __init integrator_time_init(unsigne
 	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
 	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 
-	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
-	writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
-	writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
+	set_dec(reload);
 
 	/*
 	 * Make irqs happen for the system timer
 	 */
 	setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
+
+	tscok = 1;
 }
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	unsigned long long result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	result = __ipipe_mach_tsc + integrator_getticksoffset();
+	spin_unlock_irqrestore(&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(&timer_lock, flags);
+	ticks = integrator_getticksoffset();
+	__ipipe_mach_tsc += ticks;
+	timer_lxlost += ticks;
+
+	set_dec(reload);
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return readl(TIMER1_VA_BASE + TIMER_VALUE);
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-integrator/integrator_cp.c linux-2.6.19.patched/arch/arm/mach-integrator/integrator_cp.c
--- linux-2.6.19.at91/arch/arm/mach-integrator/integrator_cp.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-integrator/integrator_cp.c	2007-04-04 11:52:05.000000000 +0200
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mach-integrator/integrator_cp.c
  *
  *  Copyright (C) 2003 Deep Blue Solutions Ltd
+ *  Copyright (C) 2005 Stelian Pop.
  *
  * 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
@@ -19,6 +20,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/kmi.h>
 #include <linux/amba/clcd.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -222,6 +224,31 @@ sic_handle_irq(unsigned int irq, struct 
 	} while (status);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+
+	if (status == 0) {
+		do_bad_IRQ(irq, desc_unused);
+		return;
+	}
+
+	do {
+		irq = ffs(status) - 1;
+		status &= ~(1 << irq);
+
+		irq += IRQ_SIC_START;
+
+		__ipipe_handle_irq(irq, regs);
+	} while (status);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 static void __init intcp_init_irq(void)
 {
 	unsigned int i;
@@ -568,9 +595,14 @@ static void __init intcp_init(void)
 
 #define TIMER_CTRL_IE	(1 << 5)			/* Interrupt Enable */
 
+#ifdef CONFIG_IPIPE
+unsigned int __ipipe_mach_ticks_per_jiffy = 1000000 * TICKS_PER_uSEC / HZ;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+#endif
+
 static void __init intcp_timer_init(void)
 {
-	integrator_time_init(1000000 / HZ, TIMER_CTRL_IE);
+	integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, TIMER_CTRL_IE);
 }
 
 static struct sys_timer cp_timer = {
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-pxa/irq.c linux-2.6.19.patched/arch/arm/mach-pxa/irq.c
--- linux-2.6.19.at91/arch/arm/mach-pxa/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-pxa/irq.c	2007-04-04 11:52:05.000000000 +0200
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -216,6 +217,42 @@ static void pxa_gpio_demux_handler(unsig
 	} while (loop);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+	unsigned int i, mask[4];
+	int loop;
+
+	do {
+		loop = 0;
+
+		mask[0] = GEDR0 & ~3;
+		mask[1] = GEDR1;
+		mask[2] = GEDR2;
+#if PXA_LAST_GPIO < 96
+		i = 3;
+#else /* PXA_LAST_GPIO >= 96 */
+		mask[3] = GEDR3;
+		i = 4;
+#endif /* PXA_LAST_GPIO >= 96 */
+		for (; i; i--) {
+			loop |= mask[i - 1];
+			while (mask[i - 1]) {
+				irq = fls(mask[i - 1]) - 1;
+				mask[i - 1] &= ~(1 << irq);
+				irq = IRQ_GPIO((i - 1) * 32 + irq);
+
+				__ipipe_handle_irq(irq, regs);
+			}
+		}
+	} while (loop);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 static void pxa_ack_muxed_gpio(unsigned int irq)
 {
 	int gpio = irq - IRQ_GPIO(2) + 2;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-pxa/time.c linux-2.6.19.patched/arch/arm/mach-pxa/time.c
--- linux-2.6.19.at91/arch/arm/mach-pxa/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-pxa/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -18,6 +18,7 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -29,6 +30,23 @@
 #include <asm/arch/pxa-regs.h>
 
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+int __ipipe_mach_timerint = IRQ_OST0;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int pxa_timer_initialized;
+static unsigned long last_jiffy_time;
+#endif /* CONFIG_IPIPE */
+
 static inline unsigned long pxa_get_rtc_time(void)
 {
 	return RCNR;
@@ -53,6 +71,9 @@ static unsigned long pxa_gettimeoffset (
 {
 	long ticks_to_match, elapsed, usec;
 
+#ifdef CONFIG_IPIPE
+	if (!__ipipe_mach_timerstolen) {
+#endif
 	/* Get ticks before next timer match */
 	ticks_to_match = OSMR0 - OSCR;
 
@@ -62,6 +83,10 @@ static unsigned long pxa_gettimeoffset (
 	/* don't get fooled by the workaround in pxa_timer_interrupt() */
 	if (elapsed <= 0)
 		return 0;
+#ifdef CONFIG_IPIPE
+	} else
+		elapsed = OSCR - last_jiffy_time;
+#endif
 
 	/* Now convert them to usec */
 	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
@@ -104,9 +129,27 @@ pxa_timer_interrupt(int irq, void *dev_i
 	 * affect things only when the timer IRQ has been delayed by nearly
 	 * exactly one tick period which should be a pretty rare event.
 	 */
+#ifdef CONFIG_IPIPE
+	/*
+	 * - if Linux is running natively (no ipipe), ack and reprogram the timer
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_jiffy_time += LATCH;
+	} else
+#endif /* CONFIG_IPIPE */
 	do {
 		timer_tick();
+#ifdef CONFIG_IPIPE
+		last_jiffy_time += LATCH;
+#else /* !CONFIG_IPIPE */
 		OSSR = OSSR_M0;  /* Clear match on timer 0 */
+#endif /* !CONFIG_IPIPE */
 		next_match = (OSMR0 += LATCH);
 	} while( (signed long)(next_match - OSCR) <= 8 );
 
@@ -138,6 +181,10 @@ static void __init pxa_timer_init(void)
 	setup_irq(IRQ_OST0, &pxa_timer_irq);
 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
 	OSCR = 0;		/* initialize free-running timer */
+
+#ifdef CONFIG_IPIPE
+	pxa_timer_initialized = 1;
+#endif /* CONFIG_IPIPE */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -215,3 +262,75 @@ struct sys_timer pxa_timer = {
 	.dyn_tick	= &pxa_dyn_tick,
 #endif
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	OSSR = OSSR_M0;  /* Clear match on timer 0 */
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(pxa_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned long low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned long low;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long stamp, flags;
+		unsigned long long result;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = OSCR;
+		if (unlikely(stamp < local_tsc->low))
+			/* 32 bit counter wrapped, increment high word. */
+			local_tsc->high++;
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	if (delay > 8) {
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		OSMR0 = delay + OSCR;
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(IRQ_OST0);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return OSMR0 - OSCR;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/irq.c linux-2.6.19.patched/arch/arm/mach-s3c2410/irq.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
-*/
+ *
+ *   30-Oct-2006  Sebastian Smolorz
+ *		  Added Adeos/I-pipe 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
@@ -668,6 +682,79 @@ int s3c24xx_irq_resume(struct sys_device
 #define s3c24xx_irq_resume  NULL
 #endif
 
+#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;
+
+	switch (irq) {
+	case IRQ_UART0:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX0, subsrc, regs);
+		break;
+	case IRQ_UART1:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX1, subsrc, regs);
+		break;
+	case IRQ_UART2:
+		__ipipe_s3c_irq_demux_uart(IRQ_S3CUART_RX2, subsrc, regs);
+		break;
+	case IRQ_ADCPARENT:
+		__ipipe_s3c_irq_demux_adc(subsrc, regs);
+		break;
+#ifdef CONFIG_CPU_S3C2440
+	case IRQ_WDT:
+		__ipipe_s3c_irq_demux_wdtac97(subsrc, regs);
+		break;
+	case IRQ_CAM:
+		__ipipe_s3c_irq_demux_cam(subsrc, regs);
+		break;
+#endif /* CONFIG_CPU_S3C2440 */
+	}
+
+	desc_unused->chip->unmask(irq);
+}
+#endif /* CONFIG_IPIPE */
+
 /* s3c24xx_init_irq
  *
  * Initialise S3C2410 IRQ system
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/s3c2440-irq.c linux-2.6.19.patched/arch/arm/mach-s3c2410/s3c2440-irq.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/s3c2440-irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/s3c2440-irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003,2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
@@ -25,6 +27,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>
@@ -96,6 +99,34 @@ static struct irqchip s3c_irq_wdtac97 = 
 	.ack	    = s3c_irq_wdtac97_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 -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-s3c2410/time.c linux-2.6.19.patched/arch/arm/mach-s3c2410/time.c
--- linux-2.6.19.at91/arch/arm/mach-s3c2410/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-s3c2410/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (C) 2003-2005 Simtec Electronics
  *	Ben Dooks, <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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
@@ -25,6 +27,7 @@
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clk.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 last_free_running_tcnt = 0;
+static unsigned long free_running_tcon = 0;
+static unsigned long timer_lxlost = 0;
+
+#ifdef CONFIG_IPIPE
+unsigned int __ipipe_mach_ticks_per_jiffy;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+int __ipipe_mach_timerint = IRQ_TIMER4;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+static unsigned long long __ipipe_mach_tsc = 0;
+static unsigned long timer_ackval = 1UL << (IRQ_TIMER4 - IRQ_EINT0);
+static IPIPE_DEFINE_SPINLOCK(timer_lock);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+#endif /* CONFIG_IPIPE */
 
 /* timer_mask_usec_ticks
  *
@@ -85,44 +105,46 @@ 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)
+static inline unsigned long timer_freerunning_getvalue(void)
 {
-	unsigned long tdone;
-	unsigned long irqpend;
-	unsigned long tval;
-
-	/* work out how many ticks have gone since last timer interrupt */
+	return __raw_readl(S3C2410_TCNTO(3));
+}
 
-        tval =  __raw_readl(S3C2410_TCNTO(4));
-	tdone = timer_startval - tval;
+static inline unsigned long timer_freerunning_getticksoffset(unsigned long tval)
+{
+	long tdone;
 
-	/* check to see if there is an interrupt pending */
+	tdone =  last_free_running_tcnt - tval;
+	if (tdone < 0)
+		tdone += 0x10000;
 
-	irqpend = __raw_readl(S3C2410_SRCPND);
-	if (irqpend & SRCPND_TIMER4) {
-		/* re-read the timer, and try and fix up for the missed
-		 * interrupt. Note, the interrupt may go off before the
-		 * timer has re-loaded from wrapping.
-		 */
+	return tdone;
+}
 
-		tval =  __raw_readl(S3C2410_TCNTO(4));
-		tdone = timer_startval - tval;
+static inline unsigned long getticksoffset(void)
+{
+	return timer_freerunning_getticksoffset(timer_freerunning_getvalue());
+}
 
-		if (tval != 0)
-			tdone += timer_startval;
-	}
+#ifdef CONFIG_IPIPE
+static inline unsigned long getticksoffset_tscupdate(void)
+{
+	unsigned long tval;
+	unsigned long ticks;
 
-	return timer_ticks_to_usec(tdone);
+	tval = timer_freerunning_getvalue();
+	ticks = timer_freerunning_getticksoffset(tval);
+	last_free_running_tcnt = tval;
+	__ipipe_mach_tsc += ticks;
+	return ticks;
 }
+#endif /* CONFIG_IPIPE */
 
+static unsigned long s3c2410_gettimeoffset (void)
+{
+	return timer_ticks_to_usec(timer_lxlost + getticksoffset());
+}
 
 /*
  * IRQ handler for the timer
@@ -131,6 +153,14 @@ static irqreturn_t
 s3c2410_timer_interrupt(int irq, void *dev_id)
 {
 	write_seqlock(&xtime_lock);
+
+#ifdef CONFIG_IPIPE
+	timer_lxlost = 0;
+
+	if (!__ipipe_mach_timerstolen)
+		getticksoffset_tscupdate();
+#endif /* CONFIG_IPIPE */
+
 	timer_tick();
 	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
@@ -149,10 +179,10 @@ static struct irqaction s3c2410_timer_ir
 	machine_is_osiris() )
 
 /*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up timer interrupt.
  *
- * Currently we only use timer4, as it is the only timer which has no
- * other function that can be exploited externally
+ * Currently we use timer4 as event timer and timer3 as tick counter which
+ * permanently counts ticks without interrupt generation.
  */
 static void s3c2410_timer_setup (void)
 {
@@ -160,6 +190,7 @@ static void s3c2410_timer_setup (void)
 	unsigned long tcnt;
 	unsigned long tcfg1;
 	unsigned long tcfg0;
+	unsigned long intmask;
 
 	tcnt = 0xffff;  /* default value for tcnt */
 
@@ -176,8 +207,8 @@ static void s3c2410_timer_setup (void)
 		timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
 		tcnt = 12000000 / HZ;
 
-		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-		tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
+		tcfg1 &= ~(S3C2410_TCFG1_MUX4_MASK | S3C2410_TCFG1_MUX3_MASK);
+		tcfg1 |= (S3C2410_TCFG1_MUX4_TCLK1 | S3C2410_TCFG1_MUX3_TCLK1);
 	} else {
 		unsigned long pclk;
 		struct clk *clk;
@@ -205,8 +236,8 @@ static void s3c2410_timer_setup (void)
 
 		timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
 
-		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-		tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+		tcfg1 &= ~(S3C2410_TCFG1_MUX4_MASK | S3C2410_TCFG1_MUX3_MASK);
+		tcfg1 |= (S3C2410_TCFG1_MUX4_DIV2 | S3C2410_TCFG1_MUX3_DIV2);
 
 		tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
 		tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
@@ -214,6 +245,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--;
@@ -230,23 +265,37 @@ 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... */
+	/* ensure timers are stopped... */
+	tcon &= ~(0x3f<<17);
+	__raw_writel(tcon, S3C2410_TCON);
 
-	tcon &= ~(7<<20);
-	tcon |= S3C2410_TCON_T4RELOAD;
-	tcon |= S3C2410_TCON_T4MANUALUPD;
+	/* Mask timer3 interrupt. */
+	intmask = __raw_readl(S3C2410_INTMSK);
+	intmask |= 1UL << (IRQ_TIMER3 - IRQ_EINT0);
+	__raw_writel(intmask, S3C2410_INTMSK);
 
-	__raw_writel(tcon, S3C2410_TCON);
+	/* Set timer values */
 	__raw_writel(tcnt, S3C2410_TCNTB(4));
 	__raw_writel(tcnt, S3C2410_TCMPB(4));
+	__raw_writel(0xffff, S3C2410_TCNTB(3));
+	__raw_writel(0xffff, S3C2410_TCMPB(3));
 
-	/* start the timer running */
-	tcon |= S3C2410_TCON_T4START;
-	tcon &= ~S3C2410_TCON_T4MANUALUPD;
+	/* Set base tcon value for later programming of timer 4 by Xenomai. */
+	free_running_tcon = tcon |  S3C2410_TCON_T3RELOAD | S3C2410_TCON_T3START;
+
+	/* Set auto reloads for both timers. */
+	tcon |= S3C2410_TCON_T3RELOAD | S3C2410_TCON_T4RELOAD;
+
+	/* Manual update */
+	__raw_writel(tcon | S3C2410_TCON_T3MANUALUPD
+			  | S3C2410_TCON_T4MANUALUPD, S3C2410_TCON);
+
+	tcon |= S3C2410_TCON_T3START | S3C2410_TCON_T4START;
+	/* Start timers.*/
 	__raw_writel(tcon, S3C2410_TCON);
+
+	/* Save start value of timer 3 as begining of first period. */
+	last_free_running_tcnt = 0xffff;
 }
 
 static void __init s3c2410_timer_init (void)
@@ -260,3 +309,56 @@ struct sys_timer s3c24xx_timer = {
 	.offset		= s3c2410_gettimeoffset,
 	.resume		= s3c2410_timer_setup
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	__raw_writel(timer_ackval, S3C2410_SRCPND);
+	__raw_writel(timer_ackval, S3C2410_INTPND);
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	unsigned long long result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	result = __ipipe_mach_tsc + getticksoffset();
+	spin_unlock_irqrestore(&timer_lock, flags);
+	return result;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+static inline void set_dec(unsigned long reload)
+{
+	__raw_writel(reload, S3C2410_TCNTB(4));
+	/* Manual update */
+	__raw_writel(free_running_tcon | S3C2410_TCON_T4MANUALUPD, S3C2410_TCON);
+	/* Start timer */
+	__raw_writel(free_running_tcon | S3C2410_TCON_T4START, S3C2410_TCON);
+}
+
+void __ipipe_mach_set_dec(unsigned long reload)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	timer_lxlost += getticksoffset_tscupdate();
+	set_dec(reload);
+	spin_unlock_irqrestore(&timer_lock, flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+	free_running_tcon |= S3C2410_TCON_T4RELOAD;
+	__ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy - 1);
+	free_running_tcon &= ~S3C2410_TCON_T4RELOAD;
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return __raw_readl(S3C2410_TCNTO(4));
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-sa1100/irq.c linux-2.6.19.patched/arch/arm/mach-sa1100/irq.c
--- linux-2.6.19.at91/arch/arm/mach-sa1100/irq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-sa1100/irq.c	2007-04-04 11:52:06.000000000 +0200
@@ -16,6 +16,7 @@
 #include <linux/ioport.h>
 #include <linux/ptrace.h>
 #include <linux/sysdev.h>
+#include <linux/ipipe.h>
 
 #include <asm/hardware.h>
 #include <asm/mach/irq.h>
@@ -137,6 +138,37 @@ sa1100_high_gpio_handler(unsigned int ir
 	} while (mask);
 }
 
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc_unused = irq_desc + irq;
+	unsigned irq_unused = irq;
+	unsigned int mask;
+
+	mask = GEDR & 0xfffff800;
+	do {
+		/*
+		 * clear down all currently active IRQ sources.
+		 * We will be processing them all.
+		 */
+		GEDR = mask;
+
+		irq = IRQ_GPIO11;
+		mask >>= 11;
+		do {
+			if (mask & 1)
+				__ipipe_handle_irq(irq, regs);
+			mask >>= 1;
+			irq++;
+		} while (mask);
+
+		mask = GEDR & 0xfffff800;
+	} while (mask);
+
+	desc_unused->chip->unmask(irq_unused);
+}
+#endif /* CONFIG_IPIPE */
+
 /*
  * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
  * In addition, the IRQs are all collected up into one bit in the
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-sa1100/time.c linux-2.6.19.patched/arch/arm/mach-sa1100/time.c
--- linux-2.6.19.at91/arch/arm/mach-sa1100/time.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mach-sa1100/time.c	2007-04-04 11:52:06.000000000 +0200
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/signal.h>
+#include <linux/module.h>
 
 #include <asm/mach/time.h>
 #include <asm/hardware.h>
@@ -21,6 +22,23 @@
 #define RTC_DEF_DIVIDER		(32768 - 1)
 #define RTC_DEF_TRIM            0
 
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+int __ipipe_mach_timerint = IRQ_OST0;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int sa1100_timer_initialized;
+static unsigned long last_jiffy_time;
+#endif /* CONFIG_IPIPE */
+
 static unsigned long __init sa1100_get_rtc_time(void)
 {
 	/*
@@ -59,11 +77,18 @@ static unsigned long sa1100_gettimeoffse
 {
 	unsigned long ticks_to_match, elapsed, usec;
 
+#ifdef CONFIG_IPIPE
+	if (!__ipipe_mach_timerstolen) {
+#endif
 	/* Get ticks before next timer match */
 	ticks_to_match = OSMR0 - OSCR;
 
 	/* We need elapsed ticks since last match */
 	elapsed = LATCH - ticks_to_match;
+#ifdef CONFIG_IPIPE
+	} else
+		elapsed = OSCR - last_jiffy_time;
+#endif
 
 	/* Now convert them to usec */
 	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
@@ -98,9 +123,27 @@ sa1100_timer_interrupt(int irq, void *de
 	 * ensured, hence we can use do_gettimeofday() from interrupt
 	 * handlers.
 	 */
+#ifdef CONFIG_IPIPE
+	/*
+	 * - if Linux is running natively (no ipipe), ack and reprogram the timer
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_jiffy_time += LATCH;
+	} else
+#endif /* CONFIG_IPIPE */
 	do {
 		timer_tick();
+#ifdef CONFIG_IPIPE
+		last_jiffy_time += LATCH;
+#else /* !CONFIG_IPIPE */
 		OSSR = OSSR_M0;  /* Clear match on timer 0 */
+#endif /* !CONFIG_IPIPE */
 		next_match = (OSMR0 += LATCH);
 	} while ((signed long)(next_match - OSCR) <= 0);
 
@@ -132,6 +175,10 @@ static void __init sa1100_timer_init(voi
 	setup_irq(IRQ_OST0, &sa1100_timer_irq);
 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
 	OSCR = 0;		/* initialize free-running timer */
+
+#ifdef CONFIG_IPIPE
+	sa1100_timer_initialized = 1;
+#endif /* CONFIG_IPIPE */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -210,3 +257,72 @@ struct sys_timer sa1100_timer = {
 	.dyn_tick	= &sa1100_dyn_tick,
 #endif
 };
+
+#ifdef CONFIG_IPIPE
+void __ipipe_mach_acktimer(void)
+{
+	OSSR = OSSR_M0;  /* Clear match on timer 0 */
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(sa1100_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned long low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned long low;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long stamp, flags;
+		unsigned long long result;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = OSCR;
+		if (unlikely(stamp < local_tsc->low))
+			/* 32 bit counter wrapped, increment high word. */
+			local_tsc->high++;
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+        OSMR0 = delay + OSCR;
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return OSMR0 - OSCR;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/copypage-v4mc.c linux-2.6.19.patched/arch/arm/mm/copypage-v4mc.c
--- linux-2.6.19.at91/arch/arm/mm/copypage-v4mc.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/copypage-v4mc.c	2007-04-04 11:52:06.000000000 +0200
@@ -43,7 +43,7 @@ static DEFINE_SPINLOCK(minicache_lock);
  * instruction.  If your processor does not supply this, you have to write your
  * own copy_user_page that does the right thing.
  */
-static void __attribute__((naked))
+static void notrace __attribute__((naked))
 mc_copy_user_page(void *from, void *to)
 {
 	asm volatile(
@@ -82,7 +82,7 @@ void v4_mc_copy_user_page(void *kto, con
 /*
  * ARMv4 optimised clear_user_page
  */
-void __attribute__((naked))
+void notrace __attribute__((naked))
 v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
 {
 	asm volatile(
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/copypage-xscale.c linux-2.6.19.patched/arch/arm/mm/copypage-xscale.c
--- linux-2.6.19.at91/arch/arm/mm/copypage-xscale.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/copypage-xscale.c	2007-04-04 11:52:06.000000000 +0200
@@ -41,7 +41,7 @@ static DEFINE_SPINLOCK(minicache_lock);
  * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
  * and merged as appropriate.
  */
-static void __attribute__((naked))
+static void notrace __attribute__((naked))
 mc_copy_user_page(void *from, void *to)
 {
 	/*
@@ -104,7 +104,7 @@ void xscale_mc_copy_user_page(void *kto,
 /*
  * XScale optimised clear_user_page
  */
-void __attribute__((naked))
+void notrace __attribute__((naked))
 xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr)
 {
 	asm volatile(
diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mm/fault.c linux-2.6.19.patched/arch/arm/mm/fault.c
--- linux-2.6.19.at91/arch/arm/mm/fault.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/arch/arm/mm/fault.c	2007-04-04 11:52:06.000000000 +0200
@@ -223,6 +223,9 @@ do_page_fault(unsigned long addr, unsign
 	struct mm_struct *mm;
 	int fault, sig, code;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+		return 0;
+
 	tsk = current;
 	mm  = tsk->mm;
 
@@ -327,6 +330,9 @@ do_translation_fault(unsigned long addr,
 	if (addr < TASK_SIZE)
 		return do_page_fault(addr, fsr, regs);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+		return 0;
+
 	index = pgd_index(addr);
 
 	/*
@@ -362,6 +368,10 @@ bad_area:
 static int
 do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+
+	if (ipipe_trap_notify(IPIPE_TRAP_SECTION,regs))
+		return 0;
+
 	do_bad_area(addr, fsr, regs);
 	return 0;
 }
@@ -372,6 +382,9 @@ do_sect_fault(unsigned long addr, unsign
 static int
 do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_DABT,regs))
+		return 0;
+
 	return 1;
 }
 
@@ -447,6 +460,9 @@ do_DataAbort(unsigned long addr, unsigne
 	if (!inf->fn(addr, fsr, regs))
 		return;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_UNKNOWN,regs))
+		return;
+
 	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
 
@@ -463,3 +479,35 @@ do_PrefetchAbort(unsigned long addr, str
 	do_translation_fault(addr, 0, regs);
 }
 
+#ifdef CONFIG_IPIPE
+static void vmalloc_sync_one(pgd_t *pgd, unsigned long addr)
+{
+	unsigned int index = pgd_index(addr);
+	pgd_t *pgd_k;
+	pmd_t *pmd, *pmd_k;
+
+	pgd += index;
+	pgd_k = init_mm.pgd + index;
+
+	if (!pgd_present(*pgd))
+		set_pgd(pgd, *pgd_k);
+
+	pmd_k = pmd_offset(pgd_k, addr);
+	pmd   = pmd_offset(pgd, addr);
+
+	copy_pmd(pmd, pmd_k);
+}
+
+int __ipipe_pin_range_mapping(struct mm_struct *mm,
+			      unsigned long start, unsigned long end)
+{
+	unsigned long next, addr = start;
+
+	do {
+		next = pgd_addr_end(addr, end);
+		vmalloc_sync_one(mm->pgd, addr);
+	} while (addr = next, addr != end);
+
+	return 0;
+}
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/drivers/pci/htirq.c linux-2.6.19.patched/drivers/pci/htirq.c
--- linux-2.6.19.at91/drivers/pci/htirq.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/drivers/pci/htirq.c	2007-04-04 11:52:06.000000000 +0200
@@ -21,7 +21,7 @@
  * With multiple simultaneous hypertransport irq devices it might pay
  * to make this more fine grained.  But start with simple, stupid, and correct.
  */
-static DEFINE_SPINLOCK(ht_irq_lock);
+static IPIPE_DEFINE_SPINLOCK(ht_irq_lock);
 
 struct ht_irq_cfg {
 	struct pci_dev *dev;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-04 11:52:06.000000000 +0200
@@ -42,7 +42,28 @@
  * Virtual to Physical Address mapping for IO devices.
  */
 #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
-#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
+#ifdef CONFIG_IPIPE
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
+#else
+#error "Unsupported AT91 processor"
+#endif
+#endif /* CONFIG_IPIPE */
 
  /* Internal SRAM is mapped below the IO devices */
 #define AT91_SRAM_MAX		SZ_1M
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -41,4 +41,23 @@
  */
 #define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
 
+#if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
+extern unsigned __ipipe_at91_gpio_banks;
+
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
+
+#endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
+
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h
--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h	2007-04-10 08:04:00.000000000 +0200
+++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h	2007-04-04 11:52:06.000000000 +0200
@@ -25,7 +25,11 @@
 
 #if defined(CONFIG_ARCH_AT91RM9200)
 
+#ifndef CONFIG_IPIPE
 #define CLOCK_TICK_RATE		(AT91_SLOW_CLOCK)
+#else /* !CONFIG_IPIPE */
+#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
+#endif /* !CONFIG_IPIPE */
 
 #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
 
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S	2007-04-04 11:52:06.000000000 +0200
@@ -22,7 +22,11 @@
 		teq	\irqstat, #0
 		ldreq	\irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]
 		moveq	\irqnr, #IRQ_CIC_START
-
+#ifdef CONFIG_IPIPE
+		tst	\irqstat, #0x00000040			@ check IRQ_TIMERINT1 first
+		movne	\irqnr, #6
+		bne	1003f
+#endif /* CONFIG_IPIPE */
 1001:		tst	\irqstat, #15
 		bne	1002f
 		add	\irqnr, \irqnr, #4
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/irqs.h linux-2.6.19.patched/include/asm-arm/arch-integrator/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -80,3 +80,6 @@
 
 #define NR_IRQS                         47
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_CP_CPPLDINT)
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/platform.h linux-2.6.19.patched/include/asm-arm/arch-integrator/platform.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/platform.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/platform.h	2007-04-04 11:52:06.000000000 +0200
@@ -26,7 +26,7 @@
  * 	NOTE: This is a multi-hosted header file for use with uHAL and
  * 	      supported debuggers.
  *
- * 	$Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $
+ * 	$Id: platform.h,v 1.2 2006/02/20 13:54:22 rpm Exp $
  *
  * ***********************************************************************/
 
@@ -436,7 +436,7 @@
  *  Timer definitions
  *
  *  Only use timer 1 & 2
- *  (both run at 24MHz and will need the clock divider set to 16).
+ *  (both run at 1MHZ on /CP and at 24MHz on /AP)
  *
  *  Timer 0 runs at bus frequency and therefore could vary and currently
  *  uHAL can't handle that.
@@ -449,7 +449,12 @@
 
 #define MAX_TIMER                       2
 #define MAX_PERIOD                      699050
+
+#ifdef CONFIG_ARCH_INTEGRATOR_CP
+#define TICKS_PER_uSEC                  1
+#else
 #define TICKS_PER_uSEC                  24
+#endif
 
 /*
  *  These are useconds NOT ticks.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/timex.h linux-2.6.19.patched/include/asm-arm/arch-integrator/timex.h
--- linux-2.6.19.at91/include/asm-arm/arch-integrator/timex.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-integrator/timex.h	2007-04-04 11:52:06.000000000 +0200
@@ -21,6 +21,6 @@
  */
 
 /*
- * ??
+ * Timer rate
  */
-#define CLOCK_TICK_RATE		(50000000 / 16)
+#define CLOCK_TICK_RATE		(1000000)
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-pxa/irqs.h linux-2.6.19.patched/include/asm-arm/arch-pxa/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-pxa/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-pxa/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -72,6 +72,10 @@
 			((i) - IRQ_GPIO(2) + 2)
 #define IRQ_TO_GPIO(i)	(((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_GPIO_2_x)
+#endif /* CONFIG_IPIPE */
+
 #if defined(CONFIG_PXA25x)
 #define PXA_LAST_GPIO	84
 #elif defined(CONFIG_PXA27x)
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-s3c2410/irqs.h linux-2.6.19.patched/include/asm-arm/arch-s3c2410/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-s3c2410/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-s3c2410/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -3,6 +3,8 @@
  * Copyright (c) 2003-2005 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
+ * Copyright (C) 2006 Sebastian Smolorz <ssmolorz@emlix.com>, 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.
@@ -116,4 +118,26 @@
 #define NR_IRQS (IRQ_S3C2440_AC97+1)
 
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_irqbit(irq)	(1 << ((irq) - S3C2410_CPUIRQ_OFFSET))
+
+#ifdef CONFIG_CPU_S3C2440
+#define __ipipe_muxed_irqmask	(__ipipe_irqbit(IRQ_UART0)	|	\
+				 __ipipe_irqbit(IRQ_UART1)	|	\
+				 __ipipe_irqbit(IRQ_UART2)	|	\
+				 __ipipe_irqbit(IRQ_ADCPARENT)	|	\
+				 __ipipe_irqbit(IRQ_WDT)	|	\
+				 __ipipe_irqbit(IRQ_CAM))
+#else /* !CONFIG_CPU_S3C2440 */
+#define __ipipe_muxed_irqmask	(__ipipe_irqbit(IRQ_UART0)	|	\
+				 __ipipe_irqbit(IRQ_UART1)	|	\
+				 __ipipe_irqbit(IRQ_UART2)	|	\
+				 __ipipe_irqbit(IRQ_ADCPARENT))
+#endif /* CONFIG_CPU_S3C2440 */
+
+#define __ipipe_mach_irq_mux_p(irq)	((irq) <= IRQ_ADCPARENT  &&	\
+					 (__ipipe_irqbit(irq) &		\
+					  __ipipe_muxed_irqmask))
+#endif /* CONFIG_IPIPE */
+
 #endif /* __ASM_ARCH_IRQ_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-sa1100/irqs.h linux-2.6.19.patched/include/asm-arm/arch-sa1100/irqs.h
--- linux-2.6.19.at91/include/asm-arm/arch-sa1100/irqs.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/arch-sa1100/irqs.h	2007-04-04 11:52:06.000000000 +0200
@@ -144,6 +144,10 @@
 #define IRQ_LOCOMO_SPI_OVRN	(IRQ_BOARD_END + 20)
 #define IRQ_LOCOMO_SPI_TEND	(IRQ_BOARD_END + 21)
 
+#ifdef CONFIG_IPIPE
+#define __ipipe_mach_irq_mux_p(irq) ((irq) == IRQ_GPIO11_27)
+#endif /* CONFIG_IPIPE */
+
 /*
  * Figure out the MAX IRQ number.
  *
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/atomic.h linux-2.6.19.patched/include/asm-arm/atomic.h
--- linux-2.6.19.at91/include/asm-arm/atomic.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/atomic.h	2007-04-04 11:52:06.000000000 +0200
@@ -103,9 +103,9 @@ static inline void atomic_clear_mask(uns
 	unsigned long tmp, tmp2;
 
 	__asm__ __volatile__("@ atomic_clear_mask\n"
-"1:	ldrex	%0, %2\n"
+"1:	ldrex	%0, [%2]\n"
 "	bic	%0, %0, %3\n"
-"	strex	%1, %0, %2\n"
+"	strex	%1, %0, [%2]\n"
 "	teq	%1, #0\n"
 "	bne	1b"
 	: "=&r" (tmp), "=&r" (tmp2)
@@ -128,10 +128,10 @@ static inline int atomic_add_return(int 
 	unsigned long flags;
 	int val;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	val = v->counter;
 	v->counter = val += i;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return val;
 }
@@ -141,10 +141,10 @@ static inline int atomic_sub_return(int 
 	unsigned long flags;
 	int val;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	val = v->counter;
 	v->counter = val -= i;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return val;
 }
@@ -154,11 +154,11 @@ static inline int atomic_cmpxchg(atomic_
 	int ret;
 	unsigned long flags;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	ret = v->counter;
 	if (likely(ret == old))
 		v->counter = new;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return ret;
 }
@@ -167,9 +167,9 @@ static inline void atomic_clear_mask(uns
 {
 	unsigned long flags;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*addr &= ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 #endif /* __LINUX_ARM_ARCH__ */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/bitops.h linux-2.6.19.patched/include/asm-arm/bitops.h
--- linux-2.6.19.at91/include/asm-arm/bitops.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/bitops.h	2007-04-04 11:52:06.000000000 +0200
@@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(un
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p |= mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
@@ -49,9 +49,9 @@ static inline void ____atomic_clear_bit(
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p &= ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
@@ -61,9 +61,9 @@ static inline void ____atomic_change_bit
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	*p ^= mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 static inline int
@@ -75,10 +75,10 @@ ____atomic_test_and_set_bit(unsigned int
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res | mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
@@ -92,10 +92,10 @@ ____atomic_test_and_clear_bit(unsigned i
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res & ~mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
@@ -109,10 +109,10 @@ ____atomic_test_and_change_bit(unsigned 
 
 	p += bit >> 5;
 
-	raw_local_irq_save(flags);
+	local_irq_save_hw(flags);
 	res = *p;
 	*p = res ^ mask;
-	raw_local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return res & mask;
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/ipipe.h linux-2.6.19.patched/include/asm-arm/ipipe.h
--- linux-2.6.19.at91/include/asm-arm/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/ipipe.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,207 @@
+/* -*- linux-c -*-
+ * include/asm-arm/ipipe.h
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ * Copyright (C) 2005 Stelian Pop.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ARM_IPIPE_H
+#define __ARM_IPIPE_H
+
+#ifdef CONFIG_IPIPE
+
+#include <asm/irq.h>
+#include <asm/percpu.h>
+
+#define IPIPE_ARCH_STRING	"1.6-05"
+#define IPIPE_MAJOR_NUMBER	1
+#define IPIPE_MINOR_NUMBER	6
+#define IPIPE_PATCH_NUMBER	5
+
+#define IPIPE_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	5	/* 25 for 32bits arch. */
+
+#ifdef CONFIG_SMP
+#error "I-pipe/arm: SMP not yet implemented"
+#define ipipe_processor_id()	(current_thread_info()->cpu)
+#else /* !CONFIG_SMP */
+#define ipipe_processor_id()	0
+#endif	/* CONFIG_SMP */
+
+/* Note that we disable the interrupts around context_switch,
+ * or we'll get into severe problems when scheduling Xenomai's
+ * user space real time threads.
+ * This can however cause high latencies, see for example:
+ * 	http://www.ussg.iu.edu/hypermail/linux/kernel/0405.2/1388.html
+ * This may need further optimization...
+ */
+#define prepare_arch_switch(next)				\
+do {								\
+	ipipe_schedule_notify(current, next);			\
+	local_irq_disable_hw();					\
+} while(0)
+
+#define task_hijacked(p)						\
+	({								\
+		int __x__ = ipipe_current_domain != ipipe_root_domain;	\
+		/* We would need to clear the SYNC flag for the root domain */ \
+		/* over the current processor in SMP mode. */		\
+		local_irq_enable_hw(); __x__;				\
+	})
+
+/* ARM traps */
+#define IPIPE_TRAP_ACCESS	 0	/* Data or instruction access exception */
+#define IPIPE_TRAP_SECTION	 1	/* Section fault */
+#define IPIPE_TRAP_DABT		 2	/* Generic data abort */
+#define IPIPE_TRAP_UNKNOWN	 3	/* Unknown exception */
+#define IPIPE_TRAP_BREAK	 4	/* Instruction breakpoint */
+#define IPIPE_TRAP_FPU		 5	/* Floating point exception */
+#define IPIPE_TRAP_VFP		 6	/* VFP floating point exception */
+#define IPIPE_TRAP_UNDEFINSTR	 7	/* Undefined instruction */
+#define IPIPE_NR_FAULTS		 8
+
+/* Pseudo-vectors used for kernel events */
+#define IPIPE_FIRST_EVENT	IPIPE_NR_FAULTS
+#define IPIPE_EVENT_SYSCALL	(IPIPE_FIRST_EVENT)
+#define IPIPE_EVENT_SCHEDULE	(IPIPE_FIRST_EVENT + 1)
+#define IPIPE_EVENT_SIGWAKE	(IPIPE_FIRST_EVENT + 2)
+#define IPIPE_EVENT_SETSCHED	(IPIPE_FIRST_EVENT + 3)
+#define IPIPE_EVENT_INIT	(IPIPE_FIRST_EVENT + 4)
+#define IPIPE_EVENT_EXIT	(IPIPE_FIRST_EVENT + 5)
+#define IPIPE_EVENT_CLEANUP	(IPIPE_FIRST_EVENT + 6)
+#define IPIPE_LAST_EVENT	IPIPE_EVENT_CLEANUP
+#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 1)
+
+extern unsigned long arm_return_addr(int level);
+
+#define BROKEN_BUILTIN_RETURN_ADDRESS
+#define __BUILTIN_RETURN_ADDRESS0 arm_return_addr(0)
+#define __BUILTIN_RETURN_ADDRESS1 arm_return_addr(1)
+
+
+struct ipipe_domain;
+
+struct ipipe_sysinfo {
+
+	int ncpus;		/* Number of CPUs on board */
+	u64 cpufreq;		/* CPU frequency (in Hz) */
+
+	/* Arch-dependent block */
+
+	struct {
+		unsigned tmirq;	/* Timer tick IRQ */
+		u64 tmfreq;	/* Timer frequency */
+	} archdep;
+};
+
+/* arch specific stuff */
+extern int __ipipe_mach_timerint;
+extern int __ipipe_mach_timerstolen;
+extern unsigned int __ipipe_mach_ticks_per_jiffy;
+extern void __ipipe_mach_acktimer(void);
+extern unsigned long long __ipipe_mach_get_tsc(void);
+extern void __ipipe_mach_set_dec(unsigned long);
+extern void __ipipe_mach_release_timer(void);
+extern unsigned long __ipipe_mach_get_dec(void);
+extern void __ipipe_mach_demux_irq(unsigned irq, struct pt_regs *regs);
+
+#define ipipe_read_tsc(t)		do { t = __ipipe_mach_get_tsc(); } while (0)
+#define __ipipe_read_timebase()		__ipipe_mach_get_tsc()
+
+#define ipipe_cpu_freq()	(HZ * __ipipe_mach_ticks_per_jiffy)
+#define ipipe_tsc2ns(t) \
+({ \
+	unsigned long long delta = (t)*1000; \
+	do_div(delta, ipipe_cpu_freq() / 1000000 + 1); \
+	(unsigned long)delta; \
+})
+#define ipipe_tsc2us(t) \
+({ \
+	unsigned long long delta = (t); \
+	do_div(delta, ipipe_cpu_freq() / 1000000 + 1); \
+	(unsigned long)delta; \
+})
+
+/* Private interface -- Internal use only */
+
+#define __ipipe_check_platform()	do { } while(0)
+
+void __ipipe_init_platform(void);
+
+#define __ipipe_enable_irq(irq)	irq_desc[irq].chip->enable(irq)
+
+#define __ipipe_disable_irq(irq)	irq_desc[irq].chip->disable(irq)
+
+#define __ipipe_hook_critical_ipi(ipd) do { } while(0)
+
+void __ipipe_enable_irqdesc(unsigned irq);
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_do_IRQ(int irq,
+		    struct pt_regs *regs);
+
+void __ipipe_do_timer(int irq,
+		      struct pt_regs *regs);
+
+void __ipipe_do_critical_sync(unsigned irq,
+			      void *cookie);
+
+extern unsigned long __ipipe_decr_ticks;
+
+extern unsigned long long __ipipe_decr_next[];
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+void __ipipe_handle_irq(int irq,
+			struct pt_regs *regs);
+
+#define __ipipe_tick_irq	ipipe_timerint
+
+static inline unsigned long __ipipe_ffnz(unsigned long ul)
+{
+	return ffs(ul) - 1;
+}
+
+/* When running handlers, enable hw interrupts for all domains but the
+ * one heading the pipeline, so that IRQs can never be significantly
+ * deferred for the latter. */
+#define __ipipe_run_isr(ipd, irq, cpuid) 	\
+do {					 	\
+	local_irq_enable_nohead(ipd);		\
+	if (ipd == ipipe_root_domain) {		\
+		((void (*)(unsigned, struct pt_regs *))			\
+		 ipd->irqs[irq].handler) (irq, __ipipe_tick_regs + cpuid); \
+	} else {							\
+		__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
+		ipd->irqs[irq].handler(irq,ipd->irqs[irq].cookie);	\
+		__set_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
+	}								\
+	local_irq_disable_nohead(ipd);					\
+} while(0)
+
+#define __ipipe_syscall_watched_p(p, sc)	\
+	(((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= __ARM_NR_BASE + 64)
+
+#else /* !CONFIG_IPIPE */
+
+#define task_hijacked(p)	0
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__ARM_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/irqflags.h linux-2.6.19.patched/include/asm-arm/irqflags.h
--- linux-2.6.19.at91/include/asm-arm/irqflags.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/irqflags.h	2007-04-04 11:52:06.000000000 +0200
@@ -10,30 +10,30 @@
  */
 #if __LINUX_ARM_ARCH__ >= 6
 
-#define raw_local_irq_save(x)					\
+#define local_irq_save_hw_notrace(x)					\
 	({							\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
+	"mrs	%0, cpsr		@ local_irq_save_hw\n"	\
 	"cpsid	i"						\
 	: "=r" (x) : : "memory", "cc");				\
 	})
 
-#define raw_local_irq_enable()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
-#define raw_local_irq_disable() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
-#define local_fiq_enable()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
-#define local_fiq_disable() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
+#define local_irq_enable_hw_notrace()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
+#define local_irq_disable_hw_notrace() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
+#define local_fiq_enable_hw_notrace()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
+#define local_fiq_disable_hw_notrace() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
 
 #else
 
 /*
  * Save the current interrupt enable state & disable IRQs
  */
-#define raw_local_irq_save(x)					\
+#define local_irq_save_hw_notrace(x)					\
 	({							\
 		unsigned long temp;				\
 		(void) (&temp == &x);				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
+	"mrs	%0, cpsr		@ local_irq_save_hw\n"	\
 "	orr	%1, %0, #128\n"					\
 "	msr	cpsr_c, %1"					\
 	: "=r" (x), "=r" (temp)					\
@@ -44,11 +44,11 @@
 /*
  * Enable IRQs
  */
-#define raw_local_irq_enable()					\
+#define local_irq_enable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_enable\n"	\
+	"mrs	%0, cpsr		@ local_irq_enable_hw\n"	\
 "	bic	%0, %0, #128\n"					\
 "	msr	cpsr_c, %0"					\
 	: "=r" (temp)						\
@@ -59,11 +59,11 @@
 /*
  * Disable IRQs
  */
-#define raw_local_irq_disable()					\
+#define local_irq_disable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_disable\n"	\
+	"mrs	%0, cpsr		@ local_irq_disable_hw\n"	\
 "	orr	%0, %0, #128\n"					\
 "	msr	cpsr_c, %0"					\
 	: "=r" (temp)						\
@@ -74,7 +74,7 @@
 /*
  * Enable FIQs
  */
-#define local_fiq_enable()					\
+#define local_fiq_enable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
@@ -89,7 +89,7 @@
 /*
  * Disable FIQs
  */
-#define local_fiq_disable()					\
+#define local_fiq_disable_hw_notrace()				\
 	({							\
 		unsigned long temp;				\
 	__asm__ __volatile__(					\
@@ -106,19 +106,19 @@
 /*
  * Save the current interrupt enable state.
  */
-#define raw_local_save_flags(x)					\
+#define local_save_flags_hw(x)					\
 	({							\
 	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_save_flags"	\
+	"mrs	%0, cpsr		@ local_save_flags_hw"	\
 	: "=r" (x) : : "memory", "cc");				\
 	})
 
 /*
  * restore saved IRQ & FIQ state
  */
-#define raw_local_irq_restore(x)				\
+#define local_irq_restore_hw_notrace(x)				\
 	__asm__ __volatile__(					\
-	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
+	"msr	cpsr_c, %0		@ local_irq_restore_hw\n"	\
 	:							\
 	: "r" (x)						\
 	: "memory", "cc")
@@ -128,5 +128,93 @@
 	(int)((flags) & PSR_I_BIT);	\
 })
 
+#define irqs_disabled_hw()			\
+({						\
+	unsigned long flags;			\
+	local_save_flags_hw(flags);		\
+	raw_irqs_disabled_flags(flags);		\
+})
+			
+
+#ifdef CONFIG_IPIPE
+
+void __ipipe_stall_root(void);
+void __ipipe_unstall_root(void);
+unsigned long __ipipe_test_root(void);
+unsigned long __ipipe_test_and_stall_root(void);
+void __ipipe_restore_root(unsigned long flags);
+
+/* PSR_I_BIT is bit no. 7 and is set if interrupts are _disabled_ */
+#define raw_local_irq_save(flags)		((flags) = __ipipe_test_and_stall_root() << 7)
+#define raw_local_irq_enable()		__ipipe_unstall_root()
+#define raw_local_irq_disable()		__ipipe_stall_root()
+#define local_fiq_enable()		__ipipe_unstall_root()
+#define local_fiq_disable()		__ipipe_stall_root()
+#define raw_local_save_flags(flags)	((flags) = __ipipe_test_root() << 7)
+#define raw_local_irq_restore(flags)	__ipipe_restore_root(flags & (1 << 7))
+
+#define raw_irqs_disabled()		__ipipe_test_root()
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+#include <linux/ipipe_trace.h>
+
+#define local_irq_disable_hw() do { \
+	if (!irqs_disabled_hw()) { \
+		local_irq_disable_hw_notrace(); \
+		ipipe_trace_begin(0x80000000); \
+	} \
+} while (0)
+#define local_irq_enable_hw() do { \
+	if (irqs_disabled_hw()) { \
+		ipipe_trace_end(0x80000000); \
+		local_irq_enable_hw_notrace(); \
+	} \
+} while (0)
+#define local_irq_save_hw(x) do { \
+	local_save_flags_hw(x); \
+	if (raw_irqs_disabled_flags(x)) { \
+		local_irq_disable_hw_notrace(); \
+		ipipe_trace_begin(0x80000001); \
+	} \
+} while (0)
+#define local_irq_restore_hw(x) do { \
+	if (raw_irqs_disabled_flags(x)) \
+		ipipe_trace_end(0x80000001); \
+	local_irq_restore_hw_notrace(x); \
+} while (0)
+
+#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#define local_irq_save_hw(flags)	local_irq_save_hw_notrace(flags)
+#define local_irq_enable_hw()		local_irq_enable_hw_notrace()
+#define local_irq_disable_hw()		local_irq_disable_hw_notrace()
+#define local_fiq_enable_hw()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable_hw()		local_fiq_disable_hw_notrace()
+#define local_irq_restore_hw(flags)	local_irq_restore_hw_notrace(flags)
+
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#else /* !CONFIG_IPIPE */
+
+#define raw_local_irq_save(flags)	local_irq_save_hw_notrace(flags)
+#define raw_local_irq_enable()		local_irq_enable_hw_notrace()
+#define raw_local_irq_disable()		local_irq_disable_hw_notrace()
+#define local_fiq_enable()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable()		local_fiq_disable_hw_notrace()
+#define raw_local_save_flags(flags)	local_save_flags_hw(flags)
+#define raw_local_irq_restore(flags)	local_irq_restore_hw_notrace(flags)
+
+#define local_irq_save_hw(flags)	local_irq_save_hw_notrace(flags)
+#define local_irq_enable_hw()		local_irq_enable_hw_notrace()
+#define local_irq_disable_hw()		local_irq_disable_hw_notrace()
+#define local_fiq_enable_hw()		local_fiq_enable_hw_notrace()
+#define local_fiq_disable_hw()		local_fiq_disable_hw_notrace()
+#define local_irq_restore_hw(flags)	local_irq_restore_hw_notrace(flags)
+
+#define irqs_disabled()		irqs_disabled_hw()
+
+#endif /* CONFIG_IPIPE */
+
 #endif
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/mmu_context.h linux-2.6.19.patched/include/asm-arm/mmu_context.h
--- linux-2.6.19.at91/include/asm-arm/mmu_context.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/mmu_context.h	2007-04-04 11:52:06.000000000 +0200
@@ -93,14 +93,17 @@ switch_mm(struct mm_struct *prev, struct
 	  struct task_struct *tsk)
 {
 #ifdef CONFIG_MMU
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu = smp_processor_id_hw();
 
 	if (prev != next) {
+		unsigned long flags;
+		local_irq_save_hw_cond(flags);
 		cpu_set(cpu, next->cpu_vm_mask);
 		check_context(next);
 		cpu_switch_mm(next->pgd, next);
 		if (cache_is_vivt())
 			cpu_clear(cpu, prev->cpu_vm_mask);
+		local_irq_restore_hw_cond(flags);
 	}
 #endif
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/system.h linux-2.6.19.patched/include/asm-arm/system.h
--- linux-2.6.19.at91/include/asm-arm/system.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/asm-arm/system.h	2007-04-04 11:52:06.000000000 +0200
@@ -286,17 +286,17 @@ static inline unsigned long __xchg(unsig
 #error SMP is not supported on this platform
 #endif
 	case 1:
-		raw_local_irq_save(flags);
+		local_irq_save_hw(flags);
 		ret = *(volatile unsigned char *)ptr;
 		*(volatile unsigned char *)ptr = x;
-		raw_local_irq_restore(flags);
+		local_irq_restore_hw(flags);
 		break;
 
 	case 4:
-		raw_local_irq_save(flags);
+		local_irq_save_hw(flags);
 		ret = *(volatile unsigned long *)ptr;
 		*(volatile unsigned long *)ptr = x;
-		raw_local_irq_restore(flags);
+		local_irq_restore_hw(flags);
 		break;
 #else
 	case 1:
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/hardirq.h linux-2.6.19.patched/include/linux/hardirq.h
--- linux-2.6.19.at91/include/linux/hardirq.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/hardirq.h	2007-04-04 11:52:06.000000000 +0200
@@ -128,7 +128,7 @@ static inline void account_system_vtime(
  */
 extern void irq_exit(void);
 
-#define nmi_enter()		do { lockdep_off(); irq_enter(); } while (0)
-#define nmi_exit()		do { __irq_exit(); lockdep_on(); } while (0)
+#define nmi_enter()		do { if (ipipe_root_domain_p) { lockdep_off(); irq_enter(); } } while (0)
+#define nmi_exit()		do { if (ipipe_root_domain_p) { __irq_exit(); lockdep_on(); } } while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/ipipe.h linux-2.6.19.patched/include/linux/ipipe.h
--- linux-2.6.19.at91/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/linux/ipipe.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,716 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe.h
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_IPIPE_H
+#define __LINUX_IPIPE_H
+
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/percpu.h>
+#include <linux/mutex.h>
+#include <linux/linkage.h>
+#include <asm/ipipe.h>
+
+#ifdef CONFIG_IPIPE
+
+#define IPIPE_VERSION_STRING	IPIPE_ARCH_STRING
+#define IPIPE_RELEASE_NUMBER	((IPIPE_MAJOR_NUMBER << 16) | \
+				 (IPIPE_MINOR_NUMBER <<  8) | \
+				 (IPIPE_PATCH_NUMBER))
+
+#ifndef BROKEN_BUILTIN_RETURN_ADDRESS
+#define __BUILTIN_RETURN_ADDRESS0 ((unsigned long)__builtin_return_address(0))
+#define __BUILTIN_RETURN_ADDRESS1 ((unsigned long)__builtin_return_address(1))
+#endif /* !BUILTIN_RETURN_ADDRESS */
+
+#define IPIPE_ROOT_PRIO		100
+#define IPIPE_ROOT_ID		0
+#define IPIPE_ROOT_NPTDKEYS	4	/* Must be <= BITS_PER_LONG */
+
+#define IPIPE_RESET_TIMER	0x1
+#define IPIPE_GRAB_TIMER	0x2
+
+/* Global domain flags */
+#define IPIPE_SPRINTK_FLAG	0	/* Synchronous printk() allowed */
+#define IPIPE_AHEAD_FLAG	1	/* Domain always heads the pipeline */
+
+/* Per-cpu pipeline status */
+#define IPIPE_STALL_FLAG	0	/* Stalls a pipeline stage -- guaranteed at bit #0 */
+#define IPIPE_SYNC_FLAG		1	/* The interrupt syncer is running for the domain */
+#define IPIPE_NOSTACK_FLAG	2	/* Domain currently runs on a foreign stack */
+
+#define IPIPE_SYNC_MASK		(1 << IPIPE_SYNC_FLAG)
+
+/* Interrupt control bits */
+#define IPIPE_HANDLE_FLAG	0
+#define IPIPE_PASS_FLAG		1
+#define IPIPE_ENABLE_FLAG	2
+#define IPIPE_DYNAMIC_FLAG	IPIPE_HANDLE_FLAG
+#define IPIPE_STICKY_FLAG	3
+#define IPIPE_SYSTEM_FLAG	4
+#define IPIPE_LOCK_FLAG		5
+#define IPIPE_WIRED_FLAG	6
+#define IPIPE_EXCLUSIVE_FLAG	7
+
+#define IPIPE_HANDLE_MASK	(1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK		(1 << IPIPE_PASS_FLAG)
+#define IPIPE_ENABLE_MASK	(1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK	IPIPE_HANDLE_MASK
+#define IPIPE_STICKY_MASK	(1 << IPIPE_STICKY_FLAG)
+#define IPIPE_SYSTEM_MASK	(1 << IPIPE_SYSTEM_FLAG)
+#define IPIPE_LOCK_MASK		(1 << IPIPE_LOCK_FLAG)
+#define IPIPE_WIRED_MASK	(1 << IPIPE_WIRED_FLAG)
+#define IPIPE_EXCLUSIVE_MASK	(1 << IPIPE_EXCLUSIVE_FLAG)
+
+#define IPIPE_DEFAULT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+#define IPIPE_STDROOT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_SYSTEM_MASK)
+
+#define IPIPE_EVENT_SELF        0x80000000
+
+/* Number of virtual IRQs */
+#define IPIPE_NR_VIRQS		BITS_PER_LONG
+/* First virtual IRQ # */
+#define IPIPE_VIRQ_BASE		(((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG)
+/* Total number of IRQ slots */
+#define IPIPE_NR_IRQS		(IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS)
+/* Number of indirect words needed to map the whole IRQ space. */
+#define IPIPE_IRQ_IWORDS	((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define IPIPE_IRQ_IMASK		(BITS_PER_LONG - 1)
+#define IPIPE_IRQMASK_ANY	(~0L)
+#define IPIPE_IRQMASK_VIRT	(IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+#ifdef CONFIG_SMP
+
+#define IPIPE_NR_CPUS		NR_CPUS
+#define ipipe_declare_cpuid	int cpuid
+#define ipipe_load_cpuid()	do { \
+					cpuid = ipipe_processor_id();	\
+				} while(0)
+#define ipipe_lock_cpu(flags)	do { \
+					local_irq_save_hw(flags); \
+					cpuid = ipipe_processor_id(); \
+				} while(0)
+#define ipipe_unlock_cpu(flags)	local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)	ipipe_lock_cpu(flags)
+#define ipipe_put_cpu(flags)	ipipe_unlock_cpu(flags)
+#define ipipe_current_domain	per_cpu(ipipe_percpu_domain, ipipe_processor_id())
+
+#else /* !CONFIG_SMP */
+
+#define IPIPE_NR_CPUS		1
+#define ipipe_declare_cpuid	const int cpuid = 0
+#define ipipe_load_cpuid()	do { } while(0)
+#define ipipe_lock_cpu(flags)	local_irq_save_hw(flags)
+#define ipipe_unlock_cpu(flags)	local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)	do { (void)(flags); } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#define ipipe_current_domain	per_cpu(ipipe_percpu_domain, 0)
+
+#endif /* CONFIG_SMP */
+
+#define ipipe_virtual_irq_p(irq)	((irq) >= IPIPE_VIRQ_BASE && \
+					 (irq) < IPIPE_NR_IRQS)
+
+typedef void (*ipipe_irq_handler_t)(unsigned irq,
+				    void *cookie);
+
+#define IPIPE_SAME_HANDLER	((ipipe_irq_handler_t)(-1))
+
+typedef int (*ipipe_irq_ackfn_t)(unsigned irq);
+
+typedef int (*ipipe_event_handler_t)(unsigned event,
+				     struct ipipe_domain *from,
+				     void *data);
+struct ipipe_domain {
+
+	struct list_head p_link;	/* Link in pipeline */
+
+	struct ipcpudata {
+		unsigned long status;
+		unsigned long irq_pending_hi;
+		unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+		struct ipirqcnt {
+			unsigned long pending_hits;
+			unsigned long total_hits;
+		} irq_counters[IPIPE_NR_IRQS];
+		unsigned long long evsync;
+	} ____cacheline_aligned_in_smp cpudata[IPIPE_NR_CPUS];
+
+	struct {
+		unsigned long control;
+		ipipe_irq_ackfn_t acknowledge;
+		ipipe_irq_handler_t handler;
+		void *cookie;
+	} ____cacheline_aligned irqs[IPIPE_NR_IRQS];
+
+	ipipe_event_handler_t evhand[IPIPE_NR_EVENTS]; /* Event handlers. */
+	unsigned long long evself;	/* Self-monitored event bits. */
+	unsigned long flags;
+	unsigned domid;
+	const char *name;
+	int priority;
+	void *pdd;
+	struct mutex mutex;
+};
+
+#define IPIPE_HEAD_PRIORITY	(-1) /* For domains always heading the pipeline */
+
+struct ipipe_domain_attr {
+
+	unsigned domid;		/* Domain identifier -- Magic value set by caller */
+	const char *name;	/* Domain name -- Warning: won't be dup'ed! */
+	int priority;		/* Priority in interrupt pipeline */
+	void (*entry) (void);	/* Domain entry point */
+	void *pdd;		/* Per-domain (opaque) data pointer */
+};
+
+/* The following macros must be used hw interrupts off. */
+
+#define __ipipe_irq_cookie(ipd,irq)	(ipd)->irqs[irq].cookie
+#define __ipipe_irq_handler(ipd,irq)	(ipd)->irqs[irq].handler
+
+#define __ipipe_cpudata_irq_hits(ipd,cpuid,irq)	((ipd)->cpudata[cpuid].irq_counters[irq].total_hits)
+
+#define __ipipe_set_irq_bit(ipd,cpuid,irq) \
+do { \
+	if (!test_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) { \
+		__set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+		__set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+	} \
+} while(0)
+
+#define __ipipe_clear_pend(ipd,cpuid,irq) \
+do { \
+	__clear_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+	if ((ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \
+		__clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+} while(0)
+
+#define __ipipe_lock_irq(ipd,cpuid,irq) \
+do { \
+	if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+		__ipipe_clear_pend(ipd,cpuid,irq); \
+} while(0)
+
+#define __ipipe_unlock_irq(ipd,irq) \
+do { \
+	int __cpuid, __nr_cpus = num_online_cpus(); \
+	if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+		for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) \
+			if ((ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits > 0) { /* We need atomic ops next. */ \
+				set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+				set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[__cpuid].irq_pending_hi); \
+			} \
+} while(0)
+
+#define __ipipe_clear_irq(ipd,irq) \
+do { \
+	int __cpuid, __nr_cpus = num_online_cpus(); \
+	clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control); \
+	for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) { \
+		(ipd)->cpudata[__cpuid].irq_counters[irq].pending_hits = 0; \
+		__ipipe_clear_pend(ipd,__cpuid,irq); \
+	} \
+} while(0)
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+#define write_lock_hw(x)		__raw_write_lock(&(x)->raw_lock)
+#define write_trylock_hw(x)		__raw_write_trylock(&(x)->raw_lock)
+#define write_unlock_hw(x)		__raw_write_unlock(&(x)->raw_lock)
+#define read_lock_hw(x)		__raw_read_lock(&(x)->raw_lock)
+#define read_trylock_hw(x)		__raw_read_trylock(&(x)->raw_lock)
+#define read_unlock_hw(x)		__raw_read_unlock(&(x)->raw_lock)
+#else /* UP non-debug */
+#define write_lock_hw(lock)		do { (void)(lock); } while (0)
+#define write_trylock_hw(lock)	({ (void)(lock); 1; })
+#define write_unlock_hw(lock)		do { (void)(lock); } while (0)
+#define read_lock_hw(lock)		do { (void)(lock); } while (0)
+#define read_trylock_hw(lock)		({ (void)(lock); 1; })
+#define read_unlock_hw(lock)		do { (void)(lock); } while (0)
+#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */
+
+typedef rwlock_t			ipipe_rwlock_t;
+#define IPIPE_RW_LOCK_UNLOCKED		RW_LOCK_UNLOCKED
+
+#define read_lock_irqsave_hw(lock, flags)	\
+do {						\
+	local_irq_save_hw(flags);		\
+	read_lock_hw(lock);			\
+} while (0)
+
+#define read_unlock_irqrestore_hw(lock, flags)	\
+do {						\
+	read_unlock_hw(lock);			\
+	local_irq_restore_hw(flags);		\
+} while (0)
+
+#define write_lock_irqsave_hw(lock, flags)	\
+do {						\
+	local_irq_save_hw(flags);		\
+	write_lock_hw(lock);			\
+} while (0)
+
+#define write_unlock_irqrestore_hw(lock, flags)	\
+do {						\
+	write_unlock_hw(lock);			\
+	local_irq_restore_hw(flags);		\
+} while (0)
+
+DECLARE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain);
+
+extern struct ipipe_domain ipipe_root;
+
+#define ipipe_root_domain (&ipipe_root)
+
+extern unsigned __ipipe_printk_virq;
+
+extern unsigned long __ipipe_virtual_irq_map;
+
+extern struct list_head __ipipe_pipeline;
+
+extern int __ipipe_event_monitors[];
+
+/* Private interface */
+
+void ipipe_init(void);
+
+#ifdef CONFIG_PROC_FS
+void ipipe_init_proc(void);
+
+#ifdef CONFIG_IPIPE_TRACE
+void __ipipe_init_tracer(void);
+#else /* !CONFIG_IPIPE_TRACE */
+#define __ipipe_init_tracer()       do { } while(0)
+#endif /* CONFIG_IPIPE_TRACE */
+
+#else	/* !CONFIG_PROC_FS */
+#define ipipe_init_proc()	do { } while(0)
+#endif	/* CONFIG_PROC_FS */
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_flush_printk(unsigned irq, void *cookie);
+
+void __ipipe_stall_root(void);
+
+void __ipipe_unstall_root(void);
+
+unsigned long __ipipe_test_root(void);
+
+unsigned long __ipipe_test_and_stall_root(void);
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid);
+
+void fastcall __ipipe_restore_root(unsigned long x);
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head);
+
+int fastcall __ipipe_dispatch_event(unsigned event, void *data);
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq);
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask);
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end);
+
+struct mm_struct;
+
+int __ipipe_pin_range_mapping(struct mm_struct *mm,
+			      unsigned long start, unsigned long end);
+
+#ifndef __ipipe_sync_pipeline
+#define __ipipe_sync_pipeline(syncmask) __ipipe_sync_stage(syncmask)
+#endif
+
+#ifndef __ipipe_run_irqtail
+#define __ipipe_run_irqtail() do { } while(0)
+#endif
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+/*
+ * Keep the following as a macro, so that client code could check for
+ * the support of the invariant pipeline head optimization.
+ */
+#define __ipipe_pipeline_head() list_entry(__ipipe_pipeline.next,struct ipipe_domain,p_link)
+
+#define __ipipe_event_monitored_p(ev) \
+	(__ipipe_event_monitors[ev] > 0 || (ipipe_current_domain->evself & (1LL << ev)))
+
+#ifdef CONFIG_SMP
+
+cpumask_t __ipipe_set_irq_affinity(unsigned irq,
+				   cpumask_t cpumask);
+
+int fastcall __ipipe_send_ipi(unsigned ipi,
+			      cpumask_t cpumask);
+
+#endif /* CONFIG_SMP */
+
+/* Called with hw interrupts off. */
+static inline void __ipipe_switch_to(struct ipipe_domain *out,
+				     struct ipipe_domain *in, int cpuid)
+{
+	void ipipe_suspend_domain(void);
+
+	/*
+	 * "in" is guaranteed to be closer than "out" from the head of the
+	 * pipeline (and obviously different).
+	 */
+
+	out->cpudata[cpuid].evsync = 0;
+	per_cpu(ipipe_percpu_domain, cpuid) = in;
+
+	ipipe_suspend_domain();	/* Sync stage and propagate interrupts. */
+	ipipe_load_cpuid();	/* Processor might have changed. */
+
+	if (per_cpu(ipipe_percpu_domain, cpuid) == in)
+		/*
+		 * Otherwise, something has changed the current domain under
+		 * our feet recycling the register set; do not override.
+		 */
+		per_cpu(ipipe_percpu_domain, cpuid) = out;
+}
+
+#define ipipe_sigwake_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SIGWAKE)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SIGWAKE,p);		\
+} while(0)
+
+#define ipipe_exit_notify(p)	\
+do {				\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_EXIT)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_EXIT,p);		\
+} while(0)
+
+#define ipipe_setsched_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SETSCHED)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SETSCHED,p);		\
+} while(0)
+
+#define ipipe_schedule_notify(prev, next)				\
+do {									\
+	if ((((prev)->flags|(next)->flags) & PF_EVNOTIFY) &&		\
+	    __ipipe_event_monitored_p(IPIPE_EVENT_SCHEDULE))		\
+		__ipipe_dispatch_event(IPIPE_EVENT_SCHEDULE,next);	\
+} while(0)
+
+#define ipipe_trap_notify(ex, regs)		\
+({						\
+	ipipe_declare_cpuid;			\
+	int ret = 0;				\
+	ipipe_load_cpuid();			\
+	if ((test_bit(IPIPE_NOSTACK_FLAG, &ipipe_current_domain->cpudata[cpuid].status) || \
+	     ((current)->flags & PF_EVNOTIFY)) &&			\
+	    __ipipe_event_monitored_p(ex))				\
+		ret = __ipipe_dispatch_event(ex, regs);			\
+	ret;								\
+})
+
+static inline void ipipe_init_notify(struct task_struct *p)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_INIT))
+		__ipipe_dispatch_event(IPIPE_EVENT_INIT,p);
+}
+
+static inline void ipipe_cleanup_notify(struct mm_struct *mm)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_CLEANUP))
+		__ipipe_dispatch_event(IPIPE_EVENT_CLEANUP,mm);
+}
+
+/* Public interface */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr);
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd);
+
+void ipipe_suspend_domain(void);
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask);
+
+int ipipe_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+unsigned ipipe_alloc_virq(void);
+
+int ipipe_free_virq(unsigned virq);
+
+int fastcall ipipe_trigger_irq(unsigned irq);
+
+static inline int ipipe_propagate_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, ipipe_current_domain->p_link.next);
+}
+
+static inline int ipipe_schedule_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, &ipipe_current_domain->p_link);
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x);
+
+static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+static inline void ipipe_restore_pipeline_nosync(struct ipipe_domain *ipd,
+						 unsigned long x, int cpuid)
+{
+	/*
+	 * If cpuid is current, then it must be held on entry
+	 * (ipipe_get_cpu/local_irq_save_hw/local_irq_disable_hw).
+	 */
+
+	if (x)
+		__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	else
+		__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+static inline void ipipe_stall_pipeline_head(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	__set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status);
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline_head(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	return __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status);
+}
+
+void ipipe_unstall_pipeline_head(void);
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head,
+					    unsigned long x);
+
+static inline void ipipe_restore_pipeline_head(unsigned long x)
+{
+	struct ipipe_domain *head = __ipipe_pipeline_head();
+	/* On some archs, __test_and_set_bit() might return different
+	 * truth value than test_bit(), so we test the exclusive OR of
+	 * both statuses, assuming that the lowest bit is always set in
+	 * the truth value (if this is wrong, the failed optimization will
+	 * be caught in __ipipe_restore_pipeline_head() if
+	 * CONFIG_DEBUG_KERNEL is set). */
+	if ((x ^ test_bit(IPIPE_STALL_FLAG, &head->cpudata[ipipe_processor_id()].status)) & 1)
+		__ipipe_restore_pipeline_head(head,x);
+}
+
+#define ipipe_unstall_pipeline() \
+	ipipe_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_unstall_pipeline() \
+	ipipe_test_and_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_pipeline() \
+	ipipe_test_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_stall_pipeline() \
+	ipipe_test_and_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_stall_pipeline() \
+	ipipe_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_restore_pipeline(x) \
+	ipipe_restore_pipeline_from(ipipe_current_domain, (x))
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr);
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *sysinfo);
+
+int ipipe_tune_timer(unsigned long ns,
+		     int flags);
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void));
+
+void ipipe_critical_exit(unsigned long flags);
+
+static inline void ipipe_set_printk_sync(struct ipipe_domain *ipd)
+{
+	set_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_printk_async(struct ipipe_domain *ipd)
+{
+	clear_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	ipipe_declare_cpuid;
+	ipipe_load_cpuid();
+	__set_bit(IPIPE_NOSTACK_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+static inline void ipipe_clear_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	ipipe_declare_cpuid;
+	ipipe_load_cpuid();
+	__clear_bit(IPIPE_NOSTACK_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+#define ipipe_safe_current()					\
+({								\
+	ipipe_declare_cpuid;					\
+	struct task_struct *p;					\
+	ipipe_load_cpuid();					\
+	p = test_bit(IPIPE_NOSTACK_FLAG,			\
+		     &per_cpu(ipipe_percpu_domain, cpuid)->cpudata[cpuid].status) ? &init_task : current; \
+	p; \
+})
+
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler);
+
+cpumask_t ipipe_set_irq_affinity(unsigned irq,
+				 cpumask_t cpumask);
+
+int fastcall ipipe_send_ipi(unsigned ipi,
+			    cpumask_t cpumask);
+
+int ipipe_setscheduler_root(struct task_struct *p,
+			    int policy,
+			    int prio);
+
+int ipipe_reenter_root(struct task_struct *prev,
+		       int policy,
+		       int prio);
+
+int ipipe_alloc_ptdkey(void);
+
+int ipipe_free_ptdkey(int key);
+
+int fastcall ipipe_set_ptd(int key,
+			   void *value);
+
+void fastcall *ipipe_get_ptd(int key);
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk);
+
+#define local_irq_enable_hw_cond()		local_irq_enable_hw()
+#define local_irq_disable_hw_cond()		local_irq_disable_hw()
+#define local_irq_save_hw_cond(flags)	local_irq_save_hw(flags)
+#define local_irq_restore_hw_cond(flags)	local_irq_restore_hw(flags)
+#define local_irq_disable_head()		ipipe_stall_pipeline_head()
+
+#define local_irq_enable_nohead(ipd)			\
+	do {						\
+		if (!__ipipe_pipeline_head_p(ipd))	\
+			local_irq_enable_hw();		\
+	} while(0)
+
+#define local_irq_disable_nohead(ipd)		\
+	do {						\
+		if (!__ipipe_pipeline_head_p(ipd))	\
+			local_irq_disable_hw();		\
+	} while(0)
+
+#define smp_processor_id_hw()				ipipe_processor_id()
+
+#define ipipe_irq_lock(irq)						\
+	do {								\
+		ipipe_declare_cpuid;					\
+		ipipe_load_cpuid();					\
+		__ipipe_lock_irq(per_cpu(ipipe_percpu_domain, cpuid), cpuid, irq);\
+	} while(0)
+
+#define ipipe_irq_unlock(irq)						\
+	do {								\
+		ipipe_declare_cpuid;					\
+		ipipe_load_cpuid();					\
+		__ipipe_unlock_irq(per_cpu(ipipe_percpu_domain, cpuid), irq);	\
+	} while(0)
+
+#define ipipe_root_domain_p		(ipipe_current_domain == ipipe_root_domain)
+
+#else	/* !CONFIG_IPIPE */
+
+#define ipipe_init()			do { } while(0)
+#define ipipe_suspend_domain()	do { } while(0)
+#define ipipe_sigwake_notify(p)	do { } while(0)
+#define ipipe_setsched_notify(p)	do { } while(0)
+#define ipipe_init_notify(p)		do { } while(0)
+#define ipipe_exit_notify(p)		do { } while(0)
+#define ipipe_cleanup_notify(mm)	do { } while(0)
+#define ipipe_trap_notify(t,r)	0
+#define ipipe_init_proc()		do { } while(0)
+#define __ipipe_pin_range_globally(start, end) do { } while(0)
+
+#define local_irq_enable_hw_cond()		do { } while(0)
+#define local_irq_disable_hw_cond()		do { } while(0)
+#define local_irq_save_hw_cond(flags)	do { (void)(flags); } while(0)
+#define local_irq_restore_hw_cond(flags)	do { } while(0)
+#define smp_processor_id_hw()			smp_processor_id()
+
+#define ipipe_irq_lock(irq)		do { } while(0)
+#define ipipe_irq_unlock(irq)		do { } while(0)
+
+#define ipipe_root_domain_p		1
+#define ipipe_safe_current		current
+
+#define local_irq_disable_head()	local_irq_disable()
+
+#endif	/* CONFIG_IPIPE */
+
+#endif	/* !__LINUX_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/ipipe_trace.h linux-2.6.19.patched/include/linux/ipipe_trace.h
--- linux-2.6.19.at91/include/linux/ipipe_trace.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/include/linux/ipipe_trace.h	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,44 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe_trace.h
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005, 2006 Jan Kiszka.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LINUX_IPIPE_TRACE_H
+#define _LINUX_IPIPE_TRACE_H
+
+#ifdef CONFIG_IPIPE_TRACE
+
+#include <linux/types.h>
+
+void ipipe_trace_begin(unsigned long v);
+void ipipe_trace_end(unsigned long v);
+void ipipe_trace_freeze(unsigned long v);
+void ipipe_trace_special(unsigned char special_id, unsigned long v);
+void ipipe_trace_pid(pid_t pid, short prio);
+
+int ipipe_trace_max_reset(void);
+int ipipe_trace_frozen_reset(void);
+
+void ipipe_trace_panic_freeze(void);
+void ipipe_trace_panic_dump(void);
+
+#endif /* CONFIG_IPIPE_TRACE */
+
+#endif	/* !__LINUX_IPIPE_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/irq.h linux-2.6.19.patched/include/linux/irq.h
--- linux-2.6.19.at91/include/linux/irq.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/irq.h	2007-04-04 11:52:06.000000000 +0200
@@ -146,6 +146,12 @@ struct irq_chip {
  * Pad this out to 32 bytes for cache and indexing reasons.
  */
 struct irq_desc {
+#ifdef CONFIG_IPIPE
+	void			fastcall (*ipipe_ack)(unsigned int irq,
+						      struct irq_desc *desc);
+	void			fastcall (*ipipe_end)(unsigned int irq,
+						      struct irq_desc *desc);
+#endif /* CONFIG_IPIPE */
 	irq_flow_handler_t	handle_irq;
 	struct irq_chip		*chip;
 	void			*handler_data;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/linkage.h linux-2.6.19.patched/include/linux/linkage.h
--- linux-2.6.19.at91/include/linux/linkage.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/linkage.h	2007-04-04 11:52:06.000000000 +0200
@@ -64,4 +64,8 @@
 #define fastcall
 #endif
 
+#ifndef notrace
+#define notrace		__attribute__((no_instrument_function))
+#endif
+
 #endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/mm.h linux-2.6.19.patched/include/linux/mm.h
--- linux-2.6.19.at91/include/linux/mm.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/mm.h	2007-04-04 11:52:06.000000000 +0200
@@ -166,6 +166,7 @@ extern unsigned int kobjsize(const void 
 #define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
 #define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
 #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
+#define VM_PINNED	0x10000000	/* Disable faults for the vma */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/preempt.h linux-2.6.19.patched/include/linux/preempt.h
--- linux-2.6.19.at91/include/linux/preempt.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/preempt.h	2007-04-04 11:52:06.000000000 +0200
@@ -26,22 +26,37 @@
 
 asmlinkage void preempt_schedule(void);
 
+#ifdef CONFIG_IPIPE
+#include <asm/ipipe.h>
+DECLARE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain);
+extern struct ipipe_domain ipipe_root;
+#define ipipe_preempt_guard() (per_cpu(ipipe_percpu_domain, ipipe_processor_id()) == &ipipe_root)
+#else  /* !CONFIG_IPIPE */
+#define ipipe_preempt_guard()	1
+#endif /* CONFIG_IPIPE */
+
 #define preempt_disable() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	inc_preempt_count(); \
 	barrier(); \
+	}								\
 } while (0)
 
 #define preempt_enable_no_resched() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	barrier(); \
 	dec_preempt_count(); \
+	}								\
 } while (0)
 
 #define preempt_check_resched() \
 do { \
+	if (ipipe_preempt_guard()) {					\
 	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
 		preempt_schedule(); \
+	}								\
 } while (0)
 
 #define preempt_enable() \
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/sched.h linux-2.6.19.patched/include/linux/sched.h
--- linux-2.6.19.at91/include/linux/sched.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/sched.h	2007-04-04 11:52:06.000000000 +0200
@@ -54,6 +54,7 @@ struct sched_param {
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/nodemask.h>
+#include <linux/ipipe.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -150,6 +151,13 @@ extern unsigned long weighted_cpuload(co
 /* in tsk->state again */
 #define TASK_NONINTERACTIVE	64
 #define TASK_DEAD		128
+#ifdef CONFIG_IPIPE
+#define TASK_ATOMICSWITCH	512
+#define TASK_NOWAKEUP          1024
+#else  /* !CONFIG_IPIPE */
+#define TASK_ATOMICSWITCH	0
+#define TASK_NOWAKEUP          0
+#endif /* CONFIG_IPIPE */
 
 #define __set_task_state(tsk, state_value)		\
 	do { (tsk)->state = (state_value); } while (0)
@@ -1015,6 +1023,9 @@ struct task_struct {
 
 	atomic_t fs_excl;	/* holding fs exclusive resources */
 	struct rcu_head rcu;
+#ifdef CONFIG_IPIPE
+	void *ptd[IPIPE_ROOT_NPTDKEYS];
+#endif
 
 	/*
 	 * cache last used pipe for splice
@@ -1115,6 +1126,11 @@ static inline void put_task_struct(struc
 #define PF_SPREAD_SLAB	0x02000000	/* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER	0x20000000	/* Thread belongs to the rt mutex tester */
+#ifdef CONFIG_IPIPE
+#define PF_EVNOTIFY    0x40000000	/* Notify other domains about internal events */
+#else
+#define PF_EVNOTIFY    0
+#endif /* CONFIG_IPIPE */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/spinlock.h linux-2.6.19.patched/include/linux/spinlock.h
--- linux-2.6.19.at91/include/linux/spinlock.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/spinlock.h	2007-04-04 11:52:06.000000000 +0200
@@ -171,7 +171,97 @@ do {								\
 #define read_trylock(lock)		__cond_lock(lock, _read_trylock(lock))
 #define write_trylock(lock)		__cond_lock(lock, _write_trylock(lock))
 
-#define spin_lock(lock)			_spin_lock(lock)
+#undef TYPE_EQUAL
+#define TYPE_EQUAL(lock, type) \
+	__builtin_types_compatible_p(typeof(lock), type *)
+
+#define PICK_SPINOP(op, lock)						\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		_spin##op((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINOP_RAW(op, lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		__raw_spin##op(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_disable_hw();					\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_enable_hw();					\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ_RAW(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_disable_hw();					\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		local_irq_disable();					\
+		__raw_spin_lock(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ_RAW(lock)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_enable_hw();				\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		__raw_spin_unlock(&((spinlock_t *)(lock))->raw_lock);	\
+		local_irq_enable();					\
+} while (0)
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+extern int __bad_spinlock_type(void);
+
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_save_hw(flags);				\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		flags = _spin_lock_irqsave((spinlock_t *)(lock));	\
+	else __bad_spinlock_type();					\
+} while (0)
+#else
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		local_irq_save_hw(flags);				\
+		__raw_spin_lock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irqsave((spinlock_t *)(lock), flags);	\
+} while (0)
+#endif
+
+#define PICK_SPINUNLOCK_IRQRESTORE(lock, flags)			\
+	do {								\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__raw_spin_unlock(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+		local_irq_restore_hw(flags);				\
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irqrestore((spinlock_t *)(lock), flags);	\
+} while (0)
+
+#define spin_lock(lock)	PICK_SPINOP(_lock, lock)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define spin_lock_nested(lock, subclass) _spin_lock_nested(lock, subclass)
@@ -184,7 +274,7 @@ do {								\
 
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
 
-#define spin_lock_irqsave(lock, flags)	flags = _spin_lock_irqsave(lock)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	flags = _read_lock_irqsave(lock)
 #define write_lock_irqsave(lock, flags)	flags = _write_lock_irqsave(lock)
 
@@ -198,7 +288,7 @@ do {								\
 
 #else
 
-#define spin_lock_irqsave(lock, flags)	_spin_lock_irqsave(lock, flags)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	_read_lock_irqsave(lock, flags)
 #define write_lock_irqsave(lock, flags)	_write_lock_irqsave(lock, flags)
 #define spin_lock_irqsave_nested(lock, flags, subclass)	\
@@ -206,7 +296,7 @@ do {								\
 
 #endif
 
-#define spin_lock_irq(lock)		_spin_lock_irq(lock)
+#define spin_lock_irq(lock)		PICK_SPINLOCK_IRQ(lock)
 #define spin_lock_bh(lock)		_spin_lock_bh(lock)
 
 #define read_lock_irq(lock)		_read_lock_irq(lock)
@@ -220,18 +310,17 @@ do {								\
  */
 #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
 	!defined(CONFIG_SMP)
-# define spin_unlock(lock)		_spin_unlock(lock)
+#define spin_unlock(lock)		PICK_SPINOP(_unlock, lock)
 # define read_unlock(lock)		_read_unlock(lock)
 # define write_unlock(lock)		_write_unlock(lock)
-# define spin_unlock_irq(lock)		_spin_unlock_irq(lock)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ(lock)
 # define read_unlock_irq(lock)		_read_unlock_irq(lock)
 # define write_unlock_irq(lock)		_write_unlock_irq(lock)
 #else
-# define spin_unlock(lock)		__raw_spin_unlock(&(lock)->raw_lock)
+# define spin_unlock(lock)		PICK_SPINOP_RAW(_unlock, lock)
 # define read_unlock(lock)		__raw_read_unlock(&(lock)->raw_lock)
 # define write_unlock(lock)		__raw_write_unlock(&(lock)->raw_lock)
-# define spin_unlock_irq(lock) \
-    do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ_RAW(lock)
 # define read_unlock_irq(lock) \
     do { __raw_read_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
 # define write_unlock_irq(lock) \
@@ -239,7 +328,7 @@ do {								\
 #endif
 
 #define spin_unlock_irqrestore(lock, flags) \
-					_spin_unlock_irqrestore(lock, flags)
+					PICK_SPINUNLOCK_IRQRESTORE(lock, flags)
 #define spin_unlock_bh(lock)		_spin_unlock_bh(lock)
 
 #define read_unlock_irqrestore(lock, flags) \
@@ -286,4 +375,16 @@ extern int _atomic_dec_and_lock(atomic_t
  */
 #define spin_can_lock(lock)	(!spin_is_locked(lock))
 
+#ifdef CONFIG_IPIPE
+#define spin_lock_irqsave_cond(lock, flags) \
+	spin_lock_irqsave(lock,flags)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock_irqrestore(lock,flags)
+#else
+#define spin_lock_irqsave_cond(lock, flags) \
+	do { (void)(flags); spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock(lock)
+#endif
+
 #endif /* __LINUX_SPINLOCK_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/linux/spinlock_types.h linux-2.6.19.patched/include/linux/spinlock_types.h
--- linux-2.6.19.at91/include/linux/spinlock_types.h	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/include/linux/spinlock_types.h	2007-04-04 11:52:06.000000000 +0200
@@ -31,6 +31,10 @@ typedef struct {
 #endif
 } spinlock_t;
 
+typedef struct {
+	raw_spinlock_t __raw_lock;
+} __ipipe_spinlock_t;
+
 #define SPINLOCK_MAGIC		0xdead4ead
 
 typedef struct {
@@ -86,9 +90,19 @@ typedef struct {
 #endif
 
 #define SPIN_LOCK_UNLOCKED	__SPIN_LOCK_UNLOCKED(old_style_spin_init)
+#define IPIPE_SPIN_LOCK_UNLOCKED					\
+	(__ipipe_spinlock_t) {	.__raw_lock = __RAW_SPIN_LOCK_UNLOCKED }
 #define RW_LOCK_UNLOCKED	__RW_LOCK_UNLOCKED(old_style_rw_init)
 
 #define DEFINE_SPINLOCK(x)	spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
 #define DEFINE_RWLOCK(x)	rwlock_t x = __RW_LOCK_UNLOCKED(x)
 
+#ifdef CONFIG_IPIPE
+# define ipipe_spinlock_t	__ipipe_spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) ipipe_spinlock_t x = IPIPE_SPIN_LOCK_UNLOCKED
+#else
+# define ipipe_spinlock_t	spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) DEFINE_SPINLOCK(x)
+#endif
+
 #endif /* __LINUX_SPINLOCK_TYPES_H */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/init/Kconfig linux-2.6.19.patched/init/Kconfig
--- linux-2.6.19.at91/init/Kconfig	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/init/Kconfig	2007-04-04 11:52:06.000000000 +0200
@@ -67,6 +67,7 @@ menu "General setup"
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-ipipe"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/init/main.c linux-2.6.19.patched/init/main.c
--- linux-2.6.19.at91/init/main.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/init/main.c	2007-04-04 11:52:06.000000000 +0200
@@ -489,7 +489,7 @@ asmlinkage void __init start_kernel(void
 	unwind_init();
 	lockdep_init();
 
-	local_irq_disable();
+	local_irq_disable_hw();
 	early_boot_irqs_off();
 	early_init_irq_lock_class();
 
@@ -535,6 +535,11 @@ asmlinkage void __init start_kernel(void
 	softirq_init();
 	timekeeping_init();
 	time_init();
+	/*
+	 * We need to wait for the interrupt and time subsystems to be
+	 * initialized before enabling the pipeline.
+	 */
+ 	ipipe_init();
 	profile_init();
 	if (!irqs_disabled())
 		printk("start_kernel(): bug: interrupts were enabled early\n");
@@ -683,6 +688,7 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
+	ipipe_init_proc();
 
 	do_initcalls();
 }
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/exit.c linux-2.6.19.patched/kernel/exit.c
--- linux-2.6.19.at91/kernel/exit.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/exit.c	2007-04-04 11:52:06.000000000 +0200
@@ -918,6 +918,7 @@ fastcall NORET_TYPE void do_exit(long co
 
 	if (group_dead)
 		acct_process();
+ 	ipipe_exit_notify(tsk);
 	exit_sem(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/fork.c linux-2.6.19.patched/kernel/fork.c
--- linux-2.6.19.at91/kernel/fork.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/fork.c	2007-04-04 11:52:06.000000000 +0200
@@ -384,6 +384,7 @@ void mmput(struct mm_struct *mm)
 	might_sleep();
 
 	if (atomic_dec_and_test(&mm->mm_users)) {
+		ipipe_cleanup_notify(mm);
 		exit_aio(mm);
 		exit_mmap(mm);
 		if (!list_empty(&mm->mmlist)) {
@@ -914,7 +915,7 @@ static inline void copy_flags(unsigned l
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE | PF_EVNOTIFY);
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
@@ -1258,6 +1259,14 @@ static struct task_struct *copy_process(
 	spin_unlock(&current->sighand->siglock);
 	write_unlock_irq(&tasklist_lock);
 	proc_fork_connector(p);
+#ifdef CONFIG_IPIPE
+	{
+	int k;
+
+	for (k = 0; k < IPIPE_ROOT_NPTDKEYS; k++)
+		p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_IPIPE */
 	return p;
 
 bad_fork_cleanup_namespaces:
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/core.c linux-2.6.19.patched/kernel/ipipe/core.c
--- linux-2.6.19.at91/kernel/ipipe/core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/core.c	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,1419 @@
+/* -*- linux-c -*-
+ * linux/kernel/ipipe/core.c
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-independent I-PIPE core support.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif	/* CONFIG_PROC_FS */
+#include <linux/irq.h>
+
+MODULE_DESCRIPTION("I-pipe");
+MODULE_LICENSE("GPL");
+
+static int __ipipe_ptd_key_count;
+
+static unsigned long __ipipe_ptd_key_map;
+
+struct ipipe_domain ipipe_root =
+	{ .cpudata = {[0 ... IPIPE_NR_CPUS-1] =
+		{ .status = (1<<IPIPE_STALL_FLAG) } } };
+
+DEFINE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain) =
+	{ &ipipe_root };
+
+static IPIPE_DEFINE_SPINLOCK(__ipipe_pipelock);
+
+LIST_HEAD(__ipipe_pipeline);
+
+unsigned long __ipipe_virtual_irq_map;
+
+#ifdef CONFIG_PRINTK
+unsigned __ipipe_printk_virq;
+#endif /* CONFIG_PRINTK */
+
+int __ipipe_event_monitors[IPIPE_NR_EVENTS];
+
+/*
+ * ipipe_init() -- Initialization routine of the IPIPE layer. Called
+ * by the host kernel early during the boot procedure.
+ */
+void ipipe_init(void)
+{
+	struct ipipe_domain *ipd = &ipipe_root;
+
+	__ipipe_check_platform();	/* Do platform dependent checks first. */
+
+	/*
+	 * A lightweight registration code for the root domain. We are
+	 * running on the boot CPU, hw interrupts are off, and
+	 * secondary CPUs are still lost in space.
+	 */
+
+	ipd->name = "Linux";
+	ipd->domid = IPIPE_ROOT_ID;
+	ipd->priority = IPIPE_ROOT_PRIO;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+	list_add_tail(&ipd->p_link, &__ipipe_pipeline);
+
+	__ipipe_init_platform();
+
+#ifdef CONFIG_PRINTK
+	__ipipe_printk_virq = ipipe_alloc_virq();	/* Cannot fail here. */
+	ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk;
+	ipd->irqs[__ipipe_printk_virq].cookie = NULL;
+	ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+	ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+#endif /* CONFIG_PRINTK */
+
+	__ipipe_enable_pipeline();
+
+	printk(KERN_INFO "I-pipe %s: pipeline enabled.\n",
+	       IPIPE_VERSION_STRING);
+}
+
+void __ipipe_init_stage(struct ipipe_domain *ipd)
+{
+	int cpuid, n;
+
+	for (cpuid = 0; cpuid < IPIPE_NR_CPUS; cpuid++) {
+		ipd->cpudata[cpuid].irq_pending_hi = 0;
+
+		for (n = 0; n < IPIPE_IRQ_IWORDS; n++)
+			ipd->cpudata[cpuid].irq_pending_lo[n] = 0;
+
+		for (n = 0; n < IPIPE_NR_IRQS; n++) {
+			ipd->cpudata[cpuid].irq_counters[n].total_hits = 0;
+			ipd->cpudata[cpuid].irq_counters[n].pending_hits = 0;
+		}
+
+		ipd->cpudata[cpuid].evsync = 0;
+	}
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++) {
+		ipd->irqs[n].acknowledge = NULL;
+		ipd->irqs[n].handler = NULL;
+		ipd->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+	for (n = 0; n < IPIPE_NR_EVENTS; n++)
+		ipd->evhand[n] = NULL;
+
+	ipd->evself = 0LL;
+	mutex_init(&ipd->mutex);
+
+	__ipipe_hook_critical_ipi(ipd);
+}
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd)
+{
+	ipipe_unstall_pipeline_from(ipd);
+
+#ifdef CONFIG_SMP
+	{
+		int cpu;
+
+		for_each_online_cpu(cpu) {
+			while (ipd->cpudata[cpu].irq_pending_hi != 0)
+				cpu_relax();
+		}
+	}
+#endif	/* CONFIG_SMP */
+}
+
+void __ipipe_stall_root(void)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+}
+
+void __ipipe_unstall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+
+	ipipe_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+
+	if (unlikely(ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0))
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+	local_irq_enable_hw();
+}
+
+unsigned long __ipipe_test_root(void)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	x = test_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	x = test_and_set_bit(IPIPE_STALL_FLAG,
+			     &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+void fastcall __ipipe_restore_root(unsigned long x)
+{
+	if (x)
+		__ipipe_stall_root();
+	else
+		__ipipe_unstall_root();
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	ipipe_declare_cpuid;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+}
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	ipipe_declare_cpuid;
+	unsigned long s;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	s = __test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	s = test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+
+	return s;
+}
+
+/*
+ * ipipe_unstall_pipeline_from() -- Unstall the pipeline and
+ * synchronize pending interrupts for a given domain. See
+ * __ipipe_walk_pipeline() for more information.
+ */
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	struct list_head *pos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (ipd == per_cpu(ipipe_percpu_domain, cpuid))
+		pos = &ipd->p_link;
+	else
+		pos = __ipipe_pipeline.next;
+
+	__ipipe_walk_pipeline(pos, cpuid);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_enable_hw();
+	else
+		ipipe_unlock_cpu(flags);
+}
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, x;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	x = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_unstall_pipeline_from(ipd);
+	ipipe_put_cpu(flags);
+
+	return x;
+}
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x)
+{
+	if (x)
+		ipipe_stall_pipeline_from(ipd);
+	else
+		ipipe_unstall_pipeline_from(ipd);
+}
+
+void ipipe_unstall_pipeline_head(void)
+{
+	struct ipipe_domain *head;
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+	head = __ipipe_pipeline_head();
+	__clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+
+	if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) {
+		if (likely(head == per_cpu(ipipe_percpu_domain, cpuid)))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+		else
+			__ipipe_walk_pipeline(&head->p_link, cpuid);
+        }
+
+	local_irq_enable_hw();
+}
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head, unsigned long x)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+	ipipe_load_cpuid();
+
+	if (x) {
+#ifdef CONFIG_DEBUG_KERNEL
+		static int warned;
+		if (!warned && test_and_set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status)) {
+			/*
+			 * Already stalled albeit ipipe_restore_pipeline_head()
+			 * should have detected it? Send a warning once.\n");
+			 */
+			warned = 1;
+			printk(KERN_WARNING
+				   "I-pipe: ipipe_restore_pipeline_head() optimization failed.\n");
+			dump_stack();
+		}
+#else /* !CONFIG_DEBUG_KERNEL */
+		set_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+#endif /* CONFIG_DEBUG_KERNEL */
+	}
+	else {
+		__clear_bit(IPIPE_STALL_FLAG, &head->cpudata[cpuid].status);
+		if (unlikely(head->cpudata[cpuid].irq_pending_hi != 0)) {
+			if (likely(head == per_cpu(ipipe_percpu_domain, cpuid)))
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else
+				__ipipe_walk_pipeline(&head->p_link, cpuid);
+		}
+		local_irq_enable_hw();
+	}
+}
+
+/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must
+   be called with local hw interrupts disabled. */
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos, int cpuid)
+{
+	struct ipipe_domain *this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status))
+			break;	/* Stalled stage -- do not go further. */
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi != 0) {
+
+			if (next_domain == this_domain)
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else {
+				__ipipe_switch_to(this_domain, next_domain,
+						  cpuid);
+
+				ipipe_load_cpuid();	/* Processor might have changed. */
+
+				if (this_domain->cpudata[cpuid].
+				    irq_pending_hi != 0
+				    && !test_bit(IPIPE_STALL_FLAG,
+						 &this_domain->cpudata[cpuid].status))
+					__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+}
+
+/*
+ * ipipe_suspend_domain() -- Suspend the current domain, switching to
+ * the next one which has pending work down the pipeline.
+ */
+void ipipe_suspend_domain(void)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	this_domain = next_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	__clear_bit(IPIPE_STALL_FLAG, &this_domain->cpudata[cpuid].status);
+
+	if (this_domain->cpudata[cpuid].irq_pending_hi != 0)
+		goto sync_stage;
+
+	for (;;) {
+		ln = next_domain->p_link.next;
+
+		if (ln == &__ipipe_pipeline)
+			break;
+
+		next_domain = list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG,
+			     &next_domain->cpudata[cpuid].status))
+			break;
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi == 0)
+			continue;
+
+		per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+
+sync_stage:
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+			/*
+			 * Something has changed the current domain under our
+			 * feet, recycling the register set; take note.
+			 */
+			this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+	}
+
+	per_cpu(ipipe_percpu_domain, cpuid) = this_domain;
+
+	ipipe_unlock_cpu(flags);
+}
+
+/* ipipe_alloc_virq() -- Allocate a pipelined virtual/soft interrupt.
+ * Virtual interrupts are handled in exactly the same way than their
+ * hw-generated counterparts wrt pipelining.
+ */
+unsigned ipipe_alloc_virq(void)
+{
+	unsigned long flags, irq = 0;
+	int ipos;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	if (__ipipe_virtual_irq_map != ~0) {
+		ipos = ffz(__ipipe_virtual_irq_map);
+		set_bit(ipos, &__ipipe_virtual_irq_map);
+		irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return irq;
+}
+
+/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw
+   acknowledge routine) to an interrupt for a given domain. */
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask)
+{
+	unsigned long flags;
+	int err;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (!test_bit(IPIPE_AHEAD_FLAG, &ipd->flags))
+		/* Silently unwire interrupts for non-heading domains. */
+		modemask &= ~IPIPE_WIRED_MASK;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	if (handler != NULL) {
+
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = ipd->irqs[irq].handler;
+			cookie = ipd->irqs[irq].cookie;
+
+			if (handler == NULL) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+		} else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+			   ipd->irqs[irq].handler != NULL) {
+			err = -EBUSY;
+			goto unlock_and_exit;
+		}
+
+		/* Wired interrupts can only be delivered to domains
+		 * always heading the pipeline, and using dynamic
+		 * propagation. */
+
+		if ((modemask & IPIPE_WIRED_MASK) != 0) {
+			if ((modemask & (IPIPE_PASS_MASK | IPIPE_STICKY_MASK)) != 0) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+			modemask |= (IPIPE_HANDLE_MASK);
+		}
+
+		if ((modemask & IPIPE_STICKY_MASK) != 0)
+			modemask |= IPIPE_HANDLE_MASK;
+	} else
+		modemask &=
+		    ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK |
+		      IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK);
+
+	if (acknowledge == NULL && !ipipe_virtual_irq_p(irq))
+		/* Acknowledge handler unspecified for a hw interrupt:
+		   use the Linux-defined handler instead. */
+		acknowledge = ipipe_root_domain->irqs[irq].acknowledge;
+
+	ipd->irqs[irq].handler = handler;
+	ipd->irqs[irq].cookie = cookie;
+	ipd->irqs[irq].acknowledge = acknowledge;
+	ipd->irqs[irq].control = modemask;
+
+	if (irq < NR_IRQS && handler != NULL && !ipipe_virtual_irq_p(irq)) {
+		__ipipe_enable_irqdesc(irq);
+
+		if ((modemask & IPIPE_ENABLE_MASK) != 0) {
+			if (ipd != ipipe_current_domain) {
+				/* IRQ enable/disable state is domain-sensitive, so we may
+				   not change it for another domain. What is allowed
+				   however is forcing some domain to handle an interrupt
+				   source, by passing the proper 'ipd' descriptor which
+				   thus may be different from ipipe_current_domain. */
+				err = -EPERM;
+				goto unlock_and_exit;
+			}
+
+			__ipipe_enable_irq(irq);
+		}
+	}
+
+	err = 0;
+
+      unlock_and_exit:
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return err;
+}
+
+/* ipipe_control_irq() -- Change modes of a pipelined interrupt for
+ * the current domain. */
+
+int ipipe_control_irq(unsigned irq, unsigned clrmask, unsigned setmask)
+{
+	struct ipipe_domain *ipd;
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	ipd = ipipe_current_domain;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (ipd->irqs[irq].handler == NULL)
+		setmask &= ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	if ((setmask & IPIPE_STICKY_MASK) != 0)
+		setmask |= IPIPE_HANDLE_MASK;
+
+	if ((clrmask & (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK)) != 0)	/* If one goes, both go. */
+		clrmask |= (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	ipd->irqs[irq].control &= ~clrmask;
+	ipd->irqs[irq].control |= setmask;
+
+	if ((setmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_enable_irq(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_disable_irq(irq);
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+/* __ipipe_dispatch_event() -- Low-level event dispatcher. */
+
+int fastcall __ipipe_dispatch_event (unsigned event, void *data)
+{
+	struct ipipe_domain *start_domain, *this_domain, *next_domain;
+	ipipe_event_handler_t evhand;
+	struct list_head *pos, *npos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+	int propagate = 1;
+
+	ipipe_lock_cpu(flags);
+
+	start_domain = this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+
+	list_for_each_safe(pos,npos,&__ipipe_pipeline) {
+
+		/*
+		 * Note: Domain migration may occur while running
+		 * event or interrupt handlers, in which case the
+		 * current register set is going to be recycled for a
+		 * different domain than the initiating one. We do
+		 * care for that, always tracking the current domain
+		 * descriptor upon return from those handlers.
+		 */
+		next_domain = list_entry(pos,struct ipipe_domain,p_link);
+
+		/*
+		 * Keep a cached copy of the handler's address since
+		 * ipipe_catch_event() may clear it under our feet.
+		 */
+
+		evhand = next_domain->evhand[event];
+
+		if (evhand != NULL) {
+			per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+			next_domain->cpudata[cpuid].evsync |= (1LL << event);
+			ipipe_unlock_cpu(flags);
+			propagate = !evhand(event,start_domain,data);
+			ipipe_lock_cpu(flags);
+			next_domain->cpudata[cpuid].evsync &= ~(1LL << event);
+			if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+				this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+		}
+
+		if (next_domain != ipipe_root_domain &&	/* NEVER sync the root stage here. */
+		    next_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) {
+			per_cpu(ipipe_percpu_domain, cpuid) = next_domain;
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			ipipe_load_cpuid();
+			if (per_cpu(ipipe_percpu_domain, cpuid) != next_domain)
+				this_domain = per_cpu(ipipe_percpu_domain, cpuid);
+		}
+
+		per_cpu(ipipe_percpu_domain, cpuid) = this_domain;
+
+		if (next_domain == this_domain || !propagate)
+			break;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return !propagate;
+}
+
+/*
+ * __ipipe_dispatch_wired -- Wired interrupt dispatcher. Wired
+ * interrupts are immediately and unconditionally delivered to the
+ * domain heading the pipeline upon receipt, and such domain must have
+ * been registered as an invariant head for the system (priority ==
+ * IPIPE_HEAD_PRIORITY). The motivation for using wired interrupts is
+ * to get an extra-fast dispatching path for those IRQs, by relying on
+ * a straightforward logic based on assumptions that must always be
+ * true for invariant head domains.  The following assumptions are
+ * made when dealing with such interrupts:
+ *
+ * 1- Wired interrupts are purely dynamic, i.e. the decision to
+ * propagate them down the pipeline must be done from the head domain
+ * ISR.
+ * 2- Wired interrupts cannot be shared or sticky.
+ * 3- The root domain cannot be an invariant pipeline head, in
+ * consequence of what the root domain cannot handle wired
+ * interrupts.
+ * 4- Wired interrupts must have a valid acknowledge handler for the
+ * head domain (if needed), and in any case, must not rely on handlers
+ * provided by lower priority domains during the acknowledge cycle
+ * (see __ipipe_handle_irq).
+ *
+ * Called with hw interrupts off.
+ */
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head, unsigned irq)
+{
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *old;
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+	cpudata = &head->cpudata[cpuid];
+	cpudata->irq_counters[irq].total_hits++;
+
+	if (test_bit(IPIPE_LOCK_FLAG, &head->irqs[irq].control)) {
+		/* If we can't process this IRQ right now, we must
+		 * mark it as pending, so that it will get played
+		 * during normal log sync when the corresponding
+		 * interrupt source is eventually unlocked. */
+		cpudata->irq_counters[irq].pending_hits++;
+		return 0;
+	}
+
+	if (test_bit(IPIPE_STALL_FLAG, &cpudata->status)) {
+		cpudata->irq_counters[irq].pending_hits++;
+		__ipipe_set_irq_bit(head, cpuid, irq);
+		return 0;
+	}
+
+	old = per_cpu(ipipe_percpu_domain, cpuid);
+	per_cpu(ipipe_percpu_domain, cpuid) = head; /* Switch to the head domain. */
+
+	__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+	head->irqs[irq].handler(irq,head->irqs[irq].cookie); /* Call the ISR. */
+	__ipipe_run_irqtail();
+	__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+	/* We expect the caller to start a complete pipeline walk upon
+	 * return, so that propagated interrupts will get played. */
+
+	if (per_cpu(ipipe_percpu_domain, cpuid) == head)
+		per_cpu(ipipe_percpu_domain, cpuid) = old; /* Back to the preempted domain. */
+
+	return 1;
+}
+
+/*
+ * __ipipe_sync_stage() -- Flush the pending IRQs for the current
+ * domain (and processor). This routine flushes the interrupt log
+ * (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+ * more on the deferred interrupt scheme). Every interrupt that
+ * occurred while the pipeline was stalled gets played. WARNING:
+ * callers on SMP boxen should always check for CPU migration on
+ * return of this routine. One can control the kind of interrupts
+ * which are going to be sync'ed using the syncmask
+ * parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+ * plays virtual interrupts only.
+ *
+ * This routine must be called with hw interrupts off.
+ */
+void fastcall __ipipe_sync_stage(unsigned long syncmask)
+{
+	unsigned long mask, submask;
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *ipd;
+	ipipe_declare_cpuid;
+	int level, rank;
+	unsigned irq;
+
+	ipipe_load_cpuid();
+	ipd = per_cpu(ipipe_percpu_domain, cpuid);
+	cpudata = &ipd->cpudata[cpuid];
+
+	if (__test_and_set_bit(IPIPE_SYNC_FLAG, &cpudata->status))
+		return;
+
+	/*
+	 * The policy here is to keep the dispatching code interrupt-free
+	 * by stalling the current stage. If the upper domain handler
+	 * (which we call) wants to re-enable interrupts while in a safe
+	 * portion of the code (e.g. SA_INTERRUPT flag unset for Linux's
+	 * sigaction()), it will have to unstall (then stall again before
+	 * returning to us!) the stage when it sees fit.
+	 */
+	while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0) {
+		level = __ipipe_ffnz(mask);
+
+		while ((submask = cpudata->irq_pending_lo[level]) != 0) {
+			rank = __ipipe_ffnz(submask);
+			irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+			if (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control)) {
+				__clear_bit(rank, &cpudata->irq_pending_lo[level]);
+				continue;
+			}
+
+			if (--cpudata->irq_counters[irq].pending_hits == 0) {
+				__clear_bit(rank, &cpudata->irq_pending_lo[level]);
+				if (cpudata->irq_pending_lo[level] == 0)
+					__clear_bit(level, &cpudata->irq_pending_hi);
+			}
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			if (ipd == ipipe_root_domain)
+				trace_hardirqs_off();
+
+			__ipipe_run_isr(ipd, irq, cpuid);
+#ifdef CONFIG_SMP
+			{
+				int _cpuid = ipipe_processor_id();
+
+				if (_cpuid != cpuid) {	/* Handle CPU migration. */
+					/*
+					 * We expect any domain to clear the SYNC bit each
+					 * time it switches in a new task, so that preemptions
+					 * and/or CPU migrations (in the SMP case) over the
+					 * ISR do not lock out the log syncer for some
+					 * indefinite amount of time. In the Linux case,
+					 * schedule() handles this (see kernel/sched.c). For
+					 * this reason, we don't bother clearing it here for
+					 * the source CPU in the migration handling case,
+					 * since it must have scheduled another task in by
+					 * now.
+					 */
+					cpuid = _cpuid;
+					cpudata = &ipd->cpudata[cpuid];
+					__set_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+				}
+			}
+#endif	/* CONFIG_SMP */
+			if (ipd == ipipe_root_domain &&
+			    test_bit(IPIPE_STALL_FLAG, &cpudata->status))
+				trace_hardirqs_on();
+
+			__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* ipipe_register_domain() -- Link a new domain to the pipeline. */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr)
+{
+	struct list_head *pos;
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may register a new domain.\n");
+		return -EPERM;
+	}
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY &&
+	    test_bit(IPIPE_AHEAD_FLAG,&__ipipe_pipeline_head()->flags))
+		return -EAGAIN;	/* Cannot override current head. */
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+		if (_ipd->domid == attr->domid)
+			break;
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (pos != &__ipipe_pipeline)
+		/* A domain with the given id already exists -- fail. */
+		return -EBUSY;
+
+	ipd->name = attr->name;
+	ipd->domid = attr->domid;
+	ipd->pdd = attr->pdd;
+	ipd->flags = 0;
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY) {
+		ipd->priority = INT_MAX;
+		__set_bit(IPIPE_AHEAD_FLAG,&ipd->flags);
+	}
+	else
+		ipd->priority = attr->priority;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_add_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+		if (ipd->priority > _ipd->priority)
+			break;
+	}
+
+	list_add_tail(&ipd->p_link, pos);
+
+	ipipe_critical_exit(flags);
+
+	printk(KERN_WARNING "I-pipe: Domain %s registered.\n", ipd->name);
+
+	/*
+	 * Finally, allow the new domain to perform its initialization
+	 * chores.
+	 */
+
+	if (attr->entry != NULL) {
+		ipipe_declare_cpuid;
+
+		ipipe_lock_cpu(flags);
+
+		per_cpu(ipipe_percpu_domain, cpuid) = ipd;
+		attr->entry();
+		per_cpu(ipipe_percpu_domain, cpuid) = ipipe_root_domain;
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,
+			      &ipipe_root_domain->cpudata[cpuid].status))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		ipipe_unlock_cpu(flags);
+	}
+
+	return 0;
+}
+
+/* ipipe_unregister_domain() -- Remove a domain from the pipeline. */
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd)
+{
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may unregister a domain.\n");
+		return -EPERM;
+	}
+
+	if (ipd == ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Cannot unregister the root domain.\n");
+		return -EPERM;
+	}
+#ifdef CONFIG_SMP
+	{
+		int nr_cpus = num_online_cpus(), _cpuid;
+		unsigned irq;
+
+		/*
+		 * In the SMP case, wait for the logged events to drain on
+		 * other processors before eventually removing the domain
+		 * from the pipeline.
+		 */
+
+		ipipe_unstall_pipeline_from(ipd);
+
+		flags = ipipe_critical_enter(NULL);
+
+		for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+			clear_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control);
+			clear_bit(IPIPE_STICKY_FLAG, &ipd->irqs[irq].control);
+			set_bit(IPIPE_PASS_FLAG, &ipd->irqs[irq].control);
+		}
+
+		ipipe_critical_exit(flags);
+
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+				while (ipd->cpudata[_cpuid].irq_counters[irq].pending_hits > 0)
+					cpu_relax();
+	}
+#endif	/* CONFIG_SMP */
+
+	mutex_lock(&ipd->mutex);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_remove_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	/*
+	 * Simply remove the domain from the pipeline and we are almost done.
+	 */
+
+	flags = ipipe_critical_enter(NULL);
+	list_del_init(&ipd->p_link);
+	ipipe_critical_exit(flags);
+
+	__ipipe_cleanup_domain(ipd);
+
+	mutex_unlock(&ipd->mutex);
+
+	printk(KERN_WARNING "I-pipe: Domain %s unregistered.\n", ipd->name);
+
+	return 0;
+}
+
+/*
+ * ipipe_propagate_irq() -- Force a given IRQ propagation on behalf of
+ * a running interrupt handler to the next domain down the pipeline.
+ * ipipe_schedule_irq() -- Does almost the same as above, but attempts
+ * to pend the interrupt for the current domain first.
+ */
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head)
+{
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	ipipe_lock_cpu(flags);
+
+	ln = head;
+
+	while (ln != &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+			list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control)) {
+			ipd->cpudata[cpuid].irq_counters[irq].total_hits++;
+			ipd->cpudata[cpuid].irq_counters[irq].pending_hits++;
+			__ipipe_set_irq_bit(ipd, cpuid, irq);
+			ipipe_unlock_cpu(flags);
+			return 1;
+		}
+
+		ln = ipd->p_link.next;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return 0;
+}
+
+/* ipipe_free_virq() -- Release a virtual/soft interrupt. */
+
+int ipipe_free_virq(unsigned virq)
+{
+	if (!ipipe_virtual_irq_p(virq))
+		return -EINVAL;
+
+	clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map);
+
+	return 0;
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr)
+{
+	attr->name = "anon";
+	attr->domid = 1;
+	attr->entry = NULL;
+	attr->priority = IPIPE_ROOT_PRIO;
+	attr->pdd = NULL;
+}
+
+/*
+ * ipipe_catch_event() -- Interpose or remove an event handler for a
+ * given domain.
+ */
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler)
+{
+	ipipe_event_handler_t old_handler;
+	unsigned long flags;
+	int self = 0, cpuid;
+
+	if (event & IPIPE_EVENT_SELF) {
+		event &= ~IPIPE_EVENT_SELF;
+		self = 1;
+	}
+
+	if (event >= IPIPE_NR_EVENTS)
+		return NULL;
+
+	flags = ipipe_critical_enter(NULL);
+
+	if (!(old_handler = xchg(&ipd->evhand[event],handler)))	{
+		if (handler) {
+			if (self)
+				ipd->evself |= (1LL << event);
+			else
+				__ipipe_event_monitors[event]++;
+		}
+	}
+	else if (!handler) {
+		if (ipd->evself & (1LL << event))
+			ipd->evself &= ~(1LL << event);
+		else
+			__ipipe_event_monitors[event]--;
+	} else if ((ipd->evself & (1LL << event)) && !self) {
+			__ipipe_event_monitors[event]++;
+			ipd->evself &= ~(1LL << event);
+	} else if (!(ipd->evself & (1LL << event)) && self) {
+			__ipipe_event_monitors[event]--;
+			ipd->evself |= (1LL << event);
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (!handler && ipipe_root_domain_p) {
+		/*
+		 * If we cleared a handler on behalf of the root
+		 * domain, we have to wait for any current invocation
+		 * to drain, since our caller might subsequently unmap
+		 * the target domain. To this aim, this code
+		 * synchronizes with __ipipe_dispatch_event(),
+		 * guaranteeing that either the dispatcher sees a null
+		 * handler in which case it discards the invocation
+		 * (which also prevents from entering a livelock), or
+		 * finds a valid handler and calls it. Symmetrically,
+		 * ipipe_catch_event() ensures that the called code
+		 * won't be unmapped under our feet until the event
+		 * synchronization flag is cleared for the given event
+		 * on all CPUs.
+		 */
+
+		for_each_online_cpu(cpuid) {
+			while (ipd->cpudata[cpuid].evsync & (1LL << event))
+				schedule_timeout_interruptible(HZ / 50);
+		}
+	}
+
+	return old_handler;
+}
+
+cpumask_t ipipe_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+{
+#ifdef CONFIG_SMP
+	if (irq >= IPIPE_NR_XIRQS)
+		/* Allow changing affinity of external IRQs only. */
+		return CPU_MASK_NONE;
+
+	if (num_online_cpus() > 1)
+		return __ipipe_set_irq_affinity(irq,cpumask);
+#endif /* CONFIG_SMP */
+
+	return CPU_MASK_NONE;
+}
+
+int fastcall ipipe_send_ipi (unsigned ipi, cpumask_t cpumask)
+
+{
+#ifdef CONFIG_SMP
+	return __ipipe_send_ipi(ipi,cpumask);
+#else /* !CONFIG_SMP */
+	return -EINVAL;
+#endif /* CONFIG_SMP */
+}
+
+int ipipe_alloc_ptdkey (void)
+{
+	unsigned long flags;
+	int key = -1;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (__ipipe_ptd_key_count < IPIPE_ROOT_NPTDKEYS) {
+		key = ffz(__ipipe_ptd_key_map);
+		set_bit(key,&__ipipe_ptd_key_map);
+		__ipipe_ptd_key_count++;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return key;
+}
+
+int ipipe_free_ptdkey (int key)
+{
+	unsigned long flags;
+
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (test_and_clear_bit(key,&__ipipe_ptd_key_map))
+		__ipipe_ptd_key_count--;
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return 0;
+}
+
+int fastcall ipipe_set_ptd (int key, void *value)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	current->ptd[key] = value;
+
+	return 0;
+}
+
+void fastcall *ipipe_get_ptd (int key)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return NULL;
+
+	return current->ptd[key];
+}
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *ipipe_proc_root;
+
+static int __ipipe_version_info_proc(char *page,
+				     char **start,
+				     off_t off, int count, int *eof, void *data)
+{
+	int len = sprintf(page, "%s\n", IPIPE_VERSION_STRING);
+
+	len -= off;
+
+	if (len <= off + count)
+		*eof = 1;
+
+	*start = page + off;
+
+	if(len > count)
+		len = count;
+
+	if(len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_common_info_show(struct seq_file *p, void *data)
+{
+	struct ipipe_domain *ipd = (struct ipipe_domain *)p->private;
+	char handling, stickiness, lockbit, exclusive, virtuality;
+
+	unsigned long ctlbits;
+	unsigned irq;
+
+	seq_printf(p, "       +----- Handling ([A]ccepted, [G]rabbed, [W]ired, [D]iscarded)\n");
+	seq_printf(p, "       |+---- Sticky\n");
+	seq_printf(p, "       ||+--- Locked\n");
+	seq_printf(p, "       |||+-- Exclusive\n");
+	seq_printf(p, "       ||||+- Virtual\n");
+	seq_printf(p, "[IRQ]  |||||\n");
+
+	mutex_lock(&ipd->mutex);
+
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+		/* Remember to protect against
+		 * ipipe_virtual_irq/ipipe_control_irq if more fields
+		 * get involved. */
+		ctlbits = ipd->irqs[irq].control;
+
+		if (irq >= IPIPE_NR_XIRQS && !ipipe_virtual_irq_p(irq))
+			/*
+			 * There might be a hole between the last external
+			 * IRQ and the first virtual one; skip it.
+			 */
+			continue;
+
+		if (ipipe_virtual_irq_p(irq)
+		    && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))
+			/* Non-allocated virtual IRQ; skip it. */
+			continue;
+
+		/*
+		 * Statuses are as follows:
+		 * o "accepted" means handled _and_ passed down the pipeline.
+		 * o "grabbed" means handled, but the interrupt might be
+		 * terminated _or_ passed down the pipeline depending on
+		 * what the domain handler asks for to the I-pipe.
+		 * o "wired" is basically the same as "grabbed", except that
+		 * the interrupt is unconditionally delivered to an invariant
+		 * pipeline head domain.
+		 * o "passed" means unhandled by the domain but passed
+		 * down the pipeline.
+		 * o "discarded" means unhandled and _not_ passed down the
+		 * pipeline. The interrupt merely disappears from the
+		 * current domain down to the end of the pipeline.
+		 */
+		if (ctlbits & IPIPE_HANDLE_MASK) {
+			if (ctlbits & IPIPE_PASS_MASK)
+				handling = 'A';
+			else if (ctlbits & IPIPE_WIRED_MASK)
+				handling = 'W';
+			else
+				handling = 'G';
+		} else if (ctlbits & IPIPE_PASS_MASK)
+			/* Do not output if no major action is taken. */
+			continue;
+		else
+			handling = 'D';
+
+		if (ctlbits & IPIPE_STICKY_MASK)
+			stickiness = 'S';
+		else
+			stickiness = '.';
+
+		if (ctlbits & IPIPE_LOCK_MASK)
+			lockbit = 'L';
+		else
+			lockbit = '.';
+
+		if (ctlbits & IPIPE_EXCLUSIVE_MASK)
+			exclusive = 'X';
+		else
+			exclusive = '.';
+
+		if (ipipe_virtual_irq_p(irq))
+			virtuality = 'V';
+		else
+			virtuality = '.';
+
+		seq_printf(p, " %3u:  %c%c%c%c%c\n",
+			     irq, handling, stickiness, lockbit, exclusive, virtuality);
+	}
+
+	seq_printf(p, "[Domain info]\n");
+
+	seq_printf(p, "id=0x%.8x\n", ipd->domid);
+
+	if (test_bit(IPIPE_AHEAD_FLAG,&ipd->flags))
+		seq_printf(p, "priority=topmost\n");
+	else
+		seq_printf(p, "priority=%d\n", ipd->priority);
+
+	mutex_unlock(&ipd->mutex);
+
+	return 0;
+}
+
+static int __ipipe_common_info_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, __ipipe_common_info_show, PROC_I(inode)->pde->data);
+}
+
+static struct file_operations __ipipe_info_proc_ops = {
+	.owner		= THIS_MODULE,
+	.open		= __ipipe_common_info_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd)
+{
+	struct proc_dir_entry *e = create_proc_entry(ipd->name, 0444, ipipe_proc_root);
+	if (e) {
+		e->proc_fops = &__ipipe_info_proc_ops;
+		e->data = (void*) ipd;
+	}
+}
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd)
+{
+	remove_proc_entry(ipd->name,ipipe_proc_root);
+}
+
+void __init ipipe_init_proc(void)
+{
+	ipipe_proc_root = create_proc_entry("ipipe",S_IFDIR, 0);
+	create_proc_read_entry("version",0444,ipipe_proc_root,&__ipipe_version_info_proc,NULL);
+	__ipipe_add_domain_proc(ipipe_root_domain);
+
+	__ipipe_init_tracer();
+}
+
+#endif	/* CONFIG_PROC_FS */
+
+EXPORT_SYMBOL(ipipe_virtualize_irq);
+EXPORT_SYMBOL(ipipe_control_irq);
+EXPORT_SYMBOL(ipipe_suspend_domain);
+EXPORT_SYMBOL(ipipe_alloc_virq);
+EXPORT_PER_CPU_SYMBOL(ipipe_percpu_domain);
+EXPORT_SYMBOL(ipipe_root);
+EXPORT_SYMBOL(ipipe_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_restore_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_head);
+EXPORT_SYMBOL(__ipipe_restore_pipeline_head);
+EXPORT_SYMBOL(__ipipe_unstall_root);
+EXPORT_SYMBOL(__ipipe_stall_root);
+EXPORT_SYMBOL(__ipipe_restore_root);
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+EXPORT_SYMBOL(__ipipe_test_root);
+EXPORT_SYMBOL(__ipipe_dispatch_event);
+EXPORT_SYMBOL(__ipipe_pipeline);
+EXPORT_SYMBOL(ipipe_register_domain);
+EXPORT_SYMBOL(ipipe_unregister_domain);
+EXPORT_SYMBOL(ipipe_free_virq);
+EXPORT_SYMBOL(ipipe_init_attr);
+EXPORT_SYMBOL(ipipe_catch_event);
+EXPORT_SYMBOL(ipipe_alloc_ptdkey);
+EXPORT_SYMBOL(ipipe_free_ptdkey);
+EXPORT_SYMBOL(ipipe_set_ptd);
+EXPORT_SYMBOL(ipipe_get_ptd);
+EXPORT_SYMBOL(ipipe_set_irq_affinity);
+EXPORT_SYMBOL(ipipe_send_ipi);
+EXPORT_SYMBOL(__ipipe_schedule_irq);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Kconfig linux-2.6.19.patched/kernel/ipipe/Kconfig
--- linux-2.6.19.at91/kernel/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Kconfig	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,6 @@
+config IPIPE
+	bool "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Kconfig.debug linux-2.6.19.patched/kernel/ipipe/Kconfig.debug
--- linux-2.6.19.at91/kernel/ipipe/Kconfig.debug	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Kconfig.debug	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,69 @@
+config IPIPE_DEBUG
+	bool "I-pipe debugging"
+	depends on IPIPE
+
+config IPIPE_TRACE
+	bool "Latency tracing"
+	depends on IPIPE_DEBUG
+	select FRAME_POINTER
+	select KALLSYMS
+	select PROC_FS
+	---help---
+	  Activate this option if you want to use per-function tracing of
+	  the kernel. The tracer will collect data via instrumentation
+	  features like the one below or with the help of explicite calls
+	  of ipipe_trace_xxx(). See include/linux/ipipe_trace.h for the
+	  in-kernel tracing API. The collected data and runtime control
+	  is available via /proc/ipipe/trace/*.
+
+config IPIPE_TRACE_ENABLE
+	bool "Enable tracing on boot"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  Disable this option if you want to arm the tracer after booting
+	  manually ("echo 1 > /proc/ipipe/tracer/enable"). This can reduce
+	  boot time on slow embedded devices due to the tracer overhead.
+
+config IPIPE_TRACE_MCOUNT
+	bool "Instrument function entries"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  When enabled, records every kernel function entry in the tracer
+	  log. While this slows down the system noticeably, it provides
+	  the highest level of information about the flow of events.
+	  However, it can be switch off in order to record only explicit
+	  I-pipe trace points.
+
+config IPIPE_TRACE_IRQSOFF
+	bool "Trace IRQs-off times"
+	depends on IPIPE_TRACE
+	default y
+	---help---
+	  Activate this option if I-pipe shall trace the longest path
+	  with hard-IRQs switched off.
+
+config IPIPE_TRACE_SHIFT
+	int "Depth of trace log (14 => 16Kpoints, 15 => 32Kpoints)"
+	range 10 18
+	default 14
+	depends on IPIPE_TRACE
+	---help---
+	  The number of trace points to hold tracing data for each
+	  trace path, as a power of 2.
+
+config IPIPE_TRACE_VMALLOC
+	bool "Use vmalloc'ed trace buffer"
+	depends on IPIPE_TRACE
+	---help---
+	  Instead of reserving static kernel data, the required buffer
+	  is allocated via vmalloc during boot-up when this option is
+	  enabled. This can help to start systems that are low on memory,
+	  but it slightly degrades overall performance. Try this option
+	  when a traced kernel hangs unexpectedly at boot time.
+
+config IPIPE_TRACE_ENABLE_VALUE
+	int
+	default 0 if !IPIPE_TRACE_ENABLE
+	default 1 if IPIPE_TRACE_ENABLE
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/Makefile linux-2.6.19.patched/kernel/ipipe/Makefile
--- linux-2.6.19.at91/kernel/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_IPIPE)	+= core.o
+obj-$(CONFIG_IPIPE_TRACE) += tracer.o
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/ipipe/tracer.c linux-2.6.19.patched/kernel/ipipe/tracer.c
--- linux-2.6.19.at91/kernel/ipipe/tracer.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.patched/kernel/ipipe/tracer.c	2007-04-04 11:52:06.000000000 +0200
@@ -0,0 +1,1275 @@
+/* -*- linux-c -*-
+ * kernel/ipipe/tracer.c
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005, 2006 Jan Kiszka.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/vmalloc.h>
+#include <linux/utsrelease.h>
+#include <linux/ipipe_trace.h>
+#include <asm/uaccess.h>
+
+#define IPIPE_TRACE_PATHS           4 /* <!> Do not lower below 3 */
+#define IPIPE_DEFAULT_ACTIVE        0
+#define IPIPE_DEFAULT_MAX           1
+#define IPIPE_DEFAULT_FROZEN        2
+
+#define IPIPE_TRACE_POINTS          (1 << CONFIG_IPIPE_TRACE_SHIFT)
+#define WRAP_POINT_NO(point)        ((point) & (IPIPE_TRACE_POINTS-1))
+
+#define IPIPE_DEFAULT_PRE_TRACE     10
+#define IPIPE_DEFAULT_POST_TRACE    10
+#define IPIPE_DEFAULT_BACK_TRACE    30
+
+#define IPIPE_DELAY_NOTE            1000  /* in nanoseconds */
+#define IPIPE_DELAY_WARN            10000 /* in nanoseconds */
+
+#define IPIPE_TFLG_NMI_LOCK         0x0001
+#define IPIPE_TFLG_NMI_HIT          0x0002
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
+#define IPIPE_TFLG_CURRDOM_SHIFT    10   /* bits 10..11: current domain */
+#define IPIPE_TFLG_CURRDOM_MASK     0x0C00
+#define IPIPE_TFLG_DOMSTATE_SHIFT   12   /* bits 12..15: domain stalled? */
+#define IPIPE_TFLG_DOMSTATE_BITS    3
+
+#define IPIPE_TFLG_DOMAIN_STALLED(point, n) \
+	(point->flags & (1 << (n + IPIPE_TFLG_DOMSTATE_SHIFT)))
+#define IPIPE_TFLG_CURRENT_DOMAIN(point) \
+	((point->flags & IPIPE_TFLG_CURRDOM_MASK) >> IPIPE_TFLG_CURRDOM_SHIFT)
+
+
+struct ipipe_trace_point{
+	short type;
+	short flags;
+	unsigned long eip;
+	unsigned long parent_eip;
+	unsigned long v;
+	unsigned long long timestamp;
+};
+
+struct ipipe_trace_path{
+	volatile int flags;
+	int dump_lock; /* separated from flags due to cross-cpu access */
+	int trace_pos; /* next point to fill */
+	int begin, end; /* finalised path begin and end */
+	int post_trace; /* non-zero when in post-trace phase */
+	unsigned long long length; /* max path length in cycles */
+	unsigned long nmi_saved_eip; /* for deferred requests from NMIs */
+	unsigned long nmi_saved_parent_eip;
+	unsigned long nmi_saved_v;
+	struct ipipe_trace_point point[IPIPE_TRACE_POINTS];
+} ____cacheline_aligned_in_smp;
+
+enum ipipe_trace_type
+{
+	IPIPE_TRACE_FUNC = 0,
+	IPIPE_TRACE_BEGIN,
+	IPIPE_TRACE_END,
+	IPIPE_TRACE_FREEZE,
+	IPIPE_TRACE_SPECIAL,
+	IPIPE_TRACE_PID,
+};
+
+#define IPIPE_TYPE_MASK             0x0007
+#define IPIPE_TYPE_BITS             3
+
+
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+
+static struct ipipe_trace_path *trace_paths[NR_CPUS];
+
+#else /* !CONFIG_IPIPE_TRACE_VMALLOC */
+
+static struct ipipe_trace_path trace_paths[NR_CPUS][IPIPE_TRACE_PATHS] =
+	{ [0 ... NR_CPUS-1] =
+		{ [0 ... IPIPE_TRACE_PATHS-1] =
+			{ .begin = -1, .end = -1 }
+		}
+	};
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+
+int ipipe_trace_enable = 0;
+
+static int active_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_ACTIVE };
+static int max_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_MAX };
+static int frozen_path[NR_CPUS] =
+	{ [0 ... NR_CPUS-1] = IPIPE_DEFAULT_FROZEN };
+static IPIPE_DEFINE_SPINLOCK(global_path_lock);
+static int pre_trace = IPIPE_DEFAULT_PRE_TRACE;
+static int post_trace = IPIPE_DEFAULT_POST_TRACE;
+static int back_trace = IPIPE_DEFAULT_BACK_TRACE;
+static int verbose_trace;
+static unsigned long trace_overhead;
+
+static DEFINE_MUTEX(out_mutex);
+static struct ipipe_trace_path *print_path;
+static struct ipipe_trace_path *panic_path;
+static int print_pre_trace;
+static int print_post_trace;
+
+
+static long __ipipe_signed_tsc2us(long long tsc);
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point);
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip);
+
+
+static notrace void
+__ipipe_store_domain_states(struct ipipe_trace_point *point, int cpu_id)
+{
+	struct list_head *pos;
+	int i = 0;
+
+	list_for_each_prev(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+			list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpu_id].status))
+			point->flags |= 1 << (i + IPIPE_TFLG_DOMSTATE_SHIFT);
+
+		if (ipd == per_cpu(ipipe_percpu_domain, cpu_id))
+			point->flags |= i << IPIPE_TFLG_CURRDOM_SHIFT;
+
+		if (++i > IPIPE_TFLG_DOMSTATE_BITS)
+			break;
+	}
+}
+
+static notrace int __ipipe_get_free_trace_path(int old, int cpu_id)
+{
+	int new_active = old;
+	struct ipipe_trace_path *tp;
+
+	do {
+		if (++new_active == IPIPE_TRACE_PATHS)
+			new_active = 0;
+		tp = &trace_paths[cpu_id][new_active];
+	} while ((new_active == max_path[cpu_id]) ||
+	         (new_active == frozen_path[cpu_id]) ||
+	         tp->dump_lock);
+
+	return new_active;
+}
+
+static notrace void
+__ipipe_migrate_pre_trace(struct ipipe_trace_path *new_tp,
+                          struct ipipe_trace_path *old_tp, int old_pos)
+{
+	int i;
+
+	new_tp->trace_pos = pre_trace+1;
+
+	for (i = new_tp->trace_pos; i > 0; i--)
+		memcpy(&new_tp->point[WRAP_POINT_NO(new_tp->trace_pos-i)],
+		       &old_tp->point[WRAP_POINT_NO(old_pos-i)],
+		       sizeof(struct ipipe_trace_point));
+
+	/* mark the end (i.e. the point before point[0]) invalid */
+	new_tp->point[IPIPE_TRACE_POINTS-1].eip = 0;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_end(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	unsigned long long length;
+
+	/* do we have a new worst case? */
+	length = tp->point[tp->end].timestamp -
+	         tp->point[tp->begin].timestamp;
+	if (length > (trace_paths[cpu_id][max_path[cpu_id]]).length) {
+		/* we need protection here against other cpus trying
+		   to start a proc dump */
+		spin_lock(&global_path_lock);
+
+		/* active path holds new worst case */
+		tp->length = length;
+		max_path[cpu_id] = active;
+
+		/* find next unused trace path */
+		active = __ipipe_get_free_trace_path(active, cpu_id);
+
+		spin_unlock(&global_path_lock);
+
+		tp = &trace_paths[cpu_id][active];
+
+		/* migrate last entries for pre-tracing */
+		__ipipe_migrate_pre_trace(tp, old_tp, pos);
+	}
+
+	return tp;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_freeze(int cpu_id, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = active_path[cpu_id];
+	int i;
+
+	/* frozen paths have no core (begin=end) */
+	tp->begin = tp->end;
+
+	/* we need protection here against other cpus trying
+	 * to set their frozen path or to start a proc dump */
+	spin_lock(&global_path_lock);
+
+	frozen_path[cpu_id] = active;
+
+	/* find next unused trace path */
+	active = __ipipe_get_free_trace_path(active, cpu_id);
+
+	/* check if this is the first frozen path */
+	for_each_online_cpu(i) {
+		if ((i != cpu_id) &&
+		    (trace_paths[i][frozen_path[i]].end >= 0))
+			tp->end = -1;
+	}
+
+	spin_unlock(&global_path_lock);
+
+	tp = &trace_paths[cpu_id][active];
+
+	/* migrate last entries for pre-tracing */
+	__ipipe_migrate_pre_trace(tp, old_tp, pos);
+
+	return tp;
+}
+
+void notrace
+__ipipe_trace(enum ipipe_trace_type type, unsigned long eip,
+              unsigned long parent_eip, unsigned long v)
+{
+	struct ipipe_trace_path *tp, *old_tp;
+	int pos, next_pos, begin;
+	struct ipipe_trace_point *point;
+	unsigned long flags;
+	int cpu_id;
+
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+ restart:
+	tp = old_tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here starts a race window with NMIs - catched below */
+
+	/* check for NMI recursion */
+	if (unlikely(tp->flags & IPIPE_TFLG_NMI_LOCK)) {
+		tp->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* first freeze request from NMI context? */
+		if ((type == IPIPE_TRACE_FREEZE) &&
+		    !(tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)) {
+			/* save arguments and mark deferred freezing */
+			tp->flags |= IPIPE_TFLG_NMI_FREEZE_REQ;
+			tp->nmi_saved_eip = eip;
+			tp->nmi_saved_parent_eip = parent_eip;
+			tp->nmi_saved_v = v;
+		}
+		return; /* no need for restoring flags inside IRQ */
+	}
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (unlikely(tp != &trace_paths[cpu_id][active_path[cpu_id]])) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	/* get the point buffer */
+	pos = tp->trace_pos;
+	point = &tp->point[pos];
+
+	/* store all trace point data */
+	point->type = type;
+	point->flags = raw_irqs_disabled_flags(flags) ? IPIPE_TFLG_HWIRQ_OFF : 0;
+	point->eip = eip;
+	point->parent_eip = parent_eip;
+	point->v = v;
+	ipipe_read_tsc(point->timestamp);
+
+	__ipipe_store_domain_states(point, cpu_id);
+
+	/* forward to next point buffer */
+	next_pos = WRAP_POINT_NO(pos+1);
+	tp->trace_pos = next_pos;
+
+	/* only mark beginning if we haven't started yet */
+	begin = tp->begin;
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
+		tp->begin = pos;
+
+	/* end of critical path, start post-trace if not already started */
+	if (unlikely(type == IPIPE_TRACE_END) &&
+	    (begin >= 0) && !tp->post_trace)
+		tp->post_trace = post_trace + 1;
+
+	/* freeze only if the slot is free and we are not already freezing */
+	if (unlikely(type == IPIPE_TRACE_FREEZE) &&
+	    (trace_paths[cpu_id][frozen_path[cpu_id]].begin < 0) &&
+	    !(tp->flags & IPIPE_TFLG_FREEZING)) {
+		tp->post_trace = post_trace + 1;
+		tp->flags |= IPIPE_TFLG_FREEZING;
+	}
+
+	/* enforce end of trace in case of overflow */
+	if (unlikely(WRAP_POINT_NO(next_pos + 1) == begin)) {
+		tp->end = pos;
+		goto enforce_end;
+	}
+
+	/* stop tracing this path if we are in post-trace and
+	 *  a) that phase is over now or
+	 *  b) a new TRACE_BEGIN came in but we are not freezing this path */
+	if (unlikely((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
+	             ((type == IPIPE_TRACE_BEGIN) &&
+	              !(tp->flags & IPIPE_TFLG_FREEZING))))) {
+		/* store the path's end (i.e. excluding post-trace) */
+		tp->end = WRAP_POINT_NO(pos - post_trace + tp->post_trace);
+
+ enforce_end:
+		if (tp->flags & IPIPE_TFLG_FREEZING)
+			tp = __ipipe_trace_freeze(cpu_id, tp, pos);
+		else
+			tp = __ipipe_trace_end(cpu_id, tp, pos);
+
+		/* reset the active path, maybe already start a new one */
+		tp->begin = (type == IPIPE_TRACE_BEGIN) ?
+			WRAP_POINT_NO(tp->trace_pos - 1) : -1;
+		tp->end = -1;
+		tp->post_trace = 0;
+		tp->flags = 0;
+
+		/* update active_path not earlier to avoid races with NMIs */
+		active_path[cpu_id] = tp - trace_paths[cpu_id];
+	}
+
+	/* we still have old_tp and point,
+	 * let's reset NMI lock and check for catches */
+	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+	if (unlikely(old_tp->flags & IPIPE_TFLG_NMI_HIT)) {
+		/* well, this late tagging may not immediately be visible for
+		 * other cpus already dumping this path - a minor issue */
+		point->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* handle deferred freezing from NMI context */
+		if (old_tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+			__ipipe_trace(IPIPE_TRACE_FREEZE, old_tp->nmi_saved_eip,
+			              old_tp->nmi_saved_parent_eip,
+			              old_tp->nmi_saved_v);
+	}
+
+	local_irq_restore_hw_notrace(flags);
+}
+
+static unsigned long __ipipe_global_path_lock(void)
+{
+	unsigned long flags;
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	spin_lock_irqsave(&global_path_lock, flags);
+
+	cpu_id = ipipe_processor_id();
+ restart:
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	/* here is small race window with NMIs - catched below */
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (tp != &trace_paths[cpu_id][active_path[cpu_id]]) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	return flags;
+}
+
+static void __ipipe_global_path_unlock(unsigned long flags)
+{
+	int cpu_id;
+	struct ipipe_trace_path *tp;
+
+	/* release spinlock first - it's not involved in the NMI issue */
+	spin_unlock(&global_path_lock);
+
+	cpu_id = ipipe_processor_id();
+	tp = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+	/* handle deferred freezing from NMI context */
+	if (tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+		__ipipe_trace(IPIPE_TRACE_FREEZE, tp->nmi_saved_eip,
+		              tp->nmi_saved_parent_eip, tp->nmi_saved_v);
+
+	local_irq_restore_hw(flags);
+}
+
+void notrace ipipe_trace_begin(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_BEGIN, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_begin);
+
+void notrace ipipe_trace_end(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_END, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_end);
+
+void notrace ipipe_trace_freeze(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_FREEZE, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_freeze);
+
+void notrace ipipe_trace_special(unsigned char id, unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_SPECIAL | (id << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_special);
+
+void notrace ipipe_trace_pid(pid_t pid, short prio)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_PID | (prio << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, pid);
+}
+EXPORT_SYMBOL(ipipe_trace_pid);
+
+int ipipe_trace_max_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_online_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][max_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+int ipipe_trace_frozen_reset(void)
+{
+	int cpu_id;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_online_cpu(cpu_id) {
+		path = &trace_paths[cpu_id][frozen_path[cpu_id]];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
+void ipipe_trace_panic_freeze(void)
+{
+	unsigned long flags;
+	int cpu_id;
+
+	ipipe_trace_enable = 0;
+	local_irq_save_hw_notrace(flags);
+
+	cpu_id = ipipe_processor_id();
+
+	panic_path = &trace_paths[cpu_id][active_path[cpu_id]];
+
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(ipipe_trace_panic_freeze);
+
+static void
+__ipipe_get_task_info(char *task_info, struct ipipe_trace_point *point,
+                      int trylock)
+{
+	struct task_struct *task = NULL;
+	char buf[8];
+	int i;
+	int locked = 1;
+
+	if (trylock && !read_trylock(&tasklist_lock))
+		locked = 0;
+	else
+		read_lock(&tasklist_lock);
+
+	if (locked)
+		task = find_task_by_pid((pid_t)point->v);
+
+	if (task)
+		strncpy(task_info, task->comm, 11);
+	else
+		strcpy(task_info, "-<?>-");
+
+	if (locked)
+		read_unlock(&tasklist_lock);
+
+	for (i = strlen(task_info); i < 11; i++)
+		task_info[i] = ' ';
+
+	sprintf(buf, " %d ", point->type >> IPIPE_TYPE_BITS);
+	strcpy(task_info + (11 - strlen(buf)), buf);
+}
+
+void ipipe_trace_panic_dump(void)
+{
+	int cnt = back_trace;
+	int start, pos;
+	char task_info[12];
+
+	printk("I-pipe tracer log (%d points):\n", cnt);
+
+	start = pos = WRAP_POINT_NO(panic_path->trace_pos-1);
+
+	while (cnt-- > 0) {
+		struct ipipe_trace_point *point = &panic_path->point[pos];
+		long time;
+		char buf[16];
+	       int i;
+
+	       printk(" %c", (point->flags & IPIPE_TFLG_HWIRQ_OFF) ?
+			      '|' : ' ');
+
+	       for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		       printk("%c",
+			      (IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			      (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				       '#' : '+') :
+			       (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				       '*' : ' '));
+
+		if (!point->eip)
+			printk("-<invalid>-\n");
+		else {
+			__ipipe_trace_point_type(buf, point);
+			printk(buf);
+
+			switch (point->type & IPIPE_TYPE_MASK) {
+				case IPIPE_TRACE_FUNC:
+					printk("           ");
+					break;
+
+				case IPIPE_TRACE_PID:
+					__ipipe_get_task_info(task_info,
+							      point, 1);
+					printk(task_info);
+					break;
+
+				default:
+					printk("0x%08lx ", point->v);
+			}
+
+			time = __ipipe_signed_tsc2us(point->timestamp -
+				panic_path->point[start].timestamp);
+			printk(" %5ld ", time);
+
+			__ipipe_print_symname(NULL, point->eip);
+			printk(" (");
+			__ipipe_print_symname(NULL, point->parent_eip);
+			printk(")\n");
+		}
+		pos = WRAP_POINT_NO(pos - 1);
+	}
+}
+EXPORT_SYMBOL(ipipe_trace_panic_dump);
+
+
+/* --- /proc output --- */
+
+static notrace int __ipipe_in_critical_trpath(long point_no)
+{
+	return ((WRAP_POINT_NO(point_no-print_path->begin) <
+	         WRAP_POINT_NO(print_path->end-print_path->begin)) ||
+	        ((print_path->end == print_path->begin) &&
+	         (WRAP_POINT_NO(point_no-print_path->end) >
+	          print_post_trace)));
+}
+
+static long __ipipe_signed_tsc2us(long long tsc)
+{
+        unsigned long long abs_tsc;
+        long us;
+
+	/* ipipe_tsc2us works on unsigned => handle sign separately */
+        abs_tsc = (tsc >= 0) ? tsc : -tsc;
+        us = ipipe_tsc2us(abs_tsc);
+        if (tsc < 0)
+                return -us;
+        else
+                return us;
+}
+
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point)
+{
+	switch (point->type & IPIPE_TYPE_MASK) {
+		case IPIPE_TRACE_FUNC:
+			strcpy(buf, "func    ");
+			break;
+
+		case IPIPE_TRACE_BEGIN:
+			strcpy(buf, "begin   ");
+			break;
+
+		case IPIPE_TRACE_END:
+			strcpy(buf, "end     ");
+			break;
+
+		case IPIPE_TRACE_FREEZE:
+			strcpy(buf, "freeze  ");
+			break;
+
+		case IPIPE_TRACE_SPECIAL:
+			sprintf(buf, "(0x%02x)  ",
+				point->type >> IPIPE_TYPE_BITS);
+			break;
+
+		case IPIPE_TRACE_PID:
+			sprintf(buf, "[%5d] ", (pid_t)point->v);
+			break;
+	}
+}
+
+static void
+__ipipe_print_pathmark(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	char mark = ' ';
+	int point_no = point - print_path->point;
+	int i;
+
+	if (print_path->end == point_no)
+		mark = '<';
+	else if (print_path->begin == point_no)
+		mark = '>';
+	else if (__ipipe_in_critical_trpath(point_no))
+		mark = ':';
+	seq_printf(m, "%c%c", mark,
+	           (point->flags & IPIPE_TFLG_HWIRQ_OFF) ? '|' : ' ');
+
+	if (!verbose_trace)
+		return;
+
+	for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		seq_printf(m, "%c",
+			(IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			    (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				'#' : '+') :
+			(IPIPE_TFLG_DOMAIN_STALLED(point, i) ? '*' : ' '));
+}
+
+static void
+__ipipe_print_delay(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	unsigned long delay = 0;
+	int next;
+	char *mark = "  ";
+
+	next = WRAP_POINT_NO(point+1 - print_path->point);
+
+	if (next != print_path->trace_pos)
+		delay = ipipe_tsc2ns(print_path->point[next].timestamp -
+		                     point->timestamp);
+
+	if (__ipipe_in_critical_trpath(point - print_path->point)) {
+		if (delay > IPIPE_DELAY_WARN)
+			mark = "! ";
+		else if (delay > IPIPE_DELAY_NOTE)
+			mark = "+ ";
+	}
+	seq_puts(m, mark);
+
+	if (verbose_trace)
+		seq_printf(m, "%3lu.%03lu%c ", delay/1000, delay%1000,
+		           (point->flags & IPIPE_TFLG_NMI_HIT) ? 'N' : ' ');
+	else
+		seq_puts(m, " ");
+}
+
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip)
+{
+	char namebuf[KSYM_NAME_LEN+1];
+	unsigned long size, offset;
+	const char *sym_name;
+	char *modname;
+
+	sym_name = kallsyms_lookup(eip, &size, &offset, &modname, namebuf);
+
+	/* printing to /proc? */
+	if (m) {
+		if (sym_name) {
+			if (verbose_trace) {
+				seq_printf(m, "%s+0x%lx", sym_name, offset);
+				if (modname)
+					seq_printf(m, " [%s]", modname);
+			} else
+				seq_puts(m, sym_name);
+		} else
+			seq_printf(m, "<%08lx>", eip);
+	} else {
+		/* panic dump */
+		if (sym_name) {
+			printk("%s+0x%lx", sym_name, offset);
+			if (modname)
+				printk(" [%s]", modname);
+		}
+	}
+}
+
+#if defined(CONFIG_XENO_OPT_DEBUG) || defined(CONFIG_DEBUG_PREEMPT)
+static void __ipipe_print_dbgwarning(struct seq_file *m)
+{
+	seq_puts(m, "\n******** WARNING ********\n"
+		"The following debugging options will increase the observed "
+		"latencies:\n"
+#ifdef CONFIG_XENO_OPT_DEBUG
+		" o CONFIG_XENO_OPT_DEBUG\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_XENO_OPT_DEBUG_QUEUES
+		" o CONFIG_XENO_OPT_DEBUG_QUEUES (very costly)\n"
+#endif /* CONFIG_XENO_OPT_DEBUG */
+#ifdef CONFIG_DEBUG_PREEMPT
+		" o CONFIG_DEBUG_PREEMPT\n"
+#endif /* CONFIG_DEBUG_PREEMPT */
+		"\n");
+}
+#else /* !WARN_ON_DEBUGGING_LATENCIES */
+# define __ipipe_print_dbgwarning(m)
+#endif /* WARN_ON_DEBUGGING_LATENCIES */
+
+static void __ipipe_print_headline(struct seq_file *m)
+{
+	seq_printf(m, "Calibrated minimum trace-point overhead: %lu.%03lu "
+		   "us\n\n", trace_overhead/1000, trace_overhead%1000);
+
+	if (verbose_trace) {
+		const char *name[4] = { [0 ... 3] = "<unused>" };
+		struct list_head *pos;
+		int i = 0;
+
+		list_for_each_prev(pos, &__ipipe_pipeline) {
+			struct ipipe_domain *ipd =
+				list_entry(pos, struct ipipe_domain, p_link);
+
+			name[i] = ipd->name;
+			if (++i > 3)
+				break;
+		}
+
+		seq_printf(m,
+		           " +----- Hard IRQs ('|': locked)\n"
+		           " |+---- %s\n"
+		           " ||+--- %s\n"
+		           " |||+-- %s\n"
+		           " ||||+- %s%s\n"
+		           " |||||                        +---------- "
+		               "Delay flag ('+': > %d us, '!': > %d us)\n"
+		           " |||||                        |        +- "
+		               "NMI noise ('N')\n"
+		           " |||||                        |        |\n"
+		           "      Type    User Val.   Time    Delay  Function "
+		               "(Parent)\n",
+		           name[3], name[2], name[1], name[0],
+		           name[0] ? " ('*': domain stalled, '+': current, "
+		               "'#': current+stalled)" : "",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+	} else
+		seq_printf(m,
+		           " +--------------- Hard IRQs ('|': locked)\n"
+		           " |             +- Delay flag "
+		               "('+': > %d us, '!': > %d us)\n"
+		           " |             |\n"
+		           "  Type     Time   Function (Parent)\n",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+}
+
+static void *__ipipe_max_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		unsigned long length_usecs;
+		int points, i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the longest of all per-cpu paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][max_path[i]];
+			if ((print_path == NULL) ||
+			    (path->length > print_path->length))
+				print_path = path;
+		}
+		print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		/* does this path actually contain data? */
+		if (print_path->end == print_path->begin)
+			return NULL;
+
+		/* number of points inside the critical path */
+		points = WRAP_POINT_NO(print_path->end-print_path->begin+1);
+
+		/* pre- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, pre-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = pre_trace;
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (points+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 1 - points -
+				print_post_trace;
+
+		length_usecs = ipipe_tsc2us(print_path->length);
+		seq_printf(m, "I-pipe worst-case tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Begin: %lld cycles, Trace Points: %d (-%d/+%d), "
+			"Length: %lu us\n",
+			print_path->point[print_path->begin].timestamp,
+			points, print_pre_trace, print_post_trace, length_usecs);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + n)];
+}
+
+static void *__ipipe_prtrace_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	loff_t n = ++*pos;
+
+	/* check if we are inside the trace range with the next entry */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + *pos)];
+}
+
+static void __ipipe_prtrace_stop(struct seq_file *m, void *p)
+{
+	if (print_path)
+		print_path->dump_lock = 0;
+	mutex_unlock(&out_mutex);
+}
+
+static int __ipipe_prtrace_show(struct seq_file *m, void *p)
+{
+	long time;
+	struct ipipe_trace_point *point = p;
+	char buf[16];
+
+	if (!point->eip) {
+		seq_puts(m, "-<invalid>-\n");
+		return 0;
+	}
+
+	__ipipe_print_pathmark(m, point);
+	__ipipe_trace_point_type(buf, point);
+	seq_puts(m, buf);
+	if (verbose_trace)
+		switch (point->type & IPIPE_TYPE_MASK) {
+			case IPIPE_TRACE_FUNC:
+				seq_puts(m, "           ");
+				break;
+
+			case IPIPE_TRACE_PID:
+				__ipipe_get_task_info(buf, point, 0);
+				seq_puts(m, buf);
+				break;
+
+			default:
+				seq_printf(m, "0x%08lx ", point->v);
+		}
+
+	time = __ipipe_signed_tsc2us(point->timestamp -
+		print_path->point[print_path->begin].timestamp);
+	seq_printf(m, "%5ld", time);
+
+	__ipipe_print_delay(m, point);
+	__ipipe_print_symname(m, point->eip);
+	seq_puts(m, " (");
+	__ipipe_print_symname(m, point->parent_eip);
+	seq_puts(m, ")\n");
+
+	return 0;
+}
+
+static struct seq_operations __ipipe_max_ptrace_ops = {
+	.start = __ipipe_max_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_max_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_max_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_max_reset(struct file *file, const char __user *pbuffer,
+                  size_t count, loff_t *data)
+{
+	mutex_lock(&out_mutex);
+	ipipe_trace_max_reset();
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_max_prtrace_fops = {
+	.open       = __ipipe_max_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_max_reset,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static void *__ipipe_frozen_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *path;
+		int i;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the first of all per-cpu frozen paths */
+		print_path = NULL;
+		for_each_online_cpu(i) {
+			path = &trace_paths[i][frozen_path[i]];
+			if (path->end >= 0)
+				print_path = path;
+		}
+		if (print_path)
+			print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		if (!print_path)
+			return NULL;
+
+		/* back- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, back-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = back_trace-1; /* substract freeze point */
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (1+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 2 -
+				print_post_trace;
+
+		seq_printf(m, "I-pipe frozen back-tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------"
+			"------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		__ipipe_print_dbgwarning(m);
+		seq_printf(m, "Freeze: %lld cycles, Trace Points: %d (+%d)\n",
+			print_path->point[print_path->begin].timestamp,
+			print_pre_trace+1, print_post_trace);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= print_pre_trace + 1 + print_post_trace)
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin-
+	                                        print_pre_trace+n)];
+}
+
+static struct seq_operations __ipipe_frozen_ptrace_ops = {
+	.start = __ipipe_frozen_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_frozen_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_frozen_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_frozen_ctrl(struct file *file, const char __user *pbuffer,
+                    size_t count, loff_t *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, pbuffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	ipipe_trace_frozen_reset();
+	if (val > 0)
+		ipipe_trace_freeze(-1);
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_frozen_prtrace_fops = {
+	.open       = __ipipe_frozen_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_frozen_ctrl,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static int __ipipe_rd_proc_val(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%u\n", *(int *)data);
+	len -= off;
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_wr_proc_val(struct file *file, const char __user *buffer,
+                               unsigned long count, void *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, buffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	*(int *)data = val;
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+extern struct proc_dir_entry *ipipe_proc_root;
+
+static void __init
+__ipipe_create_trace_proc_val(struct proc_dir_entry *trace_dir,
+                              const char *name, int *value_ptr)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_entry(name, 0644, trace_dir);
+	if (entry) {
+		entry->data = value_ptr;
+		entry->read_proc = __ipipe_rd_proc_val;
+		entry->write_proc = __ipipe_wr_proc_val;
+		entry->owner = THIS_MODULE;
+	}
+}
+
+void __init __ipipe_init_tracer(void)
+{
+	struct proc_dir_entry *trace_dir;
+	struct proc_dir_entry *entry;
+	unsigned long long start, end, min = ULLONG_MAX;
+	int i;
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+	int cpu, path;
+
+	for_each_possible_cpu(cpu) {
+		trace_paths[cpu] = vmalloc(
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		if (!trace_paths) {
+			printk(KERN_ERR "I-pipe: "
+			       "insufficient memory for trace buffer.\n");
+			return;
+		}
+		memset(trace_paths[cpu], 0,
+			sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		for (path = 0; path < IPIPE_TRACE_PATHS; path++) {
+			trace_paths[cpu][path].begin = -1;
+			trace_paths[cpu][path].end   = -1;
+		}
+	}
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+	ipipe_trace_enable = CONFIG_IPIPE_TRACE_ENABLE_VALUE;
+
+	/* Calculate minimum overhead of __ipipe_trace() */
+	local_irq_disable_hw();
+	for (i = 0; i < 100; i++) {
+		ipipe_read_tsc(start);
+		__ipipe_trace(IPIPE_TRACE_FUNC, __BUILTIN_RETURN_ADDRESS0,
+			      __BUILTIN_RETURN_ADDRESS1, 0);
+		ipipe_read_tsc(end);
+
+		end -= start;
+		if (end < min)
+			min = end;
+	}
+	local_irq_enable_hw();
+	trace_overhead = ipipe_tsc2ns(min);
+
+	trace_dir = create_proc_entry("trace", S_IFDIR, ipipe_proc_root);
+
+	entry = create_proc_entry("max", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_max_prtrace_fops;
+
+	entry = create_proc_entry("frozen", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_frozen_prtrace_fops;
+
+	__ipipe_create_trace_proc_val(trace_dir, "pre_trace_points",
+	                              &pre_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "post_trace_points",
+	                              &post_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "back_trace_points",
+	                              &back_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "verbose",
+	                              &verbose_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "enable",
+	                              &ipipe_trace_enable);
+}
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/irq/chip.c linux-2.6.19.patched/kernel/irq/chip.c
--- linux-2.6.19.at91/kernel/irq/chip.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/irq/chip.c	2007-04-04 11:52:06.000000000 +0200
@@ -308,7 +308,9 @@ handle_level_irq(unsigned int irq, struc
 	irqreturn_t action_ret;
 
 	spin_lock(&desc->lock);
+#ifndef CONFIG_IPIPE
 	mask_ack_irq(desc, irq);
+#endif /* CONFIG_IPIPE */
 
 	if (unlikely(desc->status & IRQ_INPROGRESS))
 		goto out_unlock;
@@ -431,8 +433,10 @@ handle_edge_irq(unsigned int irq, struct
 
 	kstat_cpu(cpu).irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	/* Start handling the irq */
 	desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	/* Mark the IRQ currently in progress.*/
 	desc->status |= IRQ_INPROGRESS;
@@ -472,6 +476,64 @@ out_unlock:
 	spin_unlock(&desc->lock);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_end_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	mask_ack_irq(desc, irq);
+}
+
+void fastcall __ipipe_end_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->unmask)
+		desc->chip->unmask(irq);
+}
+
+void fastcall __ipipe_ack_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_end_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->eoi(irq);
+}
+
+void fastcall __ipipe_ack_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_bad_irq(unsigned irq, struct irq_desc *desc)
+{
+	static int done;
+
+	handle_bad_irq(irq, desc);
+
+	if (!done) {
+		printk(KERN_WARNING "%s: unknown flow handler for IRQ %d\n",
+		       __FUNCTION__, irq);
+		done = 1;
+	}
+}
+
+void fastcall __ipipe_end_bad_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+#endif /* CONFIG_IPIPE */
+
 #ifdef CONFIG_SMP
 /**
  *	handle_percpu_IRQ - Per CPU local irq handler
@@ -487,8 +549,10 @@ handle_percpu_irq(unsigned int irq, stru
 
 	kstat_this_cpu.irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	if (desc->chip->ack)
 		desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
@@ -498,6 +562,22 @@ handle_percpu_irq(unsigned int irq, stru
 		desc->chip->eoi(irq);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->ack)
+		desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->eoi)
+		desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_IPIPE */
+
 #endif /* CONFIG_SMP */
 
 void
@@ -517,6 +597,34 @@ __set_irq_handler(unsigned int irq, irq_
 
 	if (!handle)
 		handle = handle_bad_irq;
+#ifdef CONFIG_IPIPE
+	else if (handle == &handle_simple_irq) {
+		desc->ipipe_ack = &__ipipe_ack_simple_irq;
+		desc->ipipe_end = &__ipipe_end_simple_irq;
+	}
+	else if (handle == &handle_level_irq) {
+		desc->ipipe_ack = &__ipipe_ack_level_irq;
+		desc->ipipe_end = &__ipipe_end_level_irq;
+	}
+	else if (handle == &handle_edge_irq) {
+		desc->ipipe_ack = &__ipipe_ack_edge_irq;
+		desc->ipipe_end = &__ipipe_end_edge_irq;
+	}
+	else if (handle == &handle_fasteoi_irq) {
+		desc->ipipe_ack = &__ipipe_ack_fasteoi_irq;
+		desc->ipipe_end = &__ipipe_end_fasteoi_irq;
+	}
+#ifdef CONFIG_SMP
+	else if (handle == &handle_percpu_irq) {
+		desc->ipipe_ack = &__ipipe_ack_percpu_irq;
+		desc->ipipe_end = &__ipipe_end_percpu_irq;
+	}
+#endif /* CONFIG_SMP */
+	else {
+		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+		desc->ipipe_end = &__ipipe_end_bad_irq;
+	}
+#endif /* CONFIG_IPIPE */
 
 	if (desc->chip == &no_irq_chip) {
 		printk(KERN_WARNING "Trying to install %sinterrupt handler "
@@ -541,6 +649,10 @@ __set_irq_handler(unsigned int irq, irq_
 		}
 		desc->status |= IRQ_DISABLED;
 		desc->depth = 1;
+#ifdef CONFIG_IPIPE
+		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+		desc->ipipe_end = &__ipipe_end_bad_irq;
+#endif /* CONFIG_IPIPE */
 	}
 	desc->handle_irq = handle;
 	desc->name = name;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/Makefile linux-2.6.19.patched/kernel/Makefile
--- linux-2.6.19.at91/kernel/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -48,6 +48,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_RELAY) += relay.o
+obj-$(CONFIG_IPIPE) += ipipe/
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/printk.c linux-2.6.19.patched/kernel/printk.c
--- linux-2.6.19.at91/kernel/printk.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/printk.c	2007-04-04 11:52:06.000000000 +0200
@@ -489,6 +489,78 @@ static int have_callable_console(void)
  * printf(3)
  */
 
+#ifdef CONFIG_IPIPE
+
+static ipipe_spinlock_t __ipipe_printk_lock = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static int __ipipe_printk_fill;
+
+static char __ipipe_printk_buf[__LOG_BUF_LEN];
+
+void __ipipe_flush_printk (unsigned virq, void *cookie)
+{
+	char *p = __ipipe_printk_buf;
+	int len, lmax, out = 0;
+	unsigned long flags;
+
+	goto start;
+
+	do {
+		spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+ start:
+		lmax = __ipipe_printk_fill;
+		while (out < lmax) {
+			len = strlen(p) + 1;
+			printk("%s",p);
+			p += len;
+			out += len;
+		}
+		spin_lock_irqsave(&__ipipe_printk_lock, flags);
+	}
+	while (__ipipe_printk_fill != lmax);
+
+	__ipipe_printk_fill = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+}
+
+asmlinkage int printk(const char *fmt, ...)
+{
+	int r, fbytes, oldcount;
+    	unsigned long flags;
+	va_list args;
+
+	va_start(args, fmt);
+
+	if (ipipe_current_domain == ipipe_root_domain ||
+	    test_bit(IPIPE_SPRINTK_FLAG,&ipipe_current_domain->flags) ||
+	    oops_in_progress) {
+		r = vprintk(fmt, args);
+		goto out;
+	}
+
+	spin_lock_irqsave(&__ipipe_printk_lock, flags);
+
+	oldcount = __ipipe_printk_fill;
+	fbytes = __LOG_BUF_LEN - oldcount;
+
+	if (fbytes > 1)	{
+		r = vscnprintf(__ipipe_printk_buf + __ipipe_printk_fill,
+			       fbytes, fmt, args) + 1; /* account for the null byte */
+		__ipipe_printk_fill += r;
+	} else
+		r = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+
+	if (oldcount == 0)
+		ipipe_trigger_irq(__ipipe_printk_virq);
+out:
+	va_end(args);
+
+	return r;
+}
+#else /* !CONFIG_IPIPE */
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
@@ -500,6 +572,7 @@ asmlinkage int printk(const char *fmt, .
 
 	return r;
 }
+#endif /* CONFIG_IPIPE */
 
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int printk_cpu = UINT_MAX;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/sched.c linux-2.6.19.patched/kernel/sched.c
--- linux-2.6.19.at91/kernel/sched.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/sched.c	2007-04-04 11:52:06.000000000 +0200
@@ -1391,7 +1391,7 @@ static int try_to_wake_up(struct task_st
 
 	rq = task_rq_lock(p, &flags);
 	old_state = p->state;
-	if (!(old_state & state))
+	if (!(old_state & state) || (old_state & TASK_NOWAKEUP))
 		goto out;
 
 	if (p->array)
@@ -1809,6 +1809,8 @@ asmlinkage void schedule_tail(struct tas
 #endif
 	if (current->set_child_tid)
 		put_user(current->pid, current->set_child_tid);
+
+	ipipe_init_notify(current);
 }
 
 /*
@@ -3324,12 +3326,17 @@ asmlinkage void __sched schedule(void)
 	long *switch_count;
 	struct rq *rq;
 
+#ifdef CONFIG_IPIPE
+	if (unlikely(!ipipe_root_domain_p))
+		return;
+#endif /* CONFIG_IPIPE */
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
 	 * schedule() atomically, we ignore that path for now.
 	 * Otherwise, whine if we are scheduling when we should not be.
 	 */
-	if (unlikely(in_atomic() && !current->exit_state)) {
+	if (unlikely(!(current->state & TASK_ATOMICSWITCH) && in_atomic() &&
+			!current->exit_state)) {
 		printk(KERN_ERR "BUG: scheduling while atomic: "
 			"%s/0x%08x/%d\n",
 			current->comm, preempt_count(), current->pid);
@@ -3337,8 +3344,13 @@ asmlinkage void __sched schedule(void)
 	}
 	profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
+	if (unlikely(current->state & TASK_ATOMICSWITCH)) {
+		current->state &= ~TASK_ATOMICSWITCH;
+		goto need_resched_nodisable;
+	}
 need_resched:
 	preempt_disable();
+need_resched_nodisable:
 	prev = current;
 	release_kernel_lock(prev);
 need_resched_nonpreemptible:
@@ -3456,6 +3468,8 @@ switch_tasks:
 		prepare_task_switch(rq, next);
 		prev = context_switch(rq, prev, next);
 		barrier();
+ 		if (task_hijacked(prev))
+ 		    return;
 		/*
 		 * this_rq must be evaluated again because prev may have moved
 		 * CPUs since it called schedule(), thus the 'rq' on its stack
@@ -3469,7 +3483,7 @@ switch_tasks:
 	if (unlikely(reacquire_kernel_lock(prev) < 0))
 		goto need_resched_nonpreemptible;
 	preempt_enable_no_resched();
-	if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
+	if (unlikely(test_thread_flag(TIF_NEED_RESCHED) && ipipe_root_domain_p))
 		goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
@@ -3487,6 +3501,11 @@ asmlinkage void __sched preempt_schedule
 	struct task_struct *task = current;
 	int saved_lock_depth;
 #endif
+#ifdef CONFIG_IPIPE
+	/* Do not reschedule over non-Linux domains. */
+	if (unlikely(!ipipe_root_domain_p))
+		return;
+#endif /* CONFIG_IPIPE */
 	/*
 	 * If there is a non-zero preempt_count or interrupts are disabled,
 	 * we do not want to preempt the current task.  Just return..
@@ -4185,6 +4204,7 @@ recheck:
 		deactivate_task(p, rq);
 	oldprio = p->prio;
 	__setscheduler(p, policy, param->sched_priority);
+	ipipe_setsched_notify(p);
 	if (array) {
 		__activate_task(p, rq);
 		/*
@@ -6950,3 +6970,50 @@ void set_curr_task(int cpu, struct task_
 }
 
 #endif
+
+#ifdef CONFIG_IPIPE
+
+int ipipe_setscheduler_root (struct task_struct *p, int policy, int prio)
+{
+	struct prio_array *array;
+	unsigned long flags;
+	struct rq *rq;
+	int oldprio;
+
+	rq = task_rq_lock(p, &flags);
+	array = p->array;
+	if (array)
+		deactivate_task(p, rq);
+	oldprio = p->prio;
+	__setscheduler(p, policy, prio);
+	if (array) {
+		__activate_task(p, rq);
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	task_rq_unlock(rq, &flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_setscheduler_root);
+
+int ipipe_reenter_root (struct task_struct *prev, int policy, int prio)
+{
+	finish_task_switch(this_rq(), prev);
+	if (reacquire_kernel_lock(current) < 0)
+		;
+	preempt_enable_no_resched();
+
+	if (current->policy != policy || current->rt_priority != prio)
+		return ipipe_setscheduler_root(current,policy,prio);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_reenter_root);
+
+#endif /* CONFIG_IPIPE */
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/signal.c linux-2.6.19.patched/kernel/signal.c
--- linux-2.6.19.at91/kernel/signal.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/signal.c	2007-04-04 11:52:06.000000000 +0200
@@ -504,6 +504,7 @@ void signal_wake_up(struct task_struct *
 	unsigned int mask;
 
 	set_tsk_thread_flag(t, TIF_SIGPENDING);
+	ipipe_sigwake_notify(t); /* TIF_SIGPENDING must be set first. */
 
 	/*
 	 * For SIGKILL, we want to wake it up in the stopped/traced case.
diff -NaurdpbB -X nodiff linux-2.6.19.at91/kernel/spinlock.c linux-2.6.19.patched/kernel/spinlock.c
--- linux-2.6.19.at91/kernel/spinlock.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/kernel/spinlock.c	2007-04-04 11:52:06.000000000 +0200
@@ -88,7 +88,7 @@ unsigned long __lockfunc _spin_lock_irqs
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_LOCKING
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
@@ -305,7 +305,7 @@ unsigned long __lockfunc _spin_lock_irqs
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_SPIN_LOCKING
+#if defined(CONFIG_PROVE_SPIN_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/ioremap.c linux-2.6.19.patched/lib/ioremap.c
--- linux-2.6.19.at91/lib/ioremap.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/ioremap.c	2007-04-04 11:52:06.000000000 +0200
@@ -11,6 +11,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
 		unsigned long end, unsigned long phys_addr, pgprot_t prot)
@@ -85,7 +86,7 @@ int ioremap_page_range(unsigned long add
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
-
+	__ipipe_pin_range_globally(start, end);
 	flush_cache_vmap(start, end);
 
 	return err;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/Kconfig.debug linux-2.6.19.patched/lib/Kconfig.debug
--- linux-2.6.19.at91/lib/Kconfig.debug	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/Kconfig.debug	2007-04-04 11:52:06.000000000 +0200
@@ -46,6 +46,8 @@ config UNUSED_SYMBOLS
 	  you really need it, and what the merge plan to the mainline kernel for
 	  your module is.
 
+source "kernel/ipipe/Kconfig.debug"
+
 config DEBUG_KERNEL
 	bool "Kernel debugging"
 	help
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/smp_processor_id.c linux-2.6.19.patched/lib/smp_processor_id.c
--- linux-2.6.19.at91/lib/smp_processor_id.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/smp_processor_id.c	2007-04-04 11:52:06.000000000 +0200
@@ -13,6 +13,11 @@ unsigned int debug_smp_processor_id(void
 	int this_cpu = raw_smp_processor_id();
 	cpumask_t this_mask;
 
+#ifdef CONFIG_IPIPE
+ 	if (ipipe_current_domain != ipipe_root_domain)
+	    return this_cpu;
+#endif /* CONFIG_IPIPE */
+
 	if (likely(preempt_count))
 		goto out;
 
diff -NaurdpbB -X nodiff linux-2.6.19.at91/lib/spinlock_debug.c linux-2.6.19.patched/lib/spinlock_debug.c
--- linux-2.6.19.at91/lib/spinlock_debug.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/lib/spinlock_debug.c	2007-04-04 11:52:06.000000000 +0200
@@ -129,6 +129,8 @@ void _raw_spin_lock(spinlock_t *lock)
 	debug_spin_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_lock);
+
 int _raw_spin_trylock(spinlock_t *lock)
 {
 	int ret = __raw_spin_trylock(&lock->raw_lock);
@@ -144,12 +146,16 @@ int _raw_spin_trylock(spinlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_spin_trylock);
+
 void _raw_spin_unlock(spinlock_t *lock)
 {
 	debug_spin_unlock(lock);
 	__raw_spin_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_unlock);
+
 static void rwlock_bug(rwlock_t *lock, const char *msg)
 {
 	if (!debug_locks_off())
@@ -195,6 +201,8 @@ void _raw_read_lock(rwlock_t *lock)
 	__raw_read_lock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_lock);
+
 int _raw_read_trylock(rwlock_t *lock)
 {
 	int ret = __raw_read_trylock(&lock->raw_lock);
@@ -208,12 +216,16 @@ int _raw_read_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_read_trylock);
+
 void _raw_read_unlock(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
 	__raw_read_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_unlock);
+
 static inline void debug_write_lock_before(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
@@ -271,6 +283,8 @@ void _raw_write_lock(rwlock_t *lock)
 	debug_write_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_write_lock);
+
 int _raw_write_trylock(rwlock_t *lock)
 {
 	int ret = __raw_write_trylock(&lock->raw_lock);
@@ -286,8 +300,12 @@ int _raw_write_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_write_trylock);
+
 void _raw_write_unlock(rwlock_t *lock)
 {
 	debug_write_unlock(lock);
 	__raw_write_unlock(&lock->raw_lock);
 }
+
+EXPORT_SYMBOL(_raw_write_unlock);
diff -NaurdpbB -X nodiff linux-2.6.19.at91/Makefile linux-2.6.19.patched/Makefile
--- linux-2.6.19.at91/Makefile	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/Makefile	2007-04-04 11:52:06.000000000 +0200
@@ -491,6 +491,10 @@ endif
 
 include $(srctree)/arch/$(ARCH)/Makefile
 
+ifdef CONFIG_IPIPE_TRACE_MCOUNT
+CFLAGS          += -pg
+endif
+
 ifdef CONFIG_FRAME_POINTER
 CFLAGS		+= -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
 else
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/memory.c linux-2.6.19.patched/mm/memory.c
--- linux-2.6.19.at91/mm/memory.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/memory.c	2007-04-04 11:52:06.000000000 +0200
@@ -50,6 +50,7 @@
 #include <linux/delayacct.h>
 #include <linux/init.h>
 #include <linux/writeback.h>
+#include <linux/vmalloc.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -418,13 +419,41 @@ struct page *vm_normal_page(struct vm_ar
 	return pfn_to_page(pfn);
 }
 
+static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
+{
+	/*
+	 * If the source page was a PFN mapping, we don't have
+	 * a "struct page" for it. We do a best-effort copy by
+	 * just copying from the original user address. If that
+	 * fails, we just zero-fill it. Live with it.
+	 */
+	if (unlikely(!src)) {
+		void *kaddr = kmap_atomic(dst, KM_USER0);
+		void __user *uaddr = (void __user *)(va & PAGE_MASK);
+
+		/*
+		 * This really shouldn't fail, because the page is there
+		 * in the page tables. But it might just be unreadable,
+		 * in which case we just give up and fill the result with
+		 * zeroes.
+		 */
+		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
+			memset(kaddr, 0, PAGE_SIZE);
+		kunmap_atomic(kaddr, KM_USER0);
+		flush_dcache_page(dst);
+		return;
+		
+	}
+	copy_user_highpage(dst, src, va);
+}
+
 /*
  * copy one vm_area from one task to the other. Assumes the page tables
  * already present in the new task to be cleared in the whole range
  * covered by this vma.
  */
 
-static inline void
+static inline int
 copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
 		unsigned long addr, int *rss)
@@ -466,6 +495,25 @@ copy_one_pte(struct mm_struct *dst_mm, s
 	 * in the parent and the child
 	 */
 	if (is_cow_mapping(vm_flags)) {
+#ifdef CONFIG_IPIPE
+		if (((vm_flags|src_mm->def_flags) & (VM_LOCKED|VM_PINNED)) == (VM_LOCKED|VM_PINNED)) {
+			struct page *old_page = vm_normal_page(vma, addr, pte);
+			page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+			if (!page)
+				return -ENOMEM;
+
+			cow_user_page(page, old_page, addr);
+			pte = mk_pte(page, vma->vm_page_prot);
+			
+			if (vm_flags & VM_SHARED)
+				pte = pte_mkclean(pte);
+			pte = pte_mkold(pte);
+
+			page_dup_rmap(page);
+			rss[!!PageAnon(page)]++;
+			goto out_set_pte;
+		}
+#endif /* CONFIG_IPIPE */
 		ptep_set_wrprotect(src_mm, addr, src_pte);
 		pte = pte_wrprotect(pte);
 	}
@@ -487,6 +535,7 @@ copy_one_pte(struct mm_struct *dst_mm, s
 
 out_set_pte:
 	set_pte_at(dst_mm, addr, dst_pte, pte);
+	return 0;
 }
 
 static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
@@ -524,7 +573,9 @@ again:
 			progress++;
 			continue;
 		}
-		copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vma, addr, rss);
+		if (copy_one_pte(dst_mm, src_mm, dst_pte,
+				 src_pte, vma, addr, rss))
+			return -ENOMEM;
 		progress += 8;
 	} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 
@@ -1431,34 +1482,6 @@ static inline pte_t maybe_mkwrite(pte_t 
 	return pte;
 }
 
-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va)
-{
-	/*
-	 * If the source page was a PFN mapping, we don't have
-	 * a "struct page" for it. We do a best-effort copy by
-	 * just copying from the original user address. If that
-	 * fails, we just zero-fill it. Live with it.
-	 */
-	if (unlikely(!src)) {
-		void *kaddr = kmap_atomic(dst, KM_USER0);
-		void __user *uaddr = (void __user *)(va & PAGE_MASK);
-
-		/*
-		 * This really shouldn't fail, because the page is there
-		 * in the page tables. But it might just be unreadable,
-		 * in which case we just give up and fill the result with
-		 * zeroes.
-		 */
-		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
-			memset(kaddr, 0, PAGE_SIZE);
-		kunmap_atomic(kaddr, KM_USER0);
-		flush_dcache_page(dst);
-		return;
-		
-	}
-	copy_user_highpage(dst, src, va);
-}
-
 /*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
@@ -2676,3 +2699,117 @@ int access_process_vm(struct task_struct
 
 	return buf - old_buf;
 }
+
+#ifdef CONFIG_IPIPE
+
+static inline int ipipe_pin_pte_range(struct mm_struct *mm, pmd_t *pmd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	spinlock_t *ptl;
+	pte_t *pte;
+	
+	do {
+		pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+		if (!pte)
+			continue;
+
+		if (!pte_present(*pte)) {
+			pte_unmap_unlock(pte, ptl);
+			continue;
+		}
+
+		if (do_wp_page(mm, vma, addr, pte, pmd, ptl, *pte) == VM_FAULT_OOM)
+			return -ENOMEM;
+	} while (addr += PAGE_SIZE, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pmd_range(struct mm_struct *mm, pud_t *pud,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if (ipipe_pin_pte_range(mm, pmd, vma, addr, end))
+			return -ENOMEM;
+	} while (pmd++, addr = next, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pud_range(struct mm_struct *mm, pgd_t *pgd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pud_t *pud;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (ipipe_pin_pmd_range(mm, pud, vma, addr, end))
+			return -ENOMEM;
+	} while (pud++, addr = next, addr != end);
+	return 0;
+}
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk)
+{
+	unsigned long addr, next, end;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	int result = 0;
+	pgd_t *pgd;
+
+	mm = get_task_mm(tsk);
+	if (!mm)
+		return -EPERM;
+
+	down_write(&mm->mmap_sem);
+	if (mm->def_flags & VM_PINNED)
+		goto done_mm;
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!is_cow_mapping(vma->vm_flags))
+			continue;
+
+		addr = vma->vm_start;
+		end = vma->vm_end;
+		
+		pgd = pgd_offset(mm, addr);
+		do {
+			next = pgd_addr_end(addr, end);
+			if (ipipe_pin_pud_range(mm, pgd, vma, addr, next)) {
+				result = -ENOMEM;
+				goto done_mm;
+			}
+		} while (pgd++, addr = next, addr != end);
+	}
+	mm->def_flags |= VM_PINNED;
+
+  done_mm:
+	up_write(&mm->mmap_sem);
+	mmput(mm);
+	return result;
+}
+
+EXPORT_SYMBOL(ipipe_disable_ondemand_mappings);
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end)
+{
+	struct task_struct *p;
+
+	read_lock(&tasklist_lock);
+
+	for_each_process(p)
+		if (p->mm)
+			__ipipe_pin_range_mapping(p->mm, start, end);
+
+	read_unlock(&tasklist_lock);
+}
+
+#endif
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/mlock.c linux-2.6.19.patched/mm/mlock.c
--- linux-2.6.19.at91/mm/mlock.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/mlock.c	2007-04-04 11:52:06.000000000 +0200
@@ -162,10 +162,10 @@ asmlinkage long sys_munlock(unsigned lon
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
-	unsigned int def_flags = 0;
+	unsigned int def_flags = current->mm->def_flags & VM_PINNED;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
+		def_flags |= VM_LOCKED;
 	current->mm->def_flags = def_flags;
 	if (flags == MCL_FUTURE)
 		goto out;
diff -NaurdpbB -X nodiff linux-2.6.19.at91/mm/vmalloc.c linux-2.6.19.patched/mm/vmalloc.c
--- linux-2.6.19.at91/mm/vmalloc.c	2006-11-29 22:57:37.000000000 +0100
+++ linux-2.6.19.patched/mm/vmalloc.c	2007-04-04 11:52:06.000000000 +0200
@@ -19,6 +19,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -156,6 +157,7 @@ int map_vm_area(struct vm_struct *area, 
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
+	__ipipe_pin_range_globally((unsigned long) area->addr, end);
 	flush_cache_vmap((unsigned long) area->addr, end);
 	return err;
 }

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-10 17:15 ` Gilles Chanteperdrix
@ 2007-04-11  9:01   ` Gregory CLEMENT
  2007-04-11  9:10     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-11  9:01 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: BOUIN Alexandre, adeos-main

[-- Attachment #1: Type: text/plain, Size: 2436 bytes --]

2007/4/10, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> Gregory CLEMENT wrote:
> > Hello,
> >
> > We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
> >
> > This patch must be applied on vanilla 2.6.19 with at91 patch (
> > http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
> > supporting AT91SAM9261.
> > So first get vanilla kernel, then apply at91 patch then apply our
> > patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
> >
> > For now it works with Xenomai on AT91SAM9261-EK, if someone is
> > intersting we can send the benchmark result.
> > As AT91SAM926x are pretty similar of AT91RM9200, there is a some
> > duplicate code and some common code.
> > In the future it could be also work on all AT91SAM926x, we can test
> > it. But before going ahead we would like some comment on this patch.
> >
> > The better would be working on 2.6.20 which already have support for
> > AT91SAM926x, but we didn't see any arm patch on this kernel nor any
> > file modified on git.
> >
> > Hope this patch will be usefull.
>
> It looks good. I will try and port the I-pipe patch for ARM to Linux
> 2.6.20. In the meantime, could you separate the AT91SAM9261 specific
> code and the changes (if any) made to the rest of the I-pipe from the
> rest of the I-pipe ? This would ease distribution and maintenance.

OK I made a diff between our patch and
adeos-ipipe-2.6.19-arm-1.6-05.patch. I had to reworked our patch for
removing fake difference.
As you will see there is not many difference between the 2 patchs and
we don't modify the rest of I-pipe.
There is also difference due to the fact that we made our patch on a
kernel patched with at91 whereas adeos patch was made on vanilla
kernel.

As this diff file isn't really readeable, I can say that the main file
we modified are:
* arch/arm/mach-at91rm9200/Kconfig
-> here we add support for AT91SAM9261

* arch/arm/mach-at91rm9200/at91sam9261.c
-> here we add support for TCB0 and modify interrupt priority in the
same way of AT91RM9200

* arch/arm/mach-at91rm9200/at91sam926x_time.c
-> and here we add the same code that was in
arch/arm/mach-at91rm9200/at91rm9200_time.c. As it is exactly the same
code added as we use the same peripheral, maybe we can add a common
file ( an at91_ipipe_time.c), instead of having duplicated code.

-- 
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40

[-- Attachment #2: adeos-ipipe-2.6.19-arm-at91sam9261.diff --]
[-- Type: text/x-patch, Size: 24273 bytes --]

--- adeos-ipipe-2.6.19-arm-1.6-05.patch	2007-04-10 11:50:07.000000000 +0200
+++ adeos-ipipe-2.6.19-arm-1.6-05-at91sam9261-reworked.patch	2007-04-11 10:34:46.000000000 +0200
@@ -1065,13 +1065,17 @@
  #ifdef CONFIG_DEBUG_USER
  	if (user_debug & UDBG_UNDEFINED) {
  		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/arch/arm/mach-at91rm9200/Kconfig ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/Kconfig
---- linux-2.6.19/arch/arm/mach-at91rm9200/Kconfig	2007-01-04 22:01:15.000000000 +0100
-+++ ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/Kconfig	2007-03-02 18:41:52.000000000 +0100
-@@ -82,6 +82,24 @@ config MACH_KAFA
- 	help
- 	  Select this if you are using Sperry-Sun's KAFA board.
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig
+--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/Kconfig  2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/Kconfig       2007-04-10 15:20:34.000000000 +0200
+@@ -118,6 +118,34 @@ endif
+ 
+ # ----------------------------------------------------------
  
++if ARCH_AT91SAM9261 || ARCH_AT91RM9200
++
++comment "Ipipe dependent"
++
 +config IPIPE_AT91_TC
 +	depends on IPIPE
 +	int "AT91 TC used as time base"
@@ -1084,19 +1088,25 @@
 +config IPIPE_AT91_MCK
 +	depends on IPIPE
 +	int "AT91 Master clock Frequency"
-+	default 46080000
++       default 59904000 if MACH_AT91RM9200EK
++       default 99328000 if MACH_AT91SAM9261EK
++       default 53000000
 +	help
 +	When Adeos interrupt pipeline is enabled, AT91 timer is based on
 +	the AT91 master clock, whose frequency need hence to be known at
 +	compilation time.
 +
- endif
++endif
++
++# ----------------------------------------------------------
++
+ comment "AT91 Board Options"
  
- # ----------------------------------------------------------
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/arch/arm/mach-at91rm9200/at91rm9200.c ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/at91rm9200.c
---- linux-2.6.19/arch/arm/mach-at91rm9200/at91rm9200.c	2007-03-20 20:32:02.000000000 +0100
-+++ ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/at91rm9200.c	2007-03-02 18:41:52.000000000 +0100
-@@ -51,6 +51,13 @@ static struct map_desc at91rm9200_io_des
+ config MTD_AT91_DATAFLASH_CARD
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c
+--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91rm9200.c     2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91rm9200.c  2007-04-04 11:52:05.000000000 +0200
+@@ -33,6 +33,13 @@ static struct map_desc at91rm9200_io_des
  		.length		= SZ_16K,
  		.type		= MT_DEVICE,
  	}, {
@@ -1107,10 +1117,10 @@
 +		.type		= MT_DEVICE,
 +        }, {
 +#endif /* CONFIG_IPIPE */
- 		.virtual	= AT91_SRAM_VIRT_BASE,
+                .virtual        = AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE,
  		.pfn		= __phys_to_pfn(AT91RM9200_SRAM_BASE),
  		.length		= AT91RM9200_SRAM_SIZE,
-@@ -249,6 +256,7 @@ void __init at91rm9200_initialize(unsign
+@@ -247,6 +254,7 @@ void __init at91rm9200_initialize(unsign
   * The default interrupt priority levels (0 = lowest, 7 = highest).
   */
  static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
@@ -1118,7 +1128,7 @@
  	7,	/* Advanced Interrupt Controller (FIQ) */
  	7,	/* System Peripherals */
  	0,	/* Parallel IO Controller A */
-@@ -281,6 +289,42 @@ static unsigned int at91rm9200_default_i
+@@ -279,6 +287,42 @@ static unsigned int at91rm9200_default_i
  	0,	/* Advanced Interrupt Controller (IRQ4) */
  	0,	/* Advanced Interrupt Controller (IRQ5) */
  	0	/* Advanced Interrupt Controller (IRQ6) */
@@ -1227,7 +1237,7 @@
  /*
   * The ST_CRTR is updated asynchronously to the master clock.  It is therefore
   *  necessary to read it twice (with the same value) to ensure accuracy.
-@@ -39,14 +95,16 @@ static unsigned long last_crtr;
+@@ -41,14 +97,16 @@ static unsigned long last_crtr;
  static inline unsigned long read_CRTR(void) {
  	unsigned long x1, x2;
  
@@ -1245,7 +1255,7 @@
  /*
   * Returns number of microseconds since last timer interrupt.  Note that interrupts
   * will have been disabled by do_gettimeofday()
-@@ -139,3 +197,209 @@ struct sys_timer at91rm9200_timer = {
+@@ -144,3 +202,209 @@ struct sys_timer at91rm9200_timer = {
  	.resume		= at91rm9200_timer_reset,
  };
  
@@ -1455,12 +1465,363 @@
 +	.resume		= NULL,
 +};
 +#endif /* CONFIG_IPIPE */
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/arch/arm/mach-at91rm9200/gpio.c ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/gpio.c
---- linux-2.6.19/arch/arm/mach-at91rm9200/gpio.c	2007-03-20 20:32:02.000000000 +0100
-+++ ipipe-2.6.19-arm/arch/arm/mach-at91rm9200/gpio.c	2007-03-02 18:41:52.000000000 +0100
-@@ -20,6 +20,11 @@
- #include <asm/io.h>
- #include <asm/hardware.h>
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c
+--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam9261.c    2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam9261.c 2007-04-10 07:58:16.000000000 +0200
+@@ -27,6 +27,13 @@ static struct map_desc at91sam9261_io_de
+                .length         = SZ_16K,
+                .type           = MT_DEVICE,
+        }, {
++#ifdef CONFIG_IPIPE
++               .virtual        = AT91_VA_BASE_TCB0,
++               .pfn            = __phys_to_pfn(AT91SAM9261_BASE_TCB0),
++               .length         = SZ_16K,
++               .type           = MT_DEVICE,
++        }, {
++#endif /* CONFIG_IPIPE */
+                .virtual        = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
+                .pfn            = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
+                .length         = AT91SAM9261_SRAM_SIZE,
+@@ -242,6 +249,7 @@ void __init at91sam9261_initialize(unsig
+  * The default interrupt priority levels (0 = lowest, 7 = highest).
+  */
+ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
++#ifndef CONFIG_IPIPE
+        7,      /* Advanced Interrupt Controller */
+        7,      /* System Peripherals */
+        0,      /* Parallel IO Controller A */
+@@ -274,6 +282,42 @@ static unsigned int at91sam9261_default_
+        0,      /* Advanced Interrupt Controller */
+        0,      /* Advanced Interrupt Controller */
+        0,      /* Advanced Interrupt Controller */
++#else /* CONFIG_IPIPE */
++/* Give the highest priority to TC, since they are used as timer interrupt by
++   I-pipe. */
++       7,      /* Advanced Interrupt Controller */
++       7,      /* System Peripherals */
++       0,      /* Parallel IO Controller A */
++       0,      /* Parallel IO Controller B */
++       0,      /* Parallel IO Controller C */
++       0,
++       6,      /* USART 0 */
++       6,      /* USART 1 */
++       6,      /* USART 2 */
++       0,      /* Multimedia Card Interface */
++       4,      /* USB Device Port */
++       0,      /* Two-Wire Interface */
++       6,      /* Serial Peripheral Interface 0 */
++       6,      /* Serial Peripheral Interface 1 */
++       5,      /* Serial Synchronous Controller 0 */
++       5,      /* Serial Synchronous Controller 1 */
++       5,      /* Serial Synchronous Controller 2 */
++       7,      /* Timer Counter 0 */
++       7,      /* Timer Counter 1 */
++       7,      /* Timer Counter 2 */
++       3,      /* USB Host port */
++       3,      /* LCD Controller */
++       0,
++       0,
++       0,
++       0,
++       0,
++       0,
++       0,
++       0,      /* Advanced Interrupt Controller */
++       0,      /* Advanced Interrupt Controller */
++       0,      /* Advanced Interrupt Controller */
++#endif /*CONFIG_IPIPE */
+ };
+ 
+ void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c
+--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/at91sam926x_time.c       2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/at91sam926x_time.c    2007-04-04 11:52:05.000000000 +0200
+@@ -22,10 +22,69 @@
+ 
+ #include <asm/arch/at91_pit.h>
+ 
++static unsigned long last_crtr;
++
++#ifdef CONFIG_IPIPE
++#include <linux/clk.h>
++#include <linux/console.h>
++#include <linux/module.h>
++#include <asm/arch/at91sam9261.h>
++#include <asm/arch/at91_tc.h>
++#include "clock.h"
++
++#ifdef CONFIG_NO_IDLE_HZ
++#error "dynamic tick timer not yet supported with IPIPE"
++#endif /* CONFIG_NO_IDLE_HZ */
++
++#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
++#define AT91_TC_REG_MASK (0xffff)
++
++#if (CONFIG_IPIPE_AT91_TC==0)
++#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC0
++#elif (CONFIG_IPIPE_AT91_TC==1)
++#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC1
++#elif (CONFIG_IPIPE_AT91_TC==2)
++#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC2
++#else
++#error IPIPE_AT91_TC must be 0, 1 or 2.
++#endif
++
++static inline unsigned int at91_tc_read(unsigned int reg_offset)
++{
++       unsigned long addr =
++               (AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
++
++       return readl((void __iomem *)(addr + reg_offset));
++}
++
++static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
++{
++       unsigned long addr =
++               (AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
++
++       writel(value, (void __iomem *)(addr + reg_offset));
++}
++
++#define read_CV() at91_tc_read(AT91_TC_CV)
++#define read_RC() at91_tc_read(AT91_TC_RC)
++#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
++
++int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
++EXPORT_SYMBOL(__ipipe_mach_timerint);
++
++int __ipipe_mach_timerstolen = 0;
++EXPORT_SYMBOL(__ipipe_mach_timerstolen);
++
++unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
++EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
++
++static int at91_timer_initialized;
++#endif /* CONFIG_IPIPE */
+ 
+ #define PIT_CPIV(x)    ((x) & AT91_PIT_CPIV)
+ #define PIT_PICNT(x)   (((x) & AT91_PIT_PICNT) >> 20)
+ 
++#ifndef CONFIG_IPIPE
+ /*
+  * Returns number of microseconds since last timer interrupt.  Note that interrupts
+  * will have been disabled by do_gettimeofday()
+@@ -112,3 +171,209 @@ struct sys_timer at91sam926x_timer = {
+        .resume         = at91sam926x_timer_reset,
+ };
+ 
++#else /* CONFIG_IPIPE */
++
++/*
++ * Returns number of microseconds since last timer interrupt.  Note that interrupts
++ * will have been disabled by do_gettimeofday()
++ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
++*  'tick' is usecs per jiffy (linux/timex.h).
++ */
++static unsigned long at91sam926x_gettimeoffset(void)
++{
++       unsigned long elapsed;
++
++       elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
++
++       return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
++}
++
++void __ipipe_mach_acktimer(void)
++{
++       at91_tc_read(AT91_TC_SR);
++}
++
++/*
++ * IRQ handler for the timer.
++ */
++static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
++{
++       /*
++        * - if Linux is running under ipipe, but it still has the control over
++        *   the timer (no Xenomai for example), then reprogram the timer (ipipe
++        *   has already acked it)
++        * - if some other domain has taken over the timer, then do nothing
++        *   (ipipe has acked it, and the other domain has reprogramed it)
++        */
++
++       write_seqlock(&xtime_lock);
++
++       if (__ipipe_mach_timerstolen) {
++               timer_tick();
++               last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
++       } else {
++               while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
++                       timer_tick();
++                       last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
++               }
++               write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
++       }
++
++       write_sequnlock(&xtime_lock);
++
++       return IRQ_HANDLED;
++}
++
++static irqreturn_t at91sam926x_bad_freq(int irq, void *dev_id)
++{
++       static int ticks = 0;
++
++       if (++ticks != HZ * 120) {
++               if (!console_drivers || try_acquire_console_sem())
++                       return at91sam926x_timer_interrupt(irq, dev_id);
++       
++               release_console_sem();
++       }
++
++       panic("AT91 clock rate incorrectly set.\n"
++             "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
++             clk_get_rate(clk_get(NULL, "mck")));
++}
++
++notrace unsigned long long __ipipe_mach_get_tsc(void)
++{
++       if (likely(at91_timer_initialized)) {
++               static union {
++#ifdef __BIG_ENDIAN
++                       struct {
++                               unsigned long high;
++                               unsigned short mid;
++                               unsigned short low;
++                       };
++#else /* __LITTLE_ENDIAN */
++                       struct {
++                               unsigned short low;
++                               unsigned short mid;
++                               unsigned long high;
++                       };
++#endif /* __LITTLE_ENDIAN */
++                       unsigned long long full;
++               } tsc[NR_CPUS], *local_tsc;
++               unsigned long long result;
++               unsigned short stamp;
++               unsigned long flags;
++
++               local_irq_save_hw(flags);
++               local_tsc = &tsc[ipipe_processor_id()];
++               stamp = read_CV();
++               if (unlikely(stamp < local_tsc->low)) {
++                       if (unlikely(!++local_tsc->mid))
++                               /* 32 bit counter wrapped, increment high word. */
++                               local_tsc->high++;
++               }
++               local_tsc->low = stamp;
++               result = local_tsc->full;
++               local_irq_restore_hw(flags);
++
++               return result;
++       }
++       
++        return 0;
++}
++EXPORT_SYMBOL(__ipipe_mach_get_tsc);
++
++/*
++ * Reprogram the timer
++ */
++
++void __ipipe_mach_set_dec(unsigned long delay)
++{
++       unsigned long flags;
++
++       if (delay > 2) {
++               local_irq_save_hw(flags);
++               write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
++               local_irq_restore_hw(flags);
++       } else
++               ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
++}
++EXPORT_SYMBOL(__ipipe_mach_set_dec);
++
++void __ipipe_mach_release_timer(void)
++{
++       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
++}
++EXPORT_SYMBOL(__ipipe_mach_release_timer);
++
++unsigned long __ipipe_mach_get_dec(void)
++{
++       return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
++}
++
++static struct irqaction at91sam926x_timer_irq = {
++       .name           = "at91_tick",
++       .flags          = IRQF_DISABLED | IRQF_TIMER,
++       .handler        = &at91sam926x_timer_interrupt
++};
++
++static char clk_name [] = "tc%";
++
++static struct clk tc = {
++       .name           = (const char *) clk_name,
++       .users          = 0,
++       .type           = CLK_TYPE_PERIPHERAL,
++       .pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
++};
++
++void __init at91sam926x_timer_init(void)
++{
++       unsigned long v;
++       
++       if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
++               at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
++
++       snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
++       clk_register(&tc);
++       clk_enable(&tc);
++       
++       /* No Sync. */
++       at91_tc_write(AT91_TC_BCR, 0);
++
++       /* program NO signal on XCN */
++       v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
++       v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
++       v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
++       writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
++
++       /* Disable the channel */
++       at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
++
++       /* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
++       at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
++
++       /* Disable all interrupts. */
++       at91_tc_write(AT91_TC_IDR, ~0ul);
++
++       /* Load the TC register C. */
++       last_crtr = 0;
++       write_RC(LATCH);
++
++       /* Enable CPCS interrupt. */
++       at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
++
++       /* Set up the interrupt. */
++       setup_irq(KERNEL_TIMER_IRQ_NUM, &at91sam926x_timer_irq);
++
++       /* Enable the channel. */
++       at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
++
++       at91_timer_initialized = 1;
++}
++
++struct sys_timer at91sam926x_timer = {
++       .init           = at91sam926x_timer_init,
++       .offset         = at91sam926x_gettimeoffset,
++       .suspend        = NULL,
++       .resume         = NULL,
++};
++#endif /* CONFIG_IPIPE */
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c
+--- linux-2.6.19.at91/arch/arm/mach-at91rm9200/gpio.c   2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/arch/arm/mach-at91rm9200/gpio.c        2007-04-04 11:52:05.000000000 +0200
+@@ -22,6 +22,11 @@
+ #include <asm/arch/at91_pio.h>
+ #include <asm/arch/at91_pmc.h>
  #include <asm/arch/gpio.h>
 +#ifdef CONFIG_IPIPE
 +#include <asm/irq.h>
@@ -1470,7 +1831,7 @@
  
  #include "generic.h"
  
-@@ -326,6 +331,9 @@ static int gpio_irq_type(unsigned pin, u
+@@ -328,6 +333,9 @@ static int gpio_irq_type(unsigned pin, u
  
  static struct irq_chip gpio_irqchip = {
  	.name		= "GPIO",
@@ -1480,7 +1841,7 @@
  	.mask		= gpio_irq_mask,
  	.unmask		= gpio_irq_unmask,
  	.set_type	= gpio_irq_type,
-@@ -374,6 +382,50 @@ static void gpio_irq_handler(unsigned ir
+@@ -376,6 +384,50 @@ static void gpio_irq_handler(unsigned ir
  	/* now it may re-trigger */
  }
  
@@ -1531,7 +1892,7 @@
  /*--------------------------------------------------------------------------*/
  
  /*
-@@ -422,4 +474,7 @@ void __init at91_gpio_init(struct at91_g
+@@ -424,4 +476,7 @@ void __init at91_gpio_init(struct at91_g
  
  	gpio = data;
  	gpio_banks = nr_banks;
@@ -2905,41 +3266,72 @@
  
  struct ht_irq_cfg {
  	struct pci_dev *dev;
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/include/asm-arm/arch-at91rm9200/hardware.h ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/hardware.h
---- linux-2.6.19/include/asm-arm/arch-at91rm9200/hardware.h	2007-03-20 20:32:37.000000000 +0100
-+++ ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/hardware.h	2007-03-02 18:41:52.000000000 +0100
-@@ -39,6 +39,9 @@
- #define AT91_VA_BASE_TWI	AT91_IO_P2V(AT91RM9200_BASE_TWI)
- #define AT91_VA_BASE_MCI	AT91_IO_P2V(AT91RM9200_BASE_MCI)
- #define AT91_VA_BASE_UDP	AT91_IO_P2V(AT91RM9200_BASE_UDP)
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h
+--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/hardware.h        2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/hardware.h     2007-04-04 11:52:06.000000000 +0200
+@@ -42,7 +42,28 @@
+  * Virtual to Physical Address mapping for IO devices.
+  */
+ #define AT91_VA_BASE_SYS       AT91_IO_P2V(AT91_BASE_SYS)
+-#define AT91_VA_BASE_EMAC      AT91_IO_P2V(AT91RM9200_BASE_EMAC)
++
++#if defined(CONFIG_ARCH_AT91RM9200)
++       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91RM9200_BASE_EMAC)
++#elif defined(CONFIG_ARCH_AT91SAM9260)
++       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
++#elif defined(CONFIG_ARCH_AT91SAM9261)
++       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
++#else
++#error "Unsupported AT91 processor"
++#endif
++
 +#ifdef CONFIG_IPIPE
++#if defined(CONFIG_ARCH_AT91RM9200)
 +#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
++#elif defined(CONFIG_ARCH_AT91SAM9260)
++       #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
++#elif defined(CONFIG_ARCH_AT91SAM9261)
++       #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
++#else
++#error "Unsupported AT91 processor"
++#endif
 +#endif /* CONFIG_IPIPE */
  
   /* Internal SRAM is mapped below the IO devices */
- #define AT91_SRAM_VIRT_BASE	(AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE)
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/include/asm-arm/arch-at91rm9200/irqs.h ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/irqs.h
---- linux-2.6.19/include/asm-arm/arch-at91rm9200/irqs.h	2007-03-20 20:32:37.000000000 +0100
-+++ ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/irqs.h	2007-03-02 18:41:52.000000000 +0100
-@@ -39,4 +39,12 @@
+ #define AT91_SRAM_MAX          SZ_1M
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h
+--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/irqs.h    2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/irqs.h 2007-04-04 11:52:06.000000000 +0200
+@@ -41,4 +41,23 @@
   */
  #define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
  
 +#if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
 +extern unsigned __ipipe_at91_gpio_banks;
 +
++#if defined(CONFIG_ARCH_AT91RM9200)
 +#define __ipipe_mach_irq_mux_p(irq) \
 +	((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
++#elif defined(CONFIG_ARCH_AT91SAM9260)
++       #define __ipipe_mach_irq_mux_p(irq) \
++               ((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
++#elif defined(CONFIG_ARCH_AT91SAM9261)
++       #define __ipipe_mach_irq_mux_p(irq) \
++               ((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
++#else
++#error "Unsupported AT91 processor"
++#endif
++
 +
 +#endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
 +
  #endif
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/include/asm-arm/arch-at91rm9200/timex.h ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/timex.h
---- linux-2.6.19/include/asm-arm/arch-at91rm9200/timex.h	2007-01-04 22:02:39.000000000 +0100
-+++ ipipe-2.6.19-arm/include/asm-arm/arch-at91rm9200/timex.h	2007-03-02 18:41:52.000000000 +0100
-@@ -23,6 +23,10 @@
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h
+--- linux-2.6.19.at91/include/asm-arm/arch-at91rm9200/timex.h   2007-04-10 08:04:00.000000000 +0200
++++ linux-2.6.19.patched/include/asm-arm/arch-at91rm9200/timex.h        2007-04-04 11:52:06.000000000 +0200
+@@ -25,7 +25,11 @@
  
- #include <asm/hardware.h>
+ #if defined(CONFIG_ARCH_AT91RM9200)
  
 +#ifndef CONFIG_IPIPE
  #define CLOCK_TICK_RATE		(AT91_SLOW_CLOCK)
@@ -2947,10 +3339,11 @@
 +#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
 +#endif /* !CONFIG_IPIPE */
  
- #endif
-diff -Naurdp -x .gitignore -x '*~' -x '*.orig' -x '*.rej' linux-2.6.19/include/asm-arm/arch-integrator/entry-macro.S ipipe-2.6.19-arm/include/asm-arm/arch-integrator/entry-macro.S
---- linux-2.6.19/include/asm-arm/arch-integrator/entry-macro.S	2006-05-07 16:42:04.000000000 +0200
-+++ ipipe-2.6.19-arm/include/asm-arm/arch-integrator/entry-macro.S	2007-03-02 18:41:52.000000000 +0100
+ #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
+ 
+diff -NaurdpbB -X nodiff linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S
+--- linux-2.6.19.at91/include/asm-arm/arch-integrator/entry-macro.S     2006-11-29 22:57:37.000000000 +0100
++++ linux-2.6.19.patched/include/asm-arm/arch-integrator/entry-macro.S  2007-04-04 11:52:06.000000000 +0200
 @@ -22,7 +22,11 @@
  		teq	\irqstat, #0
  		ldreq	\irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)]

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-11  9:01   ` Gregory CLEMENT
@ 2007-04-11  9:10     ` Gilles Chanteperdrix
  2007-04-11  9:21       ` Gregory CLEMENT
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-11  9:10 UTC (permalink / raw)
  To: Gregory CLEMENT; +Cc: BOUIN Alexandre, adeos-main

Gregory CLEMENT wrote:
> 2007/4/10, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> 
>>Gregory CLEMENT wrote:
>>
>>>Hello,
>>>
>>>We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
>>>
>>>This patch must be applied on vanilla 2.6.19 with at91 patch (
>>>http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
>>>supporting AT91SAM9261.
>>>So first get vanilla kernel, then apply at91 patch then apply our
>>>patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
>>>
>>>For now it works with Xenomai on AT91SAM9261-EK, if someone is
>>>intersting we can send the benchmark result.
>>>As AT91SAM926x are pretty similar of AT91RM9200, there is a some
>>>duplicate code and some common code.
>>>In the future it could be also work on all AT91SAM926x, we can test
>>>it. But before going ahead we would like some comment on this patch.
>>>
>>>The better would be working on 2.6.20 which already have support for
>>>AT91SAM926x, but we didn't see any arm patch on this kernel nor any
>>>file modified on git.
>>>
>>>Hope this patch will be usefull.
>>
>>It looks good. I will try and port the I-pipe patch for ARM to Linux
>>2.6.20. In the meantime, could you separate the AT91SAM9261 specific
>>code and the changes (if any) made to the rest of the I-pipe from the
>>rest of the I-pipe ? This would ease distribution and maintenance.
> 
> 
> OK I made a diff between our patch and
> adeos-ipipe-2.6.19-arm-1.6-05.patch. I had to reworked our patch for
> removing fake difference.
> As you will see there is not many difference between the 2 patchs and
> we don't modify the rest of I-pipe.
> There is also difference due to the fact that we made our patch on a
> kernel patched with at91 whereas adeos patch was made on vanilla
> kernel.
> 
> As this diff file isn't really readeable, I can say that the main file
> we modified are:
> * arch/arm/mach-at91rm9200/Kconfig
> -> here we add support for AT91SAM9261
> 
> * arch/arm/mach-at91rm9200/at91sam9261.c
> -> here we add support for TCB0 and modify interrupt priority in the
> same way of AT91RM9200
> 
> * arch/arm/mach-at91rm9200/at91sam926x_time.c
> -> and here we add the same code that was in
> arch/arm/mach-at91rm9200/at91rm9200_time.c. As it is exactly the same
> code added as we use the same peripheral, maybe we can add a common
> file ( an at91_ipipe_time.c), instead of having duplicated code.

Sorry, I did not make myself clear, I would like a difference between
the trees, not between the diffs. In other words, the modifications you
made.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-11  9:10     ` Gilles Chanteperdrix
@ 2007-04-11  9:21       ` Gregory CLEMENT
  2007-04-11 11:04         ` Jan Kiszka
  2007-04-11 12:15         ` Gilles Chanteperdrix
  0 siblings, 2 replies; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-11  9:21 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: BOUIN Alexandre, adeos-main

2007/4/11, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> Gregory CLEMENT wrote:
> > 2007/4/10, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> >
> >>Gregory CLEMENT wrote:
> >>
> >>>Hello,
> >>>
> >>>We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
> >>>
> >>>This patch must be applied on vanilla 2.6.19 with at91 patch (
> >>>http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
> >>>supporting AT91SAM9261.
> >>>So first get vanilla kernel, then apply at91 patch then apply our
> >>>patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
> >>>
> >>>For now it works with Xenomai on AT91SAM9261-EK, if someone is
> >>>intersting we can send the benchmark result.
> >>>As AT91SAM926x are pretty similar of AT91RM9200, there is a some
> >>>duplicate code and some common code.
> >>>In the future it could be also work on all AT91SAM926x, we can test
> >>>it. But before going ahead we would like some comment on this patch.
> >>>
> >>>The better would be working on 2.6.20 which already have support for
> >>>AT91SAM926x, but we didn't see any arm patch on this kernel nor any
> >>>file modified on git.
> >>>
> >>>Hope this patch will be usefull.
> >>
> >>It looks good. I will try and port the I-pipe patch for ARM to Linux
> >>2.6.20. In the meantime, could you separate the AT91SAM9261 specific
> >>code and the changes (if any) made to the rest of the I-pipe from the
> >>rest of the I-pipe ? This would ease distribution and maintenance.
> >
> >
> > OK I made a diff between our patch and
> > adeos-ipipe-2.6.19-arm-1.6-05.patch. I had to reworked our patch for
> > removing fake difference.
> > As you will see there is not many difference between the 2 patchs and
> > we don't modify the rest of I-pipe.
> > There is also difference due to the fact that we made our patch on a
> > kernel patched with at91 whereas adeos patch was made on vanilla
> > kernel.
> >
> > As this diff file isn't really readeable, I can say that the main file
> > we modified are:
> > * arch/arm/mach-at91rm9200/Kconfig
> > -> here we add support for AT91SAM9261
> >
> > * arch/arm/mach-at91rm9200/at91sam9261.c
> > -> here we add support for TCB0 and modify interrupt priority in the
> > same way of AT91RM9200
> >
> > * arch/arm/mach-at91rm9200/at91sam926x_time.c
> > -> and here we add the same code that was in
> > arch/arm/mach-at91rm9200/at91rm9200_time.c. As it is exactly the same
> > code added as we use the same peripheral, maybe we can add a common
> > file ( an at91_ipipe_time.c), instead of having duplicated code.
>
> Sorry, I did not make myself clear, I would like a difference between
> the trees, not between the diffs. In other words, the modifications you
> made.

Well this differences show the modification we made, but I agree it is
not really readable.

Between which tree do you want the diffs ?
Vanilla kernel +adeos patch  and at91 patched kernel + our patch ?
With this you'll have a lot of at91 patch in it.

Maybe we can try to make a diff between
at91 patched kernel +adeos patch  and at91 patched kernel + our patch ?
But with this solution we have to made some modification on adeos
patch for applying it on at91 patched kernel.

Last solution is to attach the file modified.

As you want.

-- 
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-11  9:21       ` Gregory CLEMENT
@ 2007-04-11 11:04         ` Jan Kiszka
  2007-04-11 12:15         ` Gilles Chanteperdrix
  1 sibling, 0 replies; 27+ messages in thread
From: Jan Kiszka @ 2007-04-11 11:04 UTC (permalink / raw)
  To: Gregory CLEMENT; +Cc: BOUIN Alexandre, adeos-main

[-- Attachment #1: Type: text/plain, Size: 3480 bytes --]

Gregory CLEMENT wrote:
> 2007/4/11, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
>> Gregory CLEMENT wrote:
>>> 2007/4/10, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
>>>
>>>> Gregory CLEMENT wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
>>>>>
>>>>> This patch must be applied on vanilla 2.6.19 with at91 patch (
>>>>> http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
>>>>> supporting AT91SAM9261.
>>>>> So first get vanilla kernel, then apply at91 patch then apply our
>>>>> patch instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
>>>>>
>>>>> For now it works with Xenomai on AT91SAM9261-EK, if someone is
>>>>> intersting we can send the benchmark result.
>>>>> As AT91SAM926x are pretty similar of AT91RM9200, there is a some
>>>>> duplicate code and some common code.
>>>>> In the future it could be also work on all AT91SAM926x, we can test
>>>>> it. But before going ahead we would like some comment on this patch.
>>>>>
>>>>> The better would be working on 2.6.20 which already have support for
>>>>> AT91SAM926x, but we didn't see any arm patch on this kernel nor any
>>>>> file modified on git.
>>>>>
>>>>> Hope this patch will be usefull.
>>>> It looks good. I will try and port the I-pipe patch for ARM to Linux
>>>> 2.6.20. In the meantime, could you separate the AT91SAM9261 specific
>>>> code and the changes (if any) made to the rest of the I-pipe from the
>>>> rest of the I-pipe ? This would ease distribution and maintenance.
>>>
>>> OK I made a diff between our patch and
>>> adeos-ipipe-2.6.19-arm-1.6-05.patch. I had to reworked our patch for
>>> removing fake difference.
>>> As you will see there is not many difference between the 2 patchs and
>>> we don't modify the rest of I-pipe.
>>> There is also difference due to the fact that we made our patch on a
>>> kernel patched with at91 whereas adeos patch was made on vanilla
>>> kernel.
>>>
>>> As this diff file isn't really readeable, I can say that the main file
>>> we modified are:
>>> * arch/arm/mach-at91rm9200/Kconfig
>>> -> here we add support for AT91SAM9261
>>>
>>> * arch/arm/mach-at91rm9200/at91sam9261.c
>>> -> here we add support for TCB0 and modify interrupt priority in the
>>> same way of AT91RM9200
>>>
>>> * arch/arm/mach-at91rm9200/at91sam926x_time.c
>>> -> and here we add the same code that was in
>>> arch/arm/mach-at91rm9200/at91rm9200_time.c. As it is exactly the same
>>> code added as we use the same peripheral, maybe we can add a common
>>> file ( an at91_ipipe_time.c), instead of having duplicated code.
>> Sorry, I did not make myself clear, I would like a difference between
>> the trees, not between the diffs. In other words, the modifications you
>> made.
> 
> Well this differences show the modification we made, but I agree it is
> not really readable.
> 
> Between which tree do you want the diffs ?
> Vanilla kernel +adeos patch  and at91 patched kernel + our patch ?
> With this you'll have a lot of at91 patch in it.
> 
> Maybe we can try to make a diff between
> at91 patched kernel +adeos patch  and at91 patched kernel + our patch ?
> But with this solution we have to made some modification on adeos
> patch for applying it on at91 patched kernel.
> 
> Last solution is to attach the file modified.

Already tried interdiff between to original ipipe patch and your version?

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-11  9:21       ` Gregory CLEMENT
  2007-04-11 11:04         ` Jan Kiszka
@ 2007-04-11 12:15         ` Gilles Chanteperdrix
  2007-04-17 21:42           ` Gilles Chanteperdrix
  1 sibling, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-11 12:15 UTC (permalink / raw)
  To: adeos-main

Gregory CLEMENT wrote:
> Maybe we can try to make a diff between
> at91 patched kernel +adeos patch  and at91 patched kernel + our patch ?
> But with this solution we have to made some modification on adeos
> patch for applying it on at91 patched kernel.
> 
> Last solution is to attach the file modified.

diff between adeos patched kernel + at91 patch and your patched tree.
But nevermind, I will do the diff myself.

-- 
                                                 Gilles Chanteperdrix



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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-10 16:47 [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel Gregory CLEMENT
  2007-04-10 17:15 ` Gilles Chanteperdrix
  2007-04-10 17:20 ` [Xenomai-core] " Gregory CLEMENT
@ 2007-04-12 17:24 ` Jose Pascual
  2007-04-12 17:31   ` Gilles Chanteperdrix
  2 siblings, 1 reply; 27+ messages in thread
From: Jose Pascual @ 2007-04-12 17:24 UTC (permalink / raw)
  To: 'Gregory CLEMENT', adeos-main, 'BOUIN Alexandre'

HI,

I'm working in a at91rm9200 custom board. Can I use this patch for
at91rm9200?
what should I change for at91rm9200?

Could you send your benchmark results? (what mherz are your PLLA working?
and your Master Clock?)?

good job
regards


> -----Mensaje original-----
> De: adeos-main-bounces@domain.hid [mailto:adeos-main-bounces@domain.hid] En
> nombre de Gregory CLEMENT
> Enviado el: martes, 10 de abril de 2007 18:48
> Para: adeos-main@gna.org; BOUIN Alexandre
> Asunto: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
> 
> Hello,
> 
> We port the adeos-ipipe-2.6.19-arm-1.6-05.patch for AT91SAM9261.
> 
> This patch must be applied on vanilla 2.6.19 with at91 patch (
> http://maxim.org.za/AT91RM9200/2.6/2.6.19-at91.patch.gz ) applied for
> supporting AT91SAM9261.
> So first get vanilla kernel, then apply at91 patch then apply our patch
> instead of adeos-ipipe-2.6.19-arm-1.6-05.patch.
> 
> For now it works with Xenomai on AT91SAM9261-EK, if someone is
> intersting we can send the benchmark result.
> As AT91SAM926x are pretty similar of AT91RM9200, there is a some
> duplicate code and some common code.
> In the future it could be also work on all AT91SAM926x, we can test it.
> But before going ahead we would like some comment on this patch.
> 
> The better would be working on 2.6.20 which already have support for
> AT91SAM926x, but we didn't see any arm patch on this kernel nor any
> file modified on git.
> 
> Hope this patch will be usefull.
> 
> PS: Would we post it on xenomai list also?
> 
> --
> Gregory CLEMENT
> Adeneo
> 2, chemin du Ruisseau - BP21
> 69136 Ecully Cedex
> France
> Tel : +33-4 72 18 08 40
> 
> 
> __________ Información de NOD32, revisión 2176 (20070410) __________
> 
> Este mensaje ha sido analizado con  NOD32 antivirus system
> http://www.nod32.com




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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-12 17:24 ` [Adeos-main] " Jose Pascual
@ 2007-04-12 17:31   ` Gilles Chanteperdrix
  2007-04-13  7:55     ` Jose Pascual
  2007-04-13  7:58     ` Jose Pascual
  0 siblings, 2 replies; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-12 17:31 UTC (permalink / raw)
  To: Jose Pascual; +Cc: adeos-main

Jose Pascual wrote:
> HI,
> 
> I'm working in a at91rm9200 custom board. Can I use this patch for
> at91rm9200?
> what should I change for at91rm9200?
> 
> Could you send your benchmark results? (what mherz are your PLLA working?
> and your Master Clock?)?

My bad, I posted this only on Xenomai mailing list and not Adeos list,
but the at91rm9200 is already supported by the latest I-pipe patch for
ARM. It is available as a separate patch for Linux 2.6.15 and already
included in the patch for Linux 2.6.19.

You can download them there:
http://svn.gna.org/svn/xenomai/trunk/ksrc/arch/arm/patches/at91/ipipe-2.6.15-at91-1.5-08.patch
http://download.gna.org/adeos/patches/v2.6/arm/adeos-ipipe-2.6.19-arm-1.6-05.patch

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-12 17:31   ` Gilles Chanteperdrix
@ 2007-04-13  7:55     ` Jose Pascual
  2007-04-13  8:53       ` Gilles Chanteperdrix
  2007-04-20  8:17       ` Gilles Chanteperdrix
  2007-04-13  7:58     ` Jose Pascual
  1 sibling, 2 replies; 27+ messages in thread
From: Jose Pascual @ 2007-04-13  7:55 UTC (permalink / raw)
  To: 'Gilles Chanteperdrix'; +Cc: adeos-main

Hi Gilles,

thank you for your answer,

Could you send your benchmark results? (what mherz are your PLLA working?
and your Master Clock?)?


regards

> -----Mensaje original-----
> De: adeos-main-bounces@domain.hid [mailto:adeos-main-bounces@domain.hid] En
> nombre de Gilles Chanteperdrix
> Enviado el: jueves, 12 de abril de 2007 19:32
> Para: Jose Pascual
> CC: adeos-main@gna.org
> Asunto: Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
> 
> Jose Pascual wrote:
> > HI,
> >
> > I'm working in a at91rm9200 custom board. Can I use this patch for
> > at91rm9200?
> > what should I change for at91rm9200?
> >
> > Could you send your benchmark results? (what mherz are your PLLA
> working?
> > and your Master Clock?)?
> 
> My bad, I posted this only on Xenomai mailing list and not Adeos list,
> but the at91rm9200 is already supported by the latest I-pipe patch for
> ARM. It is available as a separate patch for Linux 2.6.15 and already
> included in the patch for Linux 2.6.19.
> 
> You can download them there:
> http://svn.gna.org/svn/xenomai/trunk/ksrc/arch/arm/patches/at91/ipipe-
> 2.6.15-at91-1.5-08.patch
> http://download.gna.org/adeos/patches/v2.6/arm/adeos-ipipe-2.6.19-arm-
> 1.6-05.patch
> 
> --
>                                                  Gilles Chanteperdrix
> 
> _______________________________________________
> Adeos-main mailing list
> Adeos-main@domain.hid
> https://mail.gna.org/listinfo/adeos-main
> 
> __________ Informacisn de NOD32, revisisn 2184 (20070412) __________
> 
> Este mensaje ha sido analizado con  NOD32 antivirus system
> http://www.nod32.com




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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-12 17:31   ` Gilles Chanteperdrix
  2007-04-13  7:55     ` Jose Pascual
@ 2007-04-13  7:58     ` Jose Pascual
  2007-04-13  8:59       ` Gilles Chanteperdrix
  1 sibling, 1 reply; 27+ messages in thread
From: Jose Pascual @ 2007-04-13  7:58 UTC (permalink / raw)
  To: 'Gilles Chanteperdrix'; +Cc: adeos-main

Hi again Gilles,

Have you thought to make a only patch for at91rm9200 and at91sam9xxx (theses
chips are really quite similar)?

regards

> -----Mensaje original-----
> De: adeos-main-bounces@domain.hid [mailto:adeos-main-bounces@domain.hid] En
> nombre de Gilles Chanteperdrix
> Enviado el: jueves, 12 de abril de 2007 19:32
> Para: Jose Pascual
> CC: adeos-main@gna.org
> Asunto: Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
> 
> Jose Pascual wrote:
> > HI,
> >
> > I'm working in a at91rm9200 custom board. Can I use this patch for
> > at91rm9200?
> > what should I change for at91rm9200?
> >
> > Could you send your benchmark results? (what mherz are your PLLA
> working?
> > and your Master Clock?)?
> 
> My bad, I posted this only on Xenomai mailing list and not Adeos list,
> but the at91rm9200 is already supported by the latest I-pipe patch for
> ARM. It is available as a separate patch for Linux 2.6.15 and already
> included in the patch for Linux 2.6.19.
> 
> You can download them there:
> http://svn.gna.org/svn/xenomai/trunk/ksrc/arch/arm/patches/at91/ipipe-
> 2.6.15-at91-1.5-08.patch
> http://download.gna.org/adeos/patches/v2.6/arm/adeos-ipipe-2.6.19-arm-
> 1.6-05.patch
> 
> --
>                                                  Gilles Chanteperdrix
> 
> _______________________________________________
> Adeos-main mailing list
> Adeos-main@domain.hid
> https://mail.gna.org/listinfo/adeos-main
> 
> __________ Informacisn de NOD32, revisisn 2184 (20070412) __________
> 
> Este mensaje ha sido analizado con  NOD32 antivirus system
> http://www.nod32.com




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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-13  7:55     ` Jose Pascual
@ 2007-04-13  8:53       ` Gilles Chanteperdrix
  2007-04-20  8:17       ` Gilles Chanteperdrix
  1 sibling, 0 replies; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-13  8:53 UTC (permalink / raw)
  To: Jose Pascual; +Cc: adeos-main

Jose Pascual wrote:
> Hi Gilles,
> 
> thank you for your answer,
> 
> Could you send your benchmark results? (what mherz are your PLLA working?
> and your Master Clock?)?

I do not remember the PLLA setting, I know the master clock is set to 46
MHz. The user-space latencies were around 200 us under load, sometimes
even greater than that. I do not remember if I had some debug options
enabled, I will re-run some tests.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-13  7:58     ` Jose Pascual
@ 2007-04-13  8:59       ` Gilles Chanteperdrix
  0 siblings, 0 replies; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-13  8:59 UTC (permalink / raw)
  To: Jose Pascual; +Cc: adeos-main

Jose Pascual wrote:
> Hi again Gilles,
> 
> Have you thought to make a only patch for at91rm9200 and at91sam9xxx (theses
> chips are really quite similar)?

>From a maintenance point of view, having one patch with all platforms
supported gives much less work.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-11 12:15         ` Gilles Chanteperdrix
@ 2007-04-17 21:42           ` Gilles Chanteperdrix
  2007-04-18  9:51             ` Gregory CLEMENT
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-17 21:42 UTC (permalink / raw)
  To: adeos-main

[-- Attachment #1: message body and .signature --]
[-- Type: text/plain, Size: 6745 bytes --]

Gilles Chanteperdrix wrote:
 > Gregory CLEMENT wrote:
 > > Maybe we can try to make a diff between
 > > at91 patched kernel +adeos patch  and at91 patched kernel + our patch ?
 > > But with this solution we have to made some modification on adeos
 > > patch for applying it on at91 patched kernel.
 > > 
 > > Last solution is to attach the file modified.
 > 
 > diff between adeos patched kernel + at91 patch and your patched tree.
 > But nevermind, I will do the diff myself.

Ok. Attached the diff I wanted. A few comments are inlined.


> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig
> --- ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig	2007-04-17 23:04:17.000000000 +0200
> +++ ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig	2007-04-17 23:12:41.000000000 +0200
> @@ -84,24 +84,6 @@ config MACH_KAFA
>  	help
>  	  Select this if you are using Sperry-Sun's KAFA board.
>  
> -config IPIPE_AT91_TC
> -	depends on IPIPE
> -	int "AT91 TC used as time base"
> -	default 0
> -	help
> -	When Adeos interrupt pipeline is enabled, TC0 is used by default
> -	as time base, but you can use TC1 or TC2 by setting this variable to 1
> -	or 2. This should only be needed to avoid conflicts with other drivers.
> -
> -config IPIPE_AT91_MCK
> -	depends on IPIPE
> -	int "AT91 Master clock Frequency"
> -	default 46080000
> -	help
> -	When Adeos interrupt pipeline is enabled, AT91 timer is based on
> -	the AT91 master clock, whose frequency need hence to be known at
> -	compilation time.
> -
>  endif
>  
>  # ----------------------------------------------------------
> @@ -136,6 +118,34 @@ endif
>  
>  # ----------------------------------------------------------
>  
> +if ARCH_AT91SAM9261 || ARCH_AT91RM9200

What is the purpose of this if ? I mean, if the user selected IPIPE and
AT91, he probably wants to see the following settings, if some
combination is not supported, please add an explicit notice instead of
silently hiding the options.


> +
> +comment "Ipipe dependent"
> +
> +config IPIPE_AT91_TC
> +	depends on IPIPE
> +	int "AT91 TC used as time base"
> +	default 0
> +	help
> +	When Adeos interrupt pipeline is enabled, TC0 is used by default
> +	as time base, but you can use TC1 or TC2 by setting this variable to 1
> +	or 2. This should only be needed to avoid conflicts with other drivers.
> +
> +config IPIPE_AT91_MCK
> +	depends on IPIPE
> +	int "AT91 Master clock Frequency"
> +	default 59904000 if MACH_AT91RM9200EK
> +	default 99328000 if MACH_AT91SAM9261EK
> +	default 53000000

Good point. I just need to add a line for CSB637


> +	help
> +	When Adeos interrupt pipeline is enabled, AT91 timer is based on
> +	the AT91 master clock, whose frequency need hence to be known at
> +	compilation time.
> +
> +endif
> (...)
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-17 23:08:38.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-17 23:12:41.000000000 +0200
> @@ -42,9 +42,27 @@
>   * Virtual to Physical Address mapping for IO devices.
>   */
>  #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
> -#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> +
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif

What is this ?


> +
>  #ifdef CONFIG_IPIPE
> -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif
>  #endif /* CONFIG_IPIPE */

To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?


>  
>   /* Internal SRAM is mapped below the IO devices */
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-17 23:04:18.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-17 23:12:41.000000000 +0200
> @@ -44,8 +44,19 @@
>  #if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
>  extern unsigned __ipipe_at91_gpio_banks;
>  
> -#define __ipipe_mach_irq_mux_p(irq) \
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +	#define __ipipe_mach_irq_mux_p(irq) \
>  	((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +	#define __ipipe_mach_irq_mux_p(irq) \
> +		((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +	#define __ipipe_mach_irq_mux_p(irq) \
> +		((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif

Ditto with a common AT91_ID_PIOA here.


> +
>  
>  #endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
>  
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h	2007-04-17 23:09:42.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h	2007-04-17 23:12:41.000000000 +0200
> @@ -23,10 +23,13 @@
>  
>  #include <asm/hardware.h>
>  
> -#ifndef CONFIG_IPIPE
>  #if defined(CONFIG_ARCH_AT91RM9200)
>  
> +#ifndef CONFIG_IPIPE
>  #define CLOCK_TICK_RATE		(AT91_SLOW_CLOCK)
> +#else /* !CONFIG_IPIPE */
> +#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> +#endif /* !CONFIG_IPIPE */
>  
>  #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
>  
> @@ -35,8 +38,4 @@
>  
>  #endif
>  
> -#else /* !CONFIG_IPIPE */
> -#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> -#endif /* !CONFIG_IPIPE */
> -
>  #endif

I think you got CLOCK_TICK_RATE wrong here. It should be
CONFIG_IPIPE_AT91_MCK / 32 as soon as I-pipe is enabled whatever ARCH is
selected. 

-- 


					    Gilles Chanteperdrix.

[-- Attachment #2: ipipe-at91-sam.diff --]
[-- Type: text/plain, Size: 15507 bytes --]

diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig
--- ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig	2007-04-17 23:04:17.000000000 +0200
+++ ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig	2007-04-17 23:12:41.000000000 +0200
@@ -84,24 +84,6 @@ config MACH_KAFA
 	help
 	  Select this if you are using Sperry-Sun's KAFA board.
 
-config IPIPE_AT91_TC
-	depends on IPIPE
-	int "AT91 TC used as time base"
-	default 0
-	help
-	When Adeos interrupt pipeline is enabled, TC0 is used by default
-	as time base, but you can use TC1 or TC2 by setting this variable to 1
-	or 2. This should only be needed to avoid conflicts with other drivers.
-
-config IPIPE_AT91_MCK
-	depends on IPIPE
-	int "AT91 Master clock Frequency"
-	default 46080000
-	help
-	When Adeos interrupt pipeline is enabled, AT91 timer is based on
-	the AT91 master clock, whose frequency need hence to be known at
-	compilation time.
-
 endif
 
 # ----------------------------------------------------------
@@ -136,6 +118,34 @@ endif
 
 # ----------------------------------------------------------
 
+if ARCH_AT91SAM9261 || ARCH_AT91RM9200
+
+comment "Ipipe dependent"
+
+config IPIPE_AT91_TC
+	depends on IPIPE
+	int "AT91 TC used as time base"
+	default 0
+	help
+	When Adeos interrupt pipeline is enabled, TC0 is used by default
+	as time base, but you can use TC1 or TC2 by setting this variable to 1
+	or 2. This should only be needed to avoid conflicts with other drivers.
+
+config IPIPE_AT91_MCK
+	depends on IPIPE
+	int "AT91 Master clock Frequency"
+	default 59904000 if MACH_AT91RM9200EK
+	default 99328000 if MACH_AT91SAM9261EK
+	default 53000000
+	help
+	When Adeos interrupt pipeline is enabled, AT91 timer is based on
+	the AT91 master clock, whose frequency need hence to be known at
+	compilation time.
+
+endif
+
+# ----------------------------------------------------------
+
 comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam9261.c ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam9261.c
--- ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-17 23:04:17.000000000 +0200
+++ ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam9261.c	2007-04-17 23:12:41.000000000 +0200
@@ -27,6 +27,13 @@ static struct map_desc at91sam9261_io_de
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+#ifdef CONFIG_IPIPE
+		.virtual	= AT91_VA_BASE_TCB0,
+		.pfn		= __phys_to_pfn(AT91SAM9261_BASE_TCB0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+        }, {
+#endif /* CONFIG_IPIPE */
 		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
 		.pfn		= __phys_to_pfn(AT91SAM9261_SRAM_BASE),
 		.length		= AT91SAM9261_SRAM_SIZE,
@@ -242,6 +249,7 @@ void __init at91sam9261_initialize(unsig
  * The default interrupt priority levels (0 = lowest, 7 = highest).
  */
 static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+#ifndef CONFIG_IPIPE
 	7,	/* Advanced Interrupt Controller */
 	7,	/* System Peripherals */
 	0,	/* Parallel IO Controller A */
@@ -274,6 +282,42 @@ static unsigned int at91sam9261_default_
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
 	0,	/* Advanced Interrupt Controller */
+#else /* CONFIG_IPIPE */
+/* Give the highest priority to TC, since they are used as timer interrupt by
+   I-pipe. */
+	7,	/* Advanced Interrupt Controller */
+	7,	/* System Peripherals */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C */
+	0,
+	6,	/* USART 0 */
+	6,	/* USART 1 */
+	6,	/* USART 2 */
+	0,	/* Multimedia Card Interface */
+	4,	/* USB Device Port */
+	0,	/* Two-Wire Interface */
+	6,	/* Serial Peripheral Interface 0 */
+	6,	/* Serial Peripheral Interface 1 */
+	5,	/* Serial Synchronous Controller 0 */
+	5,	/* Serial Synchronous Controller 1 */
+	5,	/* Serial Synchronous Controller 2 */
+	7,	/* Timer Counter 0 */
+	7,	/* Timer Counter 1 */
+	7,	/* Timer Counter 2 */
+	3,	/* USB Host port */
+	3,	/* LCD Controller */
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+	0,	/* Advanced Interrupt Controller */
+#endif /*CONFIG_IPIPE */
 };
 
 void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam926x_time.c ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-17 23:04:17.000000000 +0200
+++ ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-04-17 23:12:41.000000000 +0200
@@ -22,10 +22,69 @@
 
 #include <asm/arch/at91_pit.h>
 
+static unsigned long last_crtr;
+
+#ifdef CONFIG_IPIPE
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/at91_tc.h>
+#include "clock.h"
+
+#ifdef CONFIG_NO_IDLE_HZ
+#error "dynamic tick timer not yet supported with IPIPE"
+#endif /* CONFIG_NO_IDLE_HZ */
+
+#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
+#define AT91_TC_REG_MASK (0xffff)
+
+#if (CONFIG_IPIPE_AT91_TC==0)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC0
+#elif (CONFIG_IPIPE_AT91_TC==1)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC1
+#elif (CONFIG_IPIPE_AT91_TC==2)
+#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC2
+#else
+#error IPIPE_AT91_TC must be 0, 1 or 2.
+#endif
+
+static inline unsigned int at91_tc_read(unsigned int reg_offset)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	return readl((void __iomem *)(addr + reg_offset));
+}
+
+static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
+{
+	unsigned long addr =
+		(AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
+
+	writel(value, (void __iomem *)(addr + reg_offset));
+}
+
+#define read_CV() at91_tc_read(AT91_TC_CV)
+#define read_RC() at91_tc_read(AT91_TC_RC)
+#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
+
+int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
+EXPORT_SYMBOL(__ipipe_mach_timerint);
+
+int __ipipe_mach_timerstolen = 0;
+EXPORT_SYMBOL(__ipipe_mach_timerstolen);
+
+unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
+EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
+
+static int at91_timer_initialized;
+#endif /* CONFIG_IPIPE */
 
 #define PIT_CPIV(x)	((x) & AT91_PIT_CPIV)
 #define PIT_PICNT(x)	(((x) & AT91_PIT_PICNT) >> 20)
 
+#ifndef CONFIG_IPIPE
 /*
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
@@ -112,3 +171,209 @@ struct sys_timer at91sam926x_timer = {
 	.resume		= at91sam926x_timer_reset,
 };
 
+#else /* CONFIG_IPIPE */
+
+/*
+ * Returns number of microseconds since last timer interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeofday()
+ *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+*  'tick' is usecs per jiffy (linux/timex.h).
+ */
+static unsigned long at91sam926x_gettimeoffset(void)
+{
+	unsigned long elapsed;
+
+	elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
+
+	return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+void __ipipe_mach_acktimer(void)
+{
+	at91_tc_read(AT91_TC_SR);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
+{
+	/*
+	 * - if Linux is running under ipipe, but it still has the control over
+	 *   the timer (no Xenomai for example), then reprogram the timer (ipipe
+	 *   has already acked it)
+	 * - if some other domain has taken over the timer, then do nothing
+	 *   (ipipe has acked it, and the other domain has reprogramed it)
+	 */
+
+	write_seqlock(&xtime_lock);
+
+	if (__ipipe_mach_timerstolen) {
+		timer_tick();
+		last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+	} else {
+		while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
+			timer_tick();
+			last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
+		}
+		write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
+	}
+
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91sam926x_bad_freq(int irq, void *dev_id)
+{
+	static int ticks = 0;
+
+	if (++ticks != HZ * 120) {
+		if (!console_drivers || try_acquire_console_sem())
+			return at91sam926x_timer_interrupt(irq, dev_id);
+	
+		release_console_sem();
+	}
+
+	panic("AT91 clock rate incorrectly set.\n"
+	      "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
+	      clk_get_rate(clk_get(NULL, "mck")));
+}
+
+notrace unsigned long long __ipipe_mach_get_tsc(void)
+{
+	if (likely(at91_timer_initialized)) {
+		static union {
+#ifdef __BIG_ENDIAN
+			struct {
+				unsigned long high;
+				unsigned short mid;
+				unsigned short low;
+			};
+#else /* __LITTLE_ENDIAN */
+			struct {
+				unsigned short low;
+				unsigned short mid;
+				unsigned long high;
+			};
+#endif /* __LITTLE_ENDIAN */
+			unsigned long long full;
+		} tsc[NR_CPUS], *local_tsc;
+		unsigned long long result;
+		unsigned short stamp;
+		unsigned long flags;
+
+		local_irq_save_hw(flags);
+		local_tsc = &tsc[ipipe_processor_id()];
+		stamp = read_CV();
+		if (unlikely(stamp < local_tsc->low)) {
+			if (unlikely(!++local_tsc->mid))
+				/* 32 bit counter wrapped, increment high word. */
+				local_tsc->high++;
+		}
+		local_tsc->low = stamp;
+		result = local_tsc->full;
+		local_irq_restore_hw(flags);
+
+		return result;
+	}
+	
+        return 0;
+}
+EXPORT_SYMBOL(__ipipe_mach_get_tsc);
+
+/*
+ * Reprogram the timer
+ */
+
+void __ipipe_mach_set_dec(unsigned long delay)
+{
+	unsigned long flags;
+
+	if (delay > 2) {
+		local_irq_save_hw(flags);
+		write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
+		local_irq_restore_hw(flags);
+	} else
+		ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
+}
+EXPORT_SYMBOL(__ipipe_mach_set_dec);
+
+void __ipipe_mach_release_timer(void)
+{
+       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+}
+EXPORT_SYMBOL(__ipipe_mach_release_timer);
+
+unsigned long __ipipe_mach_get_dec(void)
+{
+	return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
+}
+
+static struct irqaction at91sam926x_timer_irq = {
+	.name		= "at91_tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= &at91sam926x_timer_interrupt
+};
+
+static char clk_name [] = "tc%";
+
+static struct clk tc = {
+	.name		= (const char *) clk_name,
+	.users          = 0,
+	.type		= CLK_TYPE_PERIPHERAL,
+	.pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
+};
+
+void __init at91sam926x_timer_init(void)
+{
+	unsigned long v;
+	
+	if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
+		at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
+
+	snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
+	clk_register(&tc);
+	clk_enable(&tc);
+	
+	/* No Sync. */
+	at91_tc_write(AT91_TC_BCR, 0);
+
+	/* program NO signal on XCN */
+	v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+	v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
+	v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
+	writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
+
+	/* Disable the channel */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
+
+	/* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
+	at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
+
+	/* Disable all interrupts. */
+	at91_tc_write(AT91_TC_IDR, ~0ul);
+
+	/* Load the TC register C. */
+	last_crtr = 0;
+	write_RC(LATCH);
+
+	/* Enable CPCS interrupt. */
+	at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
+
+	/* Set up the interrupt. */
+	setup_irq(KERNEL_TIMER_IRQ_NUM, &at91sam926x_timer_irq);
+
+	/* Enable the channel. */
+	at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
+
+	at91_timer_initialized = 1;
+}
+
+struct sys_timer at91sam926x_timer = {
+	.init		= at91sam926x_timer_init,
+	.offset		= at91sam926x_gettimeoffset,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+#endif /* CONFIG_IPIPE */
diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h
--- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-17 23:08:38.000000000 +0200
+++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h	2007-04-17 23:12:41.000000000 +0200
@@ -42,9 +42,27 @@
  * Virtual to Physical Address mapping for IO devices.
  */
 #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
-#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
 #ifdef CONFIG_IPIPE
-#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
+#else
+#error "Unsupported AT91 processor"
+#endif
 #endif /* CONFIG_IPIPE */
 
  /* Internal SRAM is mapped below the IO devices */
diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h
--- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-17 23:04:18.000000000 +0200
+++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h	2007-04-17 23:12:41.000000000 +0200
@@ -44,8 +44,19 @@
 #if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
 extern unsigned __ipipe_at91_gpio_banks;
 
-#define __ipipe_mach_irq_mux_p(irq) \
+#if defined(CONFIG_ARCH_AT91RM9200)
+	#define __ipipe_mach_irq_mux_p(irq) \
 	((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
+#elif defined(CONFIG_ARCH_AT91SAM9261)
+	#define __ipipe_mach_irq_mux_p(irq) \
+		((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
+#else
+#error "Unsupported AT91 processor"
+#endif
+
 
 #endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
 
diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h
--- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h	2007-04-17 23:09:42.000000000 +0200
+++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h	2007-04-17 23:12:41.000000000 +0200
@@ -23,10 +23,13 @@
 
 #include <asm/hardware.h>
 
-#ifndef CONFIG_IPIPE
 #if defined(CONFIG_ARCH_AT91RM9200)
 
+#ifndef CONFIG_IPIPE
 #define CLOCK_TICK_RATE		(AT91_SLOW_CLOCK)
+#else /* !CONFIG_IPIPE */
+#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
+#endif /* !CONFIG_IPIPE */
 
 #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
 
@@ -35,8 +38,4 @@
 
 #endif
 
-#else /* !CONFIG_IPIPE */
-#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
-#endif /* !CONFIG_IPIPE */
-
 #endif

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-17 21:42           ` Gilles Chanteperdrix
@ 2007-04-18  9:51             ` Gregory CLEMENT
  2007-04-18 19:50               ` Gilles Chanteperdrix
  0 siblings, 1 reply; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-18  9:51 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: adeos-main

2007/4/17, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> Gilles Chanteperdrix wrote:
>  > Gregory CLEMENT wrote:
>  > > Maybe we can try to make a diff between
>  > > at91 patched kernel +adeos patch  and at91 patched kernel + our patch ?
>  > > But with this solution we have to made some modification on adeos
>  > > patch for applying it on at91 patched kernel.
>  > >
>  > > Last solution is to attach the file modified.
>  >
>  > diff between adeos patched kernel + at91 patch and your patched tree.
>  > But nevermind, I will do the diff myself.
>
> Ok. Attached the diff I wanted. A few comments are inlined.

My answer are following.

>
>
> > diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig
> > --- ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig   2007-04-17 23:04:17.000000000 +0200
> > +++ ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig   2007-04-17 23:12:41.000000000 +0200
> > @@ -84,24 +84,6 @@ config MACH_KAFA
> >       help
> >         Select this if you are using Sperry-Sun's KAFA board.
> >
> > -config IPIPE_AT91_TC
> > -     depends on IPIPE
> > -     int "AT91 TC used as time base"
> > -     default 0
> > -     help
> > -     When Adeos interrupt pipeline is enabled, TC0 is used by default
> > -     as time base, but you can use TC1 or TC2 by setting this variable to 1
> > -     or 2. This should only be needed to avoid conflicts with other drivers.
> > -
> > -config IPIPE_AT91_MCK
> > -     depends on IPIPE
> > -     int "AT91 Master clock Frequency"
> > -     default 46080000
> > -     help
> > -     When Adeos interrupt pipeline is enabled, AT91 timer is based on
> > -     the AT91 master clock, whose frequency need hence to be known at
> > -     compilation time.
> > -
> >  endif
> >
> >  # ----------------------------------------------------------
> > @@ -136,6 +118,34 @@ endif
> >
> >  # ----------------------------------------------------------
> >
> > +if ARCH_AT91SAM9261 || ARCH_AT91RM9200
>
> What is the purpose of this if ? I mean, if the user selected IPIPE and
> AT91, he probably wants to see the following settings, if some
> combination is not supported, please add an explicit notice instead of
> silently hiding the options.

Ok, first we'll add some comment.
Then we will test it on AT91SAM9260 as it should work without change.
(...)
> > --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h 2007-04-17 23:08:38.000000000 +0200
> > +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h 2007-04-17 23:12:41.000000000 +0200
> > @@ -42,9 +42,27 @@
> >   * Virtual to Physical Address mapping for IO devices.
> >   */
> >  #define AT91_VA_BASE_SYS     AT91_IO_P2V(AT91_BASE_SYS)
> > -#define AT91_VA_BASE_EMAC    AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> > +
> > +#if defined(CONFIG_ARCH_AT91RM9200)
> > +     #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> > +#elif defined(CONFIG_ARCH_AT91SAM9260)
> > +     #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
> > +#elif defined(CONFIG_ARCH_AT91SAM9261)
> > +     #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
> > +#else
> > +#error "Unsupported AT91 processor"
> > +#endif
>
> What is this ?

First it has nothing to do with adeos.
Then the use of AT91_VA_BASE_EMAC misunderstood, and there is no point
to do this. You can remove this.

>
>
> > +
> >  #ifdef CONFIG_IPIPE
> > -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> > +#if defined(CONFIG_ARCH_AT91RM9200)
> > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> > +#elif defined(CONFIG_ARCH_AT91SAM9260)
> > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
> > +#elif defined(CONFIG_ARCH_AT91SAM9261)
> > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
> > +#else
> > +#error "Unsupported AT91 processor"
> > +#endif
> >  #endif /* CONFIG_IPIPE */
>
> To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?

Sure it would be better, but unfortunately the mainteners of AT91
choose to produce a define per architecture even if the register are
the same.
We keep this line :
#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
and it will work I don't like having an AT91RM9200 define for chip
which are not AT91RM9200. It adds confusion.

We also could define AT91_BASE_TCB0 as you suggest, but it mean we add
a new register definition just for ipipe and it adds a little
confusion also.

Choose the solution you prefer, or an other if you have a better idea.



>
> >
> >   /* Internal SRAM is mapped below the IO devices */
> > diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h
> > --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h     2007-04-17 23:04:18.000000000 +0200
> > +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h     2007-04-17 23:12:41.000000000 +0200
> > @@ -44,8 +44,19 @@
> >  #if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
> >  extern unsigned __ipipe_at91_gpio_banks;
> >
> > -#define __ipipe_mach_irq_mux_p(irq) \
> > +#if defined(CONFIG_ARCH_AT91RM9200)
> > +     #define __ipipe_mach_irq_mux_p(irq) \
> >       ((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
> > +#elif defined(CONFIG_ARCH_AT91SAM9260)
> > +     #define __ipipe_mach_irq_mux_p(irq) \
> > +             ((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
> > +#elif defined(CONFIG_ARCH_AT91SAM9261)
> > +     #define __ipipe_mach_irq_mux_p(irq) \
> > +             ((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
> > +#else
> > +#error "Unsupported AT91 processor"
> > +#endif
>
> Ditto with a common AT91_ID_PIOA here.
>

See before.

(...)
2007-04-17 23:12:41.000000000 +0200
> > @@ -23,10 +23,13 @@
> >
> >  #include <asm/hardware.h>
> >
> > -#ifndef CONFIG_IPIPE
> >  #if defined(CONFIG_ARCH_AT91RM9200)
> >
> > +#ifndef CONFIG_IPIPE
> >  #define CLOCK_TICK_RATE              (AT91_SLOW_CLOCK)
> > +#else /* !CONFIG_IPIPE */
> > +#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> > +#endif /* !CONFIG_IPIPE */
> >
> >  #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
> >
> > @@ -35,8 +38,4 @@
> >
> >  #endif
> >
> > -#else /* !CONFIG_IPIPE */
> > -#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> > -#endif /* !CONFIG_IPIPE */
> > -
> >  #endif
>
> I think you got CLOCK_TICK_RATE wrong here. It should be
> CONFIG_IPIPE_AT91_MCK / 32 as soon as I-pipe is enabled whatever ARCH is
> selected.

Right, we will change this.

>
> --
>
>
>                                             Gilles Chanteperdrix.
>
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig
> --- ipipe-2.6-at91/arch/arm/mach-at91rm9200/Kconfig     2007-04-17 23:04:17.000000000 +0200
> +++ ipipe-at91-sam/arch/arm/mach-at91rm9200/Kconfig     2007-04-17 23:12:41.000000000 +0200
> @@ -84,24 +84,6 @@ config MACH_KAFA
>         help
>           Select this if you are using Sperry-Sun's KAFA board.
>
> -config IPIPE_AT91_TC
> -       depends on IPIPE
> -       int "AT91 TC used as time base"
> -       default 0
> -       help
> -       When Adeos interrupt pipeline is enabled, TC0 is used by default
> -       as time base, but you can use TC1 or TC2 by setting this variable to 1
> -       or 2. This should only be needed to avoid conflicts with other drivers.
> -
> -config IPIPE_AT91_MCK
> -       depends on IPIPE
> -       int "AT91 Master clock Frequency"
> -       default 46080000
> -       help
> -       When Adeos interrupt pipeline is enabled, AT91 timer is based on
> -       the AT91 master clock, whose frequency need hence to be known at
> -       compilation time.
> -
>  endif
>
>  # ----------------------------------------------------------
> @@ -136,6 +118,34 @@ endif
>
>  # ----------------------------------------------------------
>
> +if ARCH_AT91SAM9261 || ARCH_AT91RM9200
> +
> +comment "Ipipe dependent"
> +
> +config IPIPE_AT91_TC
> +       depends on IPIPE
> +       int "AT91 TC used as time base"
> +       default 0
> +       help
> +       When Adeos interrupt pipeline is enabled, TC0 is used by default
> +       as time base, but you can use TC1 or TC2 by setting this variable to 1
> +       or 2. This should only be needed to avoid conflicts with other drivers.
> +
> +config IPIPE_AT91_MCK
> +       depends on IPIPE
> +       int "AT91 Master clock Frequency"
> +       default 59904000 if MACH_AT91RM9200EK
> +       default 99328000 if MACH_AT91SAM9261EK
> +       default 53000000
> +       help
> +       When Adeos interrupt pipeline is enabled, AT91 timer is based on
> +       the AT91 master clock, whose frequency need hence to be known at
> +       compilation time.
> +
> +endif
> +
> +# ----------------------------------------------------------
> +
>  comment "AT91 Board Options"
>
>  config MTD_AT91_DATAFLASH_CARD
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam9261.c ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam9261.c
> --- ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam9261.c       2007-04-17 23:04:17.000000000 +0200
> +++ ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sa> m9261.c       2007-04-17 23:12:41.000000000 +0200
> @@ -27,6 +27,13 @@ static struct map_desc at91sam9261_io_de
>                 .length         = SZ_16K,
>                 .type           = MT_DEVICE,
>         }, {
> +#ifdef CONFIG_IPIPE
> +               .virtual        = AT91_VA_BASE_TCB0,
> +               .pfn            = __phys_to_pfn(AT91SAM9261_BASE_TCB0),
> +               .length         = SZ_16K,
> +               .type           = MT_DEVICE,
> +        }, {
> +#endif /* CONFIG_IPIPE */
>                 .virtual        = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
>                 .pfn            = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
>                 .length         = AT91SAM9261_SRAM_SIZE,
> @@ -242,6 +249,7 @@ void __init at91sam9261_initialize(unsig
>   * The default interrupt priority levels (0 = lowest, 7 = highest).
>   */
>  static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
> +#ifndef CONFIG_IPIPE
>         7,      /* Advanced Interrupt Controller */
>         7,      /* System Peripherals */
>         0,      /* Parallel IO Controller A */
> @@ -274,6 +282,42 @@ static unsigned int at91sam9261_default_
>         0,      /* Advanced Interrupt Controller */
>         0,      /* Advanced Interrupt Controller */
>         0,      /* Advanced Interrupt Controller */
> +#else /* CONFIG_IPIPE */
> +/* Give the highest priority to TC, since they are used as timer interrupt by
> +   I-pipe. */
> +       7,      /* Advanced Interrupt Controller */
> +       7,      /* System Peripherals */
> +       0,      /* Parallel IO Controller A */
> +       0,      /* Parallel IO Controller B */
> +       0,      /* Parallel IO Controller C */
> +       0,
> +       6,      /* USART 0 */
> +       6,      /* USART 1 */
> +       6,      /* USART 2 */
> +       0,      /* Multimedia Card Interface */
> +       4,      /* USB Device Port */
> +       0,      /* Two-Wire Interface */
> +       6,      /* Serial Peripheral Interface 0 */
> +       6,      /* Serial Peripheral Interface 1 */
> +       5,      /* Serial Synchronous Controller 0 */
> +       5,      /* Serial Synchronous Controller 1 */
> +       5,      /* Serial Synchronous Controller 2 */
> +       7,      /* Timer Counter 0 */
> +       7,      /* Timer Counter 1 */
> +       7,      /* Timer Counter 2 */
> +       3,      /* USB Host port */
> +       3,      /* LCD Controller */
> +       0,
> +       0,
> +       0,
> +       0,
> +       0,
> +       0,
> +       0,
> +       0,      /* Advanced Interrupt Controller */
> +       0,      /* Advanced Interrupt Controller */
> +       0,      /* Advanced Interrupt Controller */
> +#endif /*CONFIG_IPIPE */
>  };
>
>  void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam926x_time.c ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam926x_time.c
> --- ipipe-2.6-at91/arch/arm/mach-at91rm9200/at91sam926x_time.c  2007-04-17 23:04:17.000000000 +0200
> +++ ipipe-at91-sam/arch/arm/mach-at91rm9200/at91sam926x_time.c  2007-04-17 23:12:41.000000000 +0200
> @@ -22,10 +22,69 @@
>
>  #include <asm/arch/at91_pit.h>
>
> +static unsigned long last_crtr;
> +
> +#ifdef CONFIG_IPIPE
> +#include <linux/clk.h>
> +#include <linux/console.h>
> +#include <linux/module.h>
> +#include <asm/arch/at91sam9261.h>
> +#include <asm/arch/at91_tc.h>
> +#include "clock.h"
> +
> +#ifdef CONFIG_NO_IDLE_HZ
> +#error "dynamic tick timer not yet supported with IPIPE"
> +#endif /* CONFIG_NO_IDLE_HZ */
> +
> +#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
> +#define AT91_TC_REG_MASK (0xffff)
> +
> +#if (CONFIG_IPIPE_AT91_TC==0)
> +#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC0
> +#elif (CONFIG_IPIPE_AT91_TC==1)
> +#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC1
> +#elif (CONFIG_IPIPE_AT91_TC==2)
> +#   define KERNEL_TIMER_IRQ_NUM AT91SAM9261_ID_TC2
> +#else
> +#error IPIPE_AT91_TC must be 0, 1 or 2.
> +#endif
> +
> +static inline unsigned int at91_tc_read(unsigned int reg_offset)
> +{
> +       unsigned long addr =
> +               (AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
> +
> +       return readl((void __iomem *)(addr + reg_offset));
> +}
> +
> +static inline void at91_tc_write(unsigned int reg_offset, unsigned long value)
> +{
> +       unsigned long addr =
> +               (AT91_VA_BASE_TCB0 + 0x40 * CONFIG_IPIPE_AT91_TC);
> +
> +       writel(value, (void __iomem *)(addr + reg_offset));
> +}
> +
> +#define read_CV() at91_tc_read(AT91_TC_CV)
> +#define read_RC() at91_tc_read(AT91_TC_RC)
> +#define write_RC(value) at91_tc_write(AT91_TC_RC, value)
> +
> +int __ipipe_mach_timerint = KERNEL_TIMER_IRQ_NUM;
> +EXPORT_SYMBOL(__ipipe_mach_timerint);
> +
> +int __ipipe_mach_timerstolen = 0;
> +EXPORT_SYMBOL(__ipipe_mach_timerstolen);
> +
> +unsigned int __ipipe_mach_ticks_per_jiffy = LATCH;
> +EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
> +
> +static int at91_timer_initialized;
> +#endif /* CONFIG_IPIPE */
>
>  #define PIT_CPIV(x)    ((x) & AT91_PIT_CPIV)
>  #define PIT_PICNT(x)   (((x) & AT91_PIT_PICNT) >> 20)
>
> +#ifndef CONFIG_IPIPE
>  /*
>   * Returns number of microseconds since last timer interrupt.  Note that interrupts
>   * will have been disabled by do_gettimeofday()
> @@ -112,3 +171,209 @@ struct sys_timer at91sam926x_timer = {
>         .resume         = at91sam926x_timer_reset,
>  };
>
> +#else /* CONFIG_IPIPE */
> +
> +/*
> + * Returns number of microseconds since last timer interrupt.  Note that interrupts
> + * will have been disabled by do_gettimeofday()
> + *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
> +*  'tick' is usecs per jiffy (linux/timex.h).
> + */
> +static unsigned long at91sam926x_gettimeoffset(void)
> +{
> +       unsigned long elapsed;
> +
> +       elapsed = (read_CV() - last_crtr) & AT91_TC_REG_MASK;
> +
> +       return (unsigned long) (elapsed * (tick_nsec / 1000)) / LATCH;
> +}
> +
> +void __ipipe_mach_acktimer(void)
> +{
> +       at91_tc_read(AT91_TC_SR);
> +}
> +
> +/*
> + * IRQ handler for the timer.
> + */
> +static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
> +{
> +       /*
> +        * - if Linux is running under ipipe, but it still has the control over
> +        *   the timer (no Xenomai for example), then reprogram the timer (ipipe
> +        *   has already acked it)
> +        * - if some other domain has taken over the timer, then do nothing
> +        *   (ipipe has acked it, and the other domain has reprogramed it)
> +        */
> +
> +       write_seqlock(&xtime_lock);
> +
> +       if (__ipipe_mach_timerstolen) {
> +               timer_tick();
> +               last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
> +       } else {
> +               while (((read_CV() - last_crtr) & AT91_TC_REG_MASK) >= LATCH) {
> +                       timer_tick();
> +                       last_crtr = (last_crtr + LATCH) & AT91_TC_REG_MASK;
> +               }
> +               write_RC((last_crtr + LATCH) & AT91_TC_REG_MASK);
> +       }
> +
> +       write_sequnlock(&xtime_lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t at91sam926x_bad_freq(int irq, void *dev_id)
> +{
> +       static int ticks = 0;
> +
> +       if (++ticks != HZ * 120) {
> +               if (!console_drivers || try_acquire_console_sem())
> +                       return at91sam926x_timer_interrupt(irq, dev_id);
> +
> +               release_console_sem();
> +       }
> +
> +       panic("AT91 clock rate incorrectly set.\n"
> +             "Please recompile with IPIPE_AT91_MCK set to %lu Hz.",
> +             clk_get_rate(clk_get(NULL, "mck")));
> +}
> +
> +notrace unsigned long long __ipipe_mach_get_tsc(void)
> +{
> +       if (likely(at91_timer_initialized)) {
> +               static union {
> +#ifdef __BIG_ENDIAN
> +                       struct {
> +                               unsigned long high;
> +                               unsigned short mid;
> +                               unsigned short low;
> +                       };
> +#else /* __LITTLE_ENDIAN */
> +                       struct {
> +                               unsigned short low;
> +                               unsigned short mid;
> +                               unsigned long high;
> +                       };
> +#endif /* __LITTLE_ENDIAN */
> +                       unsigned long long full;
> +               } tsc[NR_CPUS], *local_tsc;
> +               unsigned long long result;
> +               unsigned short stamp;
> +               unsigned long flags;
> +
> +               local_irq_save_hw(flags);
> +               local_tsc = &tsc[ipipe_processor_id()];
> +               stamp = read_CV();
> +               if (unlikely(stamp < local_tsc->low)) {
> +                       if (unlikely(!++local_tsc->mid))
> +                               /* 32 bit counter wrapped, increment high word. */
> +                               local_tsc->high++;
> +               }
> +               local_tsc->low = stamp;
> +               result = local_tsc->full;
> +               local_irq_restore_hw(flags);
> +
> +               return result;
> +       }
> +
> +        return 0;
> +}
> +EXPORT_SYMBOL(__ipipe_mach_get_tsc);
> +
> +/*
> + * Reprogram the timer
> + */
> +
> +void __ipipe_mach_set_dec(unsigned long delay)
> +{
> +       unsigned long flags;
> +
> +       if (delay > 2) {
> +               local_irq_save_hw(flags);
> +               write_RC((read_CV() + delay) & AT91_TC_REG_MASK);
> +               local_irq_restore_hw(flags);
> +       } else
> +               ipipe_trigger_irq(KERNEL_TIMER_IRQ_NUM);
> +}
> +EXPORT_SYMBOL(__ipipe_mach_set_dec);
> +
> +void __ipipe_mach_release_timer(void)
> +{
> +       __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
> +}
> +EXPORT_SYMBOL(__ipipe_mach_release_timer);
> +
> +unsigned long __ipipe_mach_get_dec(void)
> +{
> +       return (read_RC() - read_CV()) & AT91_TC_REG_MASK;
> +}
> +
> +static struct irqaction at91sam926x_timer_irq = {
> +       .name           = "at91_tick",
> +       .flags          = IRQF_DISABLED | IRQF_TIMER,
> +       .handler        = &at91sam926x_timer_interrupt
> +};
> +
> +static char clk_name [] = "tc%";
> +
> +static struct clk tc = {
> +       .name           = (const char *) clk_name,
> +       .users          = 0,
> +       .type           = CLK_TYPE_PERIPHERAL,
> +       .pmc_mask       = 1 << (KERNEL_TIMER_IRQ_NUM),
> +};
> +
> +void __init at91sam926x_timer_init(void)
> +{
> +       unsigned long v;
> +
> +       if (clk_get_rate(clk_get(NULL, "mck")) != CONFIG_IPIPE_AT91_MCK)
> +               at91sam926x_timer_irq.handler = &at91sam926x_bad_freq;
> +
> +       snprintf(clk_name, sizeof(clk_name), "tc%d", CONFIG_IPIPE_AT91_TC);
> +       clk_register(&tc);
> +       clk_enable(&tc);
> +
> +       /* No Sync. */
> +       at91_tc_write(AT91_TC_BCR, 0);
> +
> +       /* program NO signal on XCN */
> +       v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
> +       v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3);
> +       v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */
> +       writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR));
> +
> +       /* Disable the channel */
> +       at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS);
> +
> +       /* Select TIMER_CLOCK3 (MCLK/32) as input frequency for TC. */
> +       at91_tc_write(AT91_TC_CMR, AT91_TC_TIMER_CLOCK3);
> +
> +       /* Disable all interrupts. */
> +       at91_tc_write(AT91_TC_IDR, ~0ul);
> +
> +       /* Load the TC register C. */
> +       last_crtr = 0;
> +       write_RC(LATCH);
> +
> +       /* Enable CPCS interrupt. */
> +       at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
> +
> +       /* Set up the interrupt. */
> +       setup_irq(KERNEL_TIMER_IRQ_NUM, &at91sam926x_timer_irq);
> +
> +       /* Enable the channel. */
> +       at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG);
> +
> +       at91_timer_initialized = 1;
> +}
> +
> +struct sys_timer at91sam926x_timer = {
> +       .init           = at91sam926x_timer_init,
> +       .offset         = at91sam926x_gettimeoffset,
> +       .suspend        = NULL,
> +       .resume         = NULL,
> +};
> +#endif /* CONFIG_IPIPE */
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/hardware.h   2007-04-17 23:08:38.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/hardware.h   2007-04-17 23:12:41.000000000 +0200
> @@ -42,9 +42,27 @@
>   * Virtual to Physical Address mapping for IO devices.
>   */
>  #define AT91_VA_BASE_SYS       AT91_IO_P2V(AT91_BASE_SYS)
> -#define AT91_VA_BASE_EMAC      AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> +
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91RM9200_BASE_EMAC)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9260_BASE_EMAC)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +       #define AT91_VA_BASE_EMAC       AT91_IO_P2V(AT91SAM9261_BASE_EMAC)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif
> +
>  #ifdef CONFIG_IPIPE
> -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +       #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +       #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +       #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif
>  #endif /* CONFIG_IPIPE */
>
>   /* Internal SRAM is mapped below the IO devices */
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/irqs.h       2007-04-17 23:04:18.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/irqs.h       2007-04-17 23:12:41.000000000 +0200
> @@ -44,8 +44,19 @@
>  #if defined(CONFIG_IPIPE) && !defined(__ASSEMBLY__)
>  extern unsigned __ipipe_at91_gpio_banks;
>
> -#define __ipipe_mach_irq_mux_p(irq) \
> +#if defined(CONFIG_ARCH_AT91RM9200)
> +       #define __ipipe_mach_irq_mux_p(irq) \
>         ((unsigned) (irq - AT91RM9200_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#elif defined(CONFIG_ARCH_AT91SAM9260)
> +       #define __ipipe_mach_irq_mux_p(irq) \
> +               ((unsigned) (irq - AT91SAM9260_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#elif defined(CONFIG_ARCH_AT91SAM9261)
> +       #define __ipipe_mach_irq_mux_p(irq) \
> +               ((unsigned) (irq - AT91SAM9261_ID_PIOA) < __ipipe_at91_gpio_banks)
> +#else
> +#error "Unsupported AT91 processor"
> +#endif
> +
>
>  #endif /* CONFIG_IPIPE && !__ASSEMBLY__ */
>
> diff -b -x '.git*' -x '*.orig' -x '*.rej' -x '*~' -Naurdp ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h
> --- ipipe-2.6-at91/include/asm-arm/arch-at91rm9200/timex.h      2007-04-17 23:09:42.000000000 +0200
> +++ ipipe-at91-sam/include/asm-arm/arch-at91rm9200/timex.h      2007-04-17 23:12:41.000000000 +0200
> @@ -23,10 +23,13 @@
>
>  #include <asm/hardware.h>
>
> -#ifndef CONFIG_IPIPE
>  #if defined(CONFIG_ARCH_AT91RM9200)
>
> +#ifndef CONFIG_IPIPE
>  #define CLOCK_TICK_RATE                (AT91_SLOW_CLOCK)
> +#else /* !CONFIG_IPIPE */
> +#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> +#endif /* !CONFIG_IPIPE */
>
>  #elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261)
>
> @@ -35,8 +38,4 @@
>
>  #endif
>
> -#else /* !CONFIG_IPIPE */
> -#define CLOCK_TICK_RATE         (CONFIG_IPIPE_AT91_MCK / 32)
> -#endif /* !CONFIG_IPIPE */
> -
>  #endif
>
> _______________________________________________
> Adeos-main mailing list
> Adeos-main@domain.hid
> https://mail.gna.org/listinfo/adeos-main
>
>


-- 
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-18  9:51             ` Gregory CLEMENT
@ 2007-04-18 19:50               ` Gilles Chanteperdrix
  2007-04-18 20:55                 ` Gilles Chanteperdrix
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-18 19:50 UTC (permalink / raw)
  To: gclement; +Cc: adeos-main

Gregory CLEMENT wrote:
 > > >  #ifdef CONFIG_IPIPE
 > > > -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 > > > +#if defined(CONFIG_ARCH_AT91RM9200)
 > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 > > > +#elif defined(CONFIG_ARCH_AT91SAM9260)
 > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
 > > > +#elif defined(CONFIG_ARCH_AT91SAM9261)
 > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
 > > > +#else
 > > > +#error "Unsupported AT91 processor"
 > > > +#endif
 > > >  #endif /* CONFIG_IPIPE */
 > >
 > > To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?
 > 
 > Sure it would be better, but unfortunately the mainteners of AT91
 > choose to produce a define per architecture even if the register are
 > the same.

As far as I know, the AT91RM9200_BASE_TCB0 define is provided by the
I-pipe patch, so we may name it how we want.


 > We keep this line :
 > #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 > and it will work I don't like having an AT91RM9200 define for chip
 > which are not AT91RM9200. It adds confusion.
 > 
 > We also could define AT91_BASE_TCB0 as you suggest, but it mean we add
 > a new register definition just for ipipe and it adds a little
 > confusion also.
 > 
 > Choose the solution you prefer, or an other if you have a better idea.

I do not have a better idea, but I understood why the defines are
different: the CONFIG_ARCH_AT91RM9200, CONFIG_ARCH_AT91SAM9260 and
CONFIG_ARCH_AT91SAM9261 are not mutually exclusive, it is possible to
build a kernel that works for the three machines. So, this code can not
remain as is. Please, at least, forbid in Kconfig selecting several
machines when IPIPE is enabled.

-- 


					    Gilles Chanteperdrix.


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-18 19:50               ` Gilles Chanteperdrix
@ 2007-04-18 20:55                 ` Gilles Chanteperdrix
  2007-04-20  8:32                   ` Gregory CLEMENT
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-18 20:55 UTC (permalink / raw)
  To: gclement, adeos-main

Gilles Chanteperdrix wrote:
 > Gregory CLEMENT wrote:
 >  > > >  #ifdef CONFIG_IPIPE
 >  > > > -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 >  > > > +#if defined(CONFIG_ARCH_AT91RM9200)
 >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9260)
 >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
 >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9261)
 >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
 >  > > > +#else
 >  > > > +#error "Unsupported AT91 processor"
 >  > > > +#endif
 >  > > >  #endif /* CONFIG_IPIPE */
 >  > >
 >  > > To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?
 >  > 
 >  > Sure it would be better, but unfortunately the mainteners of AT91
 >  > choose to produce a define per architecture even if the register are
 >  > the same.
 > 
 > As far as I know, the AT91RM9200_BASE_TCB0 define is provided by the
 > I-pipe patch, so we may name it how we want.

No, it is not provided by the I-pipe patch.

 > 
 > 
 >  > We keep this line :
 >  > #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
 >  > and it will work I don't like having an AT91RM9200 define for chip
 >  > which are not AT91RM9200. It adds confusion.
 >  > 
 >  > We also could define AT91_BASE_TCB0 as you suggest, but it mean we add
 >  > a new register definition just for ipipe and it adds a little
 >  > confusion also.
 >  > 
 >  > Choose the solution you prefer, or an other if you have a better idea.
 > 
 > I do not have a better idea, but I understood why the defines are
 > different: the CONFIG_ARCH_AT91RM9200, CONFIG_ARCH_AT91SAM9260 and
 > CONFIG_ARCH_AT91SAM9261 are not mutually exclusive, it is possible to
 > build a kernel that works for the three machines. So, this code can not
 > remain as is. Please, at least, forbid in Kconfig selecting several
 > machines when IPIPE is enabled.

On 2.6.20, the options ARE mutually exclusive.

-- 


					    Gilles Chanteperdrix.


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-13  7:55     ` Jose Pascual
  2007-04-13  8:53       ` Gilles Chanteperdrix
@ 2007-04-20  8:17       ` Gilles Chanteperdrix
       [not found]         ` <00e801c78328$d2569a90$7703cfb0$@com>
  1 sibling, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-20  8:17 UTC (permalink / raw)
  To: Jose Pascual; +Cc: adeos-main

Jose Pascual wrote:
 > Hi Gilles,
 > 
 > thank you for your answer,
 > 
 > Could you send your benchmark results? (what mherz are your PLLA working?
 > and your Master Clock?)?

The clock settings of the CSB637 board I am using, displayed by the
kernel are:
Clocks: CPU 184 MHz, master 46 MHz, main 3.686 MHz

Running a 2.6.20 I-pipe kernel, setting the nucleus latency
(/proc/xenomai/latency) to 70us, I get a worst case latency of 175 us
over 8 hours, under dd if=/dev/zero of=/dev/null load.

Here are the latency histogram results.
---|--param|----range-|--samples
HSD|    min|  10 - 11 |       22
HSD|    min|  11 - 12 |      746
HSD|    min|  12 - 13 |      397
HSD|    min|  13 - 14 |      206
HSD|    min|  15 - 16 |        1
HSD|    min|  20 - 21 |       31
HSD|    min|  21 - 22 |     3524
HSD|    min|  22 - 23 |    18810
HSD|    min|  23 - 24 |     3496
HSD|    min|  24 - 25 |     1135
HSD|    min|  25 - 26 |      429
HSD|    min|  26 - 27 |        1
HSD|    min|  74 - 75 |        1
---|--param|----range-|--samples
HSD|    avg|  10 - 11 |       22
HSD|    avg|  11 - 12 |      746
HSD|    avg|  12 - 13 |      397
HSD|    avg|  13 - 14 |      206
HSD|    avg|  15 - 16 |        1
HSD|    avg|  17 - 18 |        2
HSD|    avg|  18 - 19 |      137
HSD|    avg|  19 - 20 |      116
HSD|    avg|  20 - 21 |       74
HSD|    avg|  21 - 22 |     3525
HSD|    avg|  22 - 23 |    18907
HSD|    avg|  23 - 24 |     4070
HSD|    avg|  24 - 25 |     1686
HSD|    avg|  25 - 26 |     1195
HSD|    avg|  26 - 27 |      326
HSD|    avg|  27 - 28 |      971
HSD|    avg|  28 - 29 |     7377
HSD|    avg|  29 - 30 |    17482
HSD|    avg|  30 - 31 |     1602
HSD|    avg|  31 - 32 |      561
HSD|    avg|  32 - 33 |      261
HSD|    avg|  33 - 34 |      263
HSD|    avg|  34 - 35 |      271
HSD|    avg|  35 - 36 |      115
HSD|    avg|  36 - 37 |       29
HSD|    avg|  55 - 56 |       64
HSD|    avg|  56 - 57 |     1047
HSD|    avg|  57 - 58 |      222
HSD|    avg|  58 - 59 |       37
HSD|    avg|  59 - 60 |        1
HSD|    avg|  63 - 64 |        1
HSD|    avg|  70 - 71 |       10
HSD|    avg|  71 - 72 |      584
HSD|    avg|  72 - 73 |     9495
HSD|    avg|  73 - 74 |    18874
HSD|    avg|  74 - 75 |   122506
HSD|    avg|  75 - 76 |   687030
HSD|    avg|  76 - 77 |   685654
HSD|    avg|  77 - 78 |  1235930
HSD|    avg|  78 - 79 |    97036
HSD|    avg|  79 - 80 |    33766
HSD|    avg|  80 - 81 |     2983
HSD|    avg|  81 - 82 |      496
HSD|    avg|  88 - 89 |        3
HSD|    avg|  89 - 90 |        2
HSD|    avg|  90 - 91 |        9
HSD|    avg|  91 - 92 |       16
HSD|    avg|  92 - 93 |       29
HSD|    avg|  93 - 94 |      144
HSD|    avg|  94 - 95 |      167
HSD|    avg|  95 - 96 |      681
HSD|    avg|  96 - 97 |      906
HSD|    avg|  97 - 98 |    11302
HSD|    avg|  98 - 99 |    13198
HSD|    avg|  99 -100 |    14670
HSD|    avg| 100 -101 |    26229
HSD|    avg| 101 -102 |     7286
HSD|    avg| 102 -103 |    27906
HSD|    avg| 103 -104 |   173187
HSD|    avg| 104 -105 |  1694570
HSD|    avg| 105 -106 |   830944
HSD|    avg| 106 -107 |   613763
HSD|    avg| 107 -108 |    81959
HSD|    avg| 108 -109 |    41967
HSD|    avg| 109 -110 |    45206
HSD|    avg| 110 -111 |    45041
HSD|    avg| 111 -112 |  3748510
HSD|    avg| 112 -113 | 10275799
HSD|    avg| 113 -114 | 21326133
HSD|    avg| 114 -115 |  5278953
HSD|    avg| 115 -116 |  6019472
HSD|    avg| 116 -117 |  1740063
HSD|    avg| 117 -118 |  1281249
HSD|    avg| 118 -119 |   829744
HSD|    avg| 119 -120 |    30357
HSD|    avg| 120 -121 |     3123
HSD|    avg| 121 -122 |      465
HSD|    avg| 122 -123 |     1906
HSD|    avg| 123 -124 |     2173
HSD|    avg| 124 -125 |     3728
HSD|    avg| 125 -126 |     8888
HSD|    avg| 126 -127 |    25723
HSD|    avg| 127 -128 |   120826
HSD|    avg| 128 -129 |    49583
HSD|    avg| 129 -130 |    86632
HSD|    avg| 130 -131 |    33987
HSD|    avg| 131 -132 |    95449
HSD|    avg| 132 -133 |    16782
HSD|    avg| 133 -134 |     5143
HSD|    avg| 134 -135 |     1717
HSD|    avg| 135 -136 |      109
HSD|    avg| 136 -137 |      181
HSD|    avg| 137 -138 |       54
HSD|    avg| 138 -139 |       26
HSD|    avg| 139 -140 |        1
HSD|    avg| 140 -141 |        2
HSD|    avg| 142 -143 |        1
HSD|    avg| 143 -144 |        7
HSD|    avg| 144 -145 |       36
HSD|    avg| 145 -146 |       79
HSD|    avg| 146 -147 |       33
HSD|    avg| 147 -148 |       84
HSD|    avg| 148 -149 |        9
HSD|    avg| 149 -150 |        3
HSD|    avg| 150 -151 |        2
HSD|    avg| 152 -153 |        8
HSD|    avg| 153 -154 |        5
HSD|    avg| 154 -155 |       60
HSD|    avg| 155 -156 |       86
HSD|    avg| 156 -157 |      469
HSD|    avg| 157 -158 |      339
HSD|    avg| 158 -159 |      566
HSD|    avg| 159 -160 |     1962
HSD|    avg| 160 -161 |     1441
HSD|    avg| 161 -162 |     4948
HSD|    avg| 162 -163 |     2681
HSD|    avg| 163 -164 |     3713
HSD|    avg| 164 -165 |     1345
HSD|    avg| 165 -166 |     3059
HSD|    avg| 166 -167 |     1758
HSD|    avg| 167 -168 |     2036
HSD|    avg| 168 -169 |     2543
HSD|    avg| 169 -170 |      286
HSD|    avg| 170 -171 |      112
HSD|    avg| 171 -172 |        6
HSD|    avg| 172 -173 |        1
HSD|    avg| 174 -175 |        1
---|--param|----range-|--samples
HSD|    max| 122 -123 |        1
HSD|    max| 131 -132 |      243
HSD|    max| 132 -133 |      423
HSD|    max| 133 -134 |      320
HSD|    max| 134 -135 |      118
HSD|    max| 135 -136 |        4
HSD|    max| 136 -137 |       10
HSD|    max| 137 -138 |        3
HSD|    max| 138 -139 |        2
HSD|    max| 143 -144 |        6
HSD|    max| 144 -145 |       36
HSD|    max| 145 -146 |       78
HSD|    max| 146 -147 |       33
HSD|    max| 147 -148 |       84
HSD|    max| 148 -149 |        9
HSD|    max| 149 -150 |        3
HSD|    max| 150 -151 |        2
HSD|    max| 152 -153 |        8
HSD|    max| 153 -154 |        5
HSD|    max| 154 -155 |       60
HSD|    max| 155 -156 |       86
HSD|    max| 156 -157 |      469
HSD|    max| 157 -158 |      339
HSD|    max| 158 -159 |      566
HSD|    max| 159 -160 |     1962
HSD|    max| 160 -161 |     1441
HSD|    max| 161 -162 |     4948
HSD|    max| 162 -163 |     2681
HSD|    max| 163 -164 |     3713
HSD|    max| 164 -165 |     1345
HSD|    max| 165 -166 |     3059
HSD|    max| 166 -167 |     1758
HSD|    max| 167 -168 |     2035
HSD|    max| 168 -169 |     2543
HSD|    max| 169 -170 |      286
HSD|    max| 170 -171 |      112
HSD|    max| 171 -172 |        6
HSD|    max| 172 -173 |        1
HSD|    max| 174 -175 |        1
HSH|--param|--samples-|--average--|---stddev--
HSS|    min|     28799|     21.626|      2.387
HSS|    avg|  57599720|     36.359|     75.112
HSS|    max|     28799|    161.719|      6.860
---|------------|------------|------------|--------|-------------------------
RTS|      10.416|     111.111|     174.305|       0|    08:00:02/08:00:00         
-- 


					    Gilles Chanteperdrix.


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-18 20:55                 ` Gilles Chanteperdrix
@ 2007-04-20  8:32                   ` Gregory CLEMENT
  2007-04-20  8:41                     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 27+ messages in thread
From: Gregory CLEMENT @ 2007-04-20  8:32 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: adeos-main

2007/4/18, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> Gilles Chanteperdrix wrote:
>  > Gregory CLEMENT wrote:
>  >  > > >  #ifdef CONFIG_IPIPE
>  >  > > > -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>  >  > > > +#if defined(CONFIG_ARCH_AT91RM9200)
>  >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>  >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9260)
>  >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
>  >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9261)
>  >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
>  >  > > > +#else
>  >  > > > +#error "Unsupported AT91 processor"
>  >  > > > +#endif
>  >  > > >  #endif /* CONFIG_IPIPE */
>  >  > >
>  >  > > To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?
>  >  >
>  >  > Sure it would be better, but unfortunately the mainteners of AT91
>  >  > choose to produce a define per architecture even if the register are
>  >  > the same.
>  >
>  > As far as I know, the AT91RM9200_BASE_TCB0 define is provided by the
>  > I-pipe patch, so we may name it how we want.
>
> No, it is not provided by the I-pipe patch.
>
>  >
>  >
>  >  > We keep this line :
>  >  > #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>  >  > and it will work I don't like having an AT91RM9200 define for chip
>  >  > which are not AT91RM9200. It adds confusion.
>  >  >
>  >  > We also could define AT91_BASE_TCB0 as you suggest, but it mean we add
>  >  > a new register definition just for ipipe and it adds a little
>  >  > confusion also.
>  >  >
>  >  > Choose the solution you prefer, or an other if you have a better idea.
>  >
>  > I do not have a better idea, but I understood why the defines are
>  > different: the CONFIG_ARCH_AT91RM9200, CONFIG_ARCH_AT91SAM9260 and
>  > CONFIG_ARCH_AT91SAM9261 are not mutually exclusive, it is possible to
>  > build a kernel that works for the three machines. So, this code can not
>  > remain as is. Please, at least, forbid in Kconfig selecting several
>  > machines when IPIPE is enabled.
>
> On 2.6.20, the options ARE mutually exclusive.


Ok so do you want we produce a new patch taking in account your comments ?
Or have you already done it?


-- 
Gregory CLEMENT
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-20  8:32                   ` Gregory CLEMENT
@ 2007-04-20  8:41                     ` Gilles Chanteperdrix
  0 siblings, 0 replies; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-20  8:41 UTC (permalink / raw)
  To: gclement; +Cc: adeos-main

Gregory CLEMENT wrote:
> 2007/4/18, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>:
> 
>>Gilles Chanteperdrix wrote:
>> > Gregory CLEMENT wrote:
>> >  > > >  #ifdef CONFIG_IPIPE
>> >  > > > -#define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>> >  > > > +#if defined(CONFIG_ARCH_AT91RM9200)
>> >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>> >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9260)
>> >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9260_BASE_TCB0)
>> >  > > > +#elif defined(CONFIG_ARCH_AT91SAM9261)
>> >  > > > +     #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91SAM9261_BASE_TCB0)
>> >  > > > +#else
>> >  > > > +#error "Unsupported AT91 processor"
>> >  > > > +#endif
>> >  > > >  #endif /* CONFIG_IPIPE */
>> >  > >
>> >  > > To reduce the ifdef hell, can not we define a unique AT91_BASE_TCB0 ?
>> >  >
>> >  > Sure it would be better, but unfortunately the mainteners of AT91
>> >  > choose to produce a define per architecture even if the register are
>> >  > the same.
>> >
>> > As far as I know, the AT91RM9200_BASE_TCB0 define is provided by the
>> > I-pipe patch, so we may name it how we want.
>>
>>No, it is not provided by the I-pipe patch.
>>
>> >
>> >
>> >  > We keep this line :
>> >  > #define AT91_VA_BASE_TCB0       AT91_IO_P2V(AT91RM9200_BASE_TCB0)
>> >  > and it will work I don't like having an AT91RM9200 define for chip
>> >  > which are not AT91RM9200. It adds confusion.
>> >  >
>> >  > We also could define AT91_BASE_TCB0 as you suggest, but it mean we add
>> >  > a new register definition just for ipipe and it adds a little
>> >  > confusion also.
>> >  >
>> >  > Choose the solution you prefer, or an other if you have a better idea.
>> >
>> > I do not have a better idea, but I understood why the defines are
>> > different: the CONFIG_ARCH_AT91RM9200, CONFIG_ARCH_AT91SAM9260 and
>> > CONFIG_ARCH_AT91SAM9261 are not mutually exclusive, it is possible to
>> > build a kernel that works for the three machines. So, this code can not
>> > remain as is. Please, at least, forbid in Kconfig selecting several
>> > machines when IPIPE is enabled.
>>
>>On 2.6.20, the options ARE mutually exclusive.
> 
> 
> 
> Ok so do you want we produce a new patch taking in account your comments ?
> Or have you already done it?

If possible I would prefer you to produce a new patch.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
       [not found]         ` <00e801c78328$d2569a90$7703cfb0$@com>
@ 2007-04-20  9:07           ` Gilles Chanteperdrix
  2007-04-23  8:29             ` Jan Kiszka
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-20  9:07 UTC (permalink / raw)
  To: Jose Pascual; +Cc: adeos-main

Jose Pascual wrote:
> Hi Gilles,
> 
> Thank you so much for your answer,
> 
> Do you have a ipipe patch for 2.6.20? is only for at91sam9261 or I can use
> it for at91rm9200?

The patch for 2.6.20 only exists on my disk and is only tested on
at91rm9200. I need to test the compilation on other ARMs, but I should
publish it soon after.

> I'm having in ethernet driver some ROVR errors because dma became full for
> load in linux, do 
> you think adeos-ipipe can help me in it? shoud it be necessary to change
> ethernet irq (portng to adeos)?

You could port it to RTnet, you will get low latency IP/UDP, but beware,
RTnet is incompatible with plain ipv4, so, if you want to run a network
with RTnet, all machines on the network need to run RTnet.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-20  9:07           ` Gilles Chanteperdrix
@ 2007-04-23  8:29             ` Jan Kiszka
  0 siblings, 0 replies; 27+ messages in thread
From: Jan Kiszka @ 2007-04-23  8:29 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: adeos-main, Jose Pascual

[-- Attachment #1: Type: text/plain, Size: 943 bytes --]

Gilles Chanteperdrix wrote:
> Jose Pascual wrote:
>> I'm having in ethernet driver some ROVR errors because dma became full for
>> load in linux, do 
>> you think adeos-ipipe can help me in it? shoud it be necessary to change
>> ethernet irq (portng to adeos)?
> 
> You could port it to RTnet, you will get low latency IP/UDP, but beware,
> RTnet is incompatible with plain ipv4, so, if you want to run a network
> with RTnet, all machines on the network need to run RTnet.
> 

RTnet's IPv4 _is_ compatible with standard implementations. Moreover, if
you can control the network traffic deterministically without the help
of RTnet on every node, you can also run mixed network segments without
loosing real-time guarantees on the RTnet nodes. But that mode is more
tricky and far more fragile than running a dedicated RTnet segment.

Further questions can also be directed to rtnet-users at
lists.sourceforge.net.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]

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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-18  9:43 ` BOUIN Alexandre
@ 2007-04-18  9:48   ` Gilles Chanteperdrix
  0 siblings, 0 replies; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-18  9:48 UTC (permalink / raw)
  To: BOUIN Alexandre; +Cc: adeos-main

BOUIN Alexandre wrote:
> Nouveaux résultats, nouvelle ébauche de mail :
> "
> 11 hours later ... here are our results on AT91SAM9261-EK board, and our Adeos patch.
> 
> [run test]
> uclibc login: root
> # cd /usr/xenomai/bin/
> # ./latency -p 500 -h
> [results]
> HSH|--param|--samples-|--average--|---stddev--
> HSS|    min|     38253|     17.897|      1.879
> HSS|    avg|  76507896|     39.422|     16.059
> HSS|    max|     38253|     65.688|      6.736
> ---|------------|------------|------------|--------|-------------------------
> RTS|       9.023|      39.798|      94.420|       0|    10:37:32/10:37:32
> 
> There was no load while performing these tests. So Gilles, if you had made some softs to make some load, we'll be glad to know them.

Please read the TROUBLESHOOTING file.

-- 
                                                 Gilles Chanteperdrix


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
       [not found] <403B28AE6257B548B66BB88414AC78330174BBD5@domain.hid>
@ 2007-04-18  9:43 ` BOUIN Alexandre
  2007-04-18  9:48   ` Gilles Chanteperdrix
  0 siblings, 1 reply; 27+ messages in thread
From: BOUIN Alexandre @ 2007-04-18  9:43 UTC (permalink / raw)
  To: adeos-main


Nouveaux résultats, nouvelle ébauche de mail :
"
11 hours later ... here are our results on AT91SAM9261-EK board, and our Adeos patch.

[run test]
uclibc login: root
# cd /usr/xenomai/bin/
# ./latency -p 500 -h
[results]
HSH|--param|--samples-|--average--|---stddev--
HSS|    min|     38253|     17.897|      1.879
HSS|    avg|  76507896|     39.422|     16.059
HSS|    max|     38253|     65.688|      6.736
---|------------|------------|------------|--------|-------------------------
RTS|       9.023|      39.798|      94.420|       0|    10:37:32/10:37:32

There was no load while performing these tests. So Gilles, if you had made some softs to make some load, we'll be glad to know them.

Alexandre Bouin
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40
"


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
  2007-04-16 14:02 ` Gilles Chanteperdrix
@ 2007-04-16 14:35   ` BOUIN Alexandre
  0 siblings, 0 replies; 27+ messages in thread
From: BOUIN Alexandre @ 2007-04-16 14:35 UTC (permalink / raw)
  To: adeos-main

Hi, with Gregory we've worked on Xenomai implementation on AT91SAM9261-EK
board.
Here are our latency results :
[run test]
uclibc login: root
# cd /usr/xenomai/bin/
# ./latency -p 500 -h
[histogram]
---|--param|----range-|--samples
HSD|    min|  14 - 15 |        1
HSD|    min|  15 - 16 |        2
HSD|    min|  16 - 17 |        4
HSD|    min|  17 - 18 |       25
HSD|    min|  18 - 19 |        2
HSD|    min|  19 - 20 |        1
HSD|    min|  26 - 27 |        1
---|--param|----range-|--samples
HSD|    avg|  14 - 15 |        1
HSD|    avg|  15 - 16 |        2
HSD|    avg|  16 - 17 |       11
HSD|    avg|  17 - 18 |       47
HSD|    avg|  18 - 19 |       17
HSD|    avg|  19 - 20 |       22
HSD|    avg|  20 - 21 |       37
HSD|    avg|  21 - 22 |       25
HSD|    avg|  22 - 23 |        9
HSD|    avg|  23 - 24 |       43
HSD|    avg|  24 - 25 |        8
HSD|    avg|  25 - 26 |       41
HSD|    avg|  26 - 27 |    23144
HSD|    avg|  27 - 28 |     1084
HSD|    avg|  28 - 29 |       91
HSD|    avg|  29 - 30 |       35
HSD|    avg|  30 - 31 |       24
HSD|    avg|  31 - 32 |       10
HSD|    avg|  32 - 33 |       16
HSD|    avg|  33 - 34 |       22
HSD|    avg|  34 - 35 |       19
HSD|    avg|  35 - 36 |        6
HSD|    avg|  36 - 37 |        7
HSD|    avg|  37 - 38 |        4
HSD|    avg|  38 - 39 |        6
HSD|    avg|  39 - 40 |        1
HSD|    avg|  40 - 41 |       13
HSD|    avg|  41 - 42 |        7
HSD|    avg|  42 - 43 |        1
HSD|    avg|  43 - 44 |       11
HSD|    avg|  44 - 45 |       16
HSD|    avg|  45 - 46 |        3
HSD|    avg|  46 - 47 |        7
HSD|    avg|  47 - 48 |        4
HSD|    avg|  48 - 49 |       11
HSD|    avg|  49 - 50 |        5
HSD|    avg|  50 - 51 |        5
HSD|    avg|  51 - 52 |        7
HSD|    avg|  52 - 53 |        6
HSD|    avg|  53 - 54 |        9
HSD|    avg|  54 - 55 |       53
HSD|    avg|  55 - 56 |       94
HSD|    avg|  56 - 57 |      132
HSD|    avg|  57 - 58 |    11271
HSD|    avg|  58 - 59 |    35072
HSD|    avg|  59 - 60 |      598
HSD|    avg|  60 - 61 |      156
HSD|    avg|  61 - 62 |       52
HSD|    avg|  62 - 63 |       28
HSD|    avg|  63 - 64 |       33
HSD|    avg|  64 - 65 |        7
HSD|    avg|  65 - 66 |        2
HSD|    avg|  66 - 67 |        2
HSD|    avg|  67 - 68 |        7
HSD|    avg|  68 - 69 |        3
HSD|    avg|  69 - 70 |        1
HSD|    avg|  70 - 71 |        1
HSD|    avg|  71 - 72 |        2
HSD|    avg|  72 - 73 |       14
HSD|    avg|  73 - 74 |       31
HSD|    avg|  76 - 77 |        2
HSD|    avg|  79 - 80 |        7
HSD|    avg|  80 - 81 |      153
HSD|    avg|  81 - 82 |       25
---|--param|----range-|--samples
HSD|    max|  61 - 62 |        2
HSD|    max|  62 - 63 |        4
HSD|    max|  63 - 64 |        9
HSD|    max|  64 - 65 |        2
HSD|    max|  65 - 66 |        2
HSD|    max|  66 - 67 |        2
HSD|    max|  67 - 68 |        3
HSD|    max|  68 - 69 |        3
HSD|    max|  69 - 70 |        1
HSD|    max|  70 - 71 |        1
HSD|    max|  71 - 72 |        1
HSD|    max|  73 - 74 |        1
HSD|    max|  80 - 81 |        1
HSD|    max|  81 - 82 |        4
[results]
HSH|--param|--samples-|--average--|---stddev--
HSS|    min|        36|     17.056|      1.756
HSS|    avg|     72583|     47.011|     15.153
HSS|    max|        36|     67.194|      6.242
---|------------|------------|------------|--------|-------------------------
RTS|      14.501|      47.532|      81.368|       0|    00:00:37/00:00:37

We tried to run the tests under load, but it could be better to run them
again with the same load as you.
Could you say us which load test you launch during Latency tests ?

Thanks

Alexandre Bouin
Adeneo
2, chemin du Ruisseau - BP21
69136 Ecully Cedex
France
Tel : +33-4 72 18 08 40


-----Message d'origine-----
De : adeos-main-bounces@domain.hid [mailto:adeos-main-bounces@domain.hid la
part de Gilles Chanteperdrix
Envoyé : vendredi 13 avril 2007 10:54
À : Jose Pascual
Cc : adeos-main@gna.org
Objet : Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel


Jose Pascual wrote:
> Hi Gilles,
> 
> thank you for your answer,
> 
> Could you send your benchmark results? (what mherz are your PLLA working?
> and your Master Clock?)?

I do not remember the PLLA setting, I know the master clock is set to 46
MHz. The user-space latencies were around 200 us under load, sometimes
even greater than that. I do not remember if I had some debug options
enabled, I will re-run some tests.

-- 
                                                 Gilles Chanteperdrix

_______________________________________________
Adeos-main mailing list
Adeos-main@domain.hid
https://mail.gna.org/listinfo/adeos-main


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

* Re: [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel
       [not found] <403B28AE6257B548B66BB88414AC78330174BBCE@STEGOSAURE.adetel.com>
@ 2007-04-16 14:02 ` Gilles Chanteperdrix
  2007-04-16 14:35   ` BOUIN Alexandre
  0 siblings, 1 reply; 27+ messages in thread
From: Gilles Chanteperdrix @ 2007-04-16 14:02 UTC (permalink / raw)
  To: BOUIN Alexandre; +Cc: adeos-main

BOUIN Alexandre wrote:
> ---|------------|------------|------------|--------|-------------------------
> RTS|      14.501|      47.532|      81.368|       0|    00:00:37/00:00:37

A test of 37 seconds is definitely not enough. You should let the test
run for at least a few hours. And if you do not see latencies higher
than 100 microseconds you are probably not loading the system enough or
the AT91SAM9261 is much better than other ARMs.

-- 
                                                 Gilles Chanteperdrix


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

end of thread, other threads:[~2007-04-23  8:29 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-10 16:47 [Adeos-main] AT91SAM9261 adeos support for 2.6.19 kernel Gregory CLEMENT
2007-04-10 17:15 ` Gilles Chanteperdrix
2007-04-11  9:01   ` Gregory CLEMENT
2007-04-11  9:10     ` Gilles Chanteperdrix
2007-04-11  9:21       ` Gregory CLEMENT
2007-04-11 11:04         ` Jan Kiszka
2007-04-11 12:15         ` Gilles Chanteperdrix
2007-04-17 21:42           ` Gilles Chanteperdrix
2007-04-18  9:51             ` Gregory CLEMENT
2007-04-18 19:50               ` Gilles Chanteperdrix
2007-04-18 20:55                 ` Gilles Chanteperdrix
2007-04-20  8:32                   ` Gregory CLEMENT
2007-04-20  8:41                     ` Gilles Chanteperdrix
2007-04-10 17:20 ` [Xenomai-core] " Gregory CLEMENT
2007-04-12 17:24 ` [Adeos-main] " Jose Pascual
2007-04-12 17:31   ` Gilles Chanteperdrix
2007-04-13  7:55     ` Jose Pascual
2007-04-13  8:53       ` Gilles Chanteperdrix
2007-04-20  8:17       ` Gilles Chanteperdrix
     [not found]         ` <00e801c78328$d2569a90$7703cfb0$@com>
2007-04-20  9:07           ` Gilles Chanteperdrix
2007-04-23  8:29             ` Jan Kiszka
2007-04-13  7:58     ` Jose Pascual
2007-04-13  8:59       ` Gilles Chanteperdrix
     [not found] <403B28AE6257B548B66BB88414AC78330174BBCE@STEGOSAURE.adetel.com>
2007-04-16 14:02 ` Gilles Chanteperdrix
2007-04-16 14:35   ` BOUIN Alexandre
     [not found] <403B28AE6257B548B66BB88414AC78330174BBD5@domain.hid>
2007-04-18  9:43 ` BOUIN Alexandre
2007-04-18  9:48   ` Gilles Chanteperdrix

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.