--- 2.6.14/include/linux/hardirq.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/linux/hardirq.h	2005-10-31 10:15:18.000000000 +0100
@@ -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 */
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 static inline void account_user_vtime(struct task_struct *tsk)
--- 2.6.14/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/include/linux/ipipe.h	2006-01-06 12:43:53.000000000 +0100
@@ -0,0 +1,792 @@
+/* -*- 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_STALL_FLAG	0	/* Stalls a pipeline stage */
+#define IPIPE_SYNC_FLAG		1	/* The interrupt syncer is running for the domain */
+
+#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_EXCLUSIVE_FLAG	31	/* ipipe_catch_event() is the reason why. */
+
+#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_EXCLUSIVE_MASK	(1 << IPIPE_EXCLUSIVE_FLAG)
+#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_SYNC_MASK		(1 << IPIPE_SYNC_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);
+
+typedef int (*ipipe_irq_ackfn_t)(unsigned irq);
+
+#define IPIPE_SAME_HANDLER	((ipipe_irq_handler_t)(-1))
+
+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];
+
+	int (*evhand[IPIPE_NR_EVENTS])(unsigned event,
+				       struct ipipe_domain *from,
+				       void *data); /* Event handlers. */
+	unsigned long long evself;	/* Self-monitored event bits. */
+
+#ifdef CONFIG_IPIPE_STATS
+	struct ipipe_stats { /* All in timebase units. */
+		unsigned long long last_stall_date;
+		unsigned long last_stall_eip;
+		unsigned long max_stall_time;
+		unsigned long max_stall_eip;
+		struct ipipe_irq_stats {
+			unsigned long long last_receipt_date;
+			unsigned long max_delivery_time;
+		} irq_stats[IPIPE_NR_IRQS];
+	} ____cacheline_aligned_in_smp stats[IPIPE_NR_CPUS];
+#endif /* CONFIG_IPIPE_STATS */
+	unsigned long flags;
+	unsigned domid;
+	const char *name;
+	int priority;
+	void *pdd;
+};
+
+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_restore_root(unsigned long flags);
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head);
+
+int fastcall __ipipe_dispatch_event(unsigned event, void *data);
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+#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;
+}
+
+#ifdef CONFIG_IPIPE_STATS
+
+#define ipipe_mark_domain_stall(ipd, cpuid)			\
+do {								\
+	__label__ here;						\
+	struct ipipe_stats *ips;				\
+here:								\
+	ips = (ipd)->stats + cpuid;				\
+	if (ips->last_stall_date == 0) {			\
+		ipipe_read_tsc(ips->last_stall_date);		\
+		ips->last_stall_eip = (unsigned long)&&here;	\
+	}							\
+} while(0)
+
+static inline void ipipe_mark_domain_unstall(struct ipipe_domain *ipd, int cpuid)
+{ /* Called w/ hw interrupts off. */
+	struct ipipe_stats *ips = ipd->stats + cpuid;
+	unsigned long long t, d;
+
+	if (ips->last_stall_date != 0) {
+		ipipe_read_tsc(t);
+		d = t - ips->last_stall_date;
+		if (d > ips->max_stall_time) {
+			ips->max_stall_time = d;
+			ips->max_stall_eip = ips->last_stall_eip;
+		}
+		ips->last_stall_date = 0;
+	}
+}
+
+static inline void ipipe_mark_irq_receipt(struct ipipe_domain *ipd, unsigned irq, int cpuid)
+{
+	struct ipipe_stats *ips = ipd->stats + cpuid;
+
+	if (ips->irq_stats[irq].last_receipt_date == 0) {
+		ipipe_read_tsc(ips->irq_stats[irq].last_receipt_date);
+	}
+}
+
+static inline void ipipe_mark_irq_delivery(struct ipipe_domain *ipd, unsigned irq, int cpuid)
+{ /* Called w/ hw interrupts off. */
+	struct ipipe_stats *ips = ipd->stats + cpuid;
+	unsigned long long t, d;
+
+	if (ips->irq_stats[irq].last_receipt_date != 0) {
+		ipipe_read_tsc(t);
+		d = t - ips->irq_stats[irq].last_receipt_date;
+		ips->irq_stats[irq].last_receipt_date = 0;
+		if (d > ips->irq_stats[irq].max_delivery_time)
+			ips->irq_stats[irq].max_delivery_time = d;
+	}
+}
+
+static inline void ipipe_reset_stats (void)
+{
+	int cpu, irq;
+	for_each_online_cpu(cpu) {
+		ipipe_root_domain->stats[cpu].last_stall_date = 0LL;
+		for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+			ipipe_root_domain->stats[cpu].irq_stats[irq].last_receipt_date = 0LL;
+	}
+}
+
+#else /* !CONFIG_IPIPE_STATS */
+
+#define ipipe_mark_domain_stall(ipd,cpuid)	do { } while(0)
+#define ipipe_mark_domain_unstall(ipd,cpuid)	do { } while(0)
+#define ipipe_mark_irq_receipt(ipd,irq,cpuid)	do { } while(0)
+#define ipipe_mark_irq_delivery(ipd,irq,cpuid)	do { } while(0)
+#define ipipe_reset_stats()			do { } while(0)
+
+#endif /* CONFIG_IPIPE_STATS */
+
+/* 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);
+}
+
+static inline void 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);
+	ipipe_mark_domain_stall(ipd, cpuid);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_mark_domain_stall(ipd, cpuid);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+}
+
+static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	s = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+static inline unsigned long 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);
+	ipipe_mark_domain_stall(ipd, cpuid);
+
+	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);
+	ipipe_mark_domain_stall(ipd, cpuid);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+
+	return s;
+}
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+static inline unsigned long ipipe_test_and_unstall_pipeline_from(struct
+								 ipipe_domain
+								 *ipd)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	s = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_unstall_pipeline_from(ipd);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+static inline void ipipe_unstall_pipeline(void)
+{
+	ipipe_unstall_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_and_unstall_pipeline(void)
+{
+	return ipipe_test_and_unstall_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_pipeline(void)
+{
+	return ipipe_test_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline(void)
+{
+	return ipipe_test_and_stall_pipeline_from(ipipe_current_domain);
+}
+
+static inline void ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					       unsigned long flags)
+{
+	if (flags)
+		ipipe_stall_pipeline_from(ipd);
+	else
+		ipipe_unstall_pipeline_from(ipd);
+}
+
+static inline void ipipe_stall_pipeline(void)
+{
+	ipipe_stall_pipeline_from(ipipe_current_domain);
+}
+
+static inline void ipipe_restore_pipeline(unsigned long flags)
+{
+	ipipe_restore_pipeline_from(ipipe_current_domain, flags);
+}
+
+static inline void ipipe_restore_pipeline_nosync(struct ipipe_domain *ipd,
+						 unsigned long flags, 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 (flags) {
+		__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+		ipipe_mark_domain_stall(ipd,cpuid);
+	}
+	else {
+		__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+		ipipe_mark_domain_unstall(ipd,cpuid);
+	}
+}
+
+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);
+}
+
+int ipipe_catch_event(struct ipipe_domain *ipd,
+		      unsigned event,
+		      int (*handler)(unsigned event,
+				     struct ipipe_domain *ipd,
+				     void *data));
+
+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 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)
+
+#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_reset_stats()			do { } while(0)
+#define ipipe_trap_notify(t,r)			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 ipipe_irq_lock(irq)			do { } while(0)
+#define ipipe_irq_unlock(irq)			do { } while(0)
+
+#endif	/* CONFIG_IPIPE */
+
+#endif	/* !__LINUX_IPIPE_H */
--- 2.6.14/include/linux/preempt.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/linux/preempt.h	2005-10-31 10:15:18.000000000 +0100
@@ -13,41 +13,58 @@
   extern void fastcall add_preempt_count(int val);
   extern void fastcall sub_preempt_count(int val);
 #else
-# define add_preempt_count(val)	do { preempt_count() += (val); } while (0)
-# define sub_preempt_count(val)	do { preempt_count() -= (val); } while (0)
+#define add_preempt_count(val)	do { preempt_count() += (val); } while (0)
+#define sub_preempt_count(val)	do { preempt_count() -= (val); } while (0)
 #endif
 
-#define inc_preempt_count() add_preempt_count(1)
-#define dec_preempt_count() sub_preempt_count(1)
+#define inc_preempt_count()	add_preempt_count(1)
+#define dec_preempt_count()	sub_preempt_count(1)
 
-#define preempt_count()	(current_thread_info()->preempt_count)
+#define preempt_count()		(current_thread_info()->preempt_count)
 
 #ifdef CONFIG_PREEMPT
 
 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
+#define ipipe_preempt_guard()	1
+#endif
+
+#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(); \
-	preempt_check_resched(); \
+#define preempt_enable()						\
+do {									\
+	preempt_enable_no_resched();					\
+	preempt_check_resched();					\
 } while (0)
 
 #else
--- 2.6.14/include/linux/sched.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/linux/sched.h	2005-10-31 10:15:18.000000000 +0100
@@ -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>
@@ -813,6 +814,9 @@ struct task_struct {
 	int cpuset_mems_generation;
 #endif
 	atomic_t fs_excl;	/* holding fs exclusive resources */
+#ifdef CONFIG_IPIPE
+        void *ptd[IPIPE_ROOT_NPTDKEYS];
+#endif
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
--- 2.6.14/init/Kconfig	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/init/Kconfig	2006-01-05 10:18:54.000000000 +0100
@@ -69,6 +69,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.
--- 2.6.14/init/main.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/init/main.c	2005-12-29 15:25:54.000000000 +0100
@@ -402,6 +402,7 @@ static void noinline rest_init(void)
 	 */
 	schedule();
 
+ 	ipipe_reset_stats();
 	cpu_idle();
 } 
 
@@ -487,6 +488,11 @@ asmlinkage void __init start_kernel(void
 	init_timers();
 	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
@@ -611,6 +617,7 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
+	ipipe_init_proc();
 
 	/* Networking initialization needs a process context */ 
 	sock_init();
--- 2.6.14/kernel/Makefile	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/Makefile	2006-01-05 15:52:14.000000000 +0100
@@ -32,6 +32,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_SECCOMP) += seccomp.o
+obj-$(CONFIG_IPIPE) += ipipe/
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
--- 2.6.14/kernel/exit.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/exit.c	2005-10-31 10:15:18.000000000 +0100
@@ -846,6 +846,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);
--- 2.6.14/kernel/fork.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/fork.c	2005-10-31 10:15:18.000000000 +0100
@@ -1153,6 +1153,14 @@ static task_t *copy_process(unsigned lon
 	total_forks++;
 	write_unlock_irq(&tasklist_lock);
 	retval = 0;
+#ifdef CONFIG_IPIPE
+	{
+	int k;
+
+	for (k = 0; k < IPIPE_ROOT_NPTDKEYS; k++)
+	    p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_IPIPE */
 
 fork_out:
 	if (retval)
--- 2.6.14/kernel/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/kernel/ipipe/Kconfig	2005-12-30 16:26:19.000000000 +0100
@@ -0,0 +1,15 @@
+config IPIPE
+	bool "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
+
+config IPIPE_STATS
+	bool "Collect statistics"
+	depends on IPIPE
+	default n
+	---help---
+	  Activate this option if you want runtime statistics to be collected
+	  while the I-pipe is operating. This option adds a small overhead, but
+	  is useful to detect unexpected latency spots.
--- 2.6.14/kernel/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/kernel/ipipe/Makefile	2005-12-29 14:04:04.000000000 +0100
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_IPIPE)	+= core.o generic.o
+obj-$(CONFIG_IPIPE_TRACE) += tracer.o
--- 2.6.14/kernel/ipipe/core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/kernel/ipipe/core.c	2006-01-06 09:28:39.000000000 +0100
@@ -0,0 +1,827 @@
+/* -*- 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;
+
+struct 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.
+	 */
+
+	INIT_LIST_HEAD(&__ipipe_pipeline);
+
+	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 */
+	ipipe_mark_domain_stall(ipipe_root_domain,cpuid);
+}
+
+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);
+
+	ipipe_mark_domain_unstall(ipipe_root_domain, cpuid);
+
+	if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0)
+		__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+
+	local_irq_enable_hw();
+}
+
+unsigned long __ipipe_test_root(void)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	s = test_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+	s = test_and_set_bit(IPIPE_STALL_FLAG,
+			     &ipipe_root_domain->cpudata[cpuid].status);
+	ipipe_mark_domain_stall(ipipe_root_domain,cpuid);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+void fastcall __ipipe_restore_root(unsigned long flags)
+{
+	if (flags)
+		__ipipe_stall_root();
+	else
+		__ipipe_unstall_root();
+}
+
+/*
+ * 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 ipipe_domain *this_domain;
+	struct list_head *pos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	ipipe_mark_domain_unstall(ipd, cpuid);
+
+	this_domain = ipipe_percpu_domain[cpuid];
+
+	if (ipd == this_domain) {
+		if (ipd->cpudata[cpuid].irq_pending_hi != 0)
+			__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+
+		goto release_cpu_and_exit;
+	}
+
+	list_for_each(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_stage(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_stage(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+	}
+
+release_cpu_and_exit:
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_enable_hw();
+	else
+		ipipe_unlock_cpu(flags);
+}
+
+/*
+ * 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);
+
+	ipipe_mark_domain_unstall(this_domain, cpuid);
+
+	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_stage(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;
+
+	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;
+		}
+
+		if ((modemask & IPIPE_STICKY_MASK) != 0)
+			modemask |= IPIPE_HANDLE_MASK;
+	} else
+		modemask &=
+		    ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK |
+		      IPIPE_SHARED_MASK);
+
+	if (acknowledge == NULL) {
+		if ((modemask & IPIPE_SHARED_MASK) == 0)
+			/* Acknowledge handler unspecified -- 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_stage(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;
+}
+
+#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);
+
+	p += sprintf(p, "Priority=%d, Id=0x%.8x\n",
+		     ipd->priority, ipd->domid);
+	irq = 0;
+
+	while (irq < IPIPE_NR_IRQS) {
+		ctlbits =
+			(ipd->irqs[irq].
+			 control & (IPIPE_HANDLE_MASK | IPIPE_PASS_MASK |
+				    IPIPE_STICKY_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 "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
+				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;
+}
+
+#ifdef CONFIG_IPIPE_STATS
+
+static int __ipipe_stat_info_proc(char *page,
+				  char **start,
+				  off_t off, int count, int *eof, void *data)
+{
+	struct ipipe_domain *ipd = (struct ipipe_domain *)data;
+	int len = 0, cpu, irq;
+	char *p = page;
+
+	p += sprintf(p,"> STALL TIME:\n");
+
+	for_each_online_cpu(cpu) {
+		unsigned long eip = ipd->stats[cpu].max_stall_eip;
+		char namebuf[KSYM_NAME_LEN+1];
+		unsigned long offset, size, t;
+		const char *name;
+		char *modname;
+
+		name = kallsyms_lookup(eip, &size, &offset, &modname, namebuf);
+		t = ipipe_tsc2ns(ipd->stats[cpu].max_stall_time);
+
+		if (name) {
+			if (modname)
+				p += sprintf(p,"CPU%d  %12lu  (%s+%#lx [%s])\n",
+					     cpu,t,name,offset,modname);
+			else
+				p += sprintf(p,"CPU%d  %12lu  (%s+%#lx)\n",
+					     cpu,t,name,offset);
+		}
+		else
+			p += sprintf(p,"CPU%d  %12lu  (%lx)\n",
+				     cpu,t,eip);
+	}
+
+	p += sprintf(p,"> PROPAGATION TIME:\nIRQ");
+
+	for_each_online_cpu(cpu) {
+		p += sprintf(p,"         CPU%d",cpu);
+	}
+
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+
+		unsigned long long t = 0;
+
+		for_each_online_cpu(cpu) {
+			t += ipd->stats[cpu].irq_stats[irq].max_delivery_time;
+		}
+
+		if (!t)
+			continue;
+
+		p += sprintf(p,"\n%3d:",irq);
+
+		for_each_online_cpu(cpu) {
+			p += sprintf(p,"%13lu",
+				     ipipe_tsc2ns(ipd->stats[cpu].irq_stats[irq].max_delivery_time));
+		}
+	}
+
+	p += sprintf(p,"\n");
+
+	len = p - page - off;
+	if (len <= off + count) *eof = 1;
+	*start = page + off;
+	if (len > count) len = count;
+	if (len < 0) len = 0;
+
+	return len;
+}
+
+#endif /* CONFIG_IPIPE_STATS */
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd)
+{
+
+	create_proc_read_entry(ipd->name,0444,ipipe_proc_root,&__ipipe_common_info_proc,ipd);
+#ifdef CONFIG_IPIPE_STATS
+	{
+		char name[64];
+		snprintf(name,sizeof(name),"%s_stats",ipd->name);
+		create_proc_read_entry(name,0444,ipipe_proc_root,&__ipipe_stat_info_proc,ipd);
+	}
+#endif /* CONFIG_IPIPE_STATS */
+}
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd)
+{
+	remove_proc_entry(ipd->name,ipipe_proc_root);
+#ifdef CONFIG_IPIPE_STATS
+	{
+		char name[64];
+		snprintf(name,sizeof(name),"%s_stats",ipd->name);
+		remove_proc_entry(name,ipipe_proc_root);
+	}
+#endif /* CONFIG_IPIPE_STATS */
+}
+
+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_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_percpu_domain);
+EXPORT_SYMBOL(ipipe_root_domain);
+EXPORT_SYMBOL(__ipipe_unstall_root);
+EXPORT_SYMBOL(__ipipe_stall_root);
+EXPORT_SYMBOL(__ipipe_restore_root);
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+EXPORT_SYMBOL(__ipipe_test_root);
+EXPORT_SYMBOL(__ipipe_dispatch_event);
+EXPORT_SYMBOL(__ipipe_pipeline);
+EXPORT_SYMBOL(__ipipe_pipelock);
+EXPORT_SYMBOL(__ipipe_virtual_irq_map);
--- 2.6.14/kernel/ipipe/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/kernel/ipipe/generic.c	2006-01-06 09:27:24.000000000 +0100
@@ -0,0 +1,397 @@
+/* -*- 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;
+	}
+
+	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->priority = attr->priority;
+	ipd->domid = attr->domid;
+	ipd->pdd = attr->pdd;
+	ipd->flags = 0;
+
+#ifdef CONFIG_IPIPE_STATS
+	{
+		int cpu, irq;
+		for_each_online_cpu(cpu) {
+			ipd->stats[cpu].last_stall_date = 0LL;
+			for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+				ipd->stats[cpu].irq_stats[irq].last_receipt_date = 0LL;
+		}
+	}
+#endif /* CONFIG_IPIPE_STATS */
+
+	__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_stage(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_mark_irq_receipt(ipd, irq, cpuid);
+			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.
+ */
+int ipipe_catch_event(struct ipipe_domain *ipd,
+		      unsigned event,
+		      int (*handler)(unsigned event, struct ipipe_domain *ipd, void *data))
+{
+	int self = 0;
+
+	if (event & IPIPE_EVENT_SELF) {
+		event &= ~IPIPE_EVENT_SELF;
+		self = 1;
+	}
+
+	if (event >= IPIPE_NR_EVENTS)
+		return -EINVAL;
+
+	if (!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 0;
+}
+
+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);
--- 2.6.14/kernel/irq/handle.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/irq/handle.c	2005-10-31 10:15:18.000000000 +0100
@@ -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,14 +128,18 @@ fastcall unsigned int __do_IRQ(unsigned 
 		/*
 		 * No locking required for CPU-local interrupts:
 		 */
+#ifndef CONFIG_IPIPE
 		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
 	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
--- 2.6.14/kernel/printk.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/printk.c	2006-01-03 11:45:23.000000000 +0100
@@ -507,6 +507,78 @@ __attribute__((weak)) unsigned long long
  * is inspected when the actual printing occurs.
  */
 
+#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;
@@ -518,6 +590,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;
--- 2.6.14/kernel/sched.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/sched.c	2005-12-16 19:21:34.000000000 +0100
@@ -2855,6 +2855,11 @@ 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.
@@ -2872,6 +2877,12 @@ asmlinkage void __sched schedule(void)
 
 need_resched:
 	preempt_disable();
+#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:
@@ -3010,6 +3021,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
@@ -3042,6 +3055,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..
@@ -3670,6 +3688,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);
 		/*
@@ -5647,3 +5666,53 @@ 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;
+
+	if (prio < 1 || prio > MAX_RT_PRIO-1)
+		return -EINVAL;
+
+	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 */
--- 2.6.14/kernel/signal.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/kernel/signal.c	2005-10-31 10:15:18.000000000 +0100
@@ -601,6 +601,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.
--- 2.6.14/lib/smp_processor_id.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/lib/smp_processor_id.c	2005-10-31 10:15:18.000000000 +0100
@@ -12,6 +12,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;
 
--- 2.6.14/lib/spinlock_debug.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/lib/spinlock_debug.c	2005-11-02 19:21:20.000000000 +0100
@@ -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)
 {
@@ -93,6 +94,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);
@@ -108,12 +111,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;
@@ -162,6 +169,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);
@@ -175,12 +184,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");
@@ -235,6 +248,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);
@@ -250,8 +265,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);
--- 2.6.14/mm/vmalloc.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/mm/vmalloc.c	2005-10-31 10:15:18.000000000 +0100
@@ -18,6 +18,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, 
 	pgd = pgd_offset_k(addr);
 	spin_lock(&init_mm.page_table_lock);
 	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);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_cache_vmap((unsigned long) area->addr, end);
--- 2.6.14/arch/ia64/Kconfig	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/Kconfig	2005-10-31 10:27:22.000000000 +0100
@@ -298,6 +298,8 @@ config PREEMPT
 
 source "mm/Kconfig"
 
+source "kernel/ipipe/Kconfig"
+
 config IA32_SUPPORT
 	bool "Support for Linux/x86 binaries"
 	help
--- 2.6.14/arch/ia64/kernel/Makefile	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/Makefile	2005-10-31 10:15:17.000000000 +0100
@@ -9,6 +9,7 @@ obj-y := acpi.o entry.o efi.o efi_stub.o
 	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
 	 unwind.o mca.o mca_asm.o topology.o
 
+obj-$(CONFIG_IPIPE)		+= ipipe-core.o ipipe-root.o
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
 obj-$(CONFIG_IA64_HP_ZX1)	+= acpi-ext.o
--- 2.6.14/arch/ia64/kernel/entry.S	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/entry.S	2006-01-02 12:38:06.000000000 +0100
@@ -376,7 +376,7 @@ END(save_switch_stack)
  *	- b7 holds address to return to
  *	- must not touch r8-r11
  */
-ENTRY(load_switch_stack)
+GLOBAL_ENTRY(load_switch_stack)
 	.prologue
 	.altrp b7
 
@@ -682,6 +682,10 @@ END(ia64_ret_from_syscall)
  */
 ENTRY(ia64_leave_syscall)
 	PT_REGS_UNWIND_INFO(0)
+#ifdef CONFIG_IPIPE
+	cmp.ne pIFast,p0=r0,r0			// pIFast=0: regular exit from syscall
+.ipipe_leave_syscall:
+#endif /* CONFIG_IPIPE */
 	/*
 	 * work.need_resched etc. mustn't get changed by this CPU before it returns to
 	 * user- or fsys-mode, hence we disable interrupts early on.
@@ -722,9 +726,15 @@ ENTRY(ia64_leave_syscall)
 (p6)	and r15=TIF_WORK_MASK,r31		// any work other than TIF_SYSCALL_TRACE?
 	;;
 	ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE)	// load ar.bspstore (may be garbage)
+#ifdef CONFIG_IPIPE
+(pIFast) br.cond.spnt .ipipe_skip_work
+#endif /* CONFIG_IPIPE */
 (p6)	cmp4.ne.unc p6,p0=r15, r0		// any special work pending?
 (p6)	br.cond.spnt .work_pending_syscall
 	;;
+#ifdef CONFIG_IPIPE
+.ipipe_skip_work:
+#endif /* CONFIG_IPIPE */
 	// start restoring the state saved on the kernel stack (struct pt_regs):
 	ld8 r9=[r2],PT(CR_IPSR)-PT(R9)
 	ld8 r11=[r3],PT(CR_IIP)-PT(R11)
@@ -804,6 +814,10 @@ END(ia64_ret_from_ia32_execve)
 	// fall through
 #endif /* CONFIG_IA32_SUPPORT */
 GLOBAL_ENTRY(ia64_leave_kernel)
+#ifdef CONFIG_IPIPE
+	cmp.ne pIFast,p0=r0,r0	// pIFast=0: regular exit from interrupt
+.ipipe_leave_kernel:
+#endif /* CONFIG_IPIPE */
 	PT_REGS_UNWIND_INFO(0)
 	/*
 	 * work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -856,7 +870,13 @@ GLOBAL_ENTRY(ia64_leave_kernel)
 	;;
 	ld8 r29=[r2],16		// load b7
 	ld8 r30=[r3],16		// load ar.csd
+#ifdef CONFIG_IPIPE
+(pIFast)br.cond.sptk .ipipe_fast_path
 (p6)	br.cond.spnt .work_pending
+.ipipe_fast_path:	
+#else /* !CONFIG_IPIPE */
+(p6)	br.cond.spnt .work_pending
+#endif /* CONFIG_IPIPE */
 	;;
 	ld8 r31=[r2],16		// load ar.ssd
 	ld8.fill r8=[r3],16
@@ -1150,6 +1170,81 @@ skip_rbs_switch:
 
 END(ia64_leave_kernel)
 
+#ifdef CONFIG_IPIPE	
+
+GLOBAL_ENTRY(__ipipe_ret_from_intr)
+	/* We have just returned from ia64_handle_irq(). Clear pIFast
+	if we are expected to exit the interrupt context through the
+	regular Linux path, i.e. if we are running over the
+	non-stalled root domain. Otherwise, make sure that we will
+	take the fast IRQ return path (i.e. no pending work processed
+	after the IRQ has been handled). */
+	cmp.eq pIFast,p0=r8,r0
+	movl r14=.ipipe_leave_kernel
+	;; 
+	mov rp=r14
+	br.ret.sptk.many rp
+END(__ipipe_ret_from_intr)
+
+/*
+ * __ipipe_catch_syscall: Feed the Adeos pipeline with the syscall event.
+ * The value returned by __ipipe_syscall_root() will be passed
+ * unmodified to our caller. If zero is returned, the syscall is going
+ * to be executed as required. Otherwise, the syscall will be silently
+ * dropped.
+ */
+
+GLOBAL_ENTRY(__ipipe_catch_syscall)
+        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+        alloc loc1=ar.pfs,8,4,7,0
+        mov loc0=rp
+        .body
+        mov loc2=r15
+        mov loc3=b7
+        mov out0=r15
+        mov out1=in0
+        mov out2=in1
+        mov out3=in2
+        mov out4=in3
+        mov out5=in4
+        mov out6=in5
+        ;;
+        br.call.sptk.many rp=__ipipe_syscall_root
+	mov rp=loc0
+        mov ar.pfs=loc1
+        mov b7=loc3
+	mov r15=loc2
+        br.ret.sptk.many b7
+END(__ipipe_catch_syscall)
+
+/*
+ * __ipipe_bypass_syscall:
+ *
+ *	We branch here when some domain above Linux in the
+ *	pipeline intercepts and blocks the syscall. The error return
+ *	convention should have been applied to pt_regs.r8 and
+ *	pt_regs.r10 directly by the Adeos domain intercepting the
+ *	call.
+ *
+ *	r8 = return value from __ipipe_syscall_root()
+ */
+
+GLOBAL_ENTRY(__ipipe_bypass_syscall)
+
+	PT_REGS_UNWIND_INFO(0)
+	adds r2=PT(R8)+16,sp			// r2 = &pt_regs.r8
+	adds r3=PT(R10)+16,sp			// r3 = &pt_regs.r10
+	;; 
+	ld8 r8=[r2]				// load pt_regs.r8
+	;; 
+	ld8 r10=[r3]				// load pt_regs.r10
+	cmp.gt pIFast,p0=r8,r0			// r8 > 0 ? fast exit :	 std exit
+	br.cond.sptk .ipipe_leave_syscall
+
+END(__ipipe_bypass_syscall)
+	
+#endif /* CONFIG_IPIPE */
+
 ENTRY(handle_syscall_error)
 	/*
 	 * Some system calls (e.g., ptrace, mmap) can return arbitrary values which could
--- 2.6.14/arch/ia64/kernel/entry.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/entry.h	2005-10-31 10:15:17.000000000 +0100
@@ -9,6 +9,9 @@
 #define PRED_USER_STACK		3 /* returning to user-stacks? */
 #define PRED_SYSCALL		4 /* inside a system call? */
 #define PRED_NON_SYSCALL	5 /* complement of PRED_SYSCALL */
+#ifdef CONFIG_IPIPE
+#define PRED_FAST_IEXIT		22 /* fast interrupt return path? */
+#endif /* CONFIG_IPIPE */
 
 #ifdef __ASSEMBLY__
 # define PASTE2(x,y)	x##y
@@ -19,6 +22,9 @@
 # define pUStk		PASTE(p,PRED_USER_STACK)
 # define pSys		PASTE(p,PRED_SYSCALL)
 # define pNonSys	PASTE(p,PRED_NON_SYSCALL)
+#ifdef CONFIG_IPIPE
+# define pIFast		PASTE(p,PRED_FAST_IEXIT)
+#endif /* CONFIG_IPIPE */
 #endif
 
 #define PT(f)		(IA64_PT_REGS_##f##_OFFSET)
--- 2.6.14/arch/ia64/kernel/iosapic.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/iosapic.c	2005-10-31 10:15:17.000000000 +0100
@@ -188,11 +188,11 @@ gsi_to_irq (unsigned int gsi)
 	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
 	 * numbers...
 	 */
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
 	{
 		irq = _gsi_to_vector(gsi);
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 
 	return irq;
 }
@@ -277,7 +277,8 @@ mask_irq (unsigned int irq)
 	if (list_empty(&iosapic_intr_info[vec].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
+	ipipe_irq_lock(irq);
 	{
 		/* set only the mask bit */
 		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
@@ -287,7 +288,7 @@ mask_irq (unsigned int irq)
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 		}
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 }
 
 static void
@@ -303,7 +304,7 @@ unmask_irq (unsigned int irq)
 	if (list_empty(&iosapic_intr_info[vec].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
 	{
 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
 		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
@@ -312,7 +313,8 @@ unmask_irq (unsigned int irq)
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 		}
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	ipipe_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 }
 
 
@@ -344,7 +346,7 @@ iosapic_set_affinity (unsigned int irq, 
 	/* dest contains both id and eid */
 	high32 = dest << IOSAPIC_DEST_SHIFT;
 
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
 	{
 		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
 
@@ -364,7 +366,7 @@ iosapic_set_affinity (unsigned int irq, 
 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
 		}
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 #endif
 }
 
@@ -722,17 +724,17 @@ again:
 	 * shared interrupt, or we lost a race to register it),
 	 * don't touch the RTE.
 	 */
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
 	{
 		vector = gsi_to_vector(gsi);
 		if (vector > 0) {
 			rte = gsi_vector_to_rte(gsi, vector);
 			rte->refcnt++;
-			spin_unlock_irqrestore(&iosapic_lock, flags);
+			spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 			return vector;
 		}
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 
 	/* If vector is running out, we try to find a sharable vector */
 	vector = assign_irq_vector(AUTO_ASSIGN);
@@ -742,14 +744,14 @@ again:
 			return -ENOSPC;
 	}
 
-	spin_lock_irqsave(&irq_descp(vector)->lock, flags);
+	spin_lock_irqsave_hw(&irq_descp(vector)->lock, flags);
 	spin_lock(&iosapic_lock);
 	{
 		if (gsi_to_vector(gsi) > 0) {
 			if (list_empty(&iosapic_intr_info[vector].rtes))
 				free_irq_vector(vector);
 			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+			spin_unlock_irqrestore_hw(&irq_descp(vector)->lock, flags);
 			goto again;
 		}
 
@@ -772,7 +774,7 @@ again:
 		set_rte(gsi, vector, dest, mask);
 	}
 	spin_unlock(&iosapic_lock);
-	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+	spin_unlock_irqrestore_hw(&irq_descp(vector)->lock, flags);
 
 	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
 	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
@@ -807,7 +809,7 @@ iosapic_unregister_intr (unsigned int gs
 	vector = irq_to_vector(irq);
 
 	idesc = irq_descp(irq);
-	spin_lock_irqsave(&idesc->lock, flags);
+	spin_lock_irqsave_hw(&idesc->lock, flags);
 	spin_lock(&iosapic_lock);
 	{
 		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
@@ -862,7 +864,7 @@ iosapic_unregister_intr (unsigned int gs
 	}
  out:
 	spin_unlock(&iosapic_lock);
-	spin_unlock_irqrestore(&idesc->lock, flags);
+	spin_unlock_irqrestore_hw(&idesc->lock, flags);
 }
 
 /*
@@ -1064,7 +1066,7 @@ iosapic_remove (unsigned int gsi_base)
 	int index, err = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&iosapic_lock, flags);
+	spin_lock_irqsave_hw(&iosapic_lock, flags);
 	{
 		index = find_iosapic(gsi_base);
 		if (index < 0) {
@@ -1084,7 +1086,7 @@ iosapic_remove (unsigned int gsi_base)
 		iosapic_free(index);
 	}
  out:
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	spin_unlock_irqrestore_hw(&iosapic_lock, flags);
 	return err;
 }
 #endif /* CONFIG_HOTPLUG */
--- 2.6.14/arch/ia64/kernel/ipipe-core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/arch/ia64/kernel/ipipe-core.c	2006-01-04 17:37:45.000000000 +0100
@@ -0,0 +1,431 @@
+/*   -*- linux-c -*-
+ *   linux/arch/ia64/kernel/ipipe-core.c
+ *
+ *   Copyright (C) 2003-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-dependent I-PIPE core support for ia64.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+int __ipipe_tick_irq, __ipipe_host_tick_irq;
+
+volatile int __ipipe_timer_grabbed;
+
+volatile unsigned long __ipipe_itm_next[IPIPE_NR_CPUS];
+
+volatile unsigned long __ipipe_itm_delta[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);
+
+void __ipipe_send_IPI_allbutself(int vector)
+{
+	ipipe_declare_cpuid;
+	int cpu;
+
+	ipipe_load_cpuid();
+
+	for_each_online_cpu(cpu) {
+		if (cpu != cpuid)
+			platform_send_ipi(cpu, vector, IA64_IPI_DM_INT, 0);
+	}
+}
+
+/* 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. */
+			__ipipe_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);
+}
+
+/* __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 __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) {
+		/* Give a slight priority advantage to high-numbered IRQs
+		   like the virtual ones. */
+		level = ia64_fls(mask);
+		__clear_bit(level, &cpudata->irq_pending_hi);
+
+		while ((submask = cpudata->irq_pending_lo[level]) != 0) {
+			rank = ia64_fls(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]);
+				ipipe_mark_irq_delivery(ipd,irq,cpuid);
+			}
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+			ipipe_mark_domain_stall(ipd, cpuid);
+
+			if (ipd == ipipe_root_domain) {
+				struct pt_regs regs;
+				void (*handler) (unsigned, struct pt_regs *) =
+				    (__typeof(handler)) ipd->irqs[irq].handler;
+				ia64_psr(&regs)->cpl = 0;	/* CPL=0, kernel mode */
+				local_irq_enable_hw();
+				irq_enter();
+				handler(irq, &regs);
+				irq_exit();
+				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);
+			}
+
+#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);
+			ipipe_mark_domain_unstall(ipd, cpuid);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* 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 fastcall ipipe_trigger_irq(unsigned irq)
+{
+	struct pt_regs regs;
+	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);
+
+	ia64_psr(&regs)->cpl = 0;	/* CPL=0, kernel mode. */
+
+	__ipipe_handle_irq(-((long)irq), &regs);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = __ipipe_host_tick_irq;
+	info->archdep.tmfreq = ipipe_itc_freq();
+
+	return 0;
+}
+
+static void __ipipe_set_itm(void)
+{
+	unsigned long itm_next = ia64_get_itc();
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	if (__ipipe_itm_delta[cpuid] > 0) {
+		itm_next += __ipipe_itm_delta[cpuid];
+		ia64_set_itm(itm_next);
+	}
+
+	__ipipe_itm_next[cpuid] = itm_next;
+}
+
+int ipipe_tune_timer(unsigned long ns, int flags)
+{
+	int _cpuid, nr_cpus = num_online_cpus(), err = 0;
+	unsigned long x;
+	unsigned _hz;
+
+	x = ipipe_critical_enter(&__ipipe_set_itm);	/* Sync with all CPUs */
+
+	__ipipe_timer_grabbed = !!(flags & IPIPE_GRAB_TIMER);
+
+	if (!__ipipe_timer_grabbed) {
+		if (flags & IPIPE_RESET_TIMER)
+			_hz = HZ;
+		else {
+			_hz = 1000000000 / ns;
+
+			if (_hz < HZ) {
+				_hz = HZ;
+				err = -EINVAL;
+			}
+		}
+
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			__ipipe_itm_delta[_cpuid] =
+			    (cpu_data(_cpuid)->itc_freq + _hz / 2) / _hz;
+	} else
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			__ipipe_itm_delta[_cpuid] = 0;
+
+	__ipipe_set_itm();
+
+	ipipe_critical_exit(x);
+
+	return err;
+}
+
+#ifdef CONFIG_SMP
+
+cpumask_t __ipipe_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+
+{
+	cpumask_t oldmask = irq_affinity[irq];
+
+	if (irq_descp(irq)->handler->set_affinity == NULL)
+		return CPU_MASK_NONE;
+
+	if (cpus_empty(cpumask))
+		return oldmask; /* Return mask value -- no change. */
+
+	cpus_and(cpumask,cpumask,cpu_online_map);
+
+	if (cpus_empty(cpumask))
+		return CPU_MASK_NONE;	/* Error -- bad mask value. */
+
+	irq_affinity[irq] = cpumask;
+	irq_descp(irq)->handler->set_affinity(irq,cpumask);
+	return oldmask;
+}
+
+int fastcall __ipipe_send_ipi (unsigned ipi, cpumask_t cpumask)
+
+{
+	unsigned long flags;
+	ipipe_declare_cpuid;
+	int cpu, self;
+
+	if (ipi != IPIPE_SERVICE_IPI0 &&
+	    ipi != IPIPE_SERVICE_IPI1 &&
+	    ipi != IPIPE_SERVICE_IPI2 &&
+	    ipi != IPIPE_SERVICE_IPI3 &&
+	    ipi != __ipipe_host_tick_irq)
+		return -EINVAL;
+
+	ipipe_lock_cpu(flags);
+
+	self = cpu_isset(cpuid,cpumask);
+	cpu_clear(cpuid,cpumask);
+
+	if (!cpus_empty(cpumask)) {
+		for_each_online_cpu(cpu) {
+			if (cpu_isset(cpu,cpumask) && cpu_online(cpu))
+				platform_send_ipi(cpu,irq_to_vector(ipi),IA64_IPI_DM_INT,0);
+		}
+	}
+
+	if (self)
+		ipipe_trigger_irq(ipi);
+
+	ipipe_unlock_cpu(flags);
+
+	return 0;
+}
+
+#endif /* CONFIG_SMP */
+
+EXPORT_SYMBOL(__ipipe_sync_stage);
+EXPORT_SYMBOL(__ipipe_tick_irq);
+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);
--- 2.6.14/arch/ia64/kernel/ipipe-root.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/arch/ia64/kernel/ipipe-root.c	2006-01-06 12:42:57.000000000 +0100
@@ -0,0 +1,284 @@
+/*   -*- linux-c -*-
+ *   linux/arch/ia64/kernel/ipipe-root.c
+ *
+ *   Copyright (C) 2003-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-dependent I-pipe support for ia64.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/iosapic.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+
+static void __ipipe_enable_sync(void)
+{
+	int cpuid = ipipe_processor_id();
+	__ipipe_itm_next[cpuid] = local_cpu_data->itm_next;
+	__ipipe_itm_delta[cpuid] = local_cpu_data->itm_delta;
+
+}
+
+int __ipipe_ack_system_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_descp(irq);
+	desc->handler->ack(irq); /* We don't hold desc->lock on purpose. */
+
+	return 1;
+}
+
+/* __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);
+
+	for (irq = IA64_MIN_VECTORED_IRQ; irq <= IA64_MAX_VECTORED_IRQ; irq++)
+		/* Fails for IPIPE_CRITICAL_IPI but that's ok. */
+		ipipe_virtualize_irq(ipipe_root_domain,
+				     irq,
+				     (ipipe_irq_handler_t)&__do_IRQ, NULL,
+				     &__ipipe_ack_system_irq,
+				     IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	__ipipe_host_tick_irq = __ia64_local_vector_to_irq(IA64_TIMER_VECTOR);
+	__ipipe_tick_irq = __ipipe_host_tick_irq;
+
+	__ipipe_itm_next[ipipe_processor_id()] = local_cpu_data->itm_next;
+	__ipipe_itm_delta[ipipe_processor_id()] = local_cpu_data->itm_delta;
+
+	ipipe_critical_exit(flags);
+}
+
+/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must
+   be called with local hw interrupts disabled. */
+
+static inline void __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_stage(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_stage(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+}
+
+void __ipipe_handle_irq(long irq, struct pt_regs *regs)
+{
+	struct list_head *head, *pos;
+	ipipe_declare_cpuid;
+	int m_ack, s_ack;
+
+	ipipe_load_cpuid();
+
+	if (irq < 0) {
+		m_ack = s_ack = 1;
+		irq = -irq;
+	} else
+		m_ack = s_ack = 0;
+
+	if (test_bit
+	    (IPIPE_STICKY_FLAG, &ipipe_percpu_domain[cpuid]->irqs[irq].control))
+		head = &ipipe_percpu_domain[cpuid]->p_link;
+	else
+		head = __ipipe_pipeline.next;
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+		    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, &_ipd->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. */
+
+			_ipd->cpudata[cpuid].irq_counters[irq].total_hits++;
+			_ipd->cpudata[cpuid].irq_counters[irq].pending_hits++;
+			__ipipe_set_irq_bit(_ipd, cpuid, irq);
+			ipipe_mark_irq_receipt(_ipd, irq, cpuid);
+
+			/* Always get the first master acknowledge available. Once
+			   we've got it, allow slave acknowledge handlers to run
+			   (until one of them stops us). */
+
+			if (!m_ack)
+				m_ack = _ipd->irqs[irq].acknowledge(irq);
+			else if (test_bit
+				 (IPIPE_SHARED_FLAG, &_ipd->irqs[irq].control)
+				 && !s_ack)
+				s_ack = _ipd->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, &_ipd->irqs[irq].control))
+			break;
+
+		pos = _ipd->p_link.next;
+	}
+
+	if (irq == __ipipe_tick_irq) {
+		unsigned long new_itm = __ipipe_itm_next[cpuid];
+
+		if (!__ipipe_timer_grabbed) {
+			do {
+				new_itm += __ipipe_itm_delta[cpuid];
+				ia64_set_itm(new_itm);
+			}
+			while (time_after_eq(ia64_get_itc(), new_itm));
+
+			__ipipe_itm_next[cpuid] = new_itm;
+		}
+
+		__ipipe_tick_regs[cpuid].cr_iip = regs->cr_iip;
+		__ipipe_tick_regs[cpuid].cr_ipsr = regs->cr_ipsr;
+		__ipipe_tick_regs[cpuid].pr = regs->pr;
+	}
+
+	/* 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_syscall_root (unsigned long sc,
+				     unsigned long a0,
+				     unsigned long a1,
+				     unsigned long a2,
+				     unsigned long a3,
+				     unsigned long a4,
+				     unsigned long a5)
+{
+	struct pt_regs *regs, _regs;
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	/* 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))
+		return 0;
+
+	_regs.r15 = sc;
+	_regs.r16 = a0;
+	_regs.r17 = a1;
+	_regs.r18 = a2;
+	_regs.r19 = a3;
+	_regs.r20 = a4;
+	_regs.r21 = a5;
+
+	if (__ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,&_regs) > 0) {
+		regs = ia64_task_regs(current);
+		regs->r8 = _regs.r8;
+		regs->r10 = _regs.r10;
+
+		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_stage(IPIPE_IRQMASK_VIRT);
+			ipipe_unlock_cpu(flags);
+			return -1;
+		}
+		return 1;
+	}
+
+	return 0;
+}
+
+extern void show_stack(struct task_struct *task, unsigned long *sp);
+EXPORT_SYMBOL(show_stack);
+#include <asm/hw_irq.h>
+EXPORT_SYMBOL(irq_desc);
+extern struct ia64_ctx ia64_ctx;
+EXPORT_SYMBOL(ia64_ctx);
+DECLARE_PER_CPU(u8,ia64_need_tlb_flush);
+EXPORT_SYMBOL(per_cpu__ia64_need_tlb_flush);
+void wrap_mmu_context(struct mm_struct *mm);
+EXPORT_SYMBOL(wrap_mmu_context);
+void load_switch_stack(void);
+EXPORT_SYMBOL(load_switch_stack);
+void save_switch_stack(void);
+EXPORT_SYMBOL(save_switch_stack);
+EXPORT_SYMBOL(ia64_load_extra);
+EXPORT_SYMBOL(ia64_save_extra);
+EXPORT_SYMBOL(ia64_switch_to);
+#ifdef CONFIG_PERFMON
+#include <asm/perfmon.h>
+EXPORT_PER_CPU_SYMBOL(pfm_syst_info);
+#endif /* CONFIG_PERFMON */
+#include <asm/processor.h>
+EXPORT_SYMBOL(__ia64_init_fpu);
+EXPORT_SYMBOL(__ia64_load_fpu);
+EXPORT_SYMBOL(__ia64_save_fpu);
--- 2.6.14/arch/ia64/kernel/irq_ia64.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/irq_ia64.c	2005-10-31 10:15:17.000000000 +0100
@@ -99,6 +99,38 @@ free_irq_vector (int vector)
  * interrupt. This branches to the correct hardware IRQ handler via
  * function ptr.
  */
+#ifdef CONFIG_IPIPE
+int ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
+{
+	unsigned long saved_tpr;
+	ipipe_declare_cpuid;
+
+	saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
+	ia64_srlz_d();
+	while (vector != IA64_SPURIOUS_INT_VECTOR) {
+		if (!IS_RESCHEDULE(vector)) {
+			ia64_setreg(_IA64_REG_CR_TPR, vector);
+			ia64_srlz_d();
+
+			/* Send EOI _before_ running the handlers,
+			   otherwise, we would get massive jitter in
+			   domains pipelined above the Linux one. */
+
+			local_irq_disable_hw();
+			ia64_setreg(_IA64_REG_CR_TPR,saved_tpr);
+			ia64_eoi();
+			__ipipe_handle_irq(local_vector_to_irq(vector),regs);
+		} else
+			ia64_eoi();
+		vector = ia64_get_ivr();
+	}
+
+	ipipe_load_cpuid();
+
+        return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
+		!test_bit(IPIPE_STALL_FLAG,&ipipe_root_domain->cpudata[cpuid].status));
+}
+#else /* !CONFIG_IPIPE */
 void
 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
 {
@@ -165,6 +197,7 @@ ia64_handle_irq (ia64_vector vector, str
 	 */
 	irq_exit();
 }
+#endif /* CONFIG_IPIPE */
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
--- 2.6.14/arch/ia64/kernel/ivt.S	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/ivt.S	2006-01-01 19:00:14.000000000 +0100
@@ -790,6 +790,13 @@ ENTRY(break_fault)
 (p10)	br.cond.spnt.many ia64_ret_from_syscall	// B    return if bad call-frame or r15 is a NaT
 
 (p15)	ssm psr.i				// M2   restore psr.i
+#ifdef CONFIG_IPIPE
+	br.call.sptk.many b7=__ipipe_catch_syscall
+	cmp.eq p0,p7=r8,r0
+	;; 
+(p7)	br.cond.spnt __ipipe_bypass_syscall
+	;; 
+#endif /* CONFIG_IPIPE */
 (p14)	br.call.sptk.many b6=b6			// B    invoke syscall-handker (ignore return addr)
 	br.cond.spnt.many ia64_trace_syscall	// B	do syscall-tracing thingamagic
 	// NOT REACHED
@@ -825,7 +832,11 @@ ENTRY(interrupt)
 	add out1=16,sp		// pass pointer to pt_regs as second arg
 	;;
 	srlz.d			// make sure we see the effect of cr.ivr
+#ifdef CONFIG_IPIPE
+	movl r14=__ipipe_ret_from_intr
+#else /* !CONFIG_IPIPE */
 	movl r14=ia64_leave_kernel
+#endif /* CONFIG_IPIPE */
 	;;
 	mov rp=r14
 	br.call.sptk.many b6=ia64_handle_irq
--- 2.6.14/arch/ia64/kernel/process.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/process.c	2005-10-31 10:15:17.000000000 +0100
@@ -283,6 +283,7 @@ cpu_idle (void)
 			idle = pm_idle;
 			if (!idle)
 				idle = default_idle;
+ 			ipipe_suspend_domain();
 			(*idle)();
 		}
 
--- 2.6.14/arch/ia64/kernel/time.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/time.c	2005-10-31 10:15:17.000000000 +0100
@@ -62,7 +62,18 @@ timer_interrupt (int irq, void *dev_id, 
 
 	platform_timer_interrupt(irq, dev_id, regs);
 
+#ifdef CONFIG_IPIPE
+	{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags);
+	new_itm = __ipipe_itm_next[cpuid] - __ipipe_itm_delta[cpuid];
+	ipipe_put_cpu(flags);
+	}
+#else /* !CONFIG_IPIPE */
 	new_itm = local_cpu_data->itm_next;
+#endif /* CONFIG_IPIPE */
 
 	if (!time_after(ia64_get_itc(), new_itm))
 		printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
@@ -93,6 +104,7 @@ timer_interrupt (int irq, void *dev_id, 
 			break;
 	}
 
+#ifndef CONFIG_IPIPE
 	do {
 		/*
 		 * If we're too close to the next clock tick for
@@ -108,6 +120,7 @@ timer_interrupt (int irq, void *dev_id, 
 		ia64_set_itm(new_itm);
 		/* double check, in case we got hit by a (slow) PMI: */
 	} while (time_after_eq(ia64_get_itc(), new_itm));
+#endif /* !CONFIG_IPIPE */
 	return IRQ_HANDLED;
 }
 
--- 2.6.14/arch/ia64/kernel/traps.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/kernel/traps.c	2006-01-06 12:42:46.000000000 +0100
@@ -445,6 +445,36 @@ ia64_illegal_op_fault (unsigned long ec,
 	return rv;
 }
 
+#ifdef CONFIG_IPIPE
+static inline int __ipipe_pipeline_trap(int trap,
+					unsigned long vector,
+					unsigned long isr,
+					unsigned long ifa,
+					struct pt_regs *regs)
+{
+	ia64trapinfo_t info;
+
+	if (!__ipipe_event_pipelined_p(trap))
+		return 0;
+
+	info.vector = vector;
+	info.isr = isr;
+	info.address = ifa;
+	info.regs = regs;
+
+	return __ipipe_dispatch_event(trap,&info);
+}
+#else  /* !CONFIG_IPIPE */
+static inline int __ipipe_pipeline_trap(int trap,
+					unsigned long vector,
+					unsigned long isr,
+					unsigned long ifa,
+					struct pt_regs *regs)
+{
+	return 0;
+}
+#endif /* CONFIG_IPIPE */
+
 void __kprobes
 ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
 	    unsigned long iim, unsigned long itir, long arg5, long arg6,
@@ -478,6 +508,8 @@ ia64_fault (unsigned long vector, unsign
 
 	switch (vector) {
 	      case 24: /* General Exception */
+		if (__ipipe_pipeline_trap(IPIPE_GENEX_TRAP,vector,isr,ifa,&regs))
+			return;
 		code = (isr >> 4) & 0xf;
 		sprintf(buf, "General Exception: %s%s", reason[code],
 			(code == 3) ? ((isr & (1UL << 37))
@@ -493,6 +525,8 @@ ia64_fault (unsigned long vector, unsign
 		break;
 
 	      case 25: /* Disabled FP-Register */
+		if (__ipipe_pipeline_trap(IPIPE_FPDIS_TRAP,vector,isr,ifa,&regs))
+			return;
 		if (isr & 2) {
 			disabled_fph_fault(&regs);
 			return;
@@ -501,6 +535,8 @@ ia64_fault (unsigned long vector, unsign
 		break;
 
 	      case 26: /* NaT Consumption */
+		if (__ipipe_pipeline_trap(IPIPE_NATC_TRAP,vector,isr,ifa,&regs))
+			return;
 		if (user_mode(&regs)) {
 			void __user *addr;
 
@@ -531,6 +567,8 @@ ia64_fault (unsigned long vector, unsign
 		break;
 
 	      case 31: /* Unsupported Data Reference */
+		if (__ipipe_pipeline_trap(IPIPE_UDREF_TRAP,vector,isr,ifa,&regs))
+			return;
 		if (user_mode(&regs)) {
 			siginfo.si_signo = SIGILL;
 			siginfo.si_code = ILL_ILLOPN;
@@ -548,6 +586,8 @@ ia64_fault (unsigned long vector, unsign
 	      case 29: /* Debug */
 	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
+		if (__ipipe_pipeline_trap(IPIPE_DEBUG_TRAP,vector,isr,ifa,&regs))
+			return;
 		if (fsys_mode(current, &regs)) {
 			extern char __kernel_syscall_via_break[];
 			/*
@@ -595,6 +635,8 @@ ia64_fault (unsigned long vector, unsign
 
 	      case 32: /* fp fault */
 	      case 33: /* fp trap */
+		if (__ipipe_pipeline_trap(IPIPE_FPERR_TRAP,vector,isr,ifa,&regs))
+			return;
 		result = handle_fpu_swa((vector == 32) ? 1 : 0, &regs, isr);
 		if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
 			siginfo.si_signo = SIGFPE;
@@ -619,6 +661,8 @@ ia64_fault (unsigned long vector, unsign
 			ia64_psr(&regs)->lp = 0;
 			return;
 		} else {
+			if (__ipipe_pipeline_trap(IPIPE_UINST_TRAP,vector,isr,ifa,&regs))
+				return;
 			/* Unimplemented Instr. Address Trap */
 			if (user_mode(&regs)) {
 				siginfo.si_signo = SIGILL;
@@ -636,6 +680,8 @@ ia64_fault (unsigned long vector, unsign
 		break;
 
 	      case 45:
+		if (__ipipe_pipeline_trap(IPIPE_IA32_TRAP,vector,isr,ifa,&regs))
+			return;
 #ifdef CONFIG_IA32_SUPPORT
 		if (ia32_exception(&regs, isr) == 0)
 			return;
@@ -647,6 +693,8 @@ ia64_fault (unsigned long vector, unsign
 		break;
 
 	      case 46:
+		if (__ipipe_pipeline_trap(IPIPE_IA32_TRAP,vector,isr,ifa,&regs))
+			return;
 #ifdef CONFIG_IA32_SUPPORT
 		if (ia32_intercept(&regs, isr) == 0)
 			return;
@@ -658,10 +706,14 @@ ia64_fault (unsigned long vector, unsign
 		return;
 
 	      case 47:
+		if (__ipipe_pipeline_trap(IPIPE_IA32_TRAP,vector,isr,ifa,&regs))
+			return;
 		sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16);
 		break;
 
 	      default:
+		if (__ipipe_pipeline_trap(IPIPE_GENERIC_TRAP,vector,isr,ifa,&regs))
+			return;
 		sprintf(buf, "Fault %lu", vector);
 		break;
 	}
--- 2.6.14/arch/ia64/mm/fault.c	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/arch/ia64/mm/fault.c	2006-01-06 12:43:04.000000000 +0100
@@ -86,6 +86,17 @@ ia64_do_page_fault (unsigned long addres
 	struct siginfo si;
 	unsigned long mask;
 
+#ifdef CONFIG_IPIPE
+	if (__ipipe_event_pipelined_p(IPIPE_PF_TRAP)) {
+	    ia64trapinfo_t info;
+	    info.vector = 0;
+	    info.isr = isr;
+	    info.address = address;
+	    info.regs = regs;
+	    if (__ipipe_dispatch_event(IPIPE_PF_TRAP,&info))
+		return;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	/*
 	 * If we're in an interrupt or have no user context, we must not take the fault..
 	 */
--- 2.6.14/include/asm-ia64/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/include/asm-ia64/ipipe.h	2006-01-07 09:47:56.000000000 +0100
@@ -0,0 +1,174 @@
+/*   -*- linux-c -*-
+ *   include/asm-ia64/ipipe.h
+ *
+ *   Copyright (C) 2003-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 __IA64_IPIPE_H
+#define __IA64_IPIPE_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IPIPE
+
+#include <asm/types.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <linux/cpumask.h>
+#include <linux/thread_info.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#define IPIPE_ARCH_STRING	"1.1-02"
+#define IPIPE_MAJOR_NUMBER	1
+#define IPIPE_MINOR_NUMBER	1
+#define IPIPE_PATCH_NUMBER	2
+
+#define IPIPE_SERVICE_VECTOR0  0xf1
+#define IPIPE_SERVICE_IPI0     __ia64_local_vector_to_irq(IPIPE_SERVICE_VECTOR0)
+#define IPIPE_SERVICE_VECTOR1  0xf2
+#define IPIPE_SERVICE_IPI1     __ia64_local_vector_to_irq(IPIPE_SERVICE_VECTOR1)
+#define IPIPE_SERVICE_VECTOR2  0xf3
+#define IPIPE_SERVICE_IPI2     __ia64_local_vector_to_irq(IPIPE_SERVICE_VECTOR2)
+#define IPIPE_SERVICE_VECTOR3  0xf4
+#define IPIPE_SERVICE_IPI3     __ia64_local_vector_to_irq(IPIPE_SERVICE_VECTOR3)
+
+#define IPIPE_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	6	/* 2^6 for 64 bits arch. */
+
+#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;				\
+	} )
+
+/* ia64 traps */
+#define IPIPE_GENEX_TRAP	0
+#define IPIPE_FPDIS_TRAP	1
+#define IPIPE_NATC_TRAP		2
+#define IPIPE_UDREF_TRAP	3
+#define IPIPE_DEBUG_TRAP	4
+#define IPIPE_FPERR_TRAP	5
+#define IPIPE_UINST_TRAP	6
+#define IPIPE_IA32_TRAP		7
+#define IPIPE_GENERIC_TRAP	8
+#define IPIPE_PF_TRAP		9
+#define IPIPE_NR_FAULTS		10
+
+typedef struct ia64trapinfo {
+
+    unsigned long vector;
+    unsigned long isr;
+    unsigned long address;
+    struct pt_regs *regs;
+
+} ia64trapinfo_t;
+
+/* 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_LAST_EVENT	IPIPE_EVENT_EXIT
+#define IPIPE_NR_EVENTS		(IPIPE_LAST_EVENT + 1)
+
+#ifdef CONFIG_SMP
+
+#include <asm/smp.h>
+#include <asm/gcc_intrin.h>
+
+#define IPIPE_CRITICAL_VECTOR  0xf9
+#define IPIPE_CRITICAL_IPI     __ia64_local_vector_to_irq(IPIPE_CRITICAL_VECTOR)
+#define ipipe_processor_id()   (current_thread_info()->cpu)
+
+#else /* !CONFIG_SMP */
+#define ipipe_processor_id()    0
+#endif	/* CONFIG_SMP */
+
+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;
+};
+
+#define ipipe_read_tsc(t) \
+	__asm__ __volatile__("mov %0=ar.itc;;" : "=r"(t) :: "memory")
+
+#define ipipe_cpu_freq()	local_cpu_data->proc_freq
+#define ipipe_itc_freq()	local_cpu_data->itc_freq
+#define ipipe_tsc2ns(t)		(((t) * 1000) / (ipipe_cpu_freq() / 1000000))
+
+/* Private interface -- Internal use only */
+
+#define __ipipe_check_platform() do { } while(0)
+
+#define __ipipe_init_platform()	 do { } while(0)
+
+#define __ipipe_enable_irq(irq)		irq_descp(irq)->handler->enable(irq)
+
+#define __ipipe_disable_irq(irq)	irq_descp(irq)->handler->disable(irq)
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_sync_stage(unsigned long syncmask);
+
+int __ipipe_ack_system_irq(unsigned irq);
+
+void __ipipe_handle_irq(long irq,
+			struct pt_regs *regs);
+
+void __ipipe_do_critical_sync(unsigned irq);
+
+extern int __ipipe_tick_irq;
+
+extern int __ipipe_host_tick_irq;
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+extern volatile int __ipipe_timer_grabbed;
+
+extern volatile unsigned long __ipipe_itm_next[];
+
+extern volatile unsigned long __ipipe_itm_delta[];
+
+#else /* !CONFIG_IPIPE */
+
+#define task_hijacked(p)	0
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__IA64_IPIPE_H */
--- 2.6.14/include/asm-ia64/mmu_context.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/asm-ia64/mmu_context.h	2006-01-02 12:19:45.000000000 +0100
@@ -59,14 +59,14 @@ delayed_tlb_flush (void)
 	unsigned long flags;
 
 	if (unlikely(__ia64_per_cpu_var(ia64_need_tlb_flush))) {
-		spin_lock_irqsave(&ia64_ctx.lock, flags);
+		spin_lock_irqsave_hw(&ia64_ctx.lock, flags);
 		{
 			if (__ia64_per_cpu_var(ia64_need_tlb_flush)) {
 				local_flush_tlb_all();
 				__ia64_per_cpu_var(ia64_need_tlb_flush) = 0;
 			}
 		}
-		spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+		spin_unlock_irqrestore_hw(&ia64_ctx.lock, flags);
 	}
 }
 
@@ -77,7 +77,7 @@ get_mmu_context (struct mm_struct *mm)
 	nv_mm_context_t context = mm->context;
 
 	if (unlikely(!context)) {
-		spin_lock_irqsave(&ia64_ctx.lock, flags);
+		spin_lock_irqsave_hw(&ia64_ctx.lock, flags);
 		{
 			/* re-check, now that we've got the lock: */
 			context = mm->context;
@@ -88,7 +88,7 @@ get_mmu_context (struct mm_struct *mm)
 				mm->context = context = ia64_ctx.next++;
 			}
 		}
-		spin_unlock_irqrestore(&ia64_ctx.lock, flags);
+		spin_unlock_irqrestore_hw(&ia64_ctx.lock, flags);
 	}
 	/*
 	 * Ensure we're not starting to use "context" before any old
@@ -174,12 +174,15 @@ activate_context (struct mm_struct *mm)
 static inline void
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
+	unsigned long flags;
 	/*
 	 * We may get interrupts here, but that's OK because interrupt handlers cannot
-	 * touch user-space.
+	 * touch user-space, unless the I-pipe is enabled.
 	 */
+	local_irq_save_hw(flags);
 	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
 	activate_context(next);
+	local_irq_restore_hw(flags);
 }
 
 #define switch_mm(prev_mm,next_mm,next_task)	activate_mm(prev_mm, next_mm)
--- 2.6.14/include/asm-ia64/offsets.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.14-ipipe/include/asm-ia64/offsets.h	2005-10-31 10:15:18.000000000 +0100
@@ -0,0 +1 @@
+#define IA64_TASK_SIZE 0
--- 2.6.14/include/asm-ia64/pgalloc.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/asm-ia64/pgalloc.h	2005-10-31 10:15:18.000000000 +0100
@@ -142,4 +142,9 @@ static inline void pte_free_kernel(pte_t
 
 extern void check_pgt_cache(void);
 
+static inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+    /* nop */
+}
+
 #endif				/* _ASM_IA64_PGALLOC_H */
--- 2.6.14/include/asm-ia64/system.h	2005-10-28 02:02:08.000000000 +0200
+++ 2.6.14-ipipe/include/asm-ia64/system.h	2005-10-31 10:15:18.000000000 +0100
@@ -122,6 +122,64 @@ extern struct ia64_boot_param {
  *   write a floating-point register right before reading the PSR
  *   and that writes to PSR.mfl
  */
+
+#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);
+
+#define __local_irq_save(x)    ((x) = (!__ipipe_test_and_stall_root()) << IA64_PSR_I_BIT)
+#define __local_irq_disable() 	__ipipe_stall_root()
+#define __local_irq_restore(x)	__ipipe_restore_root(!(x & IA64_PSR_I))
+
+#ifdef CONFIG_IA64_DEBUG_IRQ
+#error "I-pipe: no support for IRQ debug mode"
+#endif /* CONFIG_IA64_DEBUG_IRQ */
+
+#define local_irq_save(x)	__local_irq_save(x)
+#define local_irq_disable()	__local_irq_disable()
+#define local_irq_restore(x)	__local_irq_restore(x)
+
+#define local_irq_enable()	__ipipe_unstall_root()
+#define local_save_flags(x)	((x) = (!__ipipe_test_root()) << IA64_PSR_I_BIT)
+
+#define irqs_disabled()		__ipipe_test_root()
+
+#define local_irq_disable_hw()	\
+	do {			\
+		ia64_stop();	\
+		ia64_rsm(IA64_PSR_I);	\
+	} while (0)
+
+#define local_irq_enable_hw()	\
+	({ ia64_ssm(IA64_PSR_I); ia64_srlz_d(); })
+
+#define local_irq_save_hw(x)	\
+do {					\
+	unsigned long __psr;		\
+        __psr = ia64_getreg(_IA64_REG_PSR);	\
+        ia64_stop();				\
+        ia64_rsm(IA64_PSR_I);			\
+	(x) = __psr;				\
+} while (0)
+
+#define local_irq_restore_hw(x) \
+	ia64_intrin_local_irq_restore((x) & IA64_PSR_I)
+
+#define local_save_flags_hw(x)		((x) = ia64_getreg(_IA64_REG_PSR))
+
+#define irqs_disabled_hw()		\
+	({				\
+	unsigned long flags;		\
+	local_save_flags_hw(flags);	\
+	!((x) & IA64_PSR_I);		\
+	})
+
+#else /* !CONFIG_IPIPE */
+
 #define __local_irq_save(x)			\
 do {						\
 	ia64_stop();				\
@@ -182,6 +240,13 @@ do {								\
 	(__ia64_id_flags & IA64_PSR_I) == 0;	\
 })
 
+#define local_irq_save_hw(flags)	local_irq_save(flags)
+#define local_irq_restore_hw(flags)	local_irq_restore(flags)
+#define local_irq_enable_hw()		local_irq_enable()
+#define local_irq_disable_hw(flags)	local_irq_disable()
+
+#endif /* CONFIG_IPIPE */
+
 #ifdef __KERNEL__
 
 #ifdef CONFIG_IA32_SUPPORT
