All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bart Jonkers <jonkersbart@domain.hid>
To: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Cc: xenomai@xenomai.org
Subject: Re: [Xenomai-core] Xenomai on PXA
Date: Mon, 31 Jul 2006 10:34:19 +0200	[thread overview]
Message-ID: <1154334859.9569.12.camel@domain.hid> (raw)
In-Reply-To: <17595.49478.157044.654500@domain.hid>

On Mon, 2006-07-17 at 18:56 +0200, Gilles Chanteperdrix wrote:
> Philippe Gerum wrote:
>  > On Mon, 2006-07-17 at 18:17 +0200, Gilles Chanteperdrix wrote:
>  > > replaced PSR_I_BIT with its value. I now wonder if it is the proper fix,
>  > > or if __xchg should be fixed to use local_irq_save_hw and
>  > > local_irq_restore_hw instead, as is the case for the atomic operations
>  > > defined in atomic.h and bitops.h.
>  > 
>  > Definitely, it should be fixed to use hw masking ops.
> 
> Attached a corrected patch for 2.6.16.

Hey,

I tried this patch together with your ipipe-sa1100-pxa patch on my
pxa-255 based platform. 
There are two adaptions that I need to make in arch/arm/mach-pxa/time.c
to compile the kernel properly:
- include linux/module.h to remove warnings about EXPORT_SYMBOL
- replace sa1100_timer_initialized with pxa_timer_initialized

When I boot the kernel with ipipe enabled, linux receives no interrupts
anymore. Any idea to solve this?

thanks in advance,

Bart
> 
> plain text document attachment
> (adeos-ipipe-2.6.16-arm-unofficial2.patch)
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/Kconfig linux-2.6.16.5-tcl1-ipipe/arch/arm/Kconfig
> --- linux-2.6.16.5-tcl1/arch/arm/Kconfig	2006-07-15 20:06:02.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/Kconfig	2006-07-16 15:01:24.000000000 +0200
> @@ -401,6 +401,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/Makefile linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/Makefile
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/Makefile	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/Makefile	2006-07-16 15:19:02.000000000 +0200
> @@ -21,6 +21,7 @@ obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
>  obj-$(CONFIG_PCI)		+= bios32.o
>  obj-$(CONFIG_SMP)		+= smp.o
>  obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
> +obj-$(CONFIG_IPIPE)		+= ipipe-core.o ipipe-root.o
>  
>  obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
>  AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-armv.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-armv.S
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-armv.S	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-armv.S	2006-07-16 15:19:54.000000000 +0200
> @@ -4,6 +4,7 @@
>   *  Copyright (C) 1996,1997,1998 Russell King.
>   *  ARM700 fix by Matthew Godbolt (linux-user@domain.hid)
>   *  nommu support by Hyok S. Choi (hyok.choi@domain.hid)
> + *  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
> @@ -33,7 +34,11 @@
>  	@ 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
>  	/*
> @@ -199,6 +204,11 @@ __irq_svc:
>  #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
>  	tst	r0, #_TIF_NEED_RESCHED
> @@ -209,6 +219,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
>  	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
> @@ -237,6 +250,12 @@ svc_preempt:
>  __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
> @@ -406,6 +425,12 @@ __irq_usr:
>  #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
>  	ldr	r0, [tsk, #TI_PREEMPT]
>  	str	r8, [tsk, #TI_PREEMPT]
> @@ -499,8 +524,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)
> @@ -511,10 +536,34 @@ 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
>  	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
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-common.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-common.S
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-common.S	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-common.S	2006-07-16 16:15:08.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
> @@ -20,13 +21,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
> @@ -35,6 +41,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.
>   */
> @@ -62,19 +75,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
> @@ -197,8 +206,18 @@ ENTRY(vector_swi)
>  	bic	scno, scno, #0xff000000		@ mask off SWI op-code
>  	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
>  #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
>  
> @@ -245,6 +264,9 @@ __sys_trace_return:
>  __cr_alignment:
>  	.word	cr_alignment
>  #endif
> +#ifdef CONFIG_IPIPE
> +	.word	__ipipe_syscall_root
> +#endif
>  	.ltorg
>  
>  /*
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/entry-header.S linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-header.S
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/entry-header.S	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/entry-header.S	2006-07-16 15:01:24.000000000 +0200
> @@ -68,6 +68,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-core.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-core.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-core.c	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-core.c	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,239 @@
> +/* -*- linux-c -*-
> + * linux/arch/arm/kernel/ipipe-core.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 core support for ARM.
> + */
> +
> +#include <linux/config.h>
> +#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 <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/hardirq.h>
> +#include <asm/io.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];
> +
> +#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_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);
> +}
> +
> +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;
> +}
> +
> +/*
> + * 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;
> +}
> +
> +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;
> +}
> +
> +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);
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-root.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-root.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/ipipe-root.c	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ipipe-root.c	2006-07-17 14:59:06.000000000 +0200
> @@ -0,0 +1,379 @@
> +/* -*- linux-c -*-
> + * linux/arch/arm/kernel/ipipe-root.c
> + *
> + * Copyright (C) 2002-2005 Philippe Gerum (Adeos/ppc port over 2.6).
> + * Copyright (C) 2004 Wolfgang Grandegger (Adeos/ppc port over 2.4).
> + * 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/config.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <asm/system.h>
> +#include <asm/hardirq.h>
> +#include <asm/atomic.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/unistd.h>
> +#include <asm/mach/irq.h>
> +#include <asm/mmu_context.h>
> +
> +extern struct irqdesc irq_desc[];
> +extern spinlock_t irq_controller_lock;
> +extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
> +
> +static struct irqchip __ipipe_std_irq_dtype[NR_IRQS];
> +
> +static void __ipipe_override_irq_unmask(unsigned irq)
> +{
> +	unsigned long flags;
> +
> +	local_irq_save_hw(flags);
> +	ipipe_irq_unlock(irq);
> +	__ipipe_std_irq_dtype[irq].unmask(irq);
> +	local_irq_restore_hw(flags);
> +}
> +
> +static void __ipipe_override_irq_mask(unsigned irq)
> +{
> +	unsigned long flags;
> +
> +	local_irq_save_hw(flags);
> +	ipipe_irq_lock(irq);
> +	__ipipe_std_irq_dtype[irq].mask(irq);
> +	local_irq_restore_hw(flags);
> +}
> +
> +static void __ipipe_override_irq_mask_ack(unsigned irq)
> +{
> +	unsigned long flags;
> +
> +	local_irq_save_hw(flags);
> +	ipipe_irq_lock(irq);
> +	__ipipe_std_irq_dtype[irq].ack(irq);
> +	local_irq_restore_hw(flags);
> +}
> +
> +
> +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);
> +
> +	/*
> +	 * Interpose on the IRQ control routines so we can make them
> +	 * atomic using hw masking and prevent the interrupt log from
> +	 * being untimely flushed.
> +	 */
> +
> +	for (irq = 0; irq < NR_IRQS; irq++)
> +		__ipipe_std_irq_dtype[irq] = *irq_desc[irq].chip;
> +
> +	/*
> +	 * The original controller structs are often shared, so we first
> +	 * save them all before changing any of them. Notice that we don't
> +	 * override the ack() handler since we will enforce the necessary
> +	 * setup in __ipipe_ack_irq().
> +	 */
> +
> +	for (irq = 0; irq < NR_IRQS; irq++) {
> +		if (irq_desc[irq].chip->mask != NULL)
> +			irq_desc[irq].chip->mask = __ipipe_override_irq_mask;
> +
> +		if (irq_desc[irq].chip->unmask != NULL)
> +			irq_desc[irq].chip->unmask = __ipipe_override_irq_unmask;
> +
> +		if (irq_desc[irq].chip->ack != NULL)
> +			irq_desc[irq].chip->ack = __ipipe_override_irq_mask_ack;
> +	}
> +
> +	__ipipe_decr_next[ipipe_processor_id()] =
> +		__ipipe_read_timebase() + __ipipe_mach_get_dec();
> +
> +	ipipe_critical_exit(flags);
> +}
> +
> +int __ipipe_ack_irq(unsigned irq)
> +{
> +	unsigned long flags;
> +	ipipe_declare_cpuid;
> +
> +	/*
> +	 * No need to mask IRQs at hw level: we are always called from
> +	 * __ipipe_handle_irq(), so interrupts are already off. We
> +	 * stall the pipeline so that spin_lock_irq*() ops won't
> +	 * unintentionally flush it, since this could cause infinite
> +	 * recursion.
> +	 */
> +
> +	ipipe_load_cpuid();
> +	flags = ipipe_test_and_stall_pipeline();
> +	preempt_disable();
> +	spin_lock_hw(&irq_controller_lock);
> +	__ipipe_std_irq_dtype[irq].ack(irq);
> +	spin_unlock_hw(&irq_controller_lock);
> +	preempt_enable_no_resched();
> +	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid);
> +
> +	return 1;
> +}
> +
> +int __ipipe_ack_timerirq(unsigned irq)
> +{
> +	unsigned long flags;
> +	ipipe_declare_cpuid;
> +
> +	ipipe_load_cpuid();
> +	flags = ipipe_test_and_stall_pipeline();
> +	preempt_disable();
> +	spin_lock_hw(&irq_controller_lock);
> +	__ipipe_mach_acktimer();
> +	__ipipe_std_irq_dtype[irq].ack(irq);
> +	__ipipe_std_irq_dtype[irq].unmask(irq);
> +	spin_unlock_hw(&irq_controller_lock);
> +	preempt_enable_no_resched();
> +	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid);
> +
> +	return 1;
> +}
> +
> +/*
> + * __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, s_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 = 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. */
> +
> +	s_ack = m_ack;
> +	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 (next_domain->irqs[irq].acknowledge != NULL) {
> +				if (!m_ack)
> +					m_ack = next_domain->irqs[irq].acknowledge(irq);
> +				else if (test_bit
> +					 (IPIPE_SHARED_FLAG,
> +					  &next_domain->irqs[irq].control) && !s_ack)
> +					s_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;
> +		}
> +	}
> +
> +	__ipipe_handle_irq(irq, regs);
> +
> +	ipipe_load_cpuid();
> +
> +	return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
> +		!test_bit(IPIPE_STALL_FLAG,
> +			  &ipipe_root_domain->cpudata[cpuid].status));
> +}
> +
> +asmlinkage int __ipipe_check_root(struct pt_regs *regs)
> +{
> +	ipipe_declare_cpuid;
> +	/*
> +	 * This routine is called with hw interrupts off, so no migration
> +	 * can occur while checking the identity of the current domain.
> +	 */
> +	ipipe_load_cpuid();
> +	return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
> +		!test_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_event_pipelined_p(IPIPE_EVENT_SYSCALL) &&
> +	    __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) {
> +		/*
> +		 * We might enter here over a non-root domain and exit
> +		 * over the root one as a result of the syscall
> +		 * (i.e. by recycling the register set of the current
> +		 * context across the migration), so we need to fixup
> +		 * the interrupt flag upon return too, so that
> +		 * __ipipe_unstall_iret_root() resets the correct
> +		 * stall bit on exit.
> +		 */
> +		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;
> +}
> +
> +EXPORT_SYMBOL_GPL(show_stack);
> +#ifndef MULTI_CPU
> +EXPORT_SYMBOL_GPL(cpu_do_switch_mm);
> +#endif /* MULTI_CPU */
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/irq.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/irq.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/irq.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/irq.c	2006-07-16 15:01:24.000000000 +0200
> @@ -54,10 +54,11 @@
>  
>  static int noirqdebug;
>  static volatile unsigned long irq_err_count;
> -static DEFINE_SPINLOCK(irq_controller_lock);
> +DEFINE_SPINLOCK(irq_controller_lock);
>  static LIST_HEAD(irq_pending);
>  
>  struct irqdesc irq_desc[NR_IRQS];
> +EXPORT_SYMBOL(irq_desc);
>  void (*init_arch_irq)(void) __initdata = NULL;
>  
>  /*
> @@ -412,7 +413,9 @@ do_edge_IRQ(unsigned int irq, struct irq
>  	/*
>  	 * Acknowledge and clear the IRQ, but don't mask it.
>  	 */
> +#ifndef CONFIG_IPIPE
>  	desc->chip->ack(irq);
> +#endif /* CONFIG_IPIPE */
>  
>  	/*
>  	 * Mark the IRQ currently in progress.
> @@ -450,8 +453,10 @@ do_edge_IRQ(unsigned int irq, struct irq
>  	 * currently running.  Delay it.
>  	 */
>  	desc->pending = 1;
> +#ifndef CONFIG_IPIPE
>  	desc->chip->mask(irq);
>  	desc->chip->ack(irq);
> +#endif /* CONFIG_IPIPE */
>  }
>  
>  /*
> @@ -468,7 +473,9 @@ do_level_IRQ(unsigned int irq, struct ir
>  	/*
>  	 * Acknowledge, clear _AND_ disable the interrupt.
>  	 */
> +#ifndef CONFIG_IPIPE
>  	desc->chip->ack(irq);
> +#endif /* CONFIG_IPIPE */
>  
>  	if (likely(!desc->disable_depth)) {
>  		kstat_cpu(cpu).irqs[irq]++;
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/process.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/process.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/process.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/process.c	2006-07-16 15:01:24.000000000 +0200
> @@ -89,12 +89,12 @@ static void default_idle(void)
>  	if (hlt_counter)
>  		cpu_relax();
>  	else {
> -		local_irq_disable();
> +		local_irq_disable_hw();
>  		if (!need_resched()) {
>  			timer_dyn_reprogram();
>  			arch_idle();
>  		}
> -		local_irq_enable();
> +		local_irq_enable_hw();
>  	}
>  }
>  
> @@ -120,6 +120,7 @@ void cpu_idle(void)
>  
>  		if (!idle)
>  			idle = default_idle;
> + 		ipipe_suspend_domain();
>  		leds_event(led_idle_start);
>  		while (!need_resched())
>  			idle();
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/ptrace.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ptrace.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/ptrace.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/ptrace.c	2006-07-16 15:01:24.000000000 +0200
> @@ -486,6 +486,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/kernel/traps.c linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/traps.c
> --- linux-2.6.16.5-tcl1/arch/arm/kernel/traps.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/kernel/traps.c	2006-07-16 15:01:24.000000000 +0200
> @@ -310,6 +310,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-integrator/core.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/core.c
> --- linux-2.6.16.5-tcl1/arch/arm/mach-integrator/core.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/core.c	2006-07-16 15:01:24.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
> @@ -148,53 +149,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 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());
>  }
>  
>  /*
> @@ -205,10 +210,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
>  	 */
> -	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
> +	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
> @@ -239,24 +256,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)
>  	 */
> @@ -264,12 +287,51 @@ 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);
> +}
> +
> +unsigned long long __ipipe_mach_get_tsc(void)
> +{
> +	unsigned long long result;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave_hw(&timer_lock, flags);
> +	result = __ipipe_mach_tsc + integrator_getticksoffset();
> +	spin_unlock_irqrestore_hw(&timer_lock, flags);
> +	return result;
> +}
> +EXPORT_SYMBOL(__ipipe_mach_get_tsc);
> +
> +void __ipipe_mach_set_dec(unsigned long reload)
> +{
> +	unsigned long ticks;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave_hw(&timer_lock, flags);
> +	ticks = integrator_getticksoffset();
> +	__ipipe_mach_tsc += ticks;
> +	timer_lxlost += ticks;
> +
> +	set_dec(reload);
> +	spin_unlock_irqrestore_hw(&timer_lock, flags);
> +}
> +EXPORT_SYMBOL(__ipipe_mach_set_dec);
> +
> +unsigned long __ipipe_mach_get_dec(void)
> +{
> +	return readl(TIMER1_VA_BASE + TIMER_VALUE);
> +}
> +#endif /* CONFIG_IPIPE */
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-integrator/integrator_cp.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/integrator_cp.c
> --- linux-2.6.16.5-tcl1/arch/arm/mach-integrator/integrator_cp.c	2006-05-07 16:41:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-integrator/integrator_cp.c	2006-07-16 15:01:24.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
> @@ -568,9 +569,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-pxa/time.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-pxa/time.c
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mach-sa1100/time.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mach-sa1100/time.c
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/arch/arm/mm/fault.c linux-2.6.16.5-tcl1-ipipe/arch/arm/mm/fault.c
> --- linux-2.6.16.5-tcl1/arch/arm/mm/fault.c	2005-10-28 02:02:08.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/arch/arm/mm/fault.c	2006-07-16 15:01:24.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;
>  
> @@ -354,6 +357,9 @@ do_translation_fault(unsigned long addr,
>  bad_area:
>  	tsk = current;
>  
> +	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
> +		return 0;
> +
>  	do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
>  	return 0;
>  }
> @@ -366,6 +372,10 @@ static int
>  do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
>  {
>  	struct task_struct *tsk = current;
> +
> +	if (ipipe_trap_notify(IPIPE_TRAP_SECTION,regs))
> +		return 0;
> +
>  	do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
>  	return 0;
>  }
> @@ -376,6 +386,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;
>  }
>  
> @@ -451,6 +464,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);
>  
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/drivers/pci/msi.c linux-2.6.16.5-tcl1-ipipe/drivers/pci/msi.c
> --- linux-2.6.16.5-tcl1/drivers/pci/msi.c	2006-05-07 16:41:40.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/drivers/pci/msi.c	2006-07-16 15:01:24.000000000 +0200
> @@ -151,6 +151,21 @@ static void unmask_MSI_irq(unsigned int 
>  	msi_set_mask_bit(vector, 0);
>  }
>  
> +#ifdef CONFIG_IPIPE
> +static void ack_MSI_irq_w_maskbit(unsigned int vector)
> +{
> +    mask_MSI_irq(vector);
> +    __ack_APIC_irq();
> +}
> +static void ack_MSI_irq_wo_maskbit(unsigned int vector)
> +{
> +    __ack_APIC_irq();
> +}
> +#else /* !CONFIG_IPIPE */
> +#define ack_MSI_irq_wo_maskbit  do_nothing
> +#define ack_MSI_irq_w_maskbit   mask_MSI_irq
> +#endif /* CONFIG_IPIPE */
> +
>  static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
>  {
>  	struct msi_desc *entry;
> @@ -214,7 +229,7 @@ static struct hw_interrupt_type msix_irq
>  	.shutdown	= shutdown_msi_irq,
>  	.enable		= unmask_MSI_irq,
>  	.disable	= mask_MSI_irq,
> -	.ack		= mask_MSI_irq,
> +	.ack		= ack_MSI_irq_w_maskbit,
>  	.end		= end_msi_irq_w_maskbit,
>  	.set_affinity	= set_msi_affinity
>  };
> @@ -230,7 +245,7 @@ static struct hw_interrupt_type msi_irq_
>  	.shutdown	= shutdown_msi_irq,
>  	.enable		= unmask_MSI_irq,
>  	.disable	= mask_MSI_irq,
> -	.ack		= mask_MSI_irq,
> +	.ack		= ack_MSI_irq_w_maskbit,
>  	.end		= end_msi_irq_w_maskbit,
>  	.set_affinity	= set_msi_affinity
>  };
> @@ -246,7 +261,7 @@ static struct hw_interrupt_type msi_irq_
>  	.shutdown	= shutdown_msi_irq,
>  	.enable		= do_nothing,
>  	.disable	= do_nothing,
> -	.ack		= do_nothing,
> +	.ack		= ack_MSI_irq_wo_maskbit,
>  	.end		= end_msi_irq_wo_maskbit,
>  	.set_affinity	= set_msi_affinity
>  };
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/entry-macro.S linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/entry-macro.S
> --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/entry-macro.S	2006-05-07 16:42:04.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/entry-macro.S	2006-07-16 15:01:24.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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/platform.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/platform.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/platform.h	2005-10-28 02:02:08.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/platform.h	2006-07-16 15:01:24.000000000 +0200
> @@ -26,13 +26,15 @@
>   * 	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 $
>   *
>   * ***********************************************************************/
>  
>  #ifndef __address_h
>  #define __address_h                     1
>  
> +#include <linux/config.h>
> +
>  /* ========================================================================
>   *  Integrator definitions
>   * ========================================================================
> @@ -436,7 +438,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 +451,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/timex.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/timex.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/arch-integrator/timex.h	2005-10-28 02:02:08.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/arch-integrator/timex.h	2006-07-16 15:01:24.000000000 +0200
> @@ -21,6 +21,6 @@
>   */
>  
>  /*
> - * ??
> + * Timer rate
>   */
> -#define CLOCK_TICK_RATE		(50000000 / 16)
> +#define CLOCK_TICK_RATE		(1000000)
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/atomic.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/atomic.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/atomic.h	2006-05-07 16:42:05.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/atomic.h	2006-07-16 15:01:24.000000000 +0200
> @@ -129,10 +129,10 @@ static inline int atomic_add_return(int 
>  	unsigned long flags;
>  	int val;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	val = v->counter;
>  	v->counter = val += i;
> -	local_irq_restore(flags);
> +	local_irq_restore_hw(flags);
>  
>  	return val;
>  }
> @@ -142,10 +142,10 @@ static inline int atomic_sub_return(int 
>  	unsigned long flags;
>  	int val;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	val = v->counter;
>  	v->counter = val -= i;
> -	local_irq_restore(flags);
> +	local_irq_restore_hw(flags);
>  
>  	return val;
>  }
> @@ -155,11 +155,11 @@ static inline int atomic_cmpxchg(atomic_
>  	int ret;
>  	unsigned long flags;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	ret = v->counter;
>  	if (likely(ret == old))
>  		v->counter = new;
> -	local_irq_restore(flags);
> +	local_irq_restore_hw(flags);
>  
>  	return ret;
>  }
> @@ -168,9 +168,9 @@ static inline void atomic_clear_mask(uns
>  {
>  	unsigned long flags;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	*addr &= ~mask;
> -	local_irq_restore(flags);
> +	local_irq_restore_hw(flags);
>  }
>  
>  #endif /* __LINUX_ARM_ARCH__ */
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/bitops.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/bitops.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/bitops.h	2006-05-07 16:42:05.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/bitops.h	2006-07-16 15:01:24.000000000 +0200
> @@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(un
>  
>  	p += bit >> 5;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	*p |= mask;
> -	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;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	*p &= ~mask;
> -	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;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	*p ^= mask;
> -	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;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	res = *p;
>  	*p = res | mask;
> -	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;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	res = *p;
>  	*p = res & ~mask;
> -	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;
>  
> -	local_irq_save(flags);
> +	local_irq_save_hw(flags);
>  	res = *p;
>  	*p = res ^ mask;
> -	local_irq_restore(flags);
> +	local_irq_restore_hw(flags);
>  
>  	return res & mask;
>  }
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/ipipe.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/ipipe.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/ipipe.h	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/ipipe.h	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,193 @@
> +/* -*- 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
> +
> +#include <linux/config.h>
> +
> +#ifdef CONFIG_IPIPE
> +
> +#include <linux/list.h>
> +#include <linux/cpumask.h>
> +#include <linux/threads.h>
> +#include <asm/ptrace.h>
> +#include <asm/irq.h>
> +#include <asm/bitops.h>
> +#include <asm/mach/irq.h>
> +
> +#define IPIPE_ARCH_STRING	"1.3-04"
> +#define IPIPE_MAJOR_NUMBER	1
> +#define IPIPE_MINOR_NUMBER	3
> +#define IPIPE_PATCH_NUMBER	4
> +
> +#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 Xenoma
> + * 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_dispatch_event(IPIPE_EVENT_SCHEDULE,next);	\
> +	local_irq_disable_hw();					\
> +} while(0)
> +
> +#define task_hijacked(p)					\
> +	( {							\
> +	int x = ipipe_current_domain != ipipe_root_domain;	\
> +	__clear_bit(IPIPE_SYNC_FLAG,				\
> +		    &ipipe_root_domain->cpudata[task_cpu(p)].status); \
> +	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_EXIT	(IPIPE_FIRST_EVENT + 4)
> +#define IPIPE_EVENT_CLEANUP	(IPIPE_FIRST_EVENT + 5)
> +#define IPIPE_LAST_EVENT	IPIPE_EVENT_CLEANUP
> +#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 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 unsigned long __ipipe_mach_get_dec(void);
> +
> +#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)		(((t) * 1000) / (ipipe_cpu_freq() / 1000000))
> +
> +/* Private interface -- Internal use only */
> +
> +#define __ipipe_check_platform()	do { } while(0)
> +
> +#define __ipipe_enable_irq(irq)		irq_desc[irq].chip->unmask(irq)
> +
> +#define __ipipe_disable_irq(irq)	irq_desc[irq].chip->mask(irq)
> +
> +void __ipipe_init_platform(void);
> +
> +void __ipipe_enable_pipeline(void);
> +
> +int __ipipe_ack_irq(unsigned irq);
> +
> +int __ipipe_ack_timerirq(unsigned irq);
> +
> +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;
> +}
> +
> +#define __ipipe_run_isr(ipd, irq, cpuid) 	\
> +do {					 	\
> +	if (ipd == ipipe_root_domain) {		\
> +		/*                              \
> +		 * Linux handlers are called w/ hw interrupts on so \
> +		 * that they could not defer interrupts for higher  \
> +		 * priority domains.				    \
> +		 */						    \
> +		local_irq_enable_hw();				    \
> +		((void (*)(unsigned, struct pt_regs *))			\
> +		 ipd->irqs[irq].handler) (irq, __ipipe_tick_regs + cpuid); \
> +		local_irq_disable_hw();					\
> +	} else {							\
> +		__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
> +		ipd->irqs[irq].handler(irq,ipd->irqs[irq].cookie);	\
> +		__set_bit(IPIPE_SYNC_FLAG, &cpudata->status);		\
> +	}								\
> +} while(0)
> +
> +#else /* !CONFIG_IPIPE */
> +
> +#define task_hijacked(p)	0
> +
> +#endif /* CONFIG_IPIPE */
> +
> +#endif	/* !__ARM_IPIPE_H */
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/mmu_context.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/mmu_context.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/mmu_context.h	2006-05-07 15:36:58.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/mmu_context.h	2006-07-16 15:01:24.000000000 +0200
> @@ -82,14 +82,17 @@ static inline void
>  switch_mm(struct mm_struct *prev, struct mm_struct *next,
>  	  struct task_struct *tsk)
>  {
> -	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);
>  	}
>  }
>  
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/pgalloc.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/pgalloc.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/pgalloc.h	2005-10-28 02:02:08.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/pgalloc.h	2006-07-16 15:01:24.000000000 +0200
> @@ -29,6 +29,11 @@ extern void free_pgd_slow(pgd_t *pgd);
>  
>  #define check_pgt_cache()		do { } while (0)
>  
> +static inline void set_pgdir(unsigned long address, pgd_t entry)
> +{
> +	/* nop */
> +}
> +
>  /*
>   * Allocate one PTE table.
>   *
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/asm-arm/system.h linux-2.6.16.5-tcl1-ipipe/include/asm-arm/system.h
> --- linux-2.6.16.5-tcl1/include/asm-arm/system.h	2006-05-07 16:42:05.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/asm-arm/system.h	2006-07-17 18:40:59.000000000 +0200
> @@ -186,30 +186,30 @@ static inline void sched_cacheflush(void
>   */
>  #if __LINUX_ARM_ARCH__ >= 6
>  
> -#define local_irq_save(x)					\
> +#define local_irq_save_hw(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 local_irq_enable()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
> -#define 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()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
> +#define local_irq_disable_hw() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
> +#define local_fiq_enable_hw()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
> +#define local_fiq_disable_hw() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
>  
>  #else
>  
>  /*
>   * Save the current interrupt enable state & disable IRQs
>   */
> -#define local_irq_save(x)					\
> +#define local_irq_save_hw(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)					\
> @@ -220,11 +220,11 @@ static inline void sched_cacheflush(void
>  /*
>   * Enable IRQs
>   */
> -#define local_irq_enable()					\
> +#define local_irq_enable_hw()					\
>  	({							\
>  		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)						\
> @@ -235,11 +235,11 @@ static inline void sched_cacheflush(void
>  /*
>   * Disable IRQs
>   */
> -#define local_irq_disable()					\
> +#define local_irq_disable_hw()					\
>  	({							\
>  		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)						\
> @@ -250,7 +250,7 @@ static inline void sched_cacheflush(void
>  /*
>   * Enable FIQs
>   */
> -#define local_fiq_enable()					\
> +#define local_fiq_enable_hw()					\
>  	({							\
>  		unsigned long temp;				\
>  	__asm__ __volatile__(					\
> @@ -265,7 +265,7 @@ static inline void sched_cacheflush(void
>  /*
>   * Disable FIQs
>   */
> -#define local_fiq_disable()					\
> +#define local_fiq_disable_hw()					\
>  	({							\
>  		unsigned long temp;				\
>  	__asm__ __volatile__(					\
> @@ -282,29 +282,63 @@ static inline void sched_cacheflush(void
>  /*
>   * Save the current interrupt enable state.
>   */
> -#define 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 local_irq_restore(x)					\
> +#define local_irq_restore_hw(x)					\
>  	__asm__ __volatile__(					\
> -	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
> +	"msr	cpsr_c, %0		@ local_irq_restore_hw\n"\
>  	:							\
>  	: "r" (x)						\
>  	: "memory", "cc")
>  
> -#define irqs_disabled()			\
> -({					\
> +#define irqs_disabled_hw()		\
> +	({				\
>  	unsigned long flags;		\
> -	local_save_flags(flags);	\
> +	local_save_flags_hw(flags);	\
>  	(int)(flags & PSR_I_BIT);	\
> -})
> +	})
> +
> +
> +#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 local_irq_save(flags)		((flags) = __ipipe_test_and_stall_root() << 7)
> +#define local_irq_enable()		__ipipe_unstall_root()
> +#define local_irq_disable()		__ipipe_stall_root()
> +#define local_fiq_enable()		__ipipe_unstall_root()
> +#define local_fiq_disable()		__ipipe_stall_root()
> +#define local_save_flags(flags)		((flags) = __ipipe_test_root() << 7)
> +#define local_irq_restore(flags)	__ipipe_restore_root(flags & (1 << 7))
> +
> +#define irqs_disabled()			__ipipe_test_root()
> +
> +#else /* !CONFIG_IPIPE */
> +
> +#define local_irq_save(flags)		local_irq_save_hw(flags)
> +#define local_irq_enable()		local_irq_enable_hw()
> +#define local_irq_disable()		local_irq_disable_hw()
> +#define local_fiq_enable()		local_fiq_enable_hw()
> +#define local_fiq_disable()		local_fiq_disable_hw()
> +#define local_save_flags(flags)		local_save_flags_hw(flags)
> +#define local_irq_restore(flags)	local_irq_restore_hw(flags)
> +
> +#define irqs_disabled()			irqs_disabled_hw()
> +
> +#endif /* CONFIG_IPIPE */
>  
>  #ifdef CONFIG_SMP
>  
> @@ -379,17 +413,17 @@ static inline unsigned long __xchg(unsig
>  #error SMP is not supported on this platform
>  #endif
>  	case 1:
> -		local_irq_save(flags);
> +		local_irq_save_hw(flags);
>  		ret = *(volatile unsigned char *)ptr;
>  		*(volatile unsigned char *)ptr = x;
> -		local_irq_restore(flags);
> +		local_irq_restore_hw(flags);
>  		break;
>  
>  	case 4:
> -		local_irq_save(flags);
> +		local_irq_save_hw(flags);
>  		ret = *(volatile unsigned long *)ptr;
>  		*(volatile unsigned long *)ptr = x;
> -		local_irq_restore(flags);
> +		local_irq_restore_hw(flags);
>  		break;
>  #else
>  	case 1:
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/hardirq.h linux-2.6.16.5-tcl1-ipipe/include/linux/hardirq.h
> --- linux-2.6.16.5-tcl1/include/linux/hardirq.h	2006-05-07 16:42:11.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/linux/hardirq.h	2006-07-16 15:01:24.000000000 +0200
> @@ -87,8 +87,21 @@ extern void synchronize_irq(unsigned int
>  # define synchronize_irq(irq)	barrier()
>  #endif
>  
> +#ifdef CONFIG_IPIPE
> +#define nmi_enter() \
> +do { \
> +    if (ipipe_current_domain == ipipe_root_domain) \
> +	irq_enter(); \
> +} while(0)
> +#define nmi_exit() \
> +do { \
> +    if (ipipe_current_domain == ipipe_root_domain) \
> +	sub_preempt_count(HARDIRQ_OFFSET); \
> +} while(0)
> +#else /* !CONFIG_IPIPE */
>  #define nmi_enter()		irq_enter()
>  #define nmi_exit()		sub_preempt_count(HARDIRQ_OFFSET)
> +#endif /* CONFIG_IPIPE */
>  
>  struct task_struct;
>  
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/ipipe.h linux-2.6.16.5-tcl1-ipipe/include/linux/ipipe.h
> --- linux-2.6.16.5-tcl1/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/include/linux/ipipe.h	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,699 @@
> +/* -*- 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/config.h>
> +#include <linux/spinlock.h>
> +#include <linux/cache.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 */
> +
> +#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_SYNC_MASK		(1 << IPIPE_SYNC_FLAG)
> +
> +#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_SHARED_FLAG	6
> +#define IPIPE_WIRED_FLAG	7
> +#define IPIPE_EXCLUSIVE_FLAG	8
> +
> +#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_SHARED_MASK	(1 << IPIPE_SHARED_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	(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	(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];
> +	} ____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;
> +};
> +
> +#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)
> +
> +#ifdef __RAW_SPIN_LOCK_UNLOCKED
> +#define spin_lock_hw(x)			_raw_spin_lock(x)
> +#define spin_trylock_hw(x)		_raw_spin_trylock(x)
> +#define spin_unlock_hw(x)		_raw_spin_unlock(x)
> +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
> +#define write_lock_hw(x)		_raw_write_lock(x)
> +#define write_trylock_hw(x)		_raw_write_trylock(x)
> +#define write_unlock_hw(x)		_raw_write_unlock(x)
> +#define read_lock_hw(x)			_raw_read_lock(x)
> +#define read_trylock_hw(x)		_raw_read_trylock(x)
> +#define read_unlock_hw(x)		_raw_read_unlock(x)
> +#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 */
> +#else	/* !__RAW_SPIN_LOCK_UNLOCKED */
> +#define spin_lock_hw(x)			_spin_lock(x)
> +#define spin_unlock_hw(x)		_spin_unlock(x)
> +#define spin_trylock_hw(x)		_spin_trylock(x)
> +#define write_lock_hw(x)		_write_lock(x)
> +#define write_unlock_hw(x)		_write_unlock(x)
> +#define write_trylock_hw(x)		_write_trylock(x)
> +#define read_lock_hw(x)			_read_lock(x)
> +#define read_unlock_hw(x)		_read_unlock(x)
> +#endif	/* __RAW_SPIN_LOCK_UNLOCKED */
> +
> +typedef spinlock_t			ipipe_spinlock_t;
> +typedef rwlock_t			ipipe_rwlock_t;
> +#define IPIPE_SPIN_LOCK_UNLOCKED	SPIN_LOCK_UNLOCKED
> +#define IPIPE_RW_LOCK_UNLOCKED		RW_LOCK_UNLOCKED
> +
> +#define spin_lock_irqsave_hw(x,flags)		\
> +do {						\
> +	local_irq_save_hw(flags);		\
> +	spin_lock_hw(x);			\
> +} while (0)
> +
> +#define spin_unlock_irqrestore_hw(x,flags)	\
> +do {						\
> +	spin_unlock_hw(x);			\
> +	local_irq_restore_hw(flags);		\
> +} while (0)
> +
> +#define spin_lock_irq_hw(x)			\
> +do {						\
> +	local_irq_disable_hw();			\
> +	spin_lock_hw(x);			\
> +} while (0)
> +
> +#define spin_unlock_irq_hw(x)			\
> +do {						\
> +	spin_unlock_hw(x);			\
> +	local_irq_enable_hw();			\
> +} while (0)
> +
> +#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)
> +
> +extern struct ipipe_domain *ipipe_percpu_domain[], *ipipe_root_domain;
> +
> +extern unsigned __ipipe_printk_virq;
> +
> +extern unsigned long __ipipe_virtual_irq_map;
> +
> +extern struct list_head __ipipe_pipeline;
> +
> +extern ipipe_spinlock_t __ipipe_pipelock;
> +
> +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_trace_proc(void);
> +#else /* !CONFIG_IPIPE_TRACE */
> +#define __ipipe_init_trace_proc()   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);
> +
> +#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_pipelined_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).
> +	 */
> +
> +	ipipe_percpu_domain[cpuid] = in;
> +
> +	ipipe_suspend_domain();	/* Sync stage and propagate interrupts. */
> +	ipipe_load_cpuid();	/* Processor might have changed. */
> +
> +	if (ipipe_percpu_domain[cpuid] == in)
> +		/*
> +		 * Otherwise, something has changed the current domain under
> +		 * our feet recycling the register set; do not override.
> +		 */
> +		ipipe_percpu_domain[cpuid] = out;
> +}
> +
> +static inline void ipipe_sigwake_notify(struct task_struct *p)
> +{
> +	if (__ipipe_event_pipelined_p(IPIPE_EVENT_SIGWAKE))
> +		__ipipe_dispatch_event(IPIPE_EVENT_SIGWAKE,p);
> +}
> +
> +static inline void ipipe_setsched_notify(struct task_struct *p)
> +{
> +	if (__ipipe_event_pipelined_p(IPIPE_EVENT_SETSCHED))
> +		__ipipe_dispatch_event(IPIPE_EVENT_SETSCHED,p);
> +}
> +
> +static inline void ipipe_exit_notify(struct task_struct *p)
> +{
> +	if (__ipipe_event_pipelined_p(IPIPE_EVENT_EXIT))
> +		__ipipe_dispatch_event(IPIPE_EVENT_EXIT,p);
> +}
> +
> +static inline int ipipe_trap_notify(int ex, struct pt_regs *regs)
> +{
> +	return __ipipe_event_pipelined_p(ex) ? __ipipe_dispatch_event(ex,regs) : 0;
> +}
> +
> +struct mm_struct;
> +
> +static inline void ipipe_cleanup_notify(struct mm_struct *mm)
> +{
> +	if (__ipipe_event_pipelined_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);
> +
> +static inline int ipipe_share_irq(unsigned irq,
> +								  ipipe_irq_ackfn_t acknowledge)
> +{
> +	return ipipe_virtualize_irq(ipipe_current_domain,
> +								irq,
> +								IPIPE_SAME_HANDLER,
> +								NULL,
> +								acknowledge,
> +								IPIPE_SHARED_MASK | IPIPE_HANDLE_MASK |
> +								IPIPE_PASS_MASK);
> +}
> +
> +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;
> +	unsigned long flags;
> +
> +	ipipe_lock_cpu(flags);
> +	__set_bit(IPIPE_STALL_FLAG, &__ipipe_pipeline_head()->cpudata[cpuid].status);
> +}
> +
> +static inline unsigned long ipipe_test_and_stall_pipeline_head(void)
> +{
> +	unsigned long flags;
> +	ipipe_declare_cpuid;
> +
> +	ipipe_lock_cpu(flags);
> +	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);
> +}
> +
> +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);
> +
> +#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 spin_lock_irqsave_hw_cond(lock,flags)	spin_lock_irqsave_hw(lock,flags)
> +#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock_irqrestore_hw(lock,flags)
> +#define smp_processor_id_hw()			ipipe_processor_id()
> +
> +#define ipipe_irq_lock(irq)						\
> +	do {								\
> +		ipipe_declare_cpuid;					\
> +		ipipe_load_cpuid();					\
> +		__ipipe_lock_irq(ipipe_percpu_domain[cpuid], cpuid, irq);\
> +	} while(0)
> +
> +#define ipipe_irq_unlock(irq)						\
> +	do {								\
> +		ipipe_declare_cpuid;					\
> +		ipipe_load_cpuid();					\
> +		__ipipe_unlock_irq(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_exit_notify(p)		do { } while(0)
> +#define ipipe_init_proc()			do { } while(0)
> +#define ipipe_trap_notify(t,r)		0
> +#define ipipe_cleanup_notify(mm)	do { } while(0)
> +
> +#define spin_lock_hw(lock)				spin_lock(lock)
> +#define spin_unlock_hw(lock)			spin_unlock(lock)
> +#define spin_lock_irq_hw(lock)			spin_lock_irq(lock)
> +#define spin_unlock_irq_hw(lock)		spin_unlock_irq(lock)
> +#define spin_lock_irqsave_hw(lock,flags)	spin_lock_irqsave(lock, flags)
> +#define spin_unlock_irqrestore_hw(lock,flags)	spin_unlock_irqrestore(lock, flags)
> +
> +#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 spin_lock_irqsave_hw_cond(lock,flags)	do { (void)(flags); spin_lock(lock); } while(0)
> +#define spin_unlock_irqrestore_hw_cond(lock,flags)	spin_unlock(lock)
> +#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
> +
> +#endif	/* CONFIG_IPIPE */
> +
> +#endif	/* !__LINUX_IPIPE_H */
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/linkage.h linux-2.6.16.5-tcl1-ipipe/include/linux/linkage.h
> --- linux-2.6.16.5-tcl1/include/linux/linkage.h	2005-10-28 02:02:08.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/linux/linkage.h	2006-07-16 15:01:24.000000000 +0200
> @@ -51,4 +51,8 @@
>  #define fastcall
>  #endif
>  
> +#ifndef notrace
> +#define notrace		__attribute__((no_instrument_function))
> +#endif
> +
>  #endif
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/preempt.h linux-2.6.16.5-tcl1-ipipe/include/linux/preempt.h
> --- linux-2.6.16.5-tcl1/include/linux/preempt.h	2006-05-07 15:37:01.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/linux/preempt.h	2006-07-16 15:01:24.000000000 +0200
> @@ -27,29 +27,43 @@
>  
>  asmlinkage void preempt_schedule(void);
>  
> -#define preempt_disable() \
> -do { \
> -	inc_preempt_count(); \
> -	barrier(); \
> +#ifdef CONFIG_IPIPE
> +#include <asm/ipipe.h>
> +extern struct ipipe_domain *ipipe_percpu_domain[], *ipipe_root_domain;
> +#define ipipe_preempt_guard()	(ipipe_percpu_domain[ipipe_processor_id()] == ipipe_root_domain)
> +#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 { \
> -	barrier(); \
> -	dec_preempt_count(); \
> +#define preempt_enable_no_resched()					\
> +do {									\
> +	if (ipipe_preempt_guard()) {					\
> +		barrier();						\
> +		dec_preempt_count();					\
> +	}								\
>  } while (0)
>  
> -#define preempt_check_resched() \
> -do { \
> -	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
> -		preempt_schedule(); \
> +#define preempt_check_resched()						\
> +do {									\
> +	if (ipipe_preempt_guard()) {					\
> +		if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))	\
> +			preempt_schedule();				\
> +	}								\
>  } while (0)
>  
> -#define preempt_enable() \
> -do { \
> -	preempt_enable_no_resched(); \
> +#define preempt_enable()						\
> +do {									\
> +	preempt_enable_no_resched();					\
>  	barrier(); \
> -	preempt_check_resched(); \
> +	preempt_check_resched();					\
>  } while (0)
>  
>  #else
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/include/linux/sched.h linux-2.6.16.5-tcl1-ipipe/include/linux/sched.h
> --- linux-2.6.16.5-tcl1/include/linux/sched.h	2006-05-07 16:42:13.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/include/linux/sched.h	2006-07-16 15:06:26.000000000 +0200
> @@ -4,6 +4,7 @@
>  #include <asm/param.h>	/* for HZ */
>  
>  #include <linux/config.h>
> +#include <linux/ipipe.h>
>  #include <linux/capability.h>
>  #include <linux/threads.h>
>  #include <linux/kernel.h>
> @@ -129,6 +130,11 @@ extern unsigned long nr_iowait(void);
>  #define EXIT_DEAD		32
>  /* in tsk->state again */
>  #define TASK_NONINTERACTIVE	64
> +#ifdef CONFIG_IPIPE
> +#define TASK_ATOMICSWITCH	512
> +#else  /* !CONFIG_IPIPE */
> +#define TASK_ATOMICSWITCH	0
> +#endif /* CONFIG_IPIPE */
>  
>  #define __set_task_state(tsk, state_value)		\
>  	do { (tsk)->state = (state_value); } while (0)
> @@ -871,6 +877,9 @@ struct task_struct {
>  #endif
>  	atomic_t fs_excl;	/* holding fs exclusive resources */
>  	struct rcu_head rcu;
> +#ifdef CONFIG_IPIPE
> +	void *ptd[IPIPE_ROOT_NPTDKEYS];
> +#endif
>  };
>  
>  static inline pid_t process_group(struct task_struct *tsk)
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/init/Kconfig linux-2.6.16.5-tcl1-ipipe/init/Kconfig
> --- linux-2.6.16.5-tcl1/init/Kconfig	2006-05-07 16:42:14.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/init/Kconfig	2006-07-16 15:01:24.000000000 +0200
> @@ -58,6 +58,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/init/main.c linux-2.6.16.5-tcl1-ipipe/init/main.c
> --- linux-2.6.16.5-tcl1/init/main.c	2006-07-15 20:06:03.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/init/main.c	2006-07-16 15:01:24.000000000 +0200
> @@ -488,6 +488,11 @@ asmlinkage void __init start_kernel(void
>  	hrtimers_init();
>  	softirq_init();
>  	time_init();
> +	/*
> +	 * We need to wait for the interrupt and time subsystems to be
> +	 * initialized before enabling the pipeline.
> +	 */
> + 	ipipe_init();
>  
>  	/*
>  	 * HACK ALERT! This is early. We're enabling the console before
> @@ -613,6 +618,7 @@ static void __init do_basic_setup(void)
>  #ifdef CONFIG_SYSCTL
>  	sysctl_init();
>  #endif
> +	ipipe_init_proc();
>  
>  	do_initcalls();
>  }
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/Makefile linux-2.6.16.5-tcl1-ipipe/kernel/Makefile
> --- linux-2.6.16.5-tcl1/kernel/Makefile	2006-05-07 16:42:15.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/Makefile	2006-07-16 15:01:24.000000000 +0200
> @@ -34,6 +34,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl
>  obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
>  obj-$(CONFIG_SECCOMP) += seccomp.o
>  obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
> +obj-$(CONFIG_IPIPE) += ipipe/
>  
>  ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
>  # According to Alan Modra <alan@domain.hid>, the -fno-omit-frame-pointer is
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/exit.c linux-2.6.16.5-tcl1-ipipe/kernel/exit.c
> --- linux-2.6.16.5-tcl1/kernel/exit.c	2006-05-07 16:42:15.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/exit.c	2006-07-16 15:01:24.000000000 +0200
> @@ -852,6 +852,7 @@ fastcall NORET_TYPE void do_exit(long co
>  		exit_itimers(tsk->signal);
>  		acct_process(code);
>  	}
> + 	ipipe_exit_notify(tsk);
>  	exit_mm(tsk);
>  
>  	exit_sem(tsk);
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/fork.c linux-2.6.16.5-tcl1-ipipe/kernel/fork.c
> --- linux-2.6.16.5-tcl1/kernel/fork.c	2006-07-13 15:49:59.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/fork.c	2006-07-16 15:15:30.000000000 +0200
> @@ -371,6 +371,7 @@ void fastcall __mmdrop(struct mm_struct 
>  void mmput(struct mm_struct *mm)
>  {
>  	if (atomic_dec_and_test(&mm->mm_users)) {
> +		ipipe_cleanup_notify(mm);
>  		exit_aio(mm);
>  		exit_mmap(mm);
>  		if (!list_empty(&mm->mmlist)) {
> @@ -1198,6 +1199,14 @@ static task_t *copy_process(unsigned lon
>  	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_namespace:
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/Kconfig linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Kconfig
> --- linux-2.6.16.5-tcl1/kernel/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Kconfig	2006-07-16 15:01:24.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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/Makefile linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Makefile
> --- linux-2.6.16.5-tcl1/kernel/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/Makefile	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,3 @@
> +
> +obj-$(CONFIG_IPIPE)	+= core.o generic.o
> +obj-$(CONFIG_IPIPE_TRACE) += tracer.o
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/core.c linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/core.c
> --- linux-2.6.16.5-tcl1/kernel/ipipe/core.c	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/core.c	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,1044 @@
> +/* -*- 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/sched.h>
> +#include <linux/module.h>
> +#include <linux/kallsyms.h>
> +#include <linux/interrupt.h>
> +#ifdef CONFIG_PROC_FS
> +#include <linux/proc_fs.h>
> +#endif	/* CONFIG_PROC_FS */
> +
> +static struct ipipe_domain ipipe_root =
> +	{ .cpudata = {[0 ... IPIPE_NR_CPUS-1] =
> +		{ .status = (1<<IPIPE_STALL_FLAG) } } };
> +
> +struct ipipe_domain *ipipe_root_domain = &ipipe_root;
> +
> +struct ipipe_domain *ipipe_percpu_domain[IPIPE_NR_CPUS] =
> +	{[0 ... IPIPE_NR_CPUS - 1] = &ipipe_root };
> +
> +ipipe_spinlock_t __ipipe_pipelock = IPIPE_SPIN_LOCK_UNLOCKED;
> +
> +LIST_HEAD(__ipipe_pipeline);
> +
> +unsigned long __ipipe_virtual_irq_map = 0;
> +
> +#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;
> +		}
> +	}
> +
> +	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 = 0;
> +
> +#ifdef CONFIG_SMP
> +	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = &__ipipe_ack_system_irq;
> +	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
> +	ipd->irqs[IPIPE_CRITICAL_IPI].cookie = NULL;
> +	/* Immediately handle in the current domain but *never* pass */
> +	ipd->irqs[IPIPE_CRITICAL_IPI].control =
> +		IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK;
> +#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);
> +
> +#ifdef CONFIG_SMP
> +	if (!__ipipe_pipeline_head_p(ipipe_root_domain))
> +		ipipe_put_cpu(flags);
> +#else /* CONFIG_SMP */
> +	if (__ipipe_pipeline_head_p(ipipe_root_domain))
> +		local_irq_disable_hw();
> +#endif /* CONFIG_SMP */
> +}
> +
> +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_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 (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 == 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;
> +	unsigned long flags;
> +	ipipe_declare_cpuid;
> +
> +	ipipe_lock_cpu(flags);
> +	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 == 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;
> +	unsigned long flags;
> +
> +	ipipe_lock_cpu(flags);
> +
> +	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 == 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 = 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 = 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;
> +
> +		ipipe_percpu_domain[cpuid] = next_domain;
> +
> +sync_stage:
> +		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
> +
> +		ipipe_load_cpuid();	/* Processor might have changed. */
> +
> +		if (ipipe_percpu_domain[cpuid] != next_domain)
> +			/*
> +			 * Something has changed the current domain under our
> +			 * feet, recycling the register set; take note.
> +			 */
> +			this_domain = ipipe_percpu_domain[cpuid];
> +	}
> +
> +	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_hw(&__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_hw(&__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_hw(&__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;
> +		}
> +
> +		if ((modemask & (IPIPE_SHARED_MASK | IPIPE_PASS_MASK)) ==
> +		    IPIPE_SHARED_MASK) {
> +			err = -EINVAL;
> +			goto unlock_and_exit;
> +		}
> +
> +		/* Wired interrupts can only be delivered to domains
> +		 * always heading the pipeline. */
> +
> +		if ((modemask & IPIPE_WIRED_MASK) != 0) {
> +			if ((modemask & (IPIPE_SHARED_MASK | 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_SHARED_MASK | IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK);
> +
> +	if (acknowledge == NULL) {
> +		if ((modemask & IPIPE_SHARED_MASK) == 0) {
> +			if (!ipipe_virtual_irq_p(irq)) {
> +				/* Acknowledge handler unspecified for a hw
> +				   interrupt -- this is ok in non-shared
> +				   management mode, but we will force the use
> +				   of the Linux-defined handler instead. */
> +				acknowledge = ipipe_root_domain->irqs[irq].acknowledge;
> +			}
> +		}
> +		else {
> +			/* A valid acknowledge handler to be called in shared mode
> +			   is required when declaring a shared IRQ. */
> +			err = -EINVAL;
> +			goto unlock_and_exit;
> +		}
> +	}
> +
> +	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) && (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_hw(&__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 (((setmask | clrmask) & IPIPE_SHARED_MASK) != 0)
> +		return -EINVAL;
> +
> +	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_hw(&__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_hw(&__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;
> +	struct list_head *pos, *npos;
> +	unsigned long flags;
> +	ipipe_declare_cpuid;
> +	int propagate = 1;
> +
> +	ipipe_lock_cpu(flags);
> +
> +	start_domain = this_domain = ipipe_percpu_domain[cpuid];
> +
> +	list_for_each_safe(pos,npos,&__ipipe_pipeline) {
> +
> +		next_domain = list_entry(pos,struct ipipe_domain,p_link);
> +
> +		/*
> +		 * 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.
> +		 */
> +		if (next_domain->evhand[event] != NULL)	{
> +			ipipe_percpu_domain[cpuid] = next_domain;
> +			ipipe_unlock_cpu(flags);
> +			propagate = !next_domain->evhand[event](event,start_domain,data);
> +			ipipe_lock_cpu(flags);
> +			if (ipipe_percpu_domain[cpuid] != next_domain)
> +				this_domain = 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)) {
> +			ipipe_percpu_domain[cpuid] = next_domain;
> +			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
> +			ipipe_load_cpuid();
> +			if (ipipe_percpu_domain[cpuid] != next_domain)
> +				this_domain = ipipe_percpu_domain[cpuid];
> +		}
> +
> +		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 = ipipe_percpu_domain[cpuid];
> +	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 (ipipe_percpu_domain[cpuid] == head)
> +		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 = 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);
> +		__clear_bit(level, &cpudata->irq_pending_hi);
> +
> +		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]);
> +
> +			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
> +			__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 */
> +
> +			__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
> +		}
> +	}
> +
> +	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
> +}
> +
> +#ifdef CONFIG_PROC_FS
> +
> +#include <linux/proc_fs.h>
> +
> +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_proc(char *page,
> +				    char **start,
> +				    off_t off, int count, int *eof, void *data)
> +{
> +	struct ipipe_domain *ipd = (struct ipipe_domain *)data;
> +	unsigned long ctlbits;
> +	unsigned irq, _irq;
> +	char *p = page;
> +	int len;
> +
> +	spin_lock(&__ipipe_pipelock);
> +
> +	if (test_bit(IPIPE_AHEAD_FLAG,&ipd->flags))
> +		p += sprintf(p, "Invariant head");
> +	else
> +		p += sprintf(p, "Priority=%d", ipd->priority);
> +
> +	p += sprintf(p, ", Id=0x%.8x\n", ipd->domid);
> +
> +	irq = 0;
> +
> +	while (irq < IPIPE_NR_IRQS) {
> +		ctlbits =
> +			(ipd->irqs[irq].
> +			 control & (IPIPE_HANDLE_MASK | IPIPE_PASS_MASK |
> +				    IPIPE_STICKY_MASK | IPIPE_WIRED_MASK));
> +		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.
> +			 */
> +			irq++;
> +			continue;
> +		}
> +
> +		if (ipipe_virtual_irq_p(irq)
> +		    && !test_bit(irq - IPIPE_VIRQ_BASE,
> +				 &__ipipe_virtual_irq_map)) {
> +			/* Non-allocated virtual IRQ; skip it. */
> +			irq++;
> +			continue;
> +		}
> +
> +		/*
> +		 * Attempt to group consecutive IRQ numbers having the
> +		 * same virtualization settings in a single line.
> +		 */
> +
> +		_irq = irq;
> +
> +		while (++_irq < IPIPE_NR_IRQS) {
> +			if (ipipe_virtual_irq_p(_irq) !=
> +			    ipipe_virtual_irq_p(irq)
> +			    || (ipipe_virtual_irq_p(_irq)
> +				&& !test_bit(_irq - IPIPE_VIRQ_BASE,
> +					     &__ipipe_virtual_irq_map))
> +			    || ctlbits != (ipd->irqs[_irq].
> +			     control & (IPIPE_HANDLE_MASK |
> +					IPIPE_PASS_MASK |
> +					IPIPE_STICKY_MASK)))
> +				break;
> +		}
> +
> +		if (_irq == irq + 1)
> +			p += sprintf(p, "irq%u: ", irq);
> +		else
> +			p += sprintf(p, "irq%u-%u: ", irq, _irq - 1);
> +
> +		/*
> +		 * 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)
> +				p += sprintf(p, "accepted");
> +			else if (ctlbits & IPIPE_WIRED_MASK)
> +				p += sprintf(p, "wired");
> +			else
> +				p += sprintf(p, "grabbed");
> +		} else if (ctlbits & IPIPE_PASS_MASK)
> +			p += sprintf(p, "passed");
> +		else
> +			p += sprintf(p, "discarded");
> +
> +		if (ctlbits & IPIPE_STICKY_MASK)
> +			p += sprintf(p, ", sticky");
> +
> +		if (ipipe_virtual_irq_p(irq))
> +			p += sprintf(p, ", virtual");
> +
> +		p += sprintf(p, "\n");
> +
> +		irq = _irq;
> +	}
> +
> +	spin_unlock(&__ipipe_pipelock);
> +
> +	len = p - page;
> +
> +	if (len <= off + count)
> +		*eof = 1;
> +
> +	*start = page + off;
> +
> +	len -= off;
> +
> +	if (len > count)
> +		len = count;
> +
> +	if (len < 0)
> +		len = 0;
> +
> +	return len;
> +}
> +
> +void __ipipe_add_domain_proc(struct ipipe_domain *ipd)
> +{
> +	create_proc_read_entry(ipd->name,0444,ipipe_proc_root,&__ipipe_common_info_proc,ipd);
> +}
> +
> +void __ipipe_remove_domain_proc(struct ipipe_domain *ipd)
> +{
> +	remove_proc_entry(ipd->name,ipipe_proc_root);
> +}
> +
> +void 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_init_trace_proc();
> +	__ipipe_add_domain_proc(ipipe_root_domain);
> +}
> +
> +#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_SYMBOL(ipipe_percpu_domain);
> +EXPORT_SYMBOL(ipipe_root_domain);
> +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_dispatch_wired);
> +EXPORT_SYMBOL(__ipipe_sync_stage);
> +EXPORT_SYMBOL(__ipipe_pipeline);
> +EXPORT_SYMBOL(__ipipe_pipelock);
> +EXPORT_SYMBOL(__ipipe_virtual_irq_map);
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/ipipe/generic.c linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/generic.c
> --- linux-2.6.16.5-tcl1/kernel/ipipe/generic.c	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/ipipe/generic.c	2006-07-16 15:01:24.000000000 +0200
> @@ -0,0 +1,396 @@
> +/* -*- linux-c -*-
> + * linux/kernel/ipipe/generic.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 services.
> + */
> +
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#ifdef CONFIG_PROC_FS
> +#include <linux/proc_fs.h>
> +#endif	/* CONFIG_PROC_FS */
> +
> +MODULE_DESCRIPTION("I-pipe");
> +MODULE_LICENSE("GPL");
> +
> +static int __ipipe_ptd_key_count;
> +
> +static unsigned long __ipipe_ptd_key_map;
> +
> +/* 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);
> +
> +		ipipe_percpu_domain[cpuid] = ipd;
> +		attr->entry();
> +		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 */
> +
> +#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);
> +
> +	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;
> +	int self = 0;
> +
> +	if (event & IPIPE_EVENT_SELF) {
> +		event &= ~IPIPE_EVENT_SELF;
> +		self = 1;
> +	}
> +
> +	if (event >= IPIPE_NR_EVENTS)
> +		return 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);
> +	}
> +
> +	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_hw(&__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_hw(&__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_hw(&__ipipe_pipelock,flags);
> +
> +	if (test_and_clear_bit(key,&__ipipe_ptd_key_map))
> +		__ipipe_ptd_key_count--;
> +
> +	spin_unlock_irqrestore_hw(&__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];
> +}
> +
> +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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/irq/handle.c linux-2.6.16.5-tcl1-ipipe/kernel/irq/handle.c
> --- linux-2.6.16.5-tcl1/kernel/irq/handle.c	2006-05-07 15:37:02.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/irq/handle.c	2006-07-16 15:01:24.000000000 +0200
> @@ -81,6 +81,17 @@ fastcall int handle_IRQ_event(unsigned i
>  {
>  	int ret, retval = 0, status = 0;
>  
> +#ifdef CONFIG_IPIPE
> +	/*
> +	 * If processing a timer tick, pass the original regs as
> +	 * collected during preemption and not our phony - always
> +	 * kernel-originated - frame, so that we don't wreck the
> +	 * profiling code.
> +	 */
> +	if (__ipipe_tick_irq == irq)
> +		regs = __ipipe_tick_regs + smp_processor_id();
> +#endif /* CONFIG_IPIPE */
> +
>  	if (!(action->flags & SA_INTERRUPT))
>  		local_irq_enable();
>  
> @@ -117,16 +128,20 @@ fastcall unsigned int __do_IRQ(unsigned 
>  		/*
>  		 * No locking required for CPU-local interrupts:
>  		 */
> +#ifndef CONFIG_IPIPE
>  		if (desc->handler->ack)
>  			desc->handler->ack(irq);
> +#endif /* !CONFIG_IPIPE */
>  		action_ret = handle_IRQ_event(irq, regs, desc->action);
>  		desc->handler->end(irq);
>  		return 1;
>  	}
>  
>  	spin_lock(&desc->lock);
> +#ifndef CONFIG_IPIPE
>  	if (desc->handler->ack)
>  		desc->handler->ack(irq);
> +#endif /* !CONFIG_IPIPE */
>  	/*
>  	 * REPLAY is when Linux resends an IRQ that was dropped earlier
>  	 * WAITING is used by probe to mark irqs that are being tested
> diff -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/printk.c linux-2.6.16.5-tcl1-ipipe/kernel/printk.c
> --- linux-2.6.16.5-tcl1/kernel/printk.c	2006-07-15 20:06:03.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/printk.c	2006-07-16 15:01:24.000000000 +0200
> @@ -520,6 +520,78 @@ __attribute__((weak)) unsigned long long
>   * 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_hw(&__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_hw(&__ipipe_printk_lock,flags);
> +	}
> +	while (__ipipe_printk_fill != lmax);
> +
> +	__ipipe_printk_fill = 0;
> +
> +	spin_unlock_irqrestore_hw(&__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_hw(&__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_hw(&__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;
> @@ -531,6 +603,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/sched.c linux-2.6.16.5-tcl1-ipipe/kernel/sched.c
> --- linux-2.6.16.5-tcl1/kernel/sched.c	2006-07-13 15:49:59.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/sched.c	2006-07-16 15:01:24.000000000 +0200
> @@ -2872,13 +2872,18 @@ asmlinkage void __sched schedule(void)
>  	unsigned long run_time;
>  	int cpu, idx, new_prio;
>  
> +#ifdef CONFIG_IPIPE
> +	if (unlikely(ipipe_current_domain != ipipe_root_domain)) {
> +		goto need_resched;
> +	}
> +#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 (likely(!current->exit_state)) {
> -		if (unlikely(in_atomic())) {
> +		if (unlikely(!(current->state & TASK_ATOMICSWITCH) && in_atomic())) {
>  			printk(KERN_ERR "scheduling while atomic: "
>  				"%s/0x%08x/%d\n",
>  				current->comm, preempt_count(), current->pid);
> @@ -2887,8 +2892,19 @@ asmlinkage void __sched schedule(void)
>  	}
>  	profile_hit(SCHED_PROFILING, __builtin_return_address(0));
>  
> +	if (unlikely(current->state & TASK_ATOMICSWITCH)) {
> +		current->state &= ~TASK_ATOMICSWITCH;
> +		goto preemption_off;
> +	}
>  need_resched:
>  	preempt_disable();
> +preemption_off:
> +#ifdef CONFIG_IPIPE
> +	if (unlikely(ipipe_current_domain != ipipe_root_domain)) {
> +		preempt_enable();
> +		return;
> +	}
> +#endif /* CONFIG_IPIPE */
>  	prev = current;
>  	release_kernel_lock(prev);
>  need_resched_nonpreemptible:
> @@ -3027,6 +3043,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
> @@ -3059,6 +3077,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 (ipipe_current_domain != ipipe_root_domain)
> +		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..
> @@ -3697,6 +3720,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);
>  		/*
> @@ -6165,3 +6189,50 @@ void set_curr_task(int cpu, task_t *p)
>  }
>  
>  #endif
> +
> +#ifdef CONFIG_IPIPE
> +
> +int ipipe_setscheduler_root (struct task_struct *p, int policy, int prio)
> +{
> +	prio_array_t *array;
> +	unsigned long flags;
> +	runqueue_t *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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/kernel/signal.c linux-2.6.16.5-tcl1-ipipe/kernel/signal.c
> --- linux-2.6.16.5-tcl1/kernel/signal.c	2006-07-13 15:49:59.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/kernel/signal.c	2006-07-16 15:01:24.000000000 +0200
> @@ -604,6 +604,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/lib/smp_processor_id.c linux-2.6.16.5-tcl1-ipipe/lib/smp_processor_id.c
> --- linux-2.6.16.5-tcl1/lib/smp_processor_id.c	2006-05-07 15:37:02.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/lib/smp_processor_id.c	2006-07-16 15:01:24.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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/lib/spinlock_debug.c linux-2.6.16.5-tcl1-ipipe/lib/spinlock_debug.c
> --- linux-2.6.16.5-tcl1/lib/spinlock_debug.c	2006-05-07 16:42:15.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/lib/spinlock_debug.c	2006-07-16 15:01:24.000000000 +0200
> @@ -10,6 +10,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/interrupt.h>
>  #include <linux/delay.h>
> +#include <linux/module.h>
>  
>  static void spin_bug(spinlock_t *lock, const char *msg)
>  {
> @@ -96,6 +97,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);
> @@ -111,12 +114,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)
>  {
>  	static long print_once = 1;
> @@ -167,6 +174,8 @@ void _raw_read_lock(rwlock_t *lock)
>  		__read_lock_debug(lock);
>  }
>  
> +EXPORT_SYMBOL(_raw_read_lock);
> +
>  int _raw_read_trylock(rwlock_t *lock)
>  {
>  	int ret = __raw_read_trylock(&lock->raw_lock);
> @@ -180,12 +189,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");
> @@ -241,6 +254,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);
> @@ -256,8 +271,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 -Naurdp -x '*~' -x '*.orig' -x '*.rej' linux-2.6.16.5-tcl1/mm/vmalloc.c linux-2.6.16.5-tcl1-ipipe/mm/vmalloc.c
> --- linux-2.6.16.5-tcl1/mm/vmalloc.c	2006-05-07 15:37:03.000000000 +0200
> +++ linux-2.6.16.5-tcl1-ipipe/mm/vmalloc.c	2006-07-16 15:01:24.000000000 +0200
> @@ -19,6 +19,7 @@
>  
>  #include <asm/uaccess.h>
>  #include <asm/tlbflush.h>
> +#include <asm/pgalloc.h>
>  
> 
>  DEFINE_RWLOCK(vmlist_lock);
> @@ -148,10 +149,14 @@ int map_vm_area(struct vm_struct *area, 
>  	BUG_ON(addr >= end);
>  	pgd = pgd_offset_k(addr);
>  	do {
> +		pgd_t oldpgd;
> +		memcpy(&oldpgd,pgd,sizeof(pgd_t));
>  		next = pgd_addr_end(addr, end);
>  		err = vmap_pud_range(pgd, addr, next, prot, pages);
>  		if (err)
>  			break;
> +		if (pgd_val(oldpgd) != pgd_val(*pgd))
> +			set_pgdir(addr, *pgd);
>  	} while (pgd++, addr = next, addr != end);
>  	flush_cache_vmap((unsigned long) area->addr, end);
>  	return err;
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core



  reply	other threads:[~2006-07-31  8:34 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-07 15:02 [Xenomai-core] Xenomai on PXA Danilo Levantesi
2006-07-07 20:32 ` Gilles Chanteperdrix
2006-07-11  6:20   ` Detlef Vollmann
2006-07-11 15:01     ` Stelian Pop
2006-07-12 13:13       ` Bart Jonkers
2006-07-11 15:02     ` Stelian Pop
2006-07-17 16:17     ` Gilles Chanteperdrix
2006-07-17 16:29       ` Philippe Gerum
2006-07-17 16:56         ` Gilles Chanteperdrix
2006-07-31  8:34           ` Bart Jonkers [this message]
2006-07-31  9:20             ` Detlef Vollmann
2006-07-31 10:33               ` Bart Jonkers
2006-07-31 11:08                 ` Detlef Vollmann
2006-08-02 13:09                   ` Gilles Chanteperdrix
2006-08-02 13:33                     ` Bart Jonkers
2006-08-02 13:56                       ` Gilles Chanteperdrix
2006-08-02 18:06                       ` Gilles Chanteperdrix
2006-08-03  9:12                         ` Bart Jonkers
2006-08-03 13:18                           ` Gilles Chanteperdrix
2006-08-03 14:56                             ` Philippe Gerum
2006-08-03 17:14                               ` Gilles Chanteperdrix
2006-08-04  6:10                                 ` Bart Jonkers
2006-08-04  6:10                                 ` Detlef Vollmann
2006-08-04  9:04                                   ` Philippe Gerum
2006-08-04 11:37                                   ` Gilles Chanteperdrix
2006-08-04 14:52                                 ` Bart Jonkers
2006-08-13 13:16                                   ` Gilles Chanteperdrix
2006-09-10  8:56                                     ` Detlef Vollmann
2006-09-10 12:19                                       ` Gilles Chanteperdrix
2006-09-10 16:31                                         ` Detlef Vollmann
2006-09-10 16:37                                           ` Gilles Chanteperdrix
2006-09-10 19:20                                             ` Detlef Vollmann
2006-09-10 19:42                                               ` Gilles Chanteperdrix
2006-08-03 11:23                         ` Bart Jonkers
2006-07-17 22:33       ` Danilo Levantesi
  -- strict thread matches above, loose matches on Subject: below --
2007-10-17 16:29 Patrick

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1154334859.9569.12.camel@domain.hid \
    --to=jonkersbart@domain.hid \
    --cc=gilles.chanteperdrix@xenomai.org \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.