diff -uNrp 2.6.12/arch/i386/Kconfig 2.6.12-ipipe-0.9/arch/i386/Kconfig
--- 2.6.12/arch/i386/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/Kconfig	2005-06-27 18:44:46.000000000 +0200
@@ -534,6 +534,8 @@ config PREEMPT_BKL
 	  Say Y here if you are building a kernel for a desktop system.
 	  Say N if you are unsure.
 
+source "kernel/ipipe/Kconfig"
+
 config X86_UP_APIC
 	bool "Local APIC support on uniprocessors"
 	depends on !SMP && !(X86_VISWS || X86_VOYAGER)
@@ -941,7 +943,6 @@ config SECCOMP
 
 endmenu
 
-
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
 
diff -uNrp 2.6.12/arch/i386/kernel/Makefile 2.6.12-ipipe-0.9/arch/i386/kernel/Makefile
--- 2.6.12/arch/i386/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/Makefile	2005-06-27 18:49:00.000000000 +0200
@@ -11,6 +11,7 @@ obj-y	:= process.o semaphore.o signal.o 
 
 obj-y				+= cpu/
 obj-y				+= timers/
+obj-$(CONFIG_IPIPE)		+= ipipe-core.o ipipe-root.o
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
diff -uNrp 2.6.12/arch/i386/kernel/apic.c 2.6.12-ipipe-0.9/arch/i386/kernel/apic.c
--- 2.6.12/arch/i386/kernel/apic.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/apic.c	2005-06-27 18:44:46.000000000 +0200
@@ -62,7 +62,7 @@ void ack_bad_irq(unsigned int irq)
 	 * unexpected vectors occur) that might lock up the APIC
 	 * completely.
 	 */
-	ack_APIC_irq();
+	__ack_APIC_irq();
 }
 
 void __init apic_intr_init(void)
@@ -1161,6 +1161,9 @@ inline void smp_local_timer_interrupt(st
 fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
+#ifdef CONFIG_IPIPE
+	regs =  __ipipe_tick_regs + cpu;
+#endif /* CONFIG_IPIPE */
 
 	/*
 	 * the NMI deadlock-detector uses this.
@@ -1197,7 +1200,7 @@ fastcall void smp_spurious_interrupt(str
 	 */
 	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
-		ack_APIC_irq();
+		__ack_APIC_irq();
 
 	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n",
diff -uNrp 2.6.12/arch/i386/kernel/entry.S 2.6.12-ipipe-0.9/arch/i386/kernel/entry.S
--- 2.6.12/arch/i386/kernel/entry.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/entry.S	2005-06-27 18:44:46.000000000 +0200
@@ -48,6 +48,7 @@
 #include <asm/smp.h>
 #include <asm/page.h>
 #include <asm/desc.h>
+#include <asm/ipipe.h>
 #include "irq_vectors.h"
 
 #define nr_syscalls ((syscall_table_size)/4)
@@ -75,11 +76,28 @@ DF_MASK		= 0x00000400 
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
+#ifdef CONFIG_IPIPE
+#define CLI                     call __ipipe_stall_root
+#define STI                     call __ipipe_unstall_root
+#define FIXUP_ROOT_IF           call __ipipe_if_fixup_root ; movl ORIG_EAX(%esp),%eax
+#define EMULATE_ROOT_IRET	call __ipipe_unstall_iret_root ; movl EAX(%esp),%eax
+#define TEST_PREEMPTIBLE(regs)  call __ipipe_kpreempt_root ; testl %eax,%eax
+#define restore_nocheck         unstall_and_restore_nocheck
+#define restore_nmi             restore_raw
+#else  /* !CONFIG_IPIPE */
+#define CLI                     cli
+#define STI                     sti
+#define FIXUP_ROOT_IF
+#define EMULATE_ROOT_IRET
+#define TEST_PREEMPTIBLE(regs)  testl $IF_MASK,EFLAGS(regs)
+#define restore_nmi             restore_all
+#endif /* CONFIG_IPIPE */
+
 #ifdef CONFIG_PREEMPT
-#define preempt_stop		cli
+#define preempt_stop	  CLI
 #else
 #define preempt_stop
-#define resume_kernel		restore_nocheck
+#define resume_kernel	  restore_nocheck
 #endif
 
 #define SAVE_ALL \
@@ -141,14 +159,14 @@ ENTRY(ret_from_fork)
 	ALIGN
 ret_from_exception:
 	preempt_stop
-ret_from_intr:
+ENTRY(ret_from_intr)
 	GET_THREAD_INFO(%ebp)
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
 	testl $(VM_MASK | 3), %eax
 	jz resume_kernel
 ENTRY(resume_userspace)
- 	cli				# make sure we don't miss an interrupt
+	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -159,14 +177,14 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	cli
+	CLI
 	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
 	jnz restore_nocheck
 need_resched:
 	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
-	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
+	TEST_PREEMPTIBLE(%esp)		# interrupts off (exception path) ?
 	jz restore_all
 	call preempt_schedule_irq
 	jmp need_resched
@@ -200,6 +218,7 @@ sysenter_past_esp:
 
 	pushl %eax
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	GET_THREAD_INFO(%ebp)
 
 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
@@ -209,11 +228,12 @@ sysenter_past_esp:
 	jae syscall_badsys
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
-	cli
+	CLI
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
 	jne syscall_exit_work
 /* if something modifies registers it must also disable sysexit */
+	EMULATE_ROOT_IRET
 	movl EIP(%esp), %edx
 	movl OLDESP(%esp), %ecx
 	xorl %ebp,%ebp
@@ -225,6 +245,7 @@ sysenter_past_esp:
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	GET_THREAD_INFO(%ebp)
 					# system call tracing in operation
 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
@@ -236,7 +257,7 @@ syscall_call:
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)		# store the return value
 syscall_exit:
-	cli				# make sure we don't miss an interrupt
+ 	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -253,7 +274,15 @@ restore_all:
 	andl $(VM_MASK | (4 << 8) | 3), %eax
 	cmpl $((4 << 8) | 3), %eax
 	je ldt_ss			# returning to user-space with LDT SS
+#ifdef CONFIG_IPIPE
+unstall_and_restore_nocheck:
+	call __ipipe_unstall_iret_root
+restore_raw:
+	# FIXME: we need to check for a return to
+	# user-space on a 16bit stack even in the NMI case
+#else /* !CONFIG_IPIPE */
 restore_nocheck:
+#endif /* CONFIG_IPIPE */
 	RESTORE_REGS
 	addl $4, %esp
 1:	iret
@@ -301,7 +330,7 @@ work_pending:
 	jz work_notifysig
 work_resched:
 	call schedule
-	cli				# make sure we don't miss an interrupt
+	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -348,7 +377,7 @@ syscall_trace_entry:
 syscall_exit_work:
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
-	sti				# could let do_syscall_trace() call
+	STI				# could let do_syscall_trace() call
 					# schedule() instead
 	movl %esp, %eax
 	movl $1, %edx
@@ -399,7 +428,7 @@ ENTRY(interrupt)
 
 vector=0
 ENTRY(irq_entries_start)
-.rept NR_IRQS
+.rept NR_XIRQS
 	ALIGN
 1:	pushl $vector-256
 	jmp common_interrupt
@@ -409,6 +438,28 @@ ENTRY(irq_entries_start)
 vector=vector+1
 .endr
 
+#ifdef CONFIG_IPIPE
+	ALIGN
+common_interrupt:
+	SAVE_ALL
+	call __ipipe_handle_irq
+	testl %eax,%eax
+	jnz  ret_from_intr
+	RESTORE_REGS
+	addl $4, %esp
+	iret	
+
+#define BUILD_INTERRUPT(name, nr)	\
+ENTRY(name)				\
+	pushl $nr-288;	/* nr - (256 + FIRST_EXTERNAL_VECTOR) */ \
+	SAVE_ALL;			\
+	call __ipipe_handle_irq;	\
+	testl %eax,%eax;		\
+	jnz  ret_from_intr;		\
+	RESTORE_REGS;			\
+	addl $4, %esp;			\
+	iret
+#else /* CONFIG_IPIPE */
 	ALIGN
 common_interrupt:
 	SAVE_ALL
@@ -423,6 +474,7 @@ ENTRY(name)				\
 	movl %esp,%eax;			\
 	call smp_/**/name;		\
 	jmp ret_from_intr;
+#endif /* CONFIG_IPIPE */
 
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
@@ -455,6 +507,7 @@ error_code:
 	movl %ecx, %es
 	movl %esp,%eax			# pt_regs pointer
 	call *%edi
+	FIXUP_ROOT_IF
 	jmp ret_from_exception
 
 ENTRY(coprocessor_error)
@@ -470,6 +523,7 @@ ENTRY(simd_coprocessor_error)
 ENTRY(device_not_available)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	movl %cr0, %eax
 	testl $0x4, %eax		# EM (math emulation bit)
 	jne device_not_available_emulate
@@ -511,6 +565,7 @@ ENTRY(debug)
 debug_stack_correct:
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	xorl %edx,%edx			# error code 0
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
@@ -549,7 +604,7 @@ nmi_stack_correct:
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_nmi
-	jmp restore_all
+	jmp restore_nmi
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -591,6 +646,7 @@ nmi_16bit_stack:
 ENTRY(int3)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
diff -uNrp 2.6.12/arch/i386/kernel/i8259.c 2.6.12-ipipe-0.9/arch/i386/kernel/i8259.c
--- 2.6.12/arch/i386/kernel/i8259.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/i8259.c	2005-07-03 19:45:23.000000000 +0200
@@ -92,13 +92,14 @@ void disable_8259A_irq(unsigned int irq)
 	unsigned int mask = 1 << irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
+	ipipe_irq_lock(irq);
 	cached_irq_mask |= mask;
 	if (irq & 8)
 		outb(cached_slave_mask, PIC_SLAVE_IMR);
 	else
 		outb(cached_master_mask, PIC_MASTER_IMR);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 void enable_8259A_irq(unsigned int irq)
@@ -106,13 +107,14 @@ void enable_8259A_irq(unsigned int irq)
 	unsigned int mask = ~(1 << irq);
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	cached_irq_mask &= mask;
 	if (irq & 8)
 		outb(cached_slave_mask, PIC_SLAVE_IMR);
 	else
 		outb(cached_master_mask, PIC_MASTER_IMR);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	ipipe_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 int i8259A_irq_pending(unsigned int irq)
@@ -121,12 +123,12 @@ int i8259A_irq_pending(unsigned int irq)
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	if (irq < 8)
 		ret = inb(PIC_MASTER_CMD) & mask;
 	else
 		ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 
 	return ret;
 }
@@ -173,7 +175,7 @@ static void mask_and_ack_8259A(unsigned 
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	/*
 	 * Lightweight spurious IRQ detection. We do not want
 	 * to overdo spurious IRQ handling - it's usually a sign
@@ -191,6 +193,15 @@ static void mask_and_ack_8259A(unsigned 
 	 */
 	if (cached_irq_mask & irqmask)
 		goto spurious_8259A_irq;
+#ifdef CONFIG_IPIPE
+	if (irq == 0) {
+	    /* Fast timer ack -- don't mask (unless supposedly
+	      spurious) */
+	    outb(0x20,PIC_MASTER_CMD);
+	    spin_unlock_irqrestore_hw(&i8259A_lock, flags);
+	    return;
+	}
+#endif /* CONFIG_IPIPE */
 	cached_irq_mask |= irqmask;
 
 handle_real_irq:
@@ -204,7 +215,7 @@ handle_real_irq:
 		outb(cached_master_mask, PIC_MASTER_IMR);
 		outb(0x60+irq,PIC_MASTER_CMD);	/* 'Specific EOI to master */
 	}
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 	return;
 
 spurious_8259A_irq:
@@ -293,7 +304,7 @@ void init_8259A(int auto_eoi)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 
 	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
 	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
@@ -327,7 +338,7 @@ void init_8259A(int auto_eoi)
 	outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
 	outb(cached_slave_mask, PIC_SLAVE_IMR);	  /* restore slave IRQ mask */
 
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 /*
@@ -401,7 +412,7 @@ void __init init_IRQ(void)
 	 */
 	for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
 		int vector = FIRST_EXTERNAL_VECTOR + i;
-		if (i >= NR_IRQS)
+		if (i >= NR_XIRQS)
 			break;
 		if (vector != SYSCALL_VECTOR) 
 			set_intr_gate(vector, interrupt[i]);
diff -uNrp 2.6.12/arch/i386/kernel/io_apic.c 2.6.12-ipipe-0.9/arch/i386/kernel/io_apic.c
--- 2.6.12/arch/i386/kernel/io_apic.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/io_apic.c	2005-07-03 19:45:47.000000000 +0200
@@ -174,18 +174,20 @@ static void mask_IO_APIC_irq (unsigned i
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
+	ipipe_irq_lock(irq);
 	__mask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 static void unmask_IO_APIC_irq (unsigned int irq)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
+	ipipe_irq_unlock(irq);
 	__unmask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
@@ -194,10 +196,10 @@ static void clear_IO_APIC_pin(unsigned i
 	unsigned long flags;
 	
 	/* Check delivery_mode to be sure we're not clearing an SMI pin */
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	*(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
 	*(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 	if (entry.delivery_mode == dest_SMI)
 		return;
 
@@ -206,10 +208,10 @@ static void clear_IO_APIC_pin(unsigned i
 	 */
 	memset(&entry, 0, sizeof(entry));
 	entry.mask = 1;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
 	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 static void clear_IO_APIC (void)
@@ -231,7 +233,7 @@ static void set_ioapic_affinity_irq(unsi
 	apicid_value = cpu_mask_to_apicid(cpumask);
 	/* Prepare to do the io_apic_write */
 	apicid_value = apicid_value << 24;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	for (;;) {
 		pin = entry->pin;
 		if (pin == -1)
@@ -241,7 +243,7 @@ static void set_ioapic_affinity_irq(unsi
 			break;
 		entry = irq_2_pin + entry->next;
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 #if defined(CONFIG_IRQBALANCE)
@@ -1244,10 +1246,10 @@ static void __init setup_IO_APIC_irqs(vo
 			if (!apic && (irq < 16))
 				disable_8259A_irq(irq);
 		}
-		spin_lock_irqsave(&ioapic_lock, flags);
+		spin_lock_irqsave_hw(&ioapic_lock, flags);
 		io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
 		io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
-		spin_unlock_irqrestore(&ioapic_lock, flags);
+		spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 	}
 	}
 
@@ -1291,10 +1293,10 @@ static void __init setup_ExtINT_IRQ0_pin
 	/*
 	 * Add it to the IO-APIC irq-routing table:
 	 */
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
 	io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	enable_8259A_irq(0);
 }
@@ -1574,7 +1576,7 @@ void /*__init*/ print_PIC(void)
 
 	printk(KERN_DEBUG "\nprinting PIC contents\n");
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 
 	v = inb(0xa1) << 8 | inb(0x21);
 	printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
@@ -1588,7 +1590,7 @@ void /*__init*/ print_PIC(void)
 	outb(0x0a,0xa0);
 	outb(0x0a,0x20);
 
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 
 	printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
 
@@ -1811,14 +1813,15 @@ static unsigned int startup_edge_ioapic_
 	int was_pending = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	if (irq < 16) {
 		disable_8259A_irq(irq);
 		if (i8259A_irq_pending(irq))
 			was_pending = 1;
 	}
 	__unmask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	ipipe_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return was_pending;
 }
@@ -1828,6 +1831,26 @@ static unsigned int startup_edge_ioapic_
  * interrupt for real. This prevents IRQ storms from unhandled
  * devices.
  */
+
+#ifdef CONFIG_IPIPE
+
+static void ack_edge_ioapic_irq (unsigned irq)
+
+{
+    move_irq(irq);
+    if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED))
+	{
+	unsigned long flags;
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+
+    __ack_APIC_irq();
+}
+
+#else /* !CONFIG_IPIPE */
+
 static void ack_edge_ioapic_irq(unsigned int irq)
 {
 	move_irq(irq);
@@ -1837,6 +1860,8 @@ static void ack_edge_ioapic_irq(unsigned
 	ack_APIC_irq();
 }
 
+#endif /* CONFIG_IPIPE */
+
 /*
  * Level triggered interrupts can just be masked,
  * and shutting down and starting up the interrupt
@@ -1858,6 +1883,74 @@ static unsigned int startup_level_ioapic
 	return 0; /* don't check for pending */
 }
 
+#ifdef CONFIG_IPIPE
+
+/* Prevent low priority IRQs grabbed by high priority domains from
+   being delayed, waiting for a high priority interrupt handler
+   running in a low priority domain to complete. */
+
+static unsigned long bugous_edge_triggers;
+
+static void end_level_ioapic_irq (unsigned irq)
+
+{
+    unsigned long flags;
+
+    move_irq(irq);
+
+    spin_lock_irqsave_hw(&ioapic_lock, flags);
+
+    if (test_and_clear_bit(irq,&bugous_edge_triggers))
+	{
+	atomic_inc(&irq_mis_count);
+	__unmask_and_level_IO_APIC_irq(irq);
+	}
+    else
+	__unmask_IO_APIC_irq(irq);
+
+    ipipe_irq_unlock(irq);
+
+    spin_unlock_irqrestore_hw(&ioapic_lock, flags);
+}
+
+static void mask_and_ack_level_ioapic_irq (unsigned irq)
+
+{
+    unsigned long flags, v;
+    int i;
+
+    i = IO_APIC_VECTOR(irq);
+    v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+    spin_lock_irqsave_hw(&ioapic_lock, flags);
+
+    if (!(v & (1 << (i & 0x1f))))
+	{
+	set_bit(irq,&bugous_edge_triggers);
+	__mask_and_edge_IO_APIC_irq(irq);
+	}
+    else
+	__mask_IO_APIC_irq(irq);
+
+    spin_unlock_irqrestore_hw(&ioapic_lock, flags);
+
+    __ack_APIC_irq();
+}
+
+#ifdef CONFIG_PCI_MSI
+
+static inline void mask_and_ack_level_ioapic_vector(unsigned int vector)
+
+{
+	int irq = vector_to_irq(vector);
+
+	mask_and_ack_level_ioapic_irq(irq);
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+#else /* !CONFIG_IPIPE */
+
 static void end_level_ioapic_irq (unsigned int irq)
 {
 	unsigned long v;
@@ -1898,6 +1991,8 @@ static void end_level_ioapic_irq (unsign
 	}
 }
 
+#endif /* CONFIG_IPIPE */
+
 #ifdef CONFIG_PCI_MSI
 static unsigned int startup_edge_ioapic_vector(unsigned int vector)
 {
@@ -2035,7 +2130,7 @@ static void disable_lapic_irq (unsigned 
 
 static void ack_lapic_irq (unsigned int irq)
 {
-	ack_APIC_irq();
+	__ack_APIC_irq();
 }
 
 static void end_lapic_irq (unsigned int i) { /* nothing */ }
@@ -2306,12 +2401,12 @@ static int ioapic_suspend(struct sys_dev
 	
 	data = container_of(dev, struct sysfs_ioapic_data, dev);
 	entry = data->entry;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
 		*(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
 		*(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
@@ -2327,7 +2422,7 @@ static int ioapic_resume(struct sys_devi
 	data = container_of(dev, struct sysfs_ioapic_data, dev);
 	entry = data->entry;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	reg_00.raw = io_apic_read(dev->id, 0);
 	if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
 		reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
@@ -2337,7 +2432,7 @@ static int ioapic_resume(struct sys_devi
 		io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
 		io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
@@ -2532,10 +2627,10 @@ int io_apic_set_pci_routing (int ioapic,
 	if (!ioapic && (irq < 16))
 		disable_8259A_irq(irq);
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
 	io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
diff -uNrp 2.6.12/arch/i386/kernel/ipipe-core.c 2.6.12-ipipe-0.9/arch/i386/kernel/ipipe-core.c
--- 2.6.12/arch/i386/kernel/ipipe-core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/ipipe-core.c	2005-08-05 15:04:06.000000000 +0200
@@ -0,0 +1,621 @@
+/*   -*- linux-c -*-
+ *   linux/arch/i386/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-dependent I-PIPE core support for x86.
+ */
+
+#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 <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif	/* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+int __ipipe_tick_irq;
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static raw_spinlock_t __ipipe_cpu_barrier = RAW_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+#endif	/* CONFIG_SMP */
+
+#define __ipipe_call_root_xirq_handler(ipd,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "pushl %%cs\n\t" \
+                         "pushl $1f\n\t" \
+	                 "pushl %%eax\n\t" \
+	                 "pushl %%es\n\t" \
+	                 "pushl %%ds\n\t" \
+	                 "pushl %%eax\n\t" \
+	                 "pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+	                 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+	                 "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "movl  %%esp,%%eax\n\t" \
+                         "call *%1\n\t" \
+	                 "jmp ret_from_intr\n\t" \
+	                 "1:\n" \
+			 : /* no output */ \
+			 : "a" (irq-256), "m" ((ipd)->irqs[irq].handler))
+
+#define __ipipe_call_root_virq_handler(ipd,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "pushl %%cs\n\t" \
+                         "pushl $1f\n\t" \
+	                 "pushl $-1\n\t" \
+	                 "pushl %%es\n\t" \
+	                 "pushl %%ds\n\t" \
+	                 "pushl %%eax\n\t" \
+	                 "pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+	                 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+	                 "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "pushl %%eax\n\t" \
+                         "call *%1\n\t" \
+			 "addl $4,%%esp\n\t" \
+	                 "jmp ret_from_intr\n\t" \
+	                 "1:\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((ipd)->irqs[irq].handler))
+
+static __inline__ unsigned long flnz(unsigned long word)
+{
+      __asm__("bsrl %1, %0":"=r"(word)
+      :	"r"(word));
+	return word;
+}
+
+int __ipipe_ack_system_irq(unsigned irq)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	__ack_APIC_irq();
+#endif	/* CONFIG_X86_LOCAL_APIC */
+	return 1;
+}
+
+#ifdef CONFIG_SMP
+
+/* Always called with hw interrupts off. */
+
+static void __ipipe_do_critical_sync(unsigned irq)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	cpu_set(cpuid, __ipipe_cpu_sync_map);
+
+	/* Now we are in sync with the lock requestor running on another
+	   CPU. Enter a spinning wait until he releases the global
+	   lock. */
+	spin_lock_hw(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock_hw(&__ipipe_cpu_barrier);
+
+	cpu_clear(cpuid, __ipipe_cpu_sync_map);
+}
+
+#endif	/* CONFIG_SMP */
+
+/* ipipe_critical_enter() -- Grab the superlock excluding all CPUs
+   but the current one from a critical section. This lock is used when
+   we must enforce a global critical section for a single CPU in a
+   possibly SMP system whichever context the CPUs are running. */
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+		cpumask_t lock_map;
+
+		ipipe_load_cpuid();
+
+		if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) {
+			while (cpu_test_and_set
+			       (BITS_PER_LONG - 1, __ipipe_cpu_lock_map)) {
+				int n = 0;
+				do {
+					cpu_relax();
+				} while (++n < cpuid);
+			}
+
+			spin_lock_hw(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			send_IPI_allbutself(IPIPE_CRITICAL_VECTOR);
+
+			cpus_andnot(lock_map, cpu_online_map,
+				    __ipipe_cpu_lock_map);
+
+			while (!cpus_equal(__ipipe_cpu_sync_map, lock_map))
+				cpu_relax();
+		}
+
+		atomic_inc(&__ipipe_critical_count);
+	}
+#endif	/* CONFIG_SMP */
+
+	return flags;
+}
+
+/* ipipe_critical_exit() -- Release the superlock. */
+
+void ipipe_critical_exit(unsigned long flags)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+
+		ipipe_load_cpuid();
+
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock_hw(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(cpuid, __ipipe_cpu_lock_map);
+			cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map);
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	local_irq_restore_hw(flags);
+}
+
+void __ipipe_init_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_hits[n] = 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 */
+	}
+
+#ifdef CONFIG_SMP
+	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = &__ipipe_ack_system_irq;
+	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
+	/* 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 */
+}
+
+/* __ipipe_sync_stage() -- Flush the pending IRQs for the current
+   domain (and processor).  This routine flushes the interrupt log
+   (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+   more on the deferred interrupt scheme). Every interrupt that
+   occurred while the pipeline was stalled gets played.  WARNING:
+   callers on SMP boxen should always check for CPU migration on
+   return of this routine. One can control the kind of interrupts
+   which are going to be sync'ed using the syncmask
+   parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+   plays virtual interrupts only. This routine must be called with hw
+   interrupts off. */
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask)
+{
+	unsigned long mask, submask;
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *ipd;
+	ipipe_declare_cpuid;
+	int level, rank;
+	unsigned irq;
+
+	ipipe_load_cpuid();
+	ipd = ipipe_percpu_domain[cpuid];
+	cpudata = &ipd->cpudata[cpuid];
+
+	if (__test_and_set_bit(IPIPE_SYNC_FLAG, &cpudata->status))
+		return;
+
+	/* The policy here is to keep the dispatching code interrupt-free
+	   by stalling the current stage. If the upper domain handler
+	   (which we call) wants to re-enable interrupts while in a safe
+	   portion of the code (e.g. SA_INTERRUPT flag unset for Linux's
+	   sigaction()), it will have to unstall (then stall again before
+	   returning to us!) the stage when it sees fit. */
+
+	while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0) {
+		/* Give a slight priority advantage to high-numbered IRQs
+		   like the virtual ones. */
+		level = flnz(mask);
+		__clear_bit(level, &cpudata->irq_pending_hi);
+
+		while ((submask = cpudata->irq_pending_lo[level]) != 0) {
+			rank = flnz(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_hits[irq] == 0)
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			if (ipd == ipipe_root_domain) {
+				/* Linux handlers are called hw interrupts on
+				   so that they could not defer interrupts for
+				   higher priority domains. */
+				local_irq_enable_hw();
+
+				if (likely(!ipipe_virtual_irq_p(irq))) {
+					__ipipe_call_root_xirq_handler(ipd,irq);
+				} else {
+					irq_enter();
+					__ipipe_call_root_virq_handler(ipd,irq);
+					irq_exit();
+				}
+
+				local_irq_disable_hw();
+			} else {
+				__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+				ipd->irqs[irq].handler(irq);
+				__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);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* __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;
+	}
+}
+
+/* __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+   interrupt protection log is maintained here for each domain.  Hw
+   interrupts are off on entry. */
+
+int __ipipe_handle_irq(struct pt_regs regs)
+{
+	int hw_gen = regs.orig_eax < 0, m_ack = !hw_gen, s_ack;
+	unsigned irq = regs.orig_eax & 0xff;
+	struct list_head *head, *pos;
+	struct ipipe_domain *this_domain;
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	this_domain = ipipe_percpu_domain[cpuid];
+
+	s_ack = m_ack;
+
+	if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
+		head = &this_domain->p_link;
+	else
+		head = __ipipe_pipeline.next;
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		/* For each domain handling the incoming IRQ, mark it as
+		   pending in its log. */
+
+		if (test_bit
+		    (IPIPE_HANDLE_FLAG, &next_domain->irqs[irq].control)) {
+			/* Domains that handle this IRQ are polled for
+			   acknowledging it by decreasing priority order. The
+			   interrupt must be made pending _first_ in the domain's
+			   status flags before the PIC is unlocked. */
+
+			next_domain->cpudata[cpuid].irq_hits[irq]++;
+			__ipipe_set_irq_bit(next_domain, cpuid, irq);
+
+			/* Always get the first master acknowledge available. Once
+			   we've got it, allow slave acknowledge handlers to run
+			   (until one of them stops us). */
+
+			if (!m_ack)
+				m_ack = next_domain->irqs[irq].acknowledge(irq);
+			else if (test_bit
+				 (IPIPE_SHARED_FLAG,
+				  &next_domain->irqs[irq].control) && !s_ack)
+				s_ack = next_domain->irqs[irq].acknowledge(irq);
+		}
+
+		/* If the domain does not want the IRQ to be passed down the
+		   interrupt pipe, exit the loop now. */
+
+		if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+	if (irq == __ipipe_tick_irq) {
+		__ipipe_tick_regs[cpuid].eflags = regs.eflags;
+		__ipipe_tick_regs[cpuid].eip = regs.eip;
+		__ipipe_tick_regs[cpuid].xcs = regs.xcs;
+#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
+		/* Linux profiling code needs this. */
+		__ipipe_tick_regs[cpuid].ebp = regs.ebp;
+#endif	/* CONFIG_SMP && CONFIG_FRAME_POINTER */
+	}
+
+	/* 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);
+
+	ipipe_load_cpuid();
+
+	if (ipipe_percpu_domain[cpuid] != ipipe_root_domain ||
+	    test_bit(IPIPE_STALL_FLAG,
+		     &ipipe_root_domain->cpudata[cpuid].status))
+		return 0;
+
+#ifdef CONFIG_SMP
+	/* Prevent a spurious rescheduling from being triggered on
+	   preemptible kernels along the way out through ret_from_intr. */
+	if (hw_gen)
+		__set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+#endif	/* CONFIG_SMP */
+
+	return 1;
+}
+
+/* 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);
+
+	regs.orig_eax = irq;	/* Won't be acked */
+	regs.xcs = __KERNEL_CS;
+	regs.eflags = flags;
+
+	__ipipe_handle_irq(regs);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+static inline void __fixup_if(struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags);
+
+	if (ipipe_percpu_domain[cpuid] == ipipe_root_domain) {
+		/* Have the saved hw state look like the domain stall bit, so
+		   that __ipipe_unstall_iret_root() restores the proper
+		   pipeline state for the root stage upon exit. */
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG,
+		     &ipipe_root_domain->cpudata[cpuid].status))
+			regs->eflags &= ~X86_EFLAGS_IF;
+		else
+			regs->eflags |= X86_EFLAGS_IF;
+	}
+
+	ipipe_put_cpu(flags);
+}
+
+asmlinkage void __ipipe_if_fixup_root(struct pt_regs regs)
+{
+	__fixup_if(&regs);
+}
+
+/*  Check the interrupt flag to make sure the existing preemption
+    opportunity upon in-kernel resumption could be exploited. If the
+    pipeline is active, the stall bit of the root domain is checked,
+    otherwise, the EFLAGS register from the stacked interrupt frame is
+    tested. In case a rescheduling could take place in pipelined mode,
+    the root stage is stalled before the hw interrupts are
+    re-enabled. This routine must be called with hw interrupts off. */
+
+asmlinkage int __ipipe_kpreempt_root(struct pt_regs regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags);
+
+	if (test_bit
+	    (IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status)) {
+		ipipe_put_cpu(flags);
+		return 0;	/* Root stage is stalled: rescheduling denied. */
+	}
+
+	__ipipe_stall_root();
+	local_irq_enable_hw();
+
+	return 1;		/* Ok, may reschedule now. */
+}
+
+asmlinkage void __ipipe_unstall_iret_root(struct pt_regs regs)
+{
+	ipipe_declare_cpuid;
+
+	/* Emulate IRET's handling of the interrupt flag. */
+
+	local_irq_disable_hw();
+
+	ipipe_load_cpuid();
+
+	/* Restore the software state as it used to be on kernel
+	   entry. CAUTION: NMIs must *not* return through this
+	   emulation. */
+
+	if (!(regs.eflags & X86_EFLAGS_IF)) {
+		__set_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status);
+		regs.eflags |= X86_EFLAGS_IF;
+	} else {
+		__clear_bit(IPIPE_STALL_FLAG,
+			    &ipipe_root_domain->cpudata[cpuid].status);
+
+		/* Only sync virtual IRQs here, so that we don't recurse
+		   indefinitely in case of an external interrupt flood. */
+
+		if ((ipipe_root_domain->cpudata[cpuid].
+		     irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+			__ipipe_sync_stage(IPIPE_IRQMASK_VIRT);
+	}
+}
+
+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);
diff -uNrp 2.6.12/arch/i386/kernel/ipipe-root.c 2.6.12-ipipe-0.9/arch/i386/kernel/ipipe-root.c
--- 2.6.12/arch/i386/kernel/ipipe-root.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/ipipe-root.c	2005-08-04 14:06:07.000000000 +0200
@@ -0,0 +1,354 @@
+/*   -*- linux-c -*-
+ *   linux/arch/i386/kernel/ipipe-root.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-dependent I-PIPE support for x86.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif	/* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+
+static int __ipipe_noack_irq(unsigned irq)
+{
+	return 1;
+}
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+fastcall unsigned int do_IRQ(struct pt_regs *regs);
+fastcall void smp_apic_timer_interrupt(struct pt_regs *regs);
+fastcall void smp_spurious_interrupt(struct pt_regs *regs);
+fastcall void smp_error_interrupt(struct pt_regs *regs);
+fastcall void smp_thermal_interrupt(struct pt_regs *regs);
+fastcall void smp_reschedule_interrupt(struct pt_regs *regs);
+fastcall void smp_invalidate_interrupt(struct pt_regs *regs);
+fastcall void smp_call_function_interrupt(struct pt_regs *regs);
+
+static int __ipipe_ack_common_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();	/* hw interrupts are off. */
+	flags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	desc->handler->ack(irq);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid);
+
+	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 __init __ipipe_enable_pipeline(void)
+{
+	unsigned irq;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+	/* Map the APIC system vectors. */
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     LOCAL_TIMER_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_apic_timer_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     SPURIOUS_APIC_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_spurious_interrupt,
+			     &__ipipe_noack_irq,
+			     IPIPE_STDROOT_MASK);
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     ERROR_APIC_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_error_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+
+#ifdef CONFIG_X86_MCE_P4THERMAL
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     THERMAL_APIC_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_thermal_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+#endif /* CONFIG_X86_MCE_P4THERMAL */
+
+	__ipipe_tick_irq =
+	    using_apic_timer ? LOCAL_TIMER_VECTOR - FIRST_EXTERNAL_VECTOR : 0;
+
+#else	/* !CONFIG_X86_LOCAL_APIC */
+
+	__ipipe_tick_irq = 0;
+
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     RESCHEDULE_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_reschedule_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     INVALIDATE_TLB_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_invalidate_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     CALL_FUNCTION_VECTOR - FIRST_EXTERNAL_VECTOR,
+			     (void (*)(unsigned))&smp_call_function_interrupt,
+			     &__ipipe_ack_system_irq,
+			     IPIPE_STDROOT_MASK);
+#endif	/* CONFIG_SMP */
+
+	/* Finally, virtualize the remaining ISA and IO-APIC
+	 * interrupts. Interrupts which have already been virtualized
+	 * will just beget a silent -EPERM error since
+	 * IPIPE_SYSTEM_MASK has been passed for them, that's ok. */
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		/* Fails for IPIPE_CRITICAL_IPI but that's ok. */
+		ipipe_virtualize_irq(ipipe_root_domain,
+				     irq,
+				     (void (*)(unsigned))&do_IRQ,
+				     &__ipipe_ack_common_irq,
+				     IPIPE_STDROOT_MASK);
+	}
+}
+
+/* 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,
+			 void (*handler) (unsigned irq),
+			 int (*acknowledge) (unsigned irq),
+			 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;
+
+			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].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;
+		}
+
+		irq_desc[irq].handler->enable(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;
+	irq_desc_t *desc;
+
+	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;
+
+	desc = irq_desc + irq;
+
+	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)
+		desc->handler->enable(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		desc->handler->disable(irq);
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+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 */
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = __ipipe_tick_irq;
+#ifdef CONFIG_X86_TSC
+	info->archdep.tmfreq = ipipe_cpu_freq();
+#else	/* !CONFIG_X86_TSC */
+	info->archdep.tmfreq = CLOCK_TICK_RATE;
+#endif	/* CONFIG_X86_TSC */
+
+	return 0;
+}
+
+int ipipe_tune_timer (unsigned long ns, int flags)
+
+{
+    unsigned hz, latch;
+    unsigned long x;
+
+    if (flags & IPIPE_RESET_TIMER)
+	latch = LATCH;
+    else
+	{
+	hz = 1000000000 / ns;
+
+	if (hz < HZ)
+	    return -EINVAL;
+
+	latch = (CLOCK_TICK_RATE + hz/2) / hz;
+	}
+
+    x = ipipe_critical_enter(NULL); /* Sync with all CPUs */
+
+    /* Shamelessly lifted from init_IRQ() in i8259.c */
+    outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+    outb_p(latch & 0xff,0x40);	/* LSB */
+    outb(latch >> 8,0x40);	/* MSB */
+
+    ipipe_critical_exit(x);
+
+    return 0;
+}
diff -uNrp 2.6.12/arch/i386/kernel/process.c 2.6.12-ipipe-0.9/arch/i386/kernel/process.c
--- 2.6.12/arch/i386/kernel/process.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/process.c	2005-06-27 18:44:46.000000000 +0200
@@ -161,6 +161,7 @@ void cpu_idle (void)
 				idle = default_idle;
 
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
+ 			ipipe_suspend_domain();
 			idle();
 		}
 		schedule();
diff -uNrp 2.6.12/arch/i386/kernel/smp.c 2.6.12-ipipe-0.9/arch/i386/kernel/smp.c
--- 2.6.12/arch/i386/kernel/smp.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/smp.c	2005-06-27 18:44:46.000000000 +0200
@@ -131,6 +131,9 @@ void __send_IPI_shortcut(unsigned int sh
 	 * to the APIC.
 	 */
 	unsigned int cfg;
+	unsigned long flags;
+
+	local_irq_save_hw_cond(flags);
 
 	/*
 	 * Wait for idle.
@@ -146,6 +149,8 @@ void __send_IPI_shortcut(unsigned int sh
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write_around(APIC_ICR, cfg);
+
+	local_irq_restore_hw_cond(flags);
 }
 
 void fastcall send_IPI_self(int vector)
@@ -162,7 +167,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	unsigned long cfg;
 	unsigned long flags;
 
-	local_irq_save(flags);
+	local_irq_save_hw(flags);
 		
 	/*
 	 * Wait for idle.
@@ -185,7 +190,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	 */
 	apic_write_around(APIC_ICR, cfg);
 
-	local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector)
@@ -199,7 +204,7 @@ void send_IPI_mask_sequence(cpumask_t ma
 	 * should be modified to do 1 message per cluster ID - mbligh
 	 */ 
 
-	local_irq_save(flags);
+	local_irq_save_hw(flags);
 
 	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
 		if (cpu_isset(query_cpu, mask)) {
@@ -226,7 +231,7 @@ void send_IPI_mask_sequence(cpumask_t ma
 			apic_write_around(APIC_ICR, cfg);
 		}
 	}
-	local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 #include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
@@ -310,7 +315,9 @@ static inline void leave_mm (unsigned lo
 
 fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
 {
-	unsigned long cpu;
+    	unsigned long cpu, flags;
+
+	local_irq_save_hw_cond(flags);
 
 	cpu = get_cpu();
 
@@ -340,6 +347,7 @@ fastcall void smp_invalidate_interrupt(s
 	smp_mb__after_clear_bit();
 out:
 	put_cpu_no_resched();
+	local_irq_restore_hw_cond(flags);
 }
 
 static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
@@ -400,14 +408,19 @@ void flush_tlb_current_task(void)
 {
 	struct mm_struct *mm = current->mm;
 	cpumask_t cpu_mask;
+	unsigned long flags;
 
 	preempt_disable();
+	local_irq_save_hw_cond(flags);
+
 	cpu_mask = mm->cpu_vm_mask;
 	cpu_clear(smp_processor_id(), cpu_mask);
 
 	local_flush_tlb();
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+	local_irq_restore_hw_cond(flags);
 	preempt_enable();
 }
 
@@ -435,8 +448,11 @@ void flush_tlb_page(struct vm_area_struc
 {
 	struct mm_struct *mm = vma->vm_mm;
 	cpumask_t cpu_mask;
+	unsigned long flags;
 
 	preempt_disable();
+	local_irq_save_hw_cond(flags);
+
 	cpu_mask = mm->cpu_vm_mask;
 	cpu_clear(smp_processor_id(), cpu_mask);
 
@@ -447,6 +463,8 @@ void flush_tlb_page(struct vm_area_struc
 		 	leave_mm(smp_processor_id());
 	}
 
+	local_irq_restore_hw_cond(flags);
+
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, va);
 
@@ -609,4 +627,3 @@ fastcall void smp_call_function_interrup
 		atomic_inc(&call_data->finished);
 	}
 }
-
diff -uNrp 2.6.12/arch/i386/kernel/time.c 2.6.12-ipipe-0.9/arch/i386/kernel/time.c
--- 2.6.12/arch/i386/kernel/time.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/time.c	2005-06-27 18:44:46.000000000 +0200
@@ -258,11 +258,12 @@ static inline void do_timer_interrupt(in
 		 * This will also deassert NMI lines for the watchdog if run
 		 * on an 82489DX-based system.
 		 */
-		spin_lock(&i8259A_lock);
+		unsigned long flags;
+		spin_lock_irqsave_hw_cond(&i8259A_lock,flags);
 		outb(0x0c, PIC_MASTER_OCW3);
 		/* Ack the IRQ; AEOI will end it automatically. */
 		inb(PIC_MASTER_POLL);
-		spin_unlock(&i8259A_lock);
+		spin_unlock_irqrestore_hw_cond(&i8259A_lock,flags);
 	}
 #endif
 
diff -uNrp 2.6.12/arch/i386/kernel/traps.c 2.6.12-ipipe-0.9/arch/i386/kernel/traps.c
--- 2.6.12/arch/i386/kernel/traps.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/kernel/traps.c	2005-06-27 18:44:46.000000000 +0200
@@ -226,6 +226,11 @@ void show_registers(struct pt_regs *regs
 		regs->esi, regs->edi, regs->ebp, esp);
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
+#ifdef CONFIG_IPIPE
+	if (ipipe_current_domain != ipipe_root_domain)
+	    printk("I-pipe domain %s",ipipe_current_domain->name);
+	else
+#endif /* CONFIG_IPIPE */
 	printk("Process %s (pid: %d, threadinfo=%p task=%p)",
 		current->comm, current->pid, current_thread_info(), current);
 	/*
@@ -946,12 +951,15 @@ asmlinkage void math_state_restore(struc
 {
 	struct thread_info *thread = current_thread_info();
 	struct task_struct *tsk = thread->task;
+	unsigned long flags;
 
+	local_irq_save_hw_cond(flags);
 	clts();		/* Allow maths ops (or we recurse) */
 	if (!tsk_used_math(tsk))
 		init_fpu(tsk);
 	restore_fpu(tsk);
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
+	local_irq_restore_hw_cond(flags);
 }
 
 #ifndef CONFIG_MATH_EMULATION
diff -uNrp 2.6.12/arch/i386/mach-visws/visws_apic.c 2.6.12-ipipe-0.9/arch/i386/mach-visws/visws_apic.c
--- 2.6.12/arch/i386/mach-visws/visws_apic.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/mach-visws/visws_apic.c	2005-06-27 18:44:46.000000000 +0200
@@ -199,7 +199,7 @@ static irqreturn_t piix4_master_intr(int
 	irq_desc_t *desc;
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 
 	/* Find out what's interrupting in the PIIX4 master 8259 */
 	outb(0x0c, 0x20);		/* OCW3 Poll command */
@@ -236,7 +236,7 @@ static irqreturn_t piix4_master_intr(int
 		outb(0x60 + realirq, 0x20);
 	}
 
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 
 	desc = irq_desc + realirq;
 
@@ -254,7 +254,7 @@ static irqreturn_t piix4_master_intr(int
 	return IRQ_HANDLED;
 
 out_unlock:
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 	return IRQ_NONE;
 }
 
diff -uNrp 2.6.12/arch/i386/mm/fault.c 2.6.12-ipipe-0.9/arch/i386/mm/fault.c
--- 2.6.12/arch/i386/mm/fault.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/mm/fault.c	2005-06-27 18:44:46.000000000 +0200
@@ -224,6 +224,8 @@ fastcall void do_page_fault(struct pt_re
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
+	local_irq_enable_hw_cond();
+
 	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
diff -uNrp 2.6.12/arch/i386/mm/ioremap.c 2.6.12-ipipe-0.9/arch/i386/mm/ioremap.c
--- 2.6.12/arch/i386/mm/ioremap.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/i386/mm/ioremap.c	2005-06-27 18:44:46.000000000 +0200
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 #define ISA_START_ADDRESS	0xa0000
 #define ISA_END_ADDRESS		0x100000
@@ -92,6 +93,7 @@ static int ioremap_page_range(unsigned l
 		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, flags);
 		if (err)
 			break;
+		set_pgdir(addr, *pgd);
 	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
diff -uNrp 2.6.12/arch/ia64/Kconfig 2.6.12-ipipe-0.9/arch/ia64/Kconfig
--- 2.6.12/arch/ia64/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/Kconfig	2005-07-04 09:10:21.000000000 +0200
@@ -296,6 +296,8 @@ config PREEMPT
           Say Y here if you are building a kernel for a desktop, embedded
           or real-time system.  Say N if you are unsure.
 
+source "kernel/ipipe/Kconfig"
+
 config HAVE_DEC_LOCK
 	bool
 	depends on (SMP || PREEMPT)
diff -uNrp 2.6.12/arch/ia64/kernel/Makefile 2.6.12-ipipe-0.9/arch/ia64/kernel/Makefile
--- 2.6.12/arch/ia64/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/Makefile	2005-07-04 09:10:47.000000000 +0200
@@ -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
diff -uNrp 2.6.12/arch/ia64/kernel/entry.S 2.6.12-ipipe-0.9/arch/ia64/kernel/entry.S
--- 2.6.12/arch/ia64/kernel/entry.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/entry.S	2005-07-04 09:51:03.000000000 +0200
@@ -786,6 +786,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
@@ -838,7 +842,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
@@ -1133,6 +1143,22 @@ 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)
+#endif /* CONFIG_IPIPE */
+
 ENTRY(handle_syscall_error)
 	/*
 	 * Some system calls (e.g., ptrace, mmap) can return arbitrary values which could
diff -uNrp 2.6.12/arch/ia64/kernel/entry.h 2.6.12-ipipe-0.9/arch/ia64/kernel/entry.h
--- 2.6.12/arch/ia64/kernel/entry.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/entry.h	2005-07-04 09:48:19.000000000 +0200
@@ -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)
diff -uNrp 2.6.12/arch/ia64/kernel/iosapic.c 2.6.12-ipipe-0.9/arch/ia64/kernel/iosapic.c
--- 2.6.12/arch/ia64/kernel/iosapic.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/iosapic.c	2005-07-04 13:35:13.000000000 +0200
@@ -278,7 +278,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;
@@ -288,7 +289,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
@@ -304,7 +305,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) {
@@ -313,7 +314,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);
 }
 
 
@@ -345,7 +347,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);
 
@@ -365,7 +367,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
 }
 
@@ -721,31 +723,31 @@ 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_nopanic(AUTO_ASSIGN);
 	if (vector < 0)
 		vector = iosapic_find_sharable_vector(trigger, polarity);
 
-	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;
 		}
 
@@ -763,7 +765,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"),
@@ -799,7 +801,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) {
@@ -851,7 +853,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);
 }
 #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
 
diff -uNrp 2.6.12/arch/ia64/kernel/ipipe-core.c 2.6.12-ipipe-0.9/arch/ia64/kernel/ipipe-core.c
--- 2.6.12/arch/ia64/kernel/ipipe-core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/ipipe-core.c	2005-08-05 15:04:29.000000000 +0200
@@ -0,0 +1,470 @@
+/*   -*- 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 spinlock_t __ipipe_cpu_barrier = 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. */
+
+static 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);
+}
+
+int __ipipe_acknowledge_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_descp(irq);
+	desc->handler->ack(irq); /* We don't hold desc->lock on purpose. */
+
+	return 1;
+}
+
+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_hits[n] = 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 */
+	}
+
+#ifdef CONFIG_SMP
+	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = (int (*)(unsigned))&__ipipe_acknowledge_irq;
+	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
+	/* 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 */
+}
+
+/* __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_hits[irq] == 0)
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			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);
+				__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);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* __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_hits[irq]++;
+			__ipipe_set_irq_bit(_ipd, cpuid, irq);
+
+			/* Always get the first master acknowledge available. Once
+			   we've got it, allow slave acknowledge handlers to run
+			   (until one of them stops us). */
+
+			if (!m_ack)
+				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);
+}
+
+/* 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;
+}
+
+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);
diff -uNrp 2.6.12/arch/ia64/kernel/ipipe-root.c 2.6.12-ipipe-0.9/arch/ia64/kernel/ipipe-root.c
--- 2.6.12/arch/ia64/kernel/ipipe-root.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/ipipe-root.c	2005-07-04 13:48:16.000000000 +0200
@@ -0,0 +1,293 @@
+/*   -*- 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>
+
+int __ipipe_acknowledge_irq(unsigned irq);
+
+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;
+
+}
+
+/* __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,
+				     (void (*)(unsigned))&__do_IRQ,
+				     &__ipipe_acknowledge_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_virtualize_irq() -- Attach a handler (and optionally a hw
+   acknowledge routine) to an interrupt for the given domain. */
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 void (*handler) (unsigned irq),
+			 int (*acknowledge) (unsigned irq), 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) {
+		/* A bit of hack here: if we are re-virtualizing an IRQ just
+		   to change the acknowledge routine by passing the special
+		   IPIPE_SAME_HANDLER value, then allow to recycle the current
+		   handler for the IRQ. This allows Linux device drivers
+		   managing shared IRQ lines to call ipipe_virtualize_irq() in
+		   addition to request_irq() just for the purpose of
+		   interposing their own shared acknowledge routine. */
+
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = ipd->irqs[irq].handler;
+
+			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].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;
+		}
+
+		irq_descp(irq)->handler->enable(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)
+{
+	unsigned long flags;
+	irq_desc_t *desc;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	if (ipipe_current_domain->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (((setmask | clrmask) & IPIPE_SHARED_MASK) != 0)
+		return -EINVAL;
+
+	desc = irq_descp(irq);
+
+	if (ipipe_current_domain->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);
+
+	ipipe_current_domain->irqs[irq].control &= ~clrmask;
+	ipipe_current_domain->irqs[irq].control |= setmask;
+
+	if ((setmask & IPIPE_ENABLE_MASK) != 0)
+		enable_irq(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		disable_irq(irq);
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+void __ipipe_init_domain(struct ipipe_domain *ipd, struct ipipe_domain_attr *attr)
+{
+}
+
+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 */
+}
+
+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;
+}
diff -uNrp 2.6.12/arch/ia64/kernel/irq_ia64.c 2.6.12-ipipe-0.9/arch/ia64/kernel/irq_ia64.c
--- 2.6.12/arch/ia64/kernel/irq_ia64.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/irq_ia64.c	2005-07-04 11:57:54.000000000 +0200
@@ -110,6 +110,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)
 {
@@ -176,6 +208,7 @@ ia64_handle_irq (ia64_vector vector, str
 	 */
 	irq_exit();
 }
+#endif /* CONFIG_IPIPE */
 
 #ifdef CONFIG_HOTPLUG_CPU
 /*
diff -uNrp 2.6.12/arch/ia64/kernel/ivt.S 2.6.12-ipipe-0.9/arch/ia64/kernel/ivt.S
--- 2.6.12/arch/ia64/kernel/ivt.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/ivt.S	2005-07-04 09:43:04.000000000 +0200
@@ -785,7 +785,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
diff -uNrp 2.6.12/arch/ia64/kernel/process.c 2.6.12-ipipe-0.9/arch/ia64/kernel/process.c
--- 2.6.12/arch/ia64/kernel/process.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/process.c	2005-07-04 09:41:12.000000000 +0200
@@ -281,6 +281,7 @@ cpu_idle (void)
 			idle = pm_idle;
 			if (!idle)
 				idle = default_idle;
+ 			ipipe_suspend_domain();
 			(*idle)();
 		}
 
diff -uNrp 2.6.12/arch/ia64/kernel/time.c 2.6.12-ipipe-0.9/arch/ia64/kernel/time.c
--- 2.6.12/arch/ia64/kernel/time.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ia64/kernel/time.c	2005-07-04 09:40:08.000000000 +0200
@@ -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;
 }
 
diff -uNrp 2.6.12/arch/ppc/Kconfig 2.6.12-ipipe-0.9/arch/ppc/Kconfig
--- 2.6.12/arch/ppc/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/Kconfig	2005-06-30 10:16:06.000000000 +0200
@@ -907,6 +907,8 @@ config PREEMPT
 	  Say Y here if you are building a kernel for a desktop, embedded
 	  or real-time system.  Say N if you are unsure.
 
+source "kernel/ipipe/Kconfig"
+
 config HIGHMEM
 	bool "High memory support"
 
diff -uNrp 2.6.12/arch/ppc/kernel/Makefile 2.6.12-ipipe-0.9/arch/ppc/kernel/Makefile
--- 2.6.12/arch/ppc/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/Makefile	2005-06-30 10:17:04.000000000 +0200
@@ -27,6 +27,7 @@ obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_FSL_BOOKE)		+= perfmon_fsl_booke.o
+obj-$(CONFIG_IPIPE)		+= ipipe-core.o ipipe-root.o
 
 ifndef CONFIG_MATH_EMULATION
 obj-$(CONFIG_8xx)		+= softemu8xx.o
diff -uNrp 2.6.12/arch/ppc/kernel/entry.S 2.6.12-ipipe-0.9/arch/ppc/kernel/entry.S
--- 2.6.12/arch/ppc/kernel/entry.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/entry.S	2005-06-30 10:23:38.000000000 +0200
@@ -645,6 +645,12 @@ ret_from_except:
 	SYNC			/* Some chip revs have problems here... */
 	MTMSRD(r10)		/* disable interrupts */
 
+#ifdef CONFIG_IPIPE
+        bl __ipipe_check_root
+        cmpwi   r3, 0
+        beq- restore
+#endif /* CONFIG_IPIPE */
+
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r0,r3,MSR_PR
 	beq	resume_kernel
@@ -1026,3 +1032,10 @@ machine_check_in_rtas:
 	/* XXX load up BATs and panic */
 
 #endif /* CONFIG_PPC_OF */
+
+#ifdef CONFIG_IPIPE
+_GLOBAL(__ipipe_ret_from_except)
+        cmpwi   r3, 0
+        bne+ ret_from_except
+        b restore
+#endif /* CONFIG_IPIPE */
diff -uNrp 2.6.12/arch/ppc/kernel/head.S 2.6.12-ipipe-0.9/arch/ppc/kernel/head.S
--- 2.6.12/arch/ppc/kernel/head.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head.S	2005-06-30 16:01:28.000000000 +0200
@@ -335,6 +335,12 @@ i##n:								\
 	EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full,	\
 			  ret_from_except_full)
 
+#ifdef CONFIG_IPIPE
+#define EXC_XFER_IPIPE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
+			  __ipipe_ret_from_except)
+#endif /* CONFIG_IPIPE */
+
 #define EXC_XFER_LITE(n, hdlr)		\
 	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
 			  ret_from_except)
@@ -445,7 +451,11 @@ InstructionAccess:
 #endif /* CONFIG_PPC64BRIDGE */
 
 /* External interrupt */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x500, HardwareInterrupt, __ipipe_grab_irq, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 /* Alignment exception */
 	. = 0x600
@@ -470,7 +480,11 @@ FPUnavailable:
 	EXC_XFER_EE_LITE(0x800, KernelFP)
 
 /* Decrementer */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x900, Decrementer, __ipipe_grab_timer, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 	EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE)
diff -uNrp 2.6.12/arch/ppc/kernel/head_44x.S 2.6.12-ipipe-0.9/arch/ppc/kernel/head_44x.S
--- 2.6.12/arch/ppc/kernel/head_44x.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head_44x.S	2005-06-30 16:01:38.000000000 +0200
@@ -418,7 +418,11 @@ interrupt_base:
 	INSTRUCTION_STORAGE_EXCEPTION
 
 	/* External Input Interrupt */
-	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x0500, ExternalInput, __ipipe_grab_irq, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
+ 	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 	/* Alignment Interrupt */
 	ALIGNMENT_EXCEPTION
diff -uNrp 2.6.12/arch/ppc/kernel/head_4xx.S 2.6.12-ipipe-0.9/arch/ppc/kernel/head_4xx.S
--- 2.6.12/arch/ppc/kernel/head_4xx.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head_4xx.S	2005-06-30 10:36:09.000000000 +0200
@@ -229,6 +229,12 @@ label:
 	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
 			  ret_from_except_full)
 
+#ifdef CONFIG_IPIPE
+#define EXC_XFER_IPIPE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+			  __ipipe_ret_from_except)
+#endif /* CONFIG_IPIPE */
+
 #define EXC_XFER_LITE(n, hdlr)		\
 	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
 			  ret_from_except)
@@ -396,7 +402,11 @@ label:
 	EXC_XFER_EE_LITE(0x400, handle_page_fault)
 
 /* 0x0500 - External Interrupt Exception */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x0500, HardwareInterrupt, __ipipe_grab_irq, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 /* 0x0600 - Alignment Exception */
 	START_EXCEPTION(0x0600, Alignment)
@@ -434,7 +444,11 @@ label:
 	lis	r0,TSR_PIS@h
 	mtspr	SPRN_TSR,r0		/* Clear the PIT exception */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_IPIPE
+	EXC_XFER_IPIPE(0x1000, __ipipe_grab_timer)
+#else /* !CONFIG_IPIPE */
 	EXC_XFER_LITE(0x1000, timer_interrupt)
+#endif /* CONFIG_IPIPE */
 
 #if 0
 /* NOTE:
diff -uNrp 2.6.12/arch/ppc/kernel/head_8xx.S 2.6.12-ipipe-0.9/arch/ppc/kernel/head_8xx.S
--- 2.6.12/arch/ppc/kernel/head_8xx.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head_8xx.S	2005-06-30 10:39:38.000000000 +0200
@@ -189,6 +189,11 @@ i##n:								\
 #define EXC_XFER_STD(n, hdlr)		\
 	EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full,	\
 			  ret_from_except_full)
+#ifdef CONFIG_IPIPE
+#define EXC_XFER_IPIPE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
+			  __ipipe_ret_from_except)
+#endif /* CONFIG_IPIPE */
 
 #define EXC_XFER_LITE(n, hdlr)		\
 	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
@@ -241,7 +246,11 @@ InstructionAccess:
 	EXC_XFER_EE_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x500, HardwareInterrupt, __ipipe_grab_irq, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 /* Alignment exception */
 	. = 0x600
@@ -262,7 +271,11 @@ Alignment:
 	EXCEPTION(0x800, FPUnavailable, UnknownException, EXC_XFER_STD)
 
 /* Decrementer */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x900, Decrementer, __ipipe_grab_timer, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 	EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE)
diff -uNrp 2.6.12/arch/ppc/kernel/head_booke.h 2.6.12-ipipe-0.9/arch/ppc/kernel/head_booke.h
--- 2.6.12/arch/ppc/kernel/head_booke.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head_booke.h	2005-06-30 10:42:00.000000000 +0200
@@ -225,6 +225,12 @@ label:
 	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
 			  ret_from_except_full)
 
+#ifdef CONFIG_IPIPE
+#define EXC_XFER_IPIPE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+			  __ipipe_ret_from_except)
+#endif /* CONFIG_IPIPE */
+
 #define EXC_XFER_LITE(n, hdlr)		\
 	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
 			  ret_from_except)
@@ -329,6 +335,15 @@ label:
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
 	EXC_XFER_STD(0x0700, ProgramCheckException)
 
+#ifdef CONFIG_IPIPE
+#define DECREMENTER_EXCEPTION						      \
+	START_EXCEPTION(Decrementer)					      \
+	NORMAL_EXCEPTION_PROLOG;					      \
+	lis     r0,TSR_DIS@h;           /* Setup the DEC interrupt mask */    \
+	mtspr   SPRN_TSR,r0;		/* Clear the DEC interrupt */	      \
+	addi    r3,r1,STACK_FRAME_OVERHEAD;				      \
+	EXC_XFER_IPIPE(0x0900, __ipipe_grab_timer)
+#else /* !CONFIG_IPIPE */
 #define DECREMENTER_EXCEPTION						      \
 	START_EXCEPTION(Decrementer)					      \
 	NORMAL_EXCEPTION_PROLOG;					      \
@@ -336,6 +351,7 @@ label:
 	mtspr   SPRN_TSR,r0;		/* Clear the DEC interrupt */	      \
 	addi    r3,r1,STACK_FRAME_OVERHEAD;				      \
 	EXC_XFER_LITE(0x0900, timer_interrupt)
+#endif /* CONFIG_IPIPE */
 
 #define FP_UNAVAILABLE_EXCEPTION					      \
 	START_EXCEPTION(FloatingPointUnavailable)			      \
diff -uNrp 2.6.12/arch/ppc/kernel/head_fsl_booke.S 2.6.12-ipipe-0.9/arch/ppc/kernel/head_fsl_booke.S
--- 2.6.12/arch/ppc/kernel/head_fsl_booke.S	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/head_fsl_booke.S	2005-06-30 10:44:53.000000000 +0200
@@ -508,7 +508,11 @@ interrupt_base:
 	INSTRUCTION_STORAGE_EXCEPTION
 
 	/* External Input Interrupt */
+#ifdef CONFIG_IPIPE
+	EXCEPTION(0x0500, ExternalInput, __ipipe_grab_irq, EXC_XFER_IPIPE)
+#else /* !CONFIG_IPIPE */
 	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+#endif /* CONFIG_IPIPE */
 
 	/* Alignment Interrupt */
 	ALIGNMENT_EXCEPTION
diff -uNrp 2.6.12/arch/ppc/kernel/idle.c 2.6.12-ipipe-0.9/arch/ppc/kernel/idle.c
--- 2.6.12/arch/ppc/kernel/idle.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/idle.c	2005-08-17 16:24:07.000000000 +0200
@@ -38,9 +38,14 @@ void default_idle(void)
 
 	powersave = ppc_md.power_save;
 
+	local_irq_disable_hw_cond();
+
 	if (!need_resched()) {
 		if (powersave != NULL)
+		    {
+		    	local_irq_enable_hw_cond();
 			powersave();
+		    }
 #ifdef CONFIG_SMP
 		else {
 			set_thread_flag(TIF_POLLING_NRFLAG);
@@ -50,6 +55,9 @@ void default_idle(void)
 		}
 #endif
 	}
+
+	local_irq_enable_hw_cond();
+
 	if (need_resched())
 		schedule();
 }
@@ -59,11 +67,13 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
-	for (;;)
+	for (;;) {
+		ipipe_suspend_domain();
 		if (ppc_md.idle != NULL)
 			ppc_md.idle();
 		else
 			default_idle();
+	}
 }
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
diff -uNrp 2.6.12/arch/ppc/kernel/ipipe-core.c 2.6.12-ipipe-0.9/arch/ppc/kernel/ipipe-core.c
--- 2.6.12/arch/ppc/kernel/ipipe-core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/ipipe-core.c	2005-08-21 20:26:00.000000000 +0200
@@ -0,0 +1,588 @@
+/*   -*- linux-c -*-
+ *   linux/arch/ppc/kernel/ipipe-core.c
+ *
+ *   Copyright (C) 2002-2005 Philippe Gerum.
+ *   Copyright (C) 2004 Wolfgang Grandegger (Adeos/ppc port over 2.4).
+ *   Copyright (C) 2005 Heikki Lindholm (PowerPC 970 fixes).
+ *
+ *   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 PowerPC.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+/* Current reload value for the decrementer. */
+unsigned long __ipipe_decr_ticks;
+
+/* Next tick date (timebase value). */
+unsigned long long __ipipe_decr_next[IPIPE_NR_CPUS];
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+static inline unsigned long ffnz(unsigned long ul)
+{
+
+	__asm__ __volatile__("cntlzw %0, %1":"=r"(ul):"r"(ul & (-ul)));
+	return 31 - ul;
+}
+
+#ifdef CONFIG_POWER4
+extern struct irqaction k2u3_cascade_action;
+extern int openpic2_get_irq(struct pt_regs *regs);
+#endif
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static spinlock_t __ipipe_cpu_barrier = SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+/* Always called with hw interrupts off. */
+
+static void __ipipe_do_critical_sync(unsigned irq)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	cpu_set(cpuid, __ipipe_cpu_sync_map);
+
+	/* Now we are in sync with the lock requestor running on another
+	   CPU. Enter a spinning wait until he releases the global
+	   lock. */
+	spin_lock_hw(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock_hw(&__ipipe_cpu_barrier);
+
+	cpu_clear(cpuid, __ipipe_cpu_sync_map);
+}
+
+#endif	/* CONFIG_SMP */
+
+/* ipipe_critical_enter() -- Grab the superlock excluding all CPUs
+   but the current one from a critical section. This lock is used when
+   we must enforce a global critical section for a single CPU in a
+   possibly SMP system whichever context the CPUs are running. */
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+		cpumask_t lock_map;
+
+		ipipe_load_cpuid();
+
+		if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) {
+			while (cpu_test_and_set
+			       (BITS_PER_LONG - 1, __ipipe_cpu_lock_map)) {
+				int n = 0;
+				do {
+					cpu_relax();
+				} while (++n < cpuid);
+			}
+
+			spin_lock_hw(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			send_IPI_allbutself(IPIPE_CRITICAL_VECTOR);
+
+			cpus_andnot(lock_map, cpu_online_map,
+				    __ipipe_cpu_lock_map);
+
+			while (!cpus_equal(__ipipe_cpu_sync_map, lock_map))
+				cpu_relax();
+		}
+
+		atomic_inc(&__ipipe_critical_count);
+	}
+#endif	/* CONFIG_SMP */
+
+	return flags;
+}
+
+/* ipipe_critical_exit() -- Release the superlock. */
+
+void ipipe_critical_exit(unsigned long flags)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+
+		ipipe_load_cpuid();
+
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock_hw(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(cpuid, __ipipe_cpu_lock_map);
+			cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map);
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	local_irq_restore_hw(flags);
+}
+
+void __ipipe_init_platform(void)
+{
+	unsigned timer_virq;
+
+	/* Allocate a virtual IRQ for the decrementer trap early to
+	   get it mapped to IPIPE_VIRQ_BASE */
+
+	timer_virq = ipipe_alloc_virq();
+
+	if (timer_virq != IPIPE_TIMER_VIRQ)
+		panic("I-pipe: cannot reserve timer virq #%d (got #%d)",
+		      IPIPE_TIMER_VIRQ, timer_virq);
+
+	__ipipe_decr_ticks = tb_ticks_per_jiffy;
+}
+
+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_hits[n] = 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 */
+	}
+
+#ifdef CONFIG_SMP
+	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = NULL; /* FIXME */
+	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
+	/* 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 */
+}
+
+/* __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) {
+		level = ffnz(mask);
+		__clear_bit(level, &cpudata->irq_pending_hi);
+
+		while ((submask = cpudata->irq_pending_lo[level]) != 0) {
+			rank = ffnz(submask);
+			irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+			if (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control)) {
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+				continue;
+			}
+
+			if (--cpudata->irq_hits[irq] == 0)
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			if (ipd == ipipe_root_domain) {
+				/* Linux handlers are called w/ hw
+				   interrupts on so that they could
+				   not defer interrupts for higher
+				   priority domains. */
+				local_irq_enable_hw();
+				((void (*)(unsigned, struct pt_regs *))
+				 ipd->irqs[irq].handler) (irq, __ipipe_tick_regs + cpuid);
+				local_irq_disable_hw();
+			} else {
+				__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+				ipd->irqs[irq].handler(irq);
+				__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);
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+int __ipipe_ack_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	if (desc->handler->ack == NULL)
+		return 1;
+
+	/* No need to mask IRQs at hw level: we are always called from
+	   __ipipe_handle_irq(), so interrupts are already off. We
+	   stall the pipeline so that spin_lock_irq*() ops won't
+	   unintentionally flush it, since this could cause infinite
+	   recursion. */
+
+	ipipe_load_cpuid();
+	flags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	spin_lock_hw(&desc->lock);
+	desc->handler->ack(irq);
+#ifdef CONFIG_POWER4
+	/* if it is a k2u3 cascaded irq, acknowledge it, also */
+	if (desc->action == &k2u3_cascade_action) {
+		struct pt_regs regs;
+		int irq2 = openpic2_get_irq(&regs);
+		if (irq2 != -1) {
+			irq_desc_t *desc2 = irq_desc + irq2;
+			if (desc2->handler->ack)
+				desc2->handler->ack(irq2);
+		}
+	}
+#endif
+	spin_unlock_hw(&desc->lock);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], flags, cpuid);
+
+	return 1;
+}
+
+/* __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;
+	}
+}
+
+/* __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+   interrupt protection log is maintained here for each domain.  Hw
+   interrupts are off on entry. */
+
+void __ipipe_handle_irq(int irq, struct pt_regs *regs)
+{
+	struct ipipe_domain *this_domain;
+	struct list_head *head, *pos;
+	ipipe_declare_cpuid;
+	int m_ack, s_ack;
+
+	m_ack = irq & IPIPE_IRQ_ACKED;
+	irq &= IPIPE_IRQ_ACKED_MASK;
+
+	if (irq >= IPIPE_NR_IRQS) {
+		printk(KERN_ERR "I-pipe: spurious interrupt %d\n", irq);
+		return;
+	}
+
+	ipipe_load_cpuid();
+
+	this_domain = ipipe_percpu_domain[cpuid];
+
+	s_ack = m_ack;
+
+	if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
+		head = &this_domain->p_link;
+	else
+		head = __ipipe_pipeline.next;
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		/* For each domain handling the incoming IRQ, mark it as
+		   pending in its log. */
+
+		if (test_bit
+		    (IPIPE_HANDLE_FLAG, &next_domain->irqs[irq].control)) {
+			/* Domains that handle this IRQ are polled for
+			   acknowledging it by decreasing priority order. The
+			   interrupt must be made pending _first_ in the domain's
+			   status flags before the PIC is unlocked. */
+
+			next_domain->cpudata[cpuid].irq_hits[irq]++;
+			__ipipe_set_irq_bit(next_domain, cpuid, irq);
+
+			/* Always get the first master acknowledge available. Once
+			   we've got it, allow slave acknowledge handlers to run
+			   (until one of them stops us). */
+
+			if (next_domain->irqs[irq].acknowledge != NULL) {
+				if (!m_ack)
+					m_ack = next_domain->irqs[irq].acknowledge(irq);
+				else if (test_bit
+					 (IPIPE_SHARED_FLAG,
+					  &next_domain->irqs[irq].control) && !s_ack)
+					s_ack = next_domain->irqs[irq].acknowledge(irq);
+			}
+		}
+
+		/* If the domain does not want the IRQ to be passed down the
+		   interrupt pipe, exit the loop now. */
+
+		if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+	/* Now walk the pipeline, yielding control to the highest
+	   priority domain that has pending interrupt(s) or
+	   immediately to the current domain if the interrupt has been
+	   marked as 'sticky'. This search does not go beyond the
+	   current domain in the pipeline. */
+
+	__ipipe_walk_pipeline(head, cpuid);
+}
+
+asmlinkage int __ipipe_grab_irq(struct pt_regs *regs)
+{
+	extern int ppc_spurious_interrupts;
+	ipipe_declare_cpuid;
+	int irq, first = 1;
+
+	if ((irq = ppc_md.get_irq(regs)) >= 0) {
+		__ipipe_handle_irq(irq, regs);
+		first = 0;
+	} else if (irq != -2 && first)
+		ppc_spurious_interrupts++;
+
+	ipipe_load_cpuid();
+
+	return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+void __ipipe_do_IRQ(int irq, struct pt_regs *regs)
+{
+	irq_enter();
+	__do_IRQ(irq, regs);
+	irq_exit();
+}
+
+asmlinkage int __ipipe_grab_timer(struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+
+#ifdef CONFIG_POWER4
+	/* On 970 CPUs DEC cannot be disabled, and without setting DEC
+	 * here, DEC interrupt would be triggered as soon as interrupts
+	 * are enabled in __ipipe_sync_stage
+	 */
+	set_dec(0x7fffffff);
+#endif
+
+	__ipipe_tick_regs[cpuid].msr = regs->msr; /* for do_timer() */
+
+	__ipipe_handle_irq(IPIPE_TIMER_VIRQ, regs);
+
+	ipipe_load_cpuid();
+
+#ifndef CONFIG_40x
+	if (__ipipe_decr_ticks != tb_ticks_per_jiffy) {
+		unsigned long long next_date, now;
+
+		next_date = __ipipe_decr_next[cpuid];
+
+		while ((now = __ipipe_read_timebase()) >= next_date)
+			next_date += __ipipe_decr_ticks;
+
+		set_dec(next_date - now);
+
+		__ipipe_decr_next[cpuid] = next_date;
+	}
+#endif	/* !CONFIG_40x */
+
+	return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+void __ipipe_do_timer(int irq, struct pt_regs *regs)
+{
+	timer_interrupt(regs);
+}
+
+asmlinkage int __ipipe_check_root(struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+	/* This routine is called with hw interrupts off, so no migration
+	   can occur while checking the identity of the current domain. */
+	ipipe_load_cpuid();
+	return (ipipe_percpu_domain[cpuid] == ipipe_root_domain &&
+		!test_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status));
+}
+
+/* ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+   just like if it has been actually received from a hw source. Also
+   works for virtual interrupts. */
+
+int ipipe_trigger_irq(unsigned irq)
+{
+	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);
+
+	regs.msr = flags;
+
+	__ipipe_handle_irq(irq | IPIPE_IRQ_ACKED, &regs);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+EXPORT_SYMBOL(__ipipe_sync_stage);
+EXPORT_SYMBOL(__ipipe_decr_ticks);
+EXPORT_SYMBOL(__ipipe_decr_next);
+EXPORT_SYMBOL(ipipe_critical_enter);
+EXPORT_SYMBOL(ipipe_critical_exit);
+EXPORT_SYMBOL(ipipe_trigger_irq);
diff -uNrp 2.6.12/arch/ppc/kernel/ipipe-root.c 2.6.12-ipipe-0.9/arch/ppc/kernel/ipipe-root.c
--- 2.6.12/arch/ppc/kernel/ipipe-root.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/arch/ppc/kernel/ipipe-root.c	2005-07-03 22:15:00.000000000 +0200
@@ -0,0 +1,360 @@
+/*   -*- linux-c -*-
+ *   linux/arch/ppc/kernel/ipipe-root.c
+ *
+ *   Copyright (C) 2002-2005 Philippe Gerum (Adeos/ppc port over 2.6).
+ *   Copyright (C) 2004 Wolfgang Grandegger (Adeos/ppc port over 2.4).
+ *
+ *   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 PowerPC.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+extern irq_desc_t irq_desc[];
+
+static struct hw_interrupt_type __ipipe_std_irq_dtype[NR_IRQS];
+
+static void __ipipe_override_irq_enable(unsigned irq)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+	ipipe_irq_unlock(irq);
+	__ipipe_std_irq_dtype[irq].enable(irq);
+	local_irq_restore_hw(flags);
+}
+
+static void __ipipe_override_irq_disable(unsigned irq)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+	ipipe_irq_lock(irq);
+	__ipipe_std_irq_dtype[irq].disable(irq);
+	local_irq_restore_hw(flags);
+}
+
+static void __ipipe_override_irq_end(unsigned irq)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		ipipe_irq_unlock(irq);
+
+	__ipipe_std_irq_dtype[irq].end(irq);
+
+	local_irq_restore_hw(flags);
+}
+
+static void __ipipe_override_irq_affinity(unsigned irq, cpumask_t mask)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+	__ipipe_std_irq_dtype[irq].set_affinity(irq, mask);
+	local_irq_restore_hw(flags);
+}
+
+static void __ipipe_enable_sync(void)
+{
+	__ipipe_decr_next[ipipe_processor_id()] =
+	    __ipipe_read_timebase() + get_dec();
+}
+
+/* __ipipe_enable_pipeline() -- We are running on the boot CPU, hw
+   interrupts are off, and secondary CPUs are still lost in space. */
+
+void __ipipe_enable_pipeline(void)
+{
+	unsigned long flags;
+	unsigned irq;
+
+	flags = ipipe_critical_enter(&__ipipe_enable_sync);
+
+	/* First, virtualize all interrupts from the root domain. */
+
+	for (irq = 0; irq < NR_IRQS; irq++)
+		ipipe_virtualize_irq(ipipe_root_domain,
+				     irq,
+				     (void (*)(unsigned))&__ipipe_do_IRQ,
+				     &__ipipe_ack_irq,
+				     IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	/* We use a virtual IRQ to handle the timer irq (decrementer trap)
+	   which has been allocated early in __ipipe_init_platform(). */
+
+	ipipe_virtualize_irq(ipipe_root_domain,
+			     IPIPE_TIMER_VIRQ,
+			     (void (*)(unsigned))&__ipipe_do_timer,
+			     NULL, IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	/* Interpose on the IRQ control routines so we can make them
+	   atomic using hw masking and prevent the interrupt log from
+	   being untimely flushed. */
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		if (irq_desc[irq].handler != NULL)
+			__ipipe_std_irq_dtype[irq] = *irq_desc[irq].handler;
+	}
+
+	/* The original controller structs are often shared, so we first
+	   save them all before changing any of them. Notice that we don't
+	   override the ack() handler since we will enforce the necessary
+	   setup in __ipipe_ack_irq(). */
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		struct hw_interrupt_type *handler = irq_desc[irq].handler;
+
+		if (handler == NULL)
+			continue;
+
+		if (handler->enable != NULL)
+			handler->enable = &__ipipe_override_irq_enable;
+
+		if (handler->disable != NULL)
+			handler->disable = &__ipipe_override_irq_disable;
+
+		if (handler->end != NULL)
+			handler->end = &__ipipe_override_irq_end;
+
+		if (handler->set_affinity != NULL)
+			handler->set_affinity = &__ipipe_override_irq_affinity;
+	}
+
+	__ipipe_decr_next[ipipe_processor_id()] =
+	    __ipipe_read_timebase() + get_dec();
+
+	ipipe_critical_exit(flags);
+}
+
+/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw
+   acknowledge routine) to an interrupt for the given domain. */
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 void (*handler) (unsigned irq),
+			 int (*acknowledge) (unsigned irq), 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) {
+		/* A bit of hack here: if we are re-virtualizing an IRQ just
+		   to change the acknowledge routine by passing the special
+		   IPIPE_SAME_HANDLER value, then allow to recycle the current
+		   handler for the IRQ. This allows Linux device drivers
+		   managing shared IRQ lines to call ipipe_virtualize_irq() in
+		   addition to request_irq() just for the purpose of
+		   interposing their own shared acknowledge routine. */
+
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = ipd->irqs[irq].handler;
+
+			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].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;
+		}
+
+		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)
+{
+	irq_desc_t *desc;
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	if (ipipe_current_domain->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (((setmask | clrmask) & IPIPE_SHARED_MASK) != 0)
+		return -EINVAL;
+
+	desc = irq_desc + irq;
+
+	if (ipipe_current_domain->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);
+
+	ipipe_current_domain->irqs[irq].control &= ~clrmask;
+	ipipe_current_domain->irqs[irq].control |= setmask;
+
+	if ((setmask & IPIPE_ENABLE_MASK) != 0)
+		enable_irq(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		disable_irq(irq);
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+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 */
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = IPIPE_TIMER_VIRQ;
+	info->archdep.tmfreq = info->cpufreq;
+
+	return 0;
+}
+
+static void __ipipe_set_decr(void)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	disarm_decr[cpuid] = (__ipipe_decr_ticks != tb_ticks_per_jiffy);
+#ifdef CONFIG_40x
+	/* Enable and set auto-reload. */
+	mtspr(SPRN_TCR, mfspr(SPRN_TCR) | TCR_ARE);
+	mtspr(SPRN_PIT, __ipipe_decr_ticks);
+#else	/* !CONFIG_40x */
+	__ipipe_decr_next[cpuid] = __ipipe_read_timebase() + __ipipe_decr_ticks;
+	set_dec(__ipipe_decr_ticks);
+#endif	/* CONFIG_40x */
+}
+
+int ipipe_tune_timer(unsigned long ns, int flags)
+{
+	unsigned long x, ticks;
+
+	if (flags & IPIPE_RESET_TIMER)
+		ticks = tb_ticks_per_jiffy;
+	else {
+		ticks = ns * tb_ticks_per_jiffy / (1000000000 / HZ);
+
+		if (ticks > tb_ticks_per_jiffy)
+			return -EINVAL;
+	}
+
+	x = ipipe_critical_enter(&__ipipe_set_decr);	/* Sync with all CPUs */
+	__ipipe_decr_ticks = ticks;
+	__ipipe_set_decr();
+	ipipe_critical_exit(x);
+
+	return 0;
+}
diff -uNrp 2.6.12/arch/ppc/platforms/pmac_pic.c 2.6.12-ipipe-0.9/arch/ppc/platforms/pmac_pic.c
--- 2.6.12/arch/ppc/platforms/pmac_pic.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/arch/ppc/platforms/pmac_pic.c	2005-06-30 10:48:27.000000000 +0200
@@ -387,7 +387,7 @@ static irqreturn_t k2u3_action(int cpl, 
 	return IRQ_HANDLED;
 }
 
-static struct irqaction k2u3_cascade_action = {
+struct irqaction k2u3_cascade_action = {
 	.handler	= k2u3_action,
 	.flags		= 0,
 	.mask		= CPU_MASK_NONE,
diff -uNrp 2.6.12/include/asm-i386/apic.h 2.6.12-ipipe-0.9/include/asm-i386/apic.h
--- 2.6.12/include/asm-i386/apic.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/apic.h	2005-06-27 18:44:46.000000000 +0200
@@ -69,7 +69,13 @@ int get_physical_broadcast(void);
 # define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
+#ifdef CONFIG_IPIPE
+#define ack_APIC_irq() do { } while(0)
+static inline void __ack_APIC_irq(void)
+#else /* !CONFIG_IPIPE */
+#define __ack_APIC_irq() ack_APIC_irq()
 static inline void ack_APIC_irq(void)
+#endif /* CONFIG_IPIPE */
 {
 	/*
 	 * ack_APIC_irq() actually gets compiled as a single instruction:
diff -uNrp 2.6.12/include/asm-i386/io_apic.h 2.6.12-ipipe-0.9/include/asm-i386/io_apic.h
--- 2.6.12/include/asm-i386/io_apic.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/io_apic.h	2005-06-27 18:44:46.000000000 +0200
@@ -16,7 +16,9 @@
 #ifdef CONFIG_PCI_MSI
 static inline int use_pci_vector(void)	{return 1;}
 static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+#ifndef CONFIG_IPIPE
 static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+#endif /* !CONFIG_IPIPE */
 static inline void end_edge_ioapic_vector (unsigned int vector) { }
 #define startup_level_ioapic	startup_level_ioapic_vector
 #define shutdown_level_ioapic	mask_IO_APIC_vector
@@ -35,7 +37,9 @@ static inline void end_edge_ioapic_vecto
 #else
 static inline int use_pci_vector(void)	{return 0;}
 static inline void disable_edge_ioapic_irq(unsigned int irq) { }
+#ifndef CONFIG_IPIPE
 static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
+#endif /* !CONFIG_IPIPE */
 static inline void end_edge_ioapic_irq (unsigned int irq) { }
 #define startup_level_ioapic	startup_level_ioapic_irq
 #define shutdown_level_ioapic	mask_IO_APIC_irq
diff -uNrp 2.6.12/include/asm-i386/ipipe.h 2.6.12-ipipe-0.9/include/asm-i386/ipipe.h
--- 2.6.12/include/asm-i386/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/include/asm-i386/ipipe.h	2005-08-07 11:57:28.000000000 +0200
@@ -0,0 +1,164 @@
+/*   -*- linux-c -*-
+ *   include/asm-i386/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 __I386_IPIPE_H
+#define __I386_IPIPE_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IPIPE
+
+#include <irq_vectors.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/* We want to cover the whole IRQ space when the APIC is enabled. */
+#ifdef CONFIG_PCI_MSI
+#define IPIPE_NR_XIRQS NR_IRQS
+#else	/* CONFIG_PCI_MSI */
+#define IPIPE_NR_XIRQS   224
+#endif	/* CONFIG_PCI_MSI */
+#else	/* !CONFIG_X86_LOCAL_APIC */
+#define IPIPE_NR_XIRQS   NR_IRQS
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+#define IPIPE_IRQ_ISHIFT  	5	/* 2^5 for 32bits arch. */
+#define NR_XIRQS		IPIPE_NR_XIRQS
+
+#ifndef __ASSEMBLY__
+
+#include <linux/cpumask.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+#include <asm/ptrace.h>
+
+#ifdef CONFIG_SMP
+
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#include <mach_apicdef.h>
+#include <linux/thread_info.h>
+
+#define IPIPE_NR_CPUS          NR_CPUS
+#define IPIPE_CRITICAL_VECTOR  0xf9	/* Used by ipipe_critical_enter/exit() */
+#define IPIPE_CRITICAL_IPI     (IPIPE_CRITICAL_VECTOR - FIRST_EXTERNAL_VECTOR)
+
+#define ipipe_processor_id()   (current_thread_info()->cpu)
+
+#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_processor_id()    0
+#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 { flags = flags; } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#define ipipe_current_domain    (ipipe_percpu_domain[0])
+
+#endif	/* CONFIG_SMP */
+
+#define prepare_arch_switch(rq, next)	do { } while (0)
+#define finish_arch_switch(rq, prev)	do {	\
+	__clear_bit(IPIPE_SYNC_FLAG,&ipipe_root_domain->cpudata[task_cpu(prev)].status); \
+	spin_unlock_irq(&(rq)->lock);		\
+} while(0)
+#define task_running(rq, p)		((rq)->curr == (p))
+
+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_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+#define ipipe_hw_save_flags_and_sti(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#define local_irq_disable_hw() 			__asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable_hw()			__asm__ __volatile__("sti": : :"memory")
+#define local_irq_save_hw(x)    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore_hw(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+#define local_save_flags_hw(x)   __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
+#define local_test_iflag_hw(x)   ((x) & (1<<9))
+#define irqs_disabled_hw()	\
+({					\
+	unsigned long flags;		\
+	local_save_flags_hw(flags);	\
+	!local_test_iflag_hw(flags);	\
+})
+
+#define ipipe_read_tsc(t)  __asm__ __volatile__("rdtsc" : "=A" (t))
+#define ipipe_cpu_freq() ({ unsigned long long __freq = cpu_has_tsc?(1000LL * cpu_khz):CLOCK_TICK_RATE; __freq; })
+
+/* Private interface -- Internal use only */
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+#define __ipipe_check_platform() do { } while(0)
+
+#define __ipipe_init_platform() do { } while(0)
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask);
+
+int __ipipe_ack_system_irq(unsigned irq);
+
+int __ipipe_handle_irq(struct pt_regs regs);
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+extern int __ipipe_tick_irq;
+
+#endif /* __ASSEMBLY__ */
+
+#else /* !CONFIG_IPIPE */
+
+#define NR_XIRQS NR_IRQS
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__I386_IPIPE_H */
diff -uNrp 2.6.12/include/asm-i386/mach-default/do_timer.h 2.6.12-ipipe-0.9/include/asm-i386/mach-default/do_timer.h
--- 2.6.12/include/asm-i386/mach-default/do_timer.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/mach-default/do_timer.h	2005-06-27 18:44:46.000000000 +0200
@@ -49,14 +49,15 @@ static inline void do_timer_interrupt_ho
 static inline int do_timer_overflow(int count)
 {
 	int i;
+	unsigned long flags;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp 2.6.12/include/asm-i386/mach-visws/do_timer.h 2.6.12-ipipe-0.9/include/asm-i386/mach-visws/do_timer.h
--- 2.6.12/include/asm-i386/mach-visws/do_timer.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/mach-visws/do_timer.h	2005-06-27 18:44:46.000000000 +0200
@@ -28,14 +28,15 @@ static inline void do_timer_interrupt_ho
 static inline int do_timer_overflow(int count)
 {
 	int i;
+	unsigned long flags;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp 2.6.12/include/asm-i386/pgalloc.h 2.6.12-ipipe-0.9/include/asm-i386/pgalloc.h
--- 2.6.12/include/asm-i386/pgalloc.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/pgalloc.h	2005-08-21 20:44:27.000000000 +0200
@@ -47,4 +47,27 @@ static inline void pte_free(struct page 
 
 #define check_pgt_cache()	do { } while (0)
 
+static inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+#ifdef CONFIG_IPIPE
+	struct task_struct * p;
+	struct page *page;
+	pgd_t *pgd;
+
+	read_lock(&tasklist_lock);
+
+	for_each_process(p) {
+		if(p->mm) 
+		    *pgd_offset(p->mm,address) = entry;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	for (page = pgd_list; page; page = (struct page *)page->index) {
+		pgd = (pgd_t *)page_address(page);
+		pgd[address >> PGDIR_SHIFT] = entry;
+	}
+#endif /* CONFIG_IPIPE */
+}
+
 #endif /* _I386_PGALLOC_H */
diff -uNrp 2.6.12/include/asm-i386/spinlock.h 2.6.12-ipipe-0.9/include/asm-i386/spinlock.h
--- 2.6.12/include/asm-i386/spinlock.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/spinlock.h	2005-06-27 18:44:46.000000000 +0200
@@ -57,6 +57,9 @@ typedef struct {
 	"jmp 1b\n" \
 	"3:\n\t"
 
+#ifdef CONFIG_IPIPE
+#define spin_lock_string_flags spin_lock_string
+#else /* !CONFIG_IPIPE */
 #define spin_lock_string_flags \
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
@@ -72,6 +75,7 @@ typedef struct {
 	"cli\n\t" \
 	"jmp 1b\n" \
 	"4:\n\t"
+#endif /* CONFIG_IPIPE */
 
 /*
  * This works. Despite all the confusion.
diff -uNrp 2.6.12/include/asm-i386/system.h 2.6.12-ipipe-0.9/include/asm-i386/system.h
--- 2.6.12/include/asm-i386/system.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-i386/system.h	2005-06-27 18:44:46.000000000 +0200
@@ -441,6 +441,35 @@ struct alt_instr { 
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* interrupt control.. */
+#ifdef CONFIG_IPIPE
+
+#include <linux/linkage.h>
+
+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);
+
+#define local_save_flags(x)	((x) = __ipipe_test_root())
+#define local_irq_save(x)	((x) = __ipipe_test_and_stall_root())
+#define local_irq_restore(x)	__ipipe_restore_root(x)
+#define local_irq_disable()	__ipipe_stall_root()
+#define local_irq_enable()	__ipipe_unstall_root()
+
+#define irqs_disabled()		__ipipe_test_root()
+
+#define safe_halt() do { \
+    __ipipe_unstall_root(); \
+    __asm__ __volatile__("sti; hlt": : :"memory"); \
+} while(0)
+
+#else /* !CONFIG_IPIPE */
+
 #define local_save_flags(x)	do { typecheck(unsigned long,x); __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */); } while (0)
 #define local_irq_restore(x) 	do { typecheck(unsigned long,x); __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); } while (0)
 #define local_irq_disable() 	__asm__ __volatile__("cli": : :"memory")
@@ -458,6 +487,8 @@ struct alt_instr { 
 /* For spinlocks etc */
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 
+#endif /* CONFIG_IPIPE */
+
 /*
  * disable hlt during certain critical i/o operations
  */
diff -uNrp 2.6.12/include/asm-ia64/ipipe.h 2.6.12-ipipe-0.9/include/asm-ia64/ipipe.h
--- 2.6.12/include/asm-ia64/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/include/asm-ia64/ipipe.h	2005-08-03 10:28:40.000000000 +0200
@@ -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_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	6	/* 2^6 for 64 bits arch. */
+
+#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)
+
+#ifdef CONFIG_SMP
+
+#include <asm/smp.h>
+#include <asm/gcc_intrin.h>
+
+#define IPIPE_NR_CPUS          NR_CPUS
+#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)
+#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); \
+				  ia64_stop();			  \
+                                  (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_processor_id()    0
+#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 { flags = flags; } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#define ipipe_current_domain    (ipipe_percpu_domain[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_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+#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);		\
+	})
+
+#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
+
+/* Private interface -- Internal use only */
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+#define __ipipe_check_platform() do { } while(0)
+
+#define __ipipe_init_platform()	 do { } while(0)
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void __ipipe_sync_stage(unsigned long syncmask);
+
+int __ipipe_ack_system_irq(unsigned irq);
+
+void __ipipe_handle_irq(long irq,
+			struct pt_regs *regs);
+
+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[];
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__IA64_IPIPE_H */
diff -uNrp 2.6.12/include/asm-ia64/pgalloc.h 2.6.12-ipipe-0.9/include/asm-ia64/pgalloc.h
--- 2.6.12/include/asm-ia64/pgalloc.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-ia64/pgalloc.h	2005-07-04 12:55:55.000000000 +0200
@@ -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 */
diff -uNrp 2.6.12/include/asm-ia64/system.h 2.6.12-ipipe-0.9/include/asm-ia64/system.h
--- 2.6.12/include/asm-ia64/system.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-ia64/system.h	2005-07-04 12:49:03.000000000 +0200
@@ -121,6 +121,34 @@ 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())
+#define __local_irq_disable() 	__ipipe_stall_root()
+#define __local_irq_restore(x)	__ipipe_restore_root(x)
+
+#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())
+
+#define irqs_disabled()		__ipipe_test_root()
+
+#else /* !CONFIG_IPIPE */
+
 #define __local_irq_save(x)			\
 do {						\
 	ia64_stop();				\
@@ -181,6 +209,8 @@ do {								\
 	(__ia64_id_flags & IA64_PSR_I) == 0;	\
 })
 
+#endif /* CONFIG_IPIPE */
+
 #ifdef __KERNEL__
 
 #define prepare_to_switch()    do { } while(0)
@@ -274,12 +304,27 @@ extern void ia64_load_extra (struct task
  * of that CPU which will not be released, because there we wait for the
  * tasklist_lock to become available.
  */
+#ifdef CONFIG_IPIPE
+#define prepare_arch_switch(rq, next)		\
+    do {					\
+	spin_lock(&(next)->switch_lock);	\
+	spin_unlock(&(rq)->lock);		\
+	local_irq_disable_hw();			\
+    } while (0)
+#define finish_arch_switch(rq, prev)		\
+    do {					\
+	__clear_bit(IPIPE_SYNC_FLAG,&ipipe_root_domain->cpudata[task_cpu(prev)].status); \
+	local_irq_enable_hw(); \
+    	spin_unlock_irq(&(prev)->switch_lock);	\
+    } while(0)
+#else /* !CONFIG_IPIPE */
 #define prepare_arch_switch(rq, next)		\
 do {						\
 	spin_lock(&(next)->switch_lock);	\
 	spin_unlock(&(rq)->lock);		\
 } while (0)
 #define finish_arch_switch(rq, prev)	spin_unlock_irq(&(prev)->switch_lock)
+#endif /* CONFIG_IPIPE */
 #define task_running(rq, p) 		((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
 
 #define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
diff -uNrp 2.6.12/include/asm-ppc/hw_irq.h 2.6.12-ipipe-0.9/include/asm-ppc/hw_irq.h
--- 2.6.12/include/asm-ppc/hw_irq.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-ppc/hw_irq.h	2005-06-30 10:51:07.000000000 +0200
@@ -12,6 +12,37 @@ extern void timer_interrupt(struct pt_re
 
 #define INLINE_IRQS
 
+#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 irqs_disabled()  __ipipe_test_root()
+
+static inline void local_irq_disable(void) {
+    __ipipe_stall_root();
+}
+
+static inline void local_irq_enable(void) {
+    __ipipe_unstall_root();
+}
+
+static inline void local_irq_save_ptr(unsigned long *flags) {
+    *flags = __ipipe_test_and_stall_root();
+}
+
+static inline void local_irq_restore(unsigned long flags) {
+    __ipipe_restore_root(flags);
+}
+
+#define local_save_flags(flags)		((flags) = __ipipe_test_root())
+#define local_irq_save(flags)		local_irq_save_ptr(&flags)
+
+#else /* !CONFIG_IPIPE */
+
 #define irqs_disabled()	((mfmsr() & MSR_EE) == 0)
 
 #ifdef INLINE_IRQS
@@ -57,6 +88,8 @@ extern void local_save_flags_ptr(unsigne
 
 #endif
 
+#endif /* CONFIG_IPIPE */
+
 extern void do_lost_interrupts(unsigned long);
 
 #define mask_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->disable) irq_desc[irq].handler->disable(irq);})
diff -uNrp 2.6.12/include/asm-ppc/ipipe.h 2.6.12-ipipe-0.9/include/asm-ppc/ipipe.h
--- 2.6.12/include/asm-ppc/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/include/asm-ppc/ipipe.h	2005-08-03 10:28:32.000000000 +0200
@@ -0,0 +1,186 @@
+/*   -*- linux-c -*-
+ *   include/asm-ppc/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 __PPC_IPIPE_H
+#define __PPC_IPIPE_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IPIPE
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <linux/list.h>
+#include <linux/cpumask.h>
+#include <linux/threads.h>
+
+#define IPIPE_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	5	/* 2^5 for 32bits arch. */
+
+/* The first virtual interrupt is reserved for the timer (see
+   __ipipe_init_platform). */
+#define IPIPE_TIMER_VIRQ	IPIPE_VIRQ_BASE
+#define IPIPE_IRQ_ACKED		0x1000
+#define IPIPE_IRQ_ACKED_MASK	(IPIPE_IRQ_ACKED - 1)
+
+#ifdef CONFIG_SMP
+
+#error "I-pipe/ppc: SMP not yet implemented"
+
+#define IPIPE_NR_CPUS          NR_CPUS
+
+#define ipipe_processor_id()   (current_thread_info()->cpu)
+
+#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_processor_id()    0
+#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 { flags = flags; } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#define ipipe_current_domain    (ipipe_percpu_domain[0])
+
+#endif	/* CONFIG_SMP */
+
+#define prepare_arch_switch(rq, next)	do { local_irq_disable_hw(); } while (0)
+#define finish_arch_switch(rq, prev)	do {	\
+	__clear_bit(IPIPE_SYNC_FLAG,&ipipe_root_domain->cpudata[task_cpu(prev)].status); \
+	local_irq_enable_hw(); \
+	spin_unlock_irq(&(rq)->lock);		\
+} while(0)
+#define task_running(rq, p)		((rq)->curr == (p))
+
+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_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+static inline void local_irq_disable_hw(void)
+{
+	unsigned long msr;
+	msr = mfmsr();
+	mtmsr(msr & ~MSR_EE);
+	__asm__ __volatile__("": : :"memory");
+}
+
+static inline void local_irq_enable_hw(void)
+{
+	unsigned long msr;
+	__asm__ __volatile__("": : :"memory");
+	msr = mfmsr();
+	mtmsr(msr | MSR_EE);
+}
+
+static inline void local_irq_save_ptr_hw(unsigned long *flags)
+{
+	unsigned long msr;
+	msr = mfmsr();
+	*flags = msr;
+	mtmsr(msr & ~MSR_EE);
+	__asm__ __volatile__("": : :"memory");
+}
+
+#define local_save_flags_hw(flags)	((flags) = mfmsr())
+#define local_irq_save_hw(flags)	local_irq_save_ptr_hw(&flags)
+#define local_irq_restore_hw(flags)	mtmsr(flags)
+#define local_test_iflag_hw(x)   	((x) & MSR_EE)
+#define irqs_disabled_hw()		((mfmsr() & MSR_EE) == 0)
+
+#define ipipe_read_tsc(t) \
+   ({ unsigned long __tbu; \
+   __asm__ __volatile__ ("1: mftbu %0\n" \
+			 "mftb %1\n" \
+			 "mftbu %2\n" \
+			 "cmpw %2,%0\n" \
+			 "bne- 1b\n" \
+			 :"=r" (((unsigned long *)&t)[0]), \
+			 "=r" (((unsigned long *)&t)[1]), \
+			 "=r" (__tbu)); \
+   t; })
+
+#define __ipipe_read_timebase() ({ unsigned long long t; ipipe_read_tsc(t); t; })
+
+extern unsigned tb_ticks_per_jiffy;
+#define ipipe_cpu_freq() (HZ * tb_ticks_per_jiffy)
+
+/* Private interface -- Internal use only */
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+#define __ipipe_check_platform() do { } while(0)
+
+void __ipipe_init_platform(void);
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void __ipipe_sync_stage(unsigned long syncmask);
+
+int __ipipe_ack_irq(unsigned irq);
+
+void __ipipe_do_IRQ(int irq,
+		    struct pt_regs *regs);
+
+void __ipipe_do_timer(int irq,
+		      struct pt_regs *regs);
+
+extern unsigned long __ipipe_decr_ticks;
+
+extern unsigned long long __ipipe_decr_next[];
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+#define __ipipe_tick_irq  IPIPE_TIMER_VIRQ
+
+#endif /* CONFIG_IPIPE */
+
+#endif	/* !__PPC_IPIPE_H */
diff -uNrp 2.6.12/include/asm-ppc/pgalloc.h 2.6.12-ipipe-0.9/include/asm-ppc/pgalloc.h
--- 2.6.12/include/asm-ppc/pgalloc.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/asm-ppc/pgalloc.h	2005-06-30 11:25:21.000000000 +0200
@@ -40,5 +40,10 @@ extern void pte_free(struct page *pte);
 
 #define check_pgt_cache()	do { } while (0)
 
+static inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+    /* nop */
+}
+
 #endif /* _PPC_PGALLOC_H */
 #endif /* __KERNEL__ */
diff -uNrp 2.6.12/include/linux/hardirq.h 2.6.12-ipipe-0.9/include/linux/hardirq.h
--- 2.6.12/include/linux/hardirq.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/linux/hardirq.h	2005-06-27 18:44:46.000000000 +0200
@@ -86,8 +86,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)
diff -uNrp 2.6.12/include/linux/ipipe.h 2.6.12-ipipe-0.9/include/linux/ipipe.h
--- 2.6.12/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/include/linux/ipipe.h	2005-08-21 20:28:57.000000000 +0200
@@ -0,0 +1,537 @@
+/*   -*- 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 <asm/ipipe.h>
+
+#ifdef CONFIG_IPIPE
+
+#define IPIPE_ARCH_STRING     "0.9-03"
+#define IPIPE_MAJOR_NUMBER    0
+#define IPIPE_MINOR_NUMBER    9
+#define IPIPE_PATCH_NUMBER    3
+
+#define IPIPE_VERSION_STRING  IPIPE_ARCH_STRING
+#define IPIPE_RELEASE_NUMBER  ((IPIPE_MAJOR_NUMBER<<16)|(IPIPE_MINOR_NUMBER<<8)|(IPIPE_PATCH_NUMBER))
+
+#define IPIPE_ROOT_PRIO      100
+#define IPIPE_ROOT_ID        0
+
+#define IPIPE_RESET_TIMER    0x1
+#define IPIPE_GRAB_TIMER     0x2
+#define IPIPE_SAME_HANDLER   ((void (*)(unsigned))(-1))
+
+/* Global domain flags */
+#define IPIPE_SPRINTK_FLAG 0	/* Synchronous printk() allowed */
+#define IPIPE_PPRINTK_FLAG 1	/* Asynchronous printk() request pending */
+
+#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_EXCLUSIVE_FLAG 3
+#define IPIPE_STICKY_FLAG    4
+#define IPIPE_SYSTEM_FLAG    5
+#define IPIPE_LOCK_FLAG      6
+#define IPIPE_SHARED_FLAG    7
+
+#define IPIPE_HANDLE_MASK    (1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK      (1 << IPIPE_PASS_FLAG)
+#define IPIPE_ENABLE_MASK    (1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK   IPIPE_HANDLE_MASK
+#define IPIPE_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)
+
+/* 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))
+
+struct ipipe_domain {
+
+	struct list_head p_link;	/* Link in pipeline */
+
+	struct ipcpudata {
+		volatile unsigned long status;
+		volatile unsigned long irq_pending_hi;
+		volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+		volatile unsigned irq_hits[IPIPE_NR_IRQS];
+	} cpudata[IPIPE_NR_CPUS];
+
+	struct {
+		int (*acknowledge) (unsigned irq);
+		void (*handler) (unsigned irq);
+		unsigned long control;
+	} irqs[IPIPE_NR_IRQS];
+
+	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_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_hits[irq] > 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_hits[irq] = 0; \
+       __ipipe_clear_pend(ipd,__cpuid,irq); \
+    } \
+} while(0)
+
+#ifdef CONFIG_IPIPE_PREEMPT_RT
+/* We are over a combo I-pipe+PREEMPT_RT _patched_ kernel, but
+   CONFIG_PREEMPT_RT is not necessarily enabled; use the raw spinlock
+   support for the I-pipe. */
+#define spin_lock_hw(x)     __raw_spin_lock(x)
+#define spin_unlock_hw(x)   __raw_spin_unlock(x)
+#define spin_trylock_hw(x)  __raw_spin_trylock(x)
+#define write_lock_hw(x)    __raw_write_lock(x)
+#define write_unlock_hw(x)  __raw_write_unlock(x)
+#define write_trylock_hw(x) __raw_write_trylock(x)
+#define read_lock_hw(x)     __raw_read_lock(x)
+#define read_unlock_hw(x)   __raw_read_unlock(x)
+#else	/* !CONFIG_IPIPE_PREEMPT_RT */
+#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)
+#define raw_spinlock_t         spinlock_t
+#define RAW_SPIN_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED
+#define raw_rwlock_t           rwlock_t
+#define RAW_RW_LOCK_UNLOCKED   RW_LOCK_UNLOCKED
+#endif	/* CONFIG_IPIPE_PREEMPT_RT */
+
+#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 raw_spinlock_t __ipipe_pipelock;
+
+/* Private interface */
+
+void ipipe_init(void);
+
+#ifdef CONFIG_PROC_FS
+void ipipe_init_proc(void);
+#endif	/* CONFIG_PROC_FS */
+
+void __ipipe_flush_printk(unsigned irq);
+
+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);
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+/* 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;
+}
+
+/* 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,
+			 void (*handler) (unsigned irq),
+			 int (*acknowledge) (unsigned irq),
+			 unsigned modemask);
+
+static inline int ipipe_share_irq(unsigned irq,
+				  int (*acknowledge) (unsigned irq))
+{
+	return ipipe_virtualize_irq(ipipe_current_domain,
+				    irq,
+				    IPIPE_SAME_HANDLER,
+				    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);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+}
+
+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);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	s = test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+
+	return s;
+}
+
+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);
+	else
+		__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+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);
+}
+
+#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_init_proc()         do { } while(0)
+
+#define spin_lock_hw(lock)                    spin_lock(lock)
+#define spin_unlock_hw(lock)                  spin_unlock(lock)
+#define spin_lock_irq_hw(lock)                spin_lock_irq(lock)
+#define spin_unlock_irq_hw(lock)              spin_unlock_irq(lock)
+#define spin_lock_irqsave_hw(lock,flags)      spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) spin_unlock_irqrestore(lock, flags)
+#define local_irq_save_hw(flags)              local_irq_save(flags)
+#define local_irq_restore_hw(flags)           local_irq_restore(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 { flags = 0; /* Optimized out */ } while(0)
+#define local_irq_restore_hw_cond(flags)           do { } while(0)
+#define spin_lock_irqsave_hw_cond(lock,flags)      do { flags = 0; 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 */
diff -uNrp 2.6.12/include/linux/sched.h 2.6.12-ipipe-0.9/include/linux/sched.h
--- 2.6.12/include/linux/sched.h	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/include/linux/sched.h	2005-06-27 18:44:46.000000000 +0200
@@ -4,6 +4,7 @@
 #include <asm/param.h>	/* for HZ */
 
 #include <linux/config.h>
+#include <linux/ipipe.h>
 #include <linux/capability.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
diff -uNrp 2.6.12/init/Kconfig 2.6.12-ipipe-0.9/init/Kconfig
--- 2.6.12/init/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/init/Kconfig	2005-06-27 18:44:46.000000000 +0200
@@ -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.
diff -uNrp 2.6.12/init/main.c 2.6.12-ipipe-0.9/init/main.c
--- 2.6.12/init/main.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/init/main.c	2005-07-01 12:09:23.000000000 +0200
@@ -468,6 +468,9 @@ 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
diff -uNrp 2.6.12/kernel/Makefile 2.6.12-ipipe-0.9/kernel/Makefile
--- 2.6.12/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/kernel/Makefile	2005-06-30 10:18:10.000000000 +0200
@@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 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
diff -uNrp 2.6.12/kernel/ipipe/Kconfig 2.6.12-ipipe-0.9/kernel/ipipe/Kconfig
--- 2.6.12/kernel/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/kernel/ipipe/Kconfig	2005-06-27 18:44:46.000000000 +0200
@@ -0,0 +1,9 @@
+config IPIPE
+	bool "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
+
+config IPIPE_PREEMPT_RT
+	def_bool PREEMPT_NONE || PREEMPT_VOLUNTARY || PREEMPT_DESKTOP || PREEMPT_RT
diff -uNrp 2.6.12/kernel/ipipe/Makefile 2.6.12-ipipe-0.9/kernel/ipipe/Makefile
--- 2.6.12/kernel/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/kernel/ipipe/Makefile	2005-06-27 18:47:18.000000000 +0200
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_IPIPE)	+= core.o generic.o
diff -uNrp 2.6.12/kernel/ipipe/core.c 2.6.12-ipipe-0.9/kernel/ipipe/core.c
--- 2.6.12/kernel/ipipe/core.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/kernel/ipipe/core.c	2005-08-21 20:29:03.000000000 +0200
@@ -0,0 +1,443 @@
+/*   -*- 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>
+#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 };
+
+raw_spinlock_t __ipipe_pipelock = RAW_SPIN_LOCK_UNLOCKED;
+
+struct list_head __ipipe_pipeline;
+
+unsigned long __ipipe_virtual_irq_map = 0;
+
+unsigned __ipipe_printk_virq;
+
+/* 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();
+
+	__ipipe_printk_virq = ipipe_alloc_virq();	/* Cannot fail here. */
+	ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk;
+	ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+	ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+
+	__ipipe_enable_pipeline();
+
+	printk(KERN_INFO "I-pipe %s: pipeline enabled.\n",
+	       IPIPE_VERSION_STRING);
+}
+
+void __ipipe_stall_root(void)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags); /* Care for migration. */
+
+	set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+
+#ifdef CONFIG_SMP
+	if (!__ipipe_pipeline_head_p(ipipe_root_domain))
+		ipipe_put_cpu(flags);
+#else /* CONFIG_SMP */
+	if (__ipipe_pipeline_head_p(ipipe_root_domain))
+		local_irq_disable_hw();
+#endif /* CONFIG_SMP */
+}
+
+void __ipipe_unstall_root(void)
+{
+	ipipe_declare_cpuid;
+
+	local_irq_disable_hw();
+
+	ipipe_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+
+	if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0)
+		__ipipe_sync_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_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);
+
+	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);
+
+	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;
+}
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *ipipe_proc_entry;
+
+static int __ipipe_read_proc(char *page,
+			     char **start,
+			     off_t off, int count, int *eof, void *data)
+{
+	unsigned long ctlbits;
+	struct list_head *pos;
+	unsigned irq, _irq;
+	char *p = page;
+	int len;
+
+	p += sprintf(p, "[I-pipe v%s]\n\n", IPIPE_VERSION_STRING);
+
+	spin_lock(&__ipipe_pipelock);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+
+		struct ipipe_domain *ipd =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		p += sprintf(p, "%8s: priority=%d, id=0x%.8x\n",
+			     ipd->name, 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, "\tirq%u: ", irq);
+			else
+				p += sprintf(p, "\tirq%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;
+}
+
+void ipipe_init_proc(void)
+{
+
+	ipipe_proc_entry = create_proc_read_entry("ipipe",
+						  0444,
+						  NULL,
+						  &__ipipe_read_proc, NULL);
+}
+
+#endif	/* CONFIG_PROC_FS */
+
+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_pipeline);
+EXPORT_SYMBOL(__ipipe_pipelock);
+EXPORT_SYMBOL(__ipipe_virtual_irq_map);
diff -uNrp 2.6.12/kernel/ipipe/generic.c 2.6.12-ipipe-0.9/kernel/ipipe/generic.c
--- 2.6.12/kernel/ipipe/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.12-ipipe-0.9/kernel/ipipe/generic.c	2005-08-21 20:29:08.000000000 +0200
@@ -0,0 +1,240 @@
+/*   -*- 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>
+#include <linux/irq.h>
+
+MODULE_DESCRIPTION("I-pipe");
+MODULE_LICENSE("GPL");
+
+/* 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;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+
+	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_hits[irq] > 0)
+					cpu_relax();
+	}
+#endif	/* CONFIG_SMP */
+
+	/* 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_hits[irq]++;
+			__ipipe_set_irq_bit(ipd, cpuid, irq);
+			ipipe_unlock_cpu(flags);
+			return 1;
+		}
+
+		ln = ipd->p_link.next;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return 0;
+}
+
+/* ipipe_free_virq() -- Release a virtual/soft interrupt. */
+
+int ipipe_free_virq(unsigned virq)
+{
+	if (!ipipe_virtual_irq_p(virq))
+		return -EINVAL;
+
+	clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map);
+
+	return 0;
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr)
+{
+	attr->name = "anon";
+	attr->domid = 1;
+	attr->entry = NULL;
+	attr->priority = IPIPE_ROOT_PRIO;
+	attr->pdd = NULL;
+}
+
+EXPORT_SYMBOL(ipipe_register_domain);
+EXPORT_SYMBOL(ipipe_unregister_domain);
+EXPORT_SYMBOL(ipipe_virtualize_irq);
+EXPORT_SYMBOL(ipipe_control_irq);
+EXPORT_SYMBOL(ipipe_free_virq);
+EXPORT_SYMBOL(ipipe_init_attr);
+EXPORT_SYMBOL(ipipe_get_sysinfo);
+EXPORT_SYMBOL(ipipe_tune_timer);
+EXPORT_SYMBOL(__ipipe_schedule_irq);
diff -uNrp 2.6.12/kernel/irq/handle.c 2.6.12-ipipe-0.9/kernel/irq/handle.c
--- 2.6.12/kernel/irq/handle.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/kernel/irq/handle.c	2005-06-28 12:02:37.000000000 +0200
@@ -81,6 +81,15 @@ 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 +126,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
diff -uNrp 2.6.12/kernel/printk.c 2.6.12-ipipe-0.9/kernel/printk.c
--- 2.6.12/kernel/printk.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/kernel/printk.c	2005-07-14 16:57:14.000000000 +0200
@@ -502,6 +502,66 @@ __setup("time", printk_time_setup);
  * is inspected when the actual printing occurs.
  */
 
+#ifdef CONFIG_IPIPE
+
+static raw_spinlock_t __ipipe_printk_lock = RAW_SPIN_LOCK_UNLOCKED;
+
+static int __ipipe_printk_fill;
+
+static char __ipipe_printk_buf[__LOG_BUF_LEN];
+
+void __ipipe_flush_printk (unsigned virq)
+{
+	char *p = __ipipe_printk_buf;
+	int out = 0, len;
+
+	clear_bit(IPIPE_PPRINTK_FLAG,&ipipe_root_domain->flags);
+
+	while (out < __ipipe_printk_fill) {
+		len = strlen(p) + 1;
+		printk("%s",p);
+		p += len;
+		out += len;
+	}
+	__ipipe_printk_fill = 0;
+}
+
+asmlinkage int printk(const char *fmt, ...)
+{
+	unsigned long flags;
+	int r, fbytes;
+	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);
+
+	fbytes = __LOG_BUF_LEN - __ipipe_printk_fill;
+
+	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 (!test_and_set_bit(IPIPE_PPRINTK_FLAG,&ipipe_root_domain->flags))
+		ipipe_trigger_irq(__ipipe_printk_virq);
+out: 
+	va_end(args);
+
+	return r;
+}
+#else /* !CONFIG_IPIPE */
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
@@ -513,6 +573,7 @@ asmlinkage int printk(const char *fmt, .
 
 	return r;
 }
+#endif /* CONFIG_IPIPE */
 
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
diff -uNrp 2.6.12/kernel/sched.c 2.6.12-ipipe-0.9/kernel/sched.c
--- 2.6.12/kernel/sched.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/kernel/sched.c	2005-06-28 13:12:32.000000000 +0200
@@ -2792,6 +2792,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..
diff -uNrp 2.6.12/kernel/sysctl.c 2.6.12-ipipe-0.9/kernel/sysctl.c
--- 2.6.12/kernel/sysctl.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/kernel/sysctl.c	2005-07-02 11:14:22.000000000 +0200
@@ -968,6 +968,7 @@ void __init sysctl_init(void)
 #ifdef CONFIG_PROC_FS
 	register_proc_table(root_table, proc_sys_root);
 	init_irq_proc();
+	ipipe_init_proc();
 #endif
 }
 
diff -uNrp 2.6.12/lib/kernel_lock.c 2.6.12-ipipe-0.9/lib/kernel_lock.c
--- 2.6.12/lib/kernel_lock.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/lib/kernel_lock.c	2005-06-27 18:44:46.000000000 +0200
@@ -20,6 +20,10 @@ unsigned int smp_processor_id(void)
 	unsigned long preempt_count = preempt_count();
 	int this_cpu = __smp_processor_id();
 	cpumask_t this_mask;
+#ifdef CONFIG_IPIPE
+	if (ipipe_current_domain != ipipe_root_domain)
+	    return this_cpu;
+#endif /* CONFIG_IPIPE */
 
 	if (likely(preempt_count))
 		goto out;
diff -uNrp 2.6.12/mm/vmalloc.c 2.6.12-ipipe-0.9/mm/vmalloc.c
--- 2.6.12/mm/vmalloc.c	2005-06-17 21:48:29.000000000 +0200
+++ 2.6.12-ipipe-0.9/mm/vmalloc.c	2005-06-27 18:44:46.000000000 +0200
@@ -18,6 +18,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -148,10 +149,13 @@ int map_vm_area(struct vm_struct *area, 
 	pgd = pgd_offset_k(addr);
 	spin_lock(&init_mm.page_table_lock);
 	do {
+		pgd_t oldpgd = *pgd;
 		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);
